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