Source for javax.swing.plaf.basic.BasicSplitPaneDivider

   1: /* BasicSplitPaneDivider.java --
   2:    Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.plaf.basic;
  40: 
  41: import java.awt.Component;
  42: import java.awt.Container;
  43: import java.awt.Dimension;
  44: import java.awt.Graphics;
  45: import java.awt.Insets;
  46: import java.awt.LayoutManager;
  47: import java.awt.event.MouseAdapter;
  48: import java.awt.event.MouseEvent;
  49: import java.awt.event.MouseMotionListener;
  50: import java.beans.PropertyChangeEvent;
  51: import java.beans.PropertyChangeListener;
  52: 
  53: import javax.swing.JButton;
  54: import javax.swing.JSplitPane;
  55: import javax.swing.SwingConstants;
  56: import javax.swing.border.Border;
  57: 
  58: /**
  59:  * The divider that separates the two parts of a JSplitPane in the Basic look
  60:  * and feel.
  61:  * 
  62:  * <p>
  63:  * Implementation status: We do not have a real implementation yet. Currently,
  64:  * it is mostly a stub to allow compiling other parts of the
  65:  * javax.swing.plaf.basic package, although some parts are already
  66:  * functional.
  67:  * </p>
  68:  *
  69:  * @author Sascha Brawer (brawer_AT_dandelis.ch)
  70:  */
  71: public class BasicSplitPaneDivider extends Container
  72:   implements PropertyChangeListener
  73: {
  74:   /**
  75:    * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1
  76:    * on MacOS X 10.1.5.
  77:    */
  78:   static final long serialVersionUID = 1463404307042803342L;
  79: 
  80:   /**
  81:    * The width and height of the little buttons for showing and hiding parts
  82:    * of a JSplitPane in a single mouse click.
  83:    */
  84:   protected static final int ONE_TOUCH_SIZE = 6;
  85: 
  86:   /** The distance the one touch buttons will sit from the divider's edges. */
  87:   protected static final int ONE_TOUCH_OFFSET = 2;
  88: 
  89:   /**
  90:    * An object that performs the tasks associated with an ongoing drag
  91:    * operation, or <code>null</code> if the user is currently not dragging
  92:    * the divider.
  93:    */
  94:   protected DragController dragger;
  95: 
  96:   /**
  97:    * The delegate object that is responsible for the UI of the
  98:    * <code>JSplitPane</code> that contains this divider.
  99:    */
 100:   protected BasicSplitPaneUI splitPaneUI;
 101: 
 102:   /** The thickness of the divider in pixels. */
 103:   protected int dividerSize;
 104: 
 105:   /** A divider that is used for layout purposes. */
 106:   protected Component hiddenDivider;
 107: 
 108:   /** The JSplitPane containing this divider. */
 109:   protected JSplitPane splitPane;
 110: 
 111:   /**
 112:    * The listener for handling mouse events from both the divider and the
 113:    * containing <code>JSplitPane</code>.
 114:    * 
 115:    * <p>
 116:    * The reason for also handling MouseEvents from the containing
 117:    * <code>JSplitPane</code> is that users should be able to start a drag
 118:    * gesture from inside the JSplitPane, but slightly outisde the divider.
 119:    * </p>
 120:    */
 121:   protected MouseHandler mouseHandler = new MouseHandler();
 122: 
 123:   /**
 124:    * The current orientation of the containing <code>JSplitPane</code>, which
 125:    * is either {@link javax.swing.JSplitPane#HORIZONTAL_SPLIT} or {@link
 126:    * javax.swing.JSplitPane#VERTICAL_SPLIT}.
 127:    */
 128:   protected int orientation;
 129: 
 130:   /**
 131:    * The button for showing and hiding the left (or top) component of the
 132:    * <code>JSplitPane</code>.
 133:    */
 134:   protected JButton leftButton;
 135: 
 136:   /**
 137:    * The button for showing and hiding the right (or bottom) component of the
 138:    * <code>JSplitPane</code>.
 139:    */
 140:   protected JButton rightButton;
 141: 
 142:   /**
 143:    * The border of this divider. Typically, this will be an instance of {@link
 144:    * javax.swing.plaf.basic.BasicBorders.SplitPaneDividerBorder}.
 145:    *
 146:    * @see #getBorder()
 147:    * @see #setBorder(javax.swing.border.Border)
 148:    */
 149:   private Border border;
 150: 
 151:   // This is not a pixel count.
 152:   // This int should be able to take 3 values.
 153:   // left (top), middle, right(bottom)
 154:   //    0          1          2
 155: 
 156:   /**
 157:    * Keeps track of where the divider should be placed when using one touch
 158:    * expand buttons.
 159:    * This is package-private to avoid an accessor method.
 160:    */
 161:   transient int currentDividerLocation = 1;
 162: 
 163:   /**
 164:    * Constructs a new divider.
 165:    *
 166:    * @param ui the UI delegate of the enclosing <code>JSplitPane</code>.
 167:    */
 168:   public BasicSplitPaneDivider(BasicSplitPaneUI ui)
 169:   {
 170:     setLayout(new DividerLayout());
 171:     setBasicSplitPaneUI(ui);
 172:     setDividerSize(splitPane.getDividerSize());
 173:   }
 174: 
 175:   /**
 176:    * Sets the delegate object that is responsible for the UI of the {@link
 177:    * javax.swing.JSplitPane} containing this divider.
 178:    *
 179:    * @param newUI the UI delegate, or <code>null</code> to release the
 180:    *        connection to the current delegate.
 181:    */
 182:   public void setBasicSplitPaneUI(BasicSplitPaneUI newUI)
 183:   {
 184:     /* Remove the connection to the existing JSplitPane. */
 185:     if (splitPane != null)
 186:       {
 187:     splitPane.removePropertyChangeListener(this);
 188:     removeMouseListener(mouseHandler);
 189:     removeMouseMotionListener(mouseHandler);
 190:     splitPane = null;
 191:     hiddenDivider = null;
 192:       }
 193: 
 194:     /* Establish the connection to the new JSplitPane. */
 195:     splitPaneUI = newUI;
 196:     if (splitPaneUI != null)
 197:       splitPane = newUI.getSplitPane();
 198:     if (splitPane != null)
 199:       {
 200:     splitPane.addPropertyChangeListener(this);
 201:     addMouseListener(mouseHandler);
 202:     addMouseMotionListener(mouseHandler);
 203:     hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider();
 204:     orientation = splitPane.getOrientation();
 205:     oneTouchExpandableChanged();
 206:       }
 207:   }
 208: 
 209:   /**
 210:    * Returns the delegate object that is responsible for the UI of the {@link
 211:    * javax.swing.JSplitPane} containing this divider.
 212:    *
 213:    * @return The UI for the JSplitPane.
 214:    */
 215:   public BasicSplitPaneUI getBasicSplitPaneUI()
 216:   {
 217:     return splitPaneUI;
 218:   }
 219: 
 220:   /**
 221:    * Sets the thickness of the divider.
 222:    *
 223:    * @param newSize the new width or height in pixels.
 224:    */
 225:   public void setDividerSize(int newSize)
 226:   {
 227:     this.dividerSize = newSize;
 228:   }
 229: 
 230:   /**
 231:    * Retrieves the thickness of the divider.
 232:    *
 233:    * @return The thickness of the divider.
 234:    */
 235:   public int getDividerSize()
 236:   {
 237:     return dividerSize;
 238:   }
 239: 
 240:   /**
 241:    * Sets the border of this divider.
 242:    *
 243:    * @param border the new border. Typically, this will be an instance of
 244:    *        {@link
 245:    *        javax.swing.plaf.basic.BasicBorders.SplitPaneBorder}.
 246:    *
 247:    * @since 1.3
 248:    */
 249:   public void setBorder(Border border)
 250:   {
 251:     if (border != this.border)
 252:       {
 253:     Border oldValue = this.border;
 254:     this.border = border;
 255:     firePropertyChange("border", oldValue, border);
 256:       }
 257:   }
 258: 
 259:   /**
 260:    * Retrieves the border of this divider.
 261:    *
 262:    * @return the current border, or <code>null</code> if no border has been
 263:    *         set.
 264:    *
 265:    * @since 1.3
 266:    */
 267:   public Border getBorder()
 268:   {
 269:     return border;
 270:   }
 271: 
 272:   /**
 273:    * Retrieves the insets of the divider. If a border has been installed on
 274:    * the divider, the result of calling its <code>getBorderInsets</code>
 275:    * method is returned. Otherwise, the inherited implementation will be
 276:    * invoked.
 277:    *
 278:    * @see javax.swing.border.Border#getBorderInsets(java.awt.Component)
 279:    */
 280:   public Insets getInsets()
 281:   {
 282:     if (border != null)
 283:       return border.getBorderInsets(this);
 284:     else
 285:       return super.getInsets();
 286:   }
 287: 
 288:   /**
 289:    * Returns the preferred size of this divider, which is
 290:    * <code>dividerSize</code> by <code>dividerSize</code> pixels.
 291:    *
 292:    * @return The preferred size of the divider.
 293:    */
 294:   public Dimension getPreferredSize()
 295:   {
 296:     return getLayout().preferredLayoutSize(this);
 297:   }
 298: 
 299:   /**
 300:    * Returns the minimal size of this divider, which is
 301:    * <code>dividerSize</code> by <code>dividerSize</code> pixels.
 302:    *
 303:    * @return The minimal size of the divider.
 304:    */
 305:   public Dimension getMinimumSize()
 306:   {
 307:     return getPreferredSize();
 308:   }
 309: 
 310:   /**
 311:    * Processes events from the <code>JSplitPane</code> that contains this
 312:    * divider.
 313:    *
 314:    * @param e The PropertyChangeEvent.
 315:    */
 316:   public void propertyChange(PropertyChangeEvent e)
 317:   {
 318:     if (e.getPropertyName().equals(JSplitPane.ONE_TOUCH_EXPANDABLE_PROPERTY))
 319:       oneTouchExpandableChanged();
 320:     else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY))
 321:       {
 322:     orientation = splitPane.getOrientation();
 323:     if (splitPane.isOneTouchExpandable())
 324:       {
 325:         layout();
 326:         repaint();
 327:       }
 328:       }
 329:     else if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY))
 330:       dividerSize = splitPane.getDividerSize();
 331:   }
 332: 
 333:   /**
 334:    * Paints the divider by painting its border.
 335:    *
 336:    * @param g The Graphics Object to paint with.
 337:    */
 338:   public void paint(Graphics g)
 339:   {
 340:     Dimension dividerSize;
 341: 
 342:     super.paint(g);
 343:     if (border != null)
 344:       {
 345:     dividerSize = getSize();
 346:     border.paintBorder(this, g, 0, 0, dividerSize.width, dividerSize.height);
 347:       }
 348:     if (splitPane.isOneTouchExpandable())
 349:       {
 350:         ((BasicArrowButton) rightButton).paint(g);
 351:         ((BasicArrowButton) leftButton).paint(g);
 352:       }
 353:   }
 354: 
 355:   /**
 356:    * Reacts to changes of the <code>oneToughExpandable</code> property of the
 357:    * containing <code>JSplitPane</code>.
 358:    */
 359:   protected void oneTouchExpandableChanged()
 360:   {
 361:     if (splitPane.isOneTouchExpandable())
 362:       {
 363:     leftButton = createLeftOneTouchButton();
 364:     rightButton = createRightOneTouchButton();
 365:     add(leftButton);
 366:     add(rightButton);
 367: 
 368:     leftButton.addMouseListener(mouseHandler);
 369:     rightButton.addMouseListener(mouseHandler);
 370: 
 371:     // Set it to 1.
 372:     currentDividerLocation = 1;
 373:       }
 374:     else
 375:       {
 376:     if (leftButton != null && rightButton != null)
 377:       {
 378:         leftButton.removeMouseListener(mouseHandler);
 379:         rightButton.removeMouseListener(mouseHandler);
 380: 
 381:         remove(leftButton);
 382:         remove(rightButton);
 383:         leftButton = null;
 384:         rightButton = null;
 385:       }
 386:       }
 387:     layout();
 388:     repaint();
 389:   }
 390: 
 391:   /**
 392:    * Creates a button for showing and hiding the left (or top) part of a
 393:    * <code>JSplitPane</code>.
 394:    *
 395:    * @return The left one touch button.
 396:    */
 397:   protected JButton createLeftOneTouchButton()
 398:   {
 399:     int dir = SwingConstants.WEST;
 400:     if (orientation == JSplitPane.VERTICAL_SPLIT)
 401:       dir = SwingConstants.NORTH;
 402:     JButton button = new BasicArrowButton(dir);
 403:     button.setBorder(null);
 404: 
 405:     return button;
 406:   }
 407: 
 408:   /**
 409:    * Creates a button for showing and hiding the right (or bottom) part of a
 410:    * <code>JSplitPane</code>.
 411:    *
 412:    * @return The right one touch button.
 413:    */
 414:   protected JButton createRightOneTouchButton()
 415:   {
 416:     int dir = SwingConstants.EAST;
 417:     if (orientation == JSplitPane.VERTICAL_SPLIT)
 418:       dir = SwingConstants.SOUTH;
 419:     JButton button = new BasicArrowButton(dir);
 420:     button.setBorder(null);
 421:     return button;
 422:   }
 423: 
 424:   /**
 425:    * Prepares the divider for dragging by calling the
 426:    * <code>startDragging</code> method of the UI delegate of the enclosing
 427:    * <code>JSplitPane</code>.
 428:    *
 429:    * @see BasicSplitPaneUI#startDragging()
 430:    */
 431:   protected void prepareForDragging()
 432:   {
 433:     if (splitPaneUI != null)
 434:       splitPaneUI.startDragging();
 435:   }
 436: 
 437:   /**
 438:    * Drags the divider to a given location by calling the
 439:    * <code>dragDividerTo</code> method of the UI delegate of the enclosing
 440:    * <code>JSplitPane</code>.
 441:    *
 442:    * @param location the new location of the divider.
 443:    *
 444:    * @see BasicSplitPaneUI#dragDividerTo(int location)
 445:    */
 446:   protected void dragDividerTo(int location)
 447:   {
 448:     if (splitPaneUI != null)
 449:       splitPaneUI.dragDividerTo(location);
 450:   }
 451: 
 452:   /**
 453:    * Finishes a dragging gesture by calling the <code>finishDraggingTo</code>
 454:    * method of the UI delegate of the enclosing <code>JSplitPane</code>.
 455:    *
 456:    * @param location the new, final location of the divider.
 457:    *
 458:    * @see BasicSplitPaneUI#finishDraggingTo(int location)
 459:    */
 460:   protected void finishDraggingTo(int location)
 461:   {
 462:     if (splitPaneUI != null)
 463:       splitPaneUI.finishDraggingTo(location);
 464:   }
 465: 
 466:   /**
 467:    * This helper method moves the divider to one of the  three locations when
 468:    * using one touch expand buttons. Location 0 is the left (or top) most
 469:    * location. Location 1 is the middle. Location 2 is the right (or bottom)
 470:    * most location.
 471:    * This is package-private to avoid an accessor method.
 472:    *
 473:    * @param locationIndex The location to move to.
 474:    */
 475:   void moveDividerTo(int locationIndex)
 476:   {
 477:     Insets insets = splitPane.getInsets();
 478:     switch (locationIndex)
 479:       {
 480:       case 1:
 481:     splitPane.setDividerLocation(splitPane.getLastDividerLocation());
 482:     break;
 483:       case 0:
 484:     int top = (orientation == JSplitPane.HORIZONTAL_SPLIT) ? insets.left
 485:                                                            : insets.top;
 486:     splitPane.setDividerLocation(top);
 487:     break;
 488:       case 2:
 489:     int bottom;
 490:     if (orientation == JSplitPane.HORIZONTAL_SPLIT)
 491:       bottom = splitPane.getBounds().width - insets.right - dividerSize;
 492:     else
 493:       bottom = splitPane.getBounds().height - insets.bottom - dividerSize;
 494:     splitPane.setDividerLocation(bottom);
 495:     break;
 496:       }
 497:   }
 498: 
 499:   /**
 500:    * The listener for handling mouse events from both the divider and the
 501:    * containing <code>JSplitPane</code>.
 502:    * 
 503:    * <p>
 504:    * The reason for also handling MouseEvents from the containing
 505:    * <code>JSplitPane</code> is that users should be able to start a drag
 506:    * gesture from inside the JSplitPane, but slightly outisde the divider.
 507:    * </p>
 508:    *
 509:    * @author Sascha Brawer (brawer_AT_dandelis.ch)
 510:    */
 511:   protected class MouseHandler extends MouseAdapter
 512:     implements MouseMotionListener
 513:   {
 514:     /** Keeps track of whether a drag is occurring. */
 515:     private transient boolean isDragging;
 516: 
 517:     /**
 518:      * This method is called when the mouse is pressed.
 519:      *
 520:      * @param e The MouseEvent.
 521:      */
 522:     public void mousePressed(MouseEvent e)
 523:     {
 524:       if (splitPane.isOneTouchExpandable())
 525:         {
 526:       if (e.getSource() == leftButton)
 527:         {
 528:           currentDividerLocation--;
 529:           if (currentDividerLocation < 0)
 530:         currentDividerLocation = 0;
 531:           moveDividerTo(currentDividerLocation);
 532:           return;
 533:         }
 534:       else if (e.getSource() == rightButton)
 535:         {
 536:           currentDividerLocation++;
 537:           if (currentDividerLocation > 2)
 538:         currentDividerLocation = 2;
 539:           moveDividerTo(currentDividerLocation);
 540:           return;
 541:         }
 542:         }
 543:       isDragging = true;
 544:       currentDividerLocation = 1;
 545:       if (orientation == JSplitPane.HORIZONTAL_SPLIT)
 546:     dragger = new DragController(e);
 547:       else
 548:     dragger = new VerticalDragController(e);
 549:       prepareForDragging();
 550:     }
 551: 
 552:     /**
 553:      * This method is called when the mouse is released.
 554:      *
 555:      * @param e The MouseEvent.
 556:      */
 557:     public void mouseReleased(MouseEvent e)
 558:     {
 559:       if (isDragging)
 560:         dragger.completeDrag(e);
 561:       isDragging = false;
 562:     }
 563: 
 564:     /**
 565:      * Repeatedly invoked when the user is dragging the mouse cursor while
 566:      * having pressed a mouse button.
 567:      *
 568:      * @param e The MouseEvent.
 569:      */
 570:     public void mouseDragged(MouseEvent e)
 571:     {
 572:       if (dragger != null)
 573:         dragger.continueDrag(e);
 574:     }
 575: 
 576:     /**
 577:      * Repeatedly invoked when the user is dragging the mouse cursor without
 578:      * having pressed a mouse button.
 579:      *
 580:      * @param e The MouseEvent.
 581:      */
 582:     public void mouseMoved(MouseEvent e)
 583:     {
 584:       // Do nothing.
 585:     }
 586:   }
 587: 
 588:   /**
 589:    * Performs the tasks associated with an ongoing drag operation.
 590:    *
 591:    * @author Sascha Brawer (brawer_AT_dandelis.ch)
 592:    */
 593:   protected class DragController
 594:   {
 595:     /**
 596:      * The difference between where the mouse is clicked and the  initial
 597:      * divider location.
 598:      */
 599:     transient int offset;
 600: 
 601:     /**
 602:      * Creates a new DragController object.
 603:      *
 604:      * @param e The MouseEvent to initialize with.
 605:      */
 606:     protected DragController(MouseEvent e)
 607:     {
 608:       offset = e.getX();
 609:     }
 610: 
 611:     /**
 612:      * This method returns true if the divider can move.
 613:      *
 614:      * @return True if dragging is allowed.
 615:      */
 616:     protected boolean isValid()
 617:     {
 618:       // Views can always be resized?
 619:       return true;
 620:     }
 621: 
 622:     /**
 623:      * Returns a position for the divider given the MouseEvent.
 624:      *
 625:      * @param e MouseEvent.
 626:      *
 627:      * @return The position for the divider to move to.
 628:      */
 629:     protected int positionForMouseEvent(MouseEvent e)
 630:     {
 631:       return e.getX() + getX() - offset;
 632:     }
 633: 
 634:     /**
 635:      * This method returns one of the two paramters for the orientation. In
 636:      * this case, it returns x.
 637:      *
 638:      * @param x The x coordinate.
 639:      * @param y The y coordinate.
 640:      *
 641:      * @return The x coordinate.
 642:      */
 643:     protected int getNeededLocation(int x, int y)
 644:     {
 645:       return x;
 646:     }
 647: 
 648:     /**
 649:      * This method is called to pass on the drag information to the UI through
 650:      * dragDividerTo.
 651:      *
 652:      * @param newX The x coordinate of the MouseEvent.
 653:      * @param newY The y coordinate of the MouseEvent.
 654:      */
 655:     protected void continueDrag(int newX, int newY)
 656:     {
 657:       if (isValid())
 658:     dragDividerTo(adjust(newX, newY));
 659:     }
 660: 
 661:     /**
 662:      * This method is called to pass on the drag information  to the UI
 663:      * through dragDividerTo.
 664:      *
 665:      * @param e The MouseEvent.
 666:      */
 667:     protected void continueDrag(MouseEvent e)
 668:     {
 669:       if (isValid())
 670:     dragDividerTo(positionForMouseEvent(e));
 671:     }
 672: 
 673:     /**
 674:      * This method is called to finish the drag session  by calling
 675:      * finishDraggingTo.
 676:      *
 677:      * @param x The x coordinate of the MouseEvent.
 678:      * @param y The y coordinate of the MouseEvent.
 679:      */
 680:     protected void completeDrag(int x, int y)
 681:     {
 682:       finishDraggingTo(adjust(x, y));
 683:     }
 684: 
 685:     /**
 686:      * This method is called to finish the drag session  by calling
 687:      * finishDraggingTo.
 688:      *
 689:      * @param e The MouseEvent.
 690:      */
 691:     protected void completeDrag(MouseEvent e)
 692:     {
 693:       finishDraggingTo(positionForMouseEvent(e));
 694:     }
 695: 
 696:     /**
 697:      * This is a helper method that includes the offset in the needed
 698:      * location.
 699:      *
 700:      * @param x The x coordinate of the MouseEvent.
 701:      * @param y The y coordinate of the MouseEvent.
 702:      *
 703:      * @return The needed location adjusted by the offsets.
 704:      */
 705:     int adjust(int x, int y)
 706:     {
 707:       return getNeededLocation(x, y) + getX() - offset;
 708:     }
 709:   }
 710: 
 711:   /**
 712:    * This is a helper class that controls dragging when  the orientation is
 713:    * VERTICAL_SPLIT.
 714:    */
 715:   protected class VerticalDragController extends DragController
 716:   {
 717:     /**
 718:      * Creates a new VerticalDragController object.
 719:      *
 720:      * @param e The MouseEvent to initialize with.
 721:      */
 722:     protected VerticalDragController(MouseEvent e)
 723:     {
 724:       super(e);
 725:       offset = e.getY();
 726:     }
 727: 
 728:     /**
 729:      * This method returns one of the two parameters given the orientation. In
 730:      * this case, it returns y.
 731:      *
 732:      * @param x The x coordinate of the MouseEvent.
 733:      * @param y The y coordinate of the MouseEvent.
 734:      *
 735:      * @return The y coordinate.
 736:      */
 737:     protected int getNeededLocation(int x, int y)
 738:     {
 739:       return y;
 740:     }
 741: 
 742:     /**
 743:      * This method returns the new location of the divider given a MouseEvent.
 744:      *
 745:      * @param e The MouseEvent.
 746:      *
 747:      * @return The new location of the divider.
 748:      */
 749:     protected int positionForMouseEvent(MouseEvent e)
 750:     {
 751:       return e.getY() + getY() - offset;
 752:     }
 753: 
 754:     /**
 755:      * This is a helper method that includes the offset in the needed
 756:      * location.
 757:      *
 758:      * @param x The x coordinate of the MouseEvent.
 759:      * @param y The y coordinate of the MouseEvent.
 760:      *
 761:      * @return The needed location adjusted by the offsets.
 762:      */
 763:     int adjust(int x, int y)
 764:     {
 765:       return getNeededLocation(x, y) + getY() - offset;
 766:     }
 767:   }
 768: 
 769:   /**
 770:    * This helper class acts as the Layout Manager for the divider.
 771:    */
 772:   protected class DividerLayout implements LayoutManager
 773:   {
 774:     /**
 775:      * Creates a new DividerLayout object.
 776:      */
 777:     protected DividerLayout()
 778:     {
 779:       // Nothing to do here.
 780:     }
 781: 
 782:     /**
 783:      * This method is called when a Component is added.
 784:      *
 785:      * @param string The constraints string.
 786:      * @param c The Component to add.
 787:      */
 788:     public void addLayoutComponent(String string, Component c)
 789:     {
 790:       // Do nothing.
 791:     }
 792: 
 793:     /**
 794:      * This method is called to lay out the container.
 795:      *
 796:      * @param c The container to lay out.
 797:      */
 798:     public void layoutContainer(Container c)
 799:     {
 800:       if (splitPane.isOneTouchExpandable())
 801:         {
 802:       changeButtonOrientation();
 803:       positionButtons();
 804:         }
 805:     }
 806: 
 807:     /**
 808:      * This method returns the minimum layout size.
 809:      *
 810:      * @param c The container to calculate for.
 811:      *
 812:      * @return The minimum layout size.
 813:      */
 814:     public Dimension minimumLayoutSize(Container c)
 815:     {
 816:       return preferredLayoutSize(c);
 817:     }
 818: 
 819:     /**
 820:      * This method returns the preferred layout size.
 821:      *
 822:      * @param c The container to calculate for.
 823:      *
 824:      * @return The preferred layout size.
 825:      */
 826:     public Dimension preferredLayoutSize(Container c)
 827:     {
 828:       return new Dimension(dividerSize, dividerSize);
 829:     }
 830: 
 831:     /**
 832:      * This method is called when a component is removed.
 833:      *
 834:      * @param c The component to remove.
 835:      */
 836:     public void removeLayoutComponent(Component c)
 837:     {
 838:       // Do nothing.
 839:     }
 840: 
 841:     /**
 842:      * This method changes the button orientation when the orientation of the
 843:      * SplitPane changes.
 844:      */
 845:     private void changeButtonOrientation()
 846:     {
 847:       if (orientation == JSplitPane.HORIZONTAL_SPLIT)
 848:         {
 849:       ((BasicArrowButton) rightButton).setDirection(SwingConstants.EAST);
 850:       ((BasicArrowButton) leftButton).setDirection(SwingConstants.WEST);
 851:         }
 852:       else
 853:         {
 854:       ((BasicArrowButton) rightButton).setDirection(SwingConstants.SOUTH);
 855:       ((BasicArrowButton) leftButton).setDirection(SwingConstants.NORTH);
 856:         }
 857:     }
 858: 
 859:     /**
 860:      * This method sizes and positions the buttons.
 861:      */
 862:     private void positionButtons()
 863:     {
 864:       int w = 0;
 865:       int h = 0;
 866:       if (orientation == JSplitPane.HORIZONTAL_SPLIT)
 867:         {
 868:       rightButton.setLocation(ONE_TOUCH_OFFSET, ONE_TOUCH_OFFSET);
 869:       leftButton.setLocation(ONE_TOUCH_OFFSET,
 870:                              ONE_TOUCH_OFFSET + 2 * ONE_TOUCH_SIZE);
 871:       w = dividerSize - 2 * ONE_TOUCH_OFFSET;
 872:       h = 2 * ONE_TOUCH_SIZE;
 873:         }
 874:       else
 875:         {
 876:       leftButton.setLocation(ONE_TOUCH_OFFSET, ONE_TOUCH_OFFSET);
 877:       rightButton.setLocation(ONE_TOUCH_OFFSET + 2 * ONE_TOUCH_SIZE,
 878:                               ONE_TOUCH_OFFSET);
 879:       h = dividerSize - 2 * ONE_TOUCH_OFFSET;
 880:       w = 2 * ONE_TOUCH_SIZE;
 881:         }
 882:       Dimension dims = new Dimension(w, h);
 883:       leftButton.setSize(dims);
 884:       rightButton.setSize(dims);
 885:     }
 886:   }
 887: }