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