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)
 901:       {
 902:         splitPane = (JSplitPane) c;
 903:         dividerLocationSet = false;
 904:         installDefaults();
 905:         installListeners();
 906:         installKeyboardActions();
 907:       }
 908:   }
 909: 
 910:   /**
 911:    * This method uninstalls the BasicSplitPaneUI for the given JComponent.
 912:    *
 913:    * @param c The JComponent to uninstall the UI for.
 914:    */
 915:   public void uninstallUI(JComponent c)
 916:   {
 917:     uninstallKeyboardActions();
 918:     uninstallListeners();
 919:     uninstallDefaults();
 920: 
 921:     dividerLocationSet = false;
 922:     splitPane = null;
 923:   }
 924: 
 925:   /**
 926:    * This method installs the defaults given by the Look and Feel.
 927:    */
 928:   protected void installDefaults()
 929:   {
 930:     LookAndFeel.installColors(splitPane, "SplitPane.background",
 931:                               "SplitPane.foreground");
 932:     LookAndFeel.installBorder(splitPane, "SplitPane.border");
 933:     divider = createDefaultDivider();
 934:     divider.setBorder(UIManager.getBorder("SplitPaneDivider.border"));
 935:     resetLayoutManager();
 936:     nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider();
 937:     splitPane.add(divider, JSplitPane.DIVIDER);
 938: 
 939:     // There is no need to add the nonContinuousLayoutDivider.
 940:     dividerSize = UIManager.getInt("SplitPane.dividerSize");
 941:     splitPane.setDividerSize(dividerSize);
 942:     divider.setDividerSize(dividerSize);
 943:     splitPane.setOpaque(true);
 944:   }
 945: 
 946:   /**
 947:    * This method uninstalls the defaults and nulls any objects created during
 948:    * install.
 949:    */
 950:   protected void uninstallDefaults()
 951:   {
 952:     layoutManager = null;
 953:     splitPane.remove(divider);
 954:     divider = null;
 955:     nonContinuousLayoutDivider = null;
 956: 
 957:     if (splitPane.getBackground() instanceof UIResource)
 958:       splitPane.setBackground(null);
 959:     if (splitPane.getBorder() instanceof UIResource)
 960:       splitPane.setBorder(null);
 961:   }
 962: 
 963:   /**
 964:    * This method installs the listeners needed for this UI to function.
 965:    */
 966:   protected void installListeners()
 967:   {
 968:     propertyChangeListener = createPropertyChangeListener();
 969:     focusListener = createFocusListener();
 970: 
 971:     splitPane.addPropertyChangeListener(propertyChangeListener);
 972:     splitPane.addFocusListener(focusListener);
 973:   }
 974: 
 975:   /**
 976:    * This method uninstalls all listeners registered for the UI.
 977:    */
 978:   protected void uninstallListeners()
 979:   {
 980:     splitPane.removePropertyChangeListener(propertyChangeListener);
 981:     splitPane.removeFocusListener(focusListener);
 982: 
 983:     focusListener = null;
 984:     propertyChangeListener = null;
 985:   }
 986: 
 987:   /**
 988:    * Returns the input map for the specified condition.
 989:    *
 990:    * @param condition  the condition.
 991:    *
 992:    * @return The input map.
 993:    */
 994:   InputMap getInputMap(int condition)
 995:   {
 996:     if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
 997:       return (InputMap) UIManager.get("SplitPane.ancestorInputMap");
 998:     return null;
 999:   }
1000: 
1001:   /**
1002:    * Returns the action map for the {@link JSplitPane}.  All sliders share
1003:    * a single action map which is created the first time this method is
1004:    * called, then stored in the UIDefaults table for subsequent access.
1005:    *
1006:    * @return The shared action map.
1007:    */
1008:   ActionMap getActionMap()
1009:   {
1010:     ActionMap map = (ActionMap) UIManager.get("SplitPane.actionMap");
1011: 
1012:     if (map == null) // first time here
1013:       {
1014:         map = createActionMap();
1015:         if (map != null)
1016:           UIManager.put("SplitPane.actionMap", map);
1017:       }
1018:     return map;
1019:   }
1020: 
1021:   /**
1022:    * Creates the action map shared by all {@link JSlider} instances.
1023:    * This method is called once by {@link #getActionMap()} when it
1024:    * finds no action map in the UIDefaults table...after the map is
1025:    * created, it gets added to the defaults table so that subsequent
1026:    * calls to {@link #getActionMap()} will return the same shared
1027:    * instance.
1028:    *
1029:    * @return The action map.
1030:    */
1031:   ActionMap createActionMap()
1032:   {
1033:     ActionMap map = new ActionMapUIResource();
1034:     map.put("toggleFocus",
1035:             new AbstractAction("toggleFocus") {
1036:               public void actionPerformed(ActionEvent event)
1037:               {
1038:                 // FIXME: What to do here?
1039:               }
1040:             }
1041:     );
1042:     map.put("startResize",
1043:             new AbstractAction("startResize") {
1044:               public void actionPerformed(ActionEvent event)
1045:               {
1046:                 splitPane.requestFocus();
1047:               }
1048:             }
1049:     );
1050:     map.put("selectMax",
1051:             new AbstractAction("selectMax") {
1052:               public void actionPerformed(ActionEvent event)
1053:               {
1054:                 splitPane.setDividerLocation(1.0);
1055:               }
1056:             }
1057:     );
1058:     map.put("selectMin",
1059:             new AbstractAction("selectMin") {
1060:               public void actionPerformed(ActionEvent event)
1061:               {
1062:                 splitPane.setDividerLocation(0.0);
1063:               }
1064:             }
1065:     );
1066:     map.put("negativeIncrement",
1067:             new AbstractAction("negativeIncrement") {
1068:               public void actionPerformed(ActionEvent event)
1069:               {
1070:                 int oldLoc = splitPane.getDividerLocation();
1071:                 int newLoc =
1072:                   Math.max(oldLoc - KEYBOARD_DIVIDER_MOVE_OFFSET, 0);
1073:                 splitPane.setDividerLocation(newLoc);
1074:               }
1075:             }
1076:     );
1077:     map.put("positiveIncrement",
1078:             new AbstractAction("positiveIncrement") {
1079:               public void actionPerformed(ActionEvent event)
1080:               {
1081:                 int oldLoc = splitPane.getDividerLocation();
1082:                 int newLoc =
1083:                   Math.max(oldLoc + KEYBOARD_DIVIDER_MOVE_OFFSET, 0);
1084:                 splitPane.setDividerLocation(newLoc);
1085:               }
1086:             }
1087:     );
1088:     map.put("focusOutBackward",
1089:             new AbstractAction("focusOutBackward") {
1090:               public void actionPerformed(ActionEvent event)
1091:               {
1092:                 // FIXME: implement this
1093:               }
1094:             }
1095:     );
1096:     map.put("focusOutForward",
1097:             new AbstractAction("focusOutForward") {
1098:               public void actionPerformed(ActionEvent event)
1099:               {
1100:                 // FIXME: implement this
1101:               }
1102:             }
1103:     );
1104:     return map;
1105:   }
1106: 
1107:   /**
1108:    * Installs any keyboard actions. The list of keys that need to be bound are
1109:    * listed in Basic look and feel's defaults.
1110:    */
1111:   protected void installKeyboardActions()
1112:   {
1113:     InputMap keyMap = getInputMap(
1114:         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
1115:     SwingUtilities.replaceUIInputMap(splitPane,
1116:         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap);
1117:     ActionMap map = getActionMap();
1118:     SwingUtilities.replaceUIActionMap(splitPane, map);
1119:   }
1120: 
1121:   /**
1122:    * This method reverses the work done in installKeyboardActions.
1123:    */
1124:   protected void uninstallKeyboardActions()
1125:   {
1126:     SwingUtilities.replaceUIActionMap(splitPane, null);
1127:     SwingUtilities.replaceUIInputMap(splitPane,
1128:         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
1129:   }
1130: 
1131:   /**
1132:    * This method creates a new PropertyChangeListener.
1133:    *
1134:    * @return A new PropertyChangeListener.
1135:    */
1136:   protected PropertyChangeListener createPropertyChangeListener()
1137:   {
1138:     return new PropertyHandler();
1139:   }
1140: 
1141:   /**
1142:    * This method creates a new FocusListener.
1143:    *
1144:    * @return A new FocusListener.
1145:    */
1146:   protected FocusListener createFocusListener()
1147:   {
1148:     return new FocusHandler();
1149:   }
1150: 
1151:   /**
1152:    * This method creates a new ActionListener for up and left key presses.
1153:    *
1154:    * @return A new ActionListener for up and left keys.
1155:    *
1156:    * @deprecated 1.3
1157:    */
1158:   protected ActionListener createKeyboardUpLeftListener()
1159:   {
1160:     return new KeyboardUpLeftHandler();
1161:   }
1162: 
1163:   /**
1164:    * This method creates a new ActionListener for down and right key presses.
1165:    *
1166:    * @return A new ActionListener for down and right keys.
1167:    *
1168:    * @deprecated 1.3
1169:    */
1170:   protected ActionListener createKeyboardDownRightListener()
1171:   {
1172:     return new KeyboardDownRightHandler();
1173:   }
1174: 
1175:   /**
1176:    * This method creates a new ActionListener for home key presses.
1177:    *
1178:    * @return A new ActionListener for home keys.
1179:    *
1180:    * @deprecated
1181:    */
1182:   protected ActionListener createKeyboardHomeListener()
1183:   {
1184:     return new KeyboardHomeHandler();
1185:   }
1186: 
1187:   /**
1188:    * This method creates a new ActionListener for end key presses.i
1189:    *
1190:    * @return A new ActionListener for end keys.
1191:    *
1192:    * @deprecated 1.3
1193:    */
1194:   protected ActionListener createKeyboardEndListener()
1195:   {
1196:     return new KeyboardEndHandler();
1197:   }
1198: 
1199:   /**
1200:    * This method creates a new ActionListener for resize toggle key events.
1201:    *
1202:    * @return A new ActionListener for resize toggle keys.
1203:    *
1204:    * @deprecated 1.3
1205:    */
1206:   protected ActionListener createKeyboardResizeToggleListener()
1207:   {
1208:     return new KeyboardResizeToggleHandler();
1209:   }
1210: 
1211:   /**
1212:    * This method returns the orientation of the JSplitPane.
1213:    *
1214:    * @return The orientation of the JSplitPane.
1215:    */
1216:   public int getOrientation()
1217:   {
1218:     return splitPane.getOrientation();
1219:   }
1220: 
1221:   /**
1222:    * This method sets the orientation of the JSplitPane.
1223:    *
1224:    * @param orientation The new orientation of the JSplitPane.
1225:    */
1226:   public void setOrientation(int orientation)
1227:   {
1228:     splitPane.setOrientation(orientation);
1229:   }
1230: 
1231:   /**
1232:    * This method returns true if the JSplitPane is using continuous layout.
1233:    *
1234:    * @return True if the JSplitPane is using continuous layout.
1235:    */
1236:   public boolean isContinuousLayout()
1237:   {
1238:     return splitPane.isContinuousLayout();
1239:   }
1240: 
1241:   /**
1242:    * This method sets the continuous layout property of the JSplitPane.
1243:    *
1244:    * @param b True if the JsplitPane is to use continuous layout.
1245:    */
1246:   public void setContinuousLayout(boolean b)
1247:   {
1248:     splitPane.setContinuousLayout(b);
1249:   }
1250: 
1251:   /**
1252:    * This method returns the last location the divider was dragged to.
1253:    *
1254:    * @return The last location the divider was dragged to.
1255:    */
1256:   public int getLastDragLocation()
1257:   {
1258:     return lastDragLocation;
1259:   }
1260: 
1261:   /**
1262:    * This method sets the last location the divider was dragged to.
1263:    *
1264:    * @param l The last location the divider was dragged to.
1265:    */
1266:   public void setLastDragLocation(int l)
1267:   {
1268:     lastDragLocation = l;
1269:   }
1270: 
1271:   /**
1272:    * This method returns the BasicSplitPaneDivider that divides this
1273:    * JSplitPane.
1274:    *
1275:    * @return The divider for the JSplitPane.
1276:    */
1277:   public BasicSplitPaneDivider getDivider()
1278:   {
1279:     return divider;
1280:   }
1281: 
1282:   /**
1283:    * This method creates a nonContinuousLayoutDivider for use with the
1284:    * JSplitPane in nonContinousLayout mode. The default divider is a gray
1285:    * Canvas.
1286:    *
1287:    * @return The default nonContinousLayoutDivider.
1288:    */
1289:   protected Component createDefaultNonContinuousLayoutDivider()
1290:   {
1291:     if (nonContinuousLayoutDivider == null)
1292:       {
1293:         nonContinuousLayoutDivider = new Canvas();
1294:         Color c = UIManager.getColor("SplitPaneDivider.draggingColor");
1295:         nonContinuousLayoutDivider.setBackground(c);
1296:       }
1297:     return nonContinuousLayoutDivider;
1298:   }
1299: 
1300:   /**
1301:    * This method sets the component to use as the nonContinuousLayoutDivider.
1302:    *
1303:    * @param newDivider The component to use as the nonContinuousLayoutDivider.
1304:    */
1305:   protected void setNonContinuousLayoutDivider(Component newDivider)
1306:   {
1307:     setNonContinuousLayoutDivider(newDivider, true);
1308:   }
1309: 
1310:   /**
1311:    * This method sets the component to use as the nonContinuousLayoutDivider.
1312:    *
1313:    * @param newDivider The component to use as the nonContinuousLayoutDivider.
1314:    * @param rememberSizes FIXME: document.
1315:    */
1316:   protected void setNonContinuousLayoutDivider(Component newDivider,
1317:                                                boolean rememberSizes)
1318:   {
1319:     // FIXME: use rememberSizes for something
1320:     nonContinuousLayoutDivider = newDivider;
1321:   }
1322: 
1323:   /**
1324:    * This method returns the nonContinuousLayoutDivider.
1325:    *
1326:    * @return The nonContinuousLayoutDivider.
1327:    */
1328:   public Component getNonContinuousLayoutDivider()
1329:   {
1330:     return nonContinuousLayoutDivider;
1331:   }
1332: 
1333:   /**
1334:    * This method returns the JSplitPane that this BasicSplitPaneUI draws.
1335:    *
1336:    * @return The JSplitPane.
1337:    */
1338:   public JSplitPane getSplitPane()
1339:   {
1340:     return splitPane;
1341:   }
1342: 
1343:   /**
1344:    * This method creates the divider used normally with the JSplitPane.
1345:    *
1346:    * @return The default divider.
1347:    */
1348:   public BasicSplitPaneDivider createDefaultDivider()
1349:   {
1350:     if (divider == null)
1351:       divider = new BasicSplitPaneDivider(this);
1352:     return divider;
1353:   }
1354: 
1355:   /**
1356:    * This method is called when JSplitPane's resetToPreferredSizes is called.
1357:    * It resets the sizes of all components in the JSplitPane.
1358:    *
1359:    * @param jc The JSplitPane to reset.
1360:    */
1361:   public void resetToPreferredSizes(JSplitPane jc)
1362:   {
1363:     layoutManager.resetToPreferredSizes();
1364:   }
1365: 
1366:   /**
1367:    * This method sets the location of the divider.
1368:    *
1369:    * @param jc The JSplitPane to set the divider location in.
1370:    * @param location The new location of the divider.
1371:    */
1372:   public void setDividerLocation(JSplitPane jc, int location)
1373:   {
1374:     dividerLocationSet = true;
1375:     splitPane.revalidate();
1376:     splitPane.repaint();
1377:   }
1378: 
1379:   /**
1380:    * This method returns the location of the divider.
1381:    *
1382:    * @param jc The JSplitPane to retrieve the location for.
1383:    *
1384:    * @return The location of the divider.
1385:    */
1386:   public int getDividerLocation(JSplitPane jc)
1387:   {
1388:     int loc;
1389:     if (jc.getOrientation() == JSplitPane.HORIZONTAL_SPLIT)
1390:       loc = divider.getX();
1391:     else
1392:       loc = divider.getY();
1393:     return loc;
1394:   }
1395: 
1396:   /**
1397:    * This method returns the smallest value possible for the location of the
1398:    * divider.
1399:    *
1400:    * @param jc The JSplitPane.
1401:    *
1402:    * @return The minimum divider location.
1403:    */
1404:   public int getMinimumDividerLocation(JSplitPane jc)
1405:   {
1406:     int value = layoutManager.getInitialLocation(jc.getInsets());
1407:     if (layoutManager.components[0] != null)
1408:       value += layoutManager.minimumSizeOfComponent(0);
1409:     return value;
1410:   }
1411: 
1412:   /**
1413:    * This method returns the largest value possible for the location of the
1414:    * divider.
1415:    *
1416:    * @param jc The JSplitPane.
1417:    *
1418:    * @return The maximum divider location.
1419:    */
1420:   public int getMaximumDividerLocation(JSplitPane jc)
1421:   {
1422:     int value = layoutManager.getInitialLocation(jc.getInsets())
1423:                 + layoutManager.getAvailableSize(jc.getSize(), jc.getInsets())
1424:                 - splitPane.getDividerSize();
1425:     if (layoutManager.components[1] != null)
1426:       value -= layoutManager.minimumSizeOfComponent(1);
1427:     return value;
1428:   }
1429: 
1430:   /**
1431:    * This method is called after the children of the JSplitPane are painted.
1432:    *
1433:    * @param jc The JSplitPane.
1434:    * @param g The Graphics object to paint with.
1435:    */
1436:   public void finishedPaintingChildren(JSplitPane jc, Graphics g)
1437:   {
1438:     if (! splitPane.isContinuousLayout() && nonContinuousLayoutDivider != null
1439:         && nonContinuousLayoutDivider.isVisible())
1440:       javax.swing.SwingUtilities.paintComponent(g, nonContinuousLayoutDivider,
1441:                                                 null,
1442:                                                 nonContinuousLayoutDivider
1443:                                                 .getBounds());
1444:   }
1445: 
1446:   /**
1447:    * This method is called to paint the JSplitPane.
1448:    *
1449:    * @param g The Graphics object to paint with.
1450:    * @param jc The JSplitPane to paint.
1451:    */
1452:   public void paint(Graphics g, JComponent jc)
1453:   {
1454:     // TODO: What should be done here?
1455:   }
1456: 
1457:   /**
1458:    * This method returns the preferred size of the JSplitPane.
1459:    *
1460:    * @param jc The JSplitPane.
1461:    *
1462:    * @return The preferred size of the JSplitPane.
1463:    */
1464:   public Dimension getPreferredSize(JComponent jc)
1465:   {
1466:     return layoutManager.preferredLayoutSize(jc);
1467:   }
1468: 
1469:   /**
1470:    * This method returns the minimum size of the JSplitPane.
1471:    *
1472:    * @param jc The JSplitPane.
1473:    *
1474:    * @return The minimum size of the JSplitPane.
1475:    */
1476:   public Dimension getMinimumSize(JComponent jc)
1477:   {
1478:     return layoutManager.minimumLayoutSize(jc);
1479:   }
1480: 
1481:   /**
1482:    * This method returns the maximum size of the JSplitPane.
1483:    *
1484:    * @param jc The JSplitPane.
1485:    *
1486:    * @return The maximum size of the JSplitPane.
1487:    */
1488:   public Dimension getMaximumSize(JComponent jc)
1489:   {
1490:     return layoutManager.maximumLayoutSize(jc);
1491:   }
1492: 
1493:   /**
1494:    * This method returns the border insets of the current border.
1495:    *
1496:    * @param jc The JSplitPane.
1497:    *
1498:    * @return The current border insets.
1499:    */
1500:   public Insets getInsets(JComponent jc)
1501:   {
1502:     return splitPane.getBorder().getBorderInsets(splitPane);
1503:   }
1504: 
1505:   /**
1506:    * This method resets the current layout manager. The type of layout manager
1507:    * is dependent on the current orientation.
1508:    */
1509:   protected void resetLayoutManager()
1510:   {
1511:     if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT)
1512:       layoutManager = new BasicHorizontalLayoutManager();
1513:     else
1514:       layoutManager = new BasicVerticalLayoutManager();
1515:     getSplitPane().setLayout(layoutManager);
1516:     layoutManager.updateComponents();
1517: 
1518:     // invalidating by itself does not invalidate the layout.
1519:     getSplitPane().revalidate();
1520:   }
1521: 
1522:   /**
1523:    * This method is called when dragging starts. It resets lastDragLocation
1524:    * and dividerSize.
1525:    */
1526:   protected void startDragging()
1527:   {
1528:     Component left = splitPane.getLeftComponent();
1529:     Component right = splitPane.getRightComponent();
1530:     dividerSize = divider.getDividerSize();
1531:     setLastDragLocation(-1);
1532: 
1533:     if ((left != null && !left.isLightweight())
1534:         || (right != null && !right.isLightweight()))
1535:       draggingHW = true;
1536: 
1537:     if (splitPane.isContinuousLayout())
1538:       nonContinuousLayoutDivider.setVisible(false);
1539:     else
1540:       {
1541:         nonContinuousLayoutDivider.setVisible(true);
1542:         nonContinuousLayoutDivider.setBounds(divider.getBounds());
1543:       }
1544:   }
1545: 
1546:   /**
1547:    * This method is called whenever the divider is dragged. If the JSplitPane
1548:    * is in continuousLayout mode, the divider needs to be moved and the
1549:    * JSplitPane needs to be laid out.
1550:    *
1551:    * @param location The new location of the divider.
1552:    */
1553:   protected void dragDividerTo(int location)
1554:   {
1555:     location = validLocation(location);
1556:     if (beginDragDividerLocation == -1)
1557:       beginDragDividerLocation = location;
1558: 
1559:     if (splitPane.isContinuousLayout())
1560:       splitPane.setDividerLocation(location);
1561:     else
1562:       {
1563:         Point p = nonContinuousLayoutDivider.getLocation();
1564:         if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT)
1565:           p.x = location;
1566:         else
1567:           p.y = location;
1568:         nonContinuousLayoutDivider.setLocation(p);
1569:       }
1570:     setLastDragLocation(location);
1571:     splitPane.repaint();
1572:   }
1573: 
1574:   /**
1575:    * This method is called when the dragging is finished.
1576:    *
1577:    * @param location The location where the drag finished.
1578:    */
1579:   protected void finishDraggingTo(int location)
1580:   {
1581:     if (nonContinuousLayoutDivider != null)
1582:       nonContinuousLayoutDivider.setVisible(false);
1583:     draggingHW = false;
1584:     location = validLocation(location);
1585:     splitPane.setDividerLocation(location);
1586:     splitPane.setLastDividerLocation(beginDragDividerLocation);
1587:     beginDragDividerLocation = -1;
1588:   }
1589: 
1590:   /**
1591:    * This method returns the width of one of the sides of the divider's border.
1592:    *
1593:    * @return The width of one side of the divider's border.
1594:    *
1595:    * @deprecated 1.3
1596:    */
1597:   protected int getDividerBorderSize()
1598:   {
1599:     if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT)
1600:       return divider.getBorder().getBorderInsets(divider).left;
1601:     else
1602:       return divider.getBorder().getBorderInsets(divider).top;
1603:   }
1604: 
1605:   /**
1606:    * This is a helper method that returns a valid location for the divider
1607:    * when dragging.
1608:    *
1609:    * @param location The location to check.
1610:    *
1611:    * @return A valid location.
1612:    */
1613:   private int validLocation(int location)
1614:   {
1615:     int min = getMinimumDividerLocation(splitPane);
1616:     int max = getMaximumDividerLocation(splitPane);
1617:     if (min > 0 && location < min)
1618:       return min;
1619:     if (max > 0 && location > max)
1620:       return max;
1621:     return location;
1622:   }
1623: }