001 /* BasicSplitPaneDivider.java --
002 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.swing.plaf.basic;
040
041 import java.awt.Color;
042 import java.awt.Component;
043 import java.awt.Container;
044 import java.awt.Dimension;
045 import java.awt.Graphics;
046 import java.awt.Insets;
047 import java.awt.LayoutManager;
048 import java.awt.event.ActionEvent;
049 import java.awt.event.ActionListener;
050 import java.awt.event.MouseAdapter;
051 import java.awt.event.MouseEvent;
052 import java.awt.event.MouseMotionListener;
053 import java.beans.PropertyChangeEvent;
054 import java.beans.PropertyChangeListener;
055
056 import javax.swing.JButton;
057 import javax.swing.JSplitPane;
058 import javax.swing.UIManager;
059 import javax.swing.border.Border;
060
061 /**
062 * The divider that separates the two parts of a JSplitPane in the Basic look
063 * and feel.
064 *
065 * <p>
066 * Implementation status: We do not have a real implementation yet. Currently,
067 * it is mostly a stub to allow compiling other parts of the
068 * javax.swing.plaf.basic package, although some parts are already
069 * functional.
070 * </p>
071 *
072 * @author Sascha Brawer (brawer_AT_dandelis.ch)
073 */
074 public class BasicSplitPaneDivider extends Container
075 implements PropertyChangeListener
076 {
077 /**
078 * The buttons used as one touch buttons.
079 */
080 private class BasicOneTouchButton
081 extends JButton
082 {
083 /**
084 * Denotes a left button.
085 */
086 static final int LEFT = 0;
087
088 /**
089 * Denotes a right button.
090 */
091 static final int RIGHT = 1;
092
093 /**
094 * The x points for the arrow.
095 */
096 private int[] xpoints;
097
098 /**
099 * The y points for the arrow.
100 */
101 private int[] ypoints;
102
103 /**
104 * Either LEFT or RIGHT.
105 */
106 private int direction;
107
108 /**
109 * Creates a new instance.
110 *
111 * @param dir either LEFT or RIGHT
112 */
113 BasicOneTouchButton(int dir)
114 {
115 direction = dir;
116 xpoints = new int[3];
117 ypoints = new int[3];
118 }
119
120 /**
121 * Never allow borders.
122 */
123 public void setBorder(Border b)
124 {
125 }
126
127 /**
128 * Never allow focus traversal.
129 */
130 public boolean isFocusTraversable()
131 {
132 return false;
133 }
134
135 /**
136 * Paints the one touch button.
137 */
138 public void paint(Graphics g)
139 {
140 if (splitPane != null)
141 {
142 // Fill background.
143 g.setColor(splitPane.getBackground());
144 g.fillRect(0, 0, getWidth(), getHeight());
145
146 // Draw arrow.
147 int size;
148 if (direction == LEFT)
149 {
150 if (orientation == JSplitPane.VERTICAL_SPLIT)
151 {
152 size = Math.min(getHeight(), ONE_TOUCH_SIZE);
153 xpoints[0] = 0;
154 xpoints[1] = size / 2;
155 xpoints[2] = size;
156 ypoints[0] = size;
157 ypoints[1] = 0;
158 ypoints[2] = size;
159 }
160 else
161 {
162 size = Math.min(getWidth(), ONE_TOUCH_SIZE);
163 xpoints[0] = size;
164 xpoints[1] = 0;
165 xpoints[2] = size;
166 ypoints[0] = 0;
167 ypoints[1] = size / 2;
168 ypoints[2] = size;
169 }
170 }
171 else
172 {
173 if (orientation == JSplitPane.VERTICAL_SPLIT)
174 {
175 size = Math.min(getHeight(), ONE_TOUCH_SIZE);
176 xpoints[0] = 0;
177 xpoints[1] = size / 2;
178 xpoints[2] = size;
179 ypoints[0] = 0;
180 ypoints[1] = size;
181 ypoints[2] = 0;
182 }
183 else
184 {
185 size = Math.min(getWidth(), ONE_TOUCH_SIZE);
186 xpoints[0] = 0;
187 xpoints[1] = size;
188 xpoints[2] = 0;
189 ypoints[0] = 0;
190 ypoints[1] = size / 2;
191 ypoints[2] = size;
192 }
193 }
194 g.setColor(Color.BLACK);
195 g.fillPolygon(xpoints, ypoints, 3);
196 }
197 }
198 }
199
200 /**
201 * Listens for actions on the one touch buttons.
202 */
203 private class OneTouchAction
204 implements ActionListener
205 {
206
207 public void actionPerformed(ActionEvent ev)
208 {
209 Insets insets = splitPane.getInsets();
210 int lastLoc = splitPane.getLastDividerLocation();
211 int currentLoc = splitPaneUI.getDividerLocation(splitPane);
212 int newLoc;
213
214 if (ev.getSource() == leftButton)
215 {
216 if (orientation == JSplitPane.VERTICAL_SPLIT)
217 {
218 if (currentLoc
219 >= splitPane.getHeight() - insets.bottom - getHeight())
220 {
221 newLoc = Math.min(splitPane.getMaximumDividerLocation(),
222 lastLoc);
223 }
224 else
225 {
226 newLoc = insets.top;
227 }
228 }
229 else
230 {
231 if (currentLoc
232 >= splitPane.getWidth() - insets.right - getWidth())
233 {
234 newLoc = Math.min(splitPane.getMaximumDividerLocation(),
235 lastLoc);
236 }
237 else
238 {
239 newLoc = insets.left;
240 }
241 }
242 }
243 else
244 {
245 if (orientation == JSplitPane.VERTICAL_SPLIT)
246 {
247 if (currentLoc == insets.top)
248 {
249 newLoc = Math.min(splitPane.getMaximumDividerLocation(),
250 lastLoc);
251 }
252 else
253 {
254 newLoc = splitPane.getHeight() - insets.top - getHeight();
255 }
256 }
257 else
258 {
259 if (currentLoc == insets.left)
260 {
261 newLoc = Math.min(splitPane.getMaximumDividerLocation(),
262 lastLoc);
263 }
264 else
265 {
266 newLoc = splitPane.getWidth() - insets.left - getWidth();
267 }
268 }
269 }
270 if (currentLoc != newLoc)
271 {
272 splitPane.setDividerLocation(newLoc);
273 splitPane.setLastDividerLocation(currentLoc);
274 }
275 }
276 }
277
278 /**
279 * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1
280 * on MacOS X 10.1.5.
281 */
282 static final long serialVersionUID = 1463404307042803342L;
283
284 /**
285 * The width and height of the little buttons for showing and hiding parts
286 * of a JSplitPane in a single mouse click.
287 */
288 protected static final int ONE_TOUCH_SIZE = 6;
289
290 /** The distance the one touch buttons will sit from the divider's edges. */
291 protected static final int ONE_TOUCH_OFFSET = 2;
292
293 /**
294 * An object that performs the tasks associated with an ongoing drag
295 * operation, or <code>null</code> if the user is currently not dragging
296 * the divider.
297 */
298 protected DragController dragger;
299
300 /**
301 * The delegate object that is responsible for the UI of the
302 * <code>JSplitPane</code> that contains this divider.
303 */
304 protected BasicSplitPaneUI splitPaneUI;
305
306 /** The thickness of the divider in pixels. */
307 protected int dividerSize;
308
309 /** A divider that is used for layout purposes. */
310 protected Component hiddenDivider;
311
312 /** The JSplitPane containing this divider. */
313 protected JSplitPane splitPane;
314
315 /**
316 * The listener for handling mouse events from both the divider and the
317 * containing <code>JSplitPane</code>.
318 *
319 * <p>
320 * The reason for also handling MouseEvents from the containing
321 * <code>JSplitPane</code> is that users should be able to start a drag
322 * gesture from inside the JSplitPane, but slightly outisde the divider.
323 * </p>
324 */
325 protected MouseHandler mouseHandler = new MouseHandler();
326
327 /**
328 * The current orientation of the containing <code>JSplitPane</code>, which
329 * is either {@link javax.swing.JSplitPane#HORIZONTAL_SPLIT} or {@link
330 * javax.swing.JSplitPane#VERTICAL_SPLIT}.
331 */
332 protected int orientation;
333
334 /**
335 * The button for showing and hiding the left (or top) component of the
336 * <code>JSplitPane</code>.
337 */
338 protected JButton leftButton;
339
340 /**
341 * The button for showing and hiding the right (or bottom) component of the
342 * <code>JSplitPane</code>.
343 */
344 protected JButton rightButton;
345
346 /**
347 * The border of this divider. Typically, this will be an instance of {@link
348 * javax.swing.plaf.basic.BasicBorders.SplitPaneDividerBorder}.
349 *
350 * @see #getBorder()
351 * @see #setBorder(javax.swing.border.Border)
352 */
353 private Border border;
354
355 // This is not a pixel count.
356 // This int should be able to take 3 values.
357 // left (top), middle, right(bottom)
358 // 0 1 2
359
360 /**
361 * Keeps track of where the divider should be placed when using one touch
362 * expand buttons.
363 * This is package-private to avoid an accessor method.
364 */
365 transient int currentDividerLocation = 1;
366
367 /**
368 * Indicates if the ont touch buttons are laid out centered or at the
369 * top/left.
370 *
371 * Package private to avoid accessor method.
372 */
373 boolean centerOneTouchButtons;
374
375 /**
376 * Constructs a new divider.
377 *
378 * @param ui the UI delegate of the enclosing <code>JSplitPane</code>.
379 */
380 public BasicSplitPaneDivider(BasicSplitPaneUI ui)
381 {
382 setLayout(new DividerLayout());
383 setBasicSplitPaneUI(ui);
384 setDividerSize(splitPane.getDividerSize());
385 centerOneTouchButtons =
386 UIManager.getBoolean("SplitPane.centerOneTouchButtons");
387 }
388
389 /**
390 * Sets the delegate object that is responsible for the UI of the {@link
391 * javax.swing.JSplitPane} containing this divider.
392 *
393 * @param newUI the UI delegate, or <code>null</code> to release the
394 * connection to the current delegate.
395 */
396 public void setBasicSplitPaneUI(BasicSplitPaneUI newUI)
397 {
398 /* Remove the connection to the existing JSplitPane. */
399 if (splitPane != null)
400 {
401 splitPane.removePropertyChangeListener(this);
402 removeMouseListener(mouseHandler);
403 removeMouseMotionListener(mouseHandler);
404 splitPane = null;
405 hiddenDivider = null;
406 }
407
408 /* Establish the connection to the new JSplitPane. */
409 splitPaneUI = newUI;
410 if (splitPaneUI != null)
411 splitPane = newUI.getSplitPane();
412 if (splitPane != null)
413 {
414 splitPane.addPropertyChangeListener(this);
415 addMouseListener(mouseHandler);
416 addMouseMotionListener(mouseHandler);
417 hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider();
418 orientation = splitPane.getOrientation();
419 if (splitPane.isOneTouchExpandable())
420 oneTouchExpandableChanged();
421 }
422 }
423
424 /**
425 * Returns the delegate object that is responsible for the UI of the {@link
426 * javax.swing.JSplitPane} containing this divider.
427 *
428 * @return The UI for the JSplitPane.
429 */
430 public BasicSplitPaneUI getBasicSplitPaneUI()
431 {
432 return splitPaneUI;
433 }
434
435 /**
436 * Sets the thickness of the divider.
437 *
438 * @param newSize the new width or height in pixels.
439 */
440 public void setDividerSize(int newSize)
441 {
442 this.dividerSize = newSize;
443 }
444
445 /**
446 * Retrieves the thickness of the divider.
447 *
448 * @return The thickness of the divider.
449 */
450 public int getDividerSize()
451 {
452 return dividerSize;
453 }
454
455 /**
456 * Sets the border of this divider.
457 *
458 * @param border the new border. Typically, this will be an instance of
459 * {@link
460 * javax.swing.plaf.basic.BasicBorders.SplitPaneBorder}.
461 *
462 * @since 1.3
463 */
464 public void setBorder(Border border)
465 {
466 if (border != this.border)
467 {
468 Border oldValue = this.border;
469 this.border = border;
470 firePropertyChange("border", oldValue, border);
471 }
472 }
473
474 /**
475 * Retrieves the border of this divider.
476 *
477 * @return the current border, or <code>null</code> if no border has been
478 * set.
479 *
480 * @since 1.3
481 */
482 public Border getBorder()
483 {
484 return border;
485 }
486
487 /**
488 * Retrieves the insets of the divider. If a border has been installed on
489 * the divider, the result of calling its <code>getBorderInsets</code>
490 * method is returned. Otherwise, the inherited implementation will be
491 * invoked.
492 *
493 * @see javax.swing.border.Border#getBorderInsets(java.awt.Component)
494 */
495 public Insets getInsets()
496 {
497 if (border != null)
498 return border.getBorderInsets(this);
499 else
500 return super.getInsets();
501 }
502
503 /**
504 * Returns the preferred size of this divider, which is
505 * <code>dividerSize</code> by <code>dividerSize</code> pixels.
506 *
507 * @return The preferred size of the divider.
508 */
509 public Dimension getPreferredSize()
510 {
511 Dimension d;
512 if (orientation == JSplitPane.HORIZONTAL_SPLIT)
513 d = new Dimension(getDividerSize(), 1);
514 else
515 d = new Dimension(1, getDividerSize());
516 return d;
517 }
518
519 /**
520 * Returns the minimal size of this divider, which is
521 * <code>dividerSize</code> by <code>dividerSize</code> pixels.
522 *
523 * @return The minimal size of the divider.
524 */
525 public Dimension getMinimumSize()
526 {
527 return getPreferredSize();
528 }
529
530 /**
531 * Processes events from the <code>JSplitPane</code> that contains this
532 * divider.
533 *
534 * @param e The PropertyChangeEvent.
535 */
536 public void propertyChange(PropertyChangeEvent e)
537 {
538 if (e.getPropertyName().equals(JSplitPane.ONE_TOUCH_EXPANDABLE_PROPERTY))
539 oneTouchExpandableChanged();
540 else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY))
541 {
542 orientation = splitPane.getOrientation();
543 invalidate();
544 if (splitPane != null)
545 splitPane.revalidate();
546 }
547 else if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY))
548 dividerSize = splitPane.getDividerSize();
549 }
550
551 /**
552 * Paints the divider by painting its border.
553 *
554 * @param g The Graphics Object to paint with.
555 */
556 public void paint(Graphics g)
557 {
558 Dimension dividerSize;
559
560 super.paint(g);
561 if (border != null)
562 {
563 dividerSize = getSize();
564 border.paintBorder(this, g, 0, 0, dividerSize.width, dividerSize.height);
565 }
566 }
567
568 /**
569 * Reacts to changes of the <code>oneToughExpandable</code> property of the
570 * containing <code>JSplitPane</code>.
571 */
572 protected void oneTouchExpandableChanged()
573 {
574 if (splitPane.isOneTouchExpandable())
575 {
576 leftButton = createLeftOneTouchButton();
577 if (leftButton != null)
578 leftButton.addActionListener(new OneTouchAction());
579
580 rightButton = createRightOneTouchButton();
581 if (rightButton != null)
582 rightButton.addActionListener(new OneTouchAction());
583
584 // Only add them when both are non-null.
585 if (leftButton != null && rightButton != null)
586 {
587 add(leftButton);
588 add(rightButton);
589 }
590 }
591 invalidate();
592 if (splitPane != null)
593 splitPane.revalidate();
594 }
595
596 /**
597 * Creates a button for showing and hiding the left (or top) part of a
598 * <code>JSplitPane</code>.
599 *
600 * @return The left one touch button.
601 */
602 protected JButton createLeftOneTouchButton()
603 {
604 JButton button = new BasicOneTouchButton(BasicOneTouchButton.LEFT);
605 button.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE));
606 button.setRequestFocusEnabled(false);
607 return button;
608 }
609
610 /**
611 * Creates a button for showing and hiding the right (or bottom) part of a
612 * <code>JSplitPane</code>.
613 *
614 * @return The right one touch button.
615 */
616 protected JButton createRightOneTouchButton()
617 {
618 JButton button = new BasicOneTouchButton(BasicOneTouchButton.RIGHT);
619 button.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE));
620 button.setRequestFocusEnabled(false);
621 return button;
622 }
623
624 /**
625 * Prepares the divider for dragging by calling the
626 * <code>startDragging</code> method of the UI delegate of the enclosing
627 * <code>JSplitPane</code>.
628 *
629 * @see BasicSplitPaneUI#startDragging()
630 */
631 protected void prepareForDragging()
632 {
633 if (splitPaneUI != null)
634 splitPaneUI.startDragging();
635 }
636
637 /**
638 * Drags the divider to a given location by calling the
639 * <code>dragDividerTo</code> method of the UI delegate of the enclosing
640 * <code>JSplitPane</code>.
641 *
642 * @param location the new location of the divider.
643 *
644 * @see BasicSplitPaneUI#dragDividerTo(int location)
645 */
646 protected void dragDividerTo(int location)
647 {
648 if (splitPaneUI != null)
649 splitPaneUI.dragDividerTo(location);
650 }
651
652 /**
653 * Finishes a dragging gesture by calling the <code>finishDraggingTo</code>
654 * method of the UI delegate of the enclosing <code>JSplitPane</code>.
655 *
656 * @param location the new, final location of the divider.
657 *
658 * @see BasicSplitPaneUI#finishDraggingTo(int location)
659 */
660 protected void finishDraggingTo(int location)
661 {
662 if (splitPaneUI != null)
663 splitPaneUI.finishDraggingTo(location);
664 }
665
666 /**
667 * This helper method moves the divider to one of the three locations when
668 * using one touch expand buttons. Location 0 is the left (or top) most
669 * location. Location 1 is the middle. Location 2 is the right (or bottom)
670 * most location.
671 * This is package-private to avoid an accessor method.
672 *
673 * @param locationIndex The location to move to.
674 */
675 void moveDividerTo(int locationIndex)
676 {
677 Insets insets = splitPane.getInsets();
678 switch (locationIndex)
679 {
680 case 1:
681 splitPane.setDividerLocation(splitPane.getLastDividerLocation());
682 break;
683 case 0:
684 int top = (orientation == JSplitPane.HORIZONTAL_SPLIT) ? insets.left
685 : insets.top;
686 splitPane.setDividerLocation(top);
687 break;
688 case 2:
689 int bottom;
690 if (orientation == JSplitPane.HORIZONTAL_SPLIT)
691 bottom = splitPane.getBounds().width - insets.right - dividerSize;
692 else
693 bottom = splitPane.getBounds().height - insets.bottom - dividerSize;
694 splitPane.setDividerLocation(bottom);
695 break;
696 }
697 }
698
699 /**
700 * The listener for handling mouse events from both the divider and the
701 * containing <code>JSplitPane</code>.
702 *
703 * <p>
704 * The reason for also handling MouseEvents from the containing
705 * <code>JSplitPane</code> is that users should be able to start a drag
706 * gesture from inside the JSplitPane, but slightly outisde the divider.
707 * </p>
708 *
709 * @author Sascha Brawer (brawer_AT_dandelis.ch)
710 */
711 protected class MouseHandler extends MouseAdapter
712 implements MouseMotionListener
713 {
714 /** Keeps track of whether a drag is occurring. */
715 private transient boolean isDragging;
716
717 /**
718 * This method is called when the mouse is pressed.
719 *
720 * @param e The MouseEvent.
721 */
722 public void mousePressed(MouseEvent e)
723 {
724 isDragging = true;
725 currentDividerLocation = 1;
726 if (orientation == JSplitPane.HORIZONTAL_SPLIT)
727 dragger = new DragController(e);
728 else
729 dragger = new VerticalDragController(e);
730 prepareForDragging();
731 }
732
733 /**
734 * This method is called when the mouse is released.
735 *
736 * @param e The MouseEvent.
737 */
738 public void mouseReleased(MouseEvent e)
739 {
740 if (isDragging)
741 dragger.completeDrag(e);
742 isDragging = false;
743 }
744
745 /**
746 * Repeatedly invoked when the user is dragging the mouse cursor while
747 * having pressed a mouse button.
748 *
749 * @param e The MouseEvent.
750 */
751 public void mouseDragged(MouseEvent e)
752 {
753 if (dragger != null)
754 dragger.continueDrag(e);
755 }
756
757 /**
758 * Repeatedly invoked when the user is dragging the mouse cursor without
759 * having pressed a mouse button.
760 *
761 * @param e The MouseEvent.
762 */
763 public void mouseMoved(MouseEvent e)
764 {
765 // Do nothing.
766 }
767 }
768
769 /**
770 * Performs the tasks associated with an ongoing drag operation.
771 *
772 * @author Sascha Brawer (brawer_AT_dandelis.ch)
773 */
774 protected class DragController
775 {
776 /**
777 * The difference between where the mouse is clicked and the initial
778 * divider location.
779 */
780 transient int offset;
781
782 /**
783 * Creates a new DragController object.
784 *
785 * @param e The MouseEvent to initialize with.
786 */
787 protected DragController(MouseEvent e)
788 {
789 offset = e.getX();
790 }
791
792 /**
793 * This method returns true if the divider can move.
794 *
795 * @return True if dragging is allowed.
796 */
797 protected boolean isValid()
798 {
799 // Views can always be resized?
800 return true;
801 }
802
803 /**
804 * Returns a position for the divider given the MouseEvent.
805 *
806 * @param e MouseEvent.
807 *
808 * @return The position for the divider to move to.
809 */
810 protected int positionForMouseEvent(MouseEvent e)
811 {
812 return e.getX() + getX() - offset;
813 }
814
815 /**
816 * This method returns one of the two paramters for the orientation. In
817 * this case, it returns x.
818 *
819 * @param x The x coordinate.
820 * @param y The y coordinate.
821 *
822 * @return The x coordinate.
823 */
824 protected int getNeededLocation(int x, int y)
825 {
826 return x;
827 }
828
829 /**
830 * This method is called to pass on the drag information to the UI through
831 * dragDividerTo.
832 *
833 * @param newX The x coordinate of the MouseEvent.
834 * @param newY The y coordinate of the MouseEvent.
835 */
836 protected void continueDrag(int newX, int newY)
837 {
838 if (isValid())
839 dragDividerTo(adjust(newX, newY));
840 }
841
842 /**
843 * This method is called to pass on the drag information to the UI
844 * through dragDividerTo.
845 *
846 * @param e The MouseEvent.
847 */
848 protected void continueDrag(MouseEvent e)
849 {
850 if (isValid())
851 dragDividerTo(positionForMouseEvent(e));
852 }
853
854 /**
855 * This method is called to finish the drag session by calling
856 * finishDraggingTo.
857 *
858 * @param x The x coordinate of the MouseEvent.
859 * @param y The y coordinate of the MouseEvent.
860 */
861 protected void completeDrag(int x, int y)
862 {
863 finishDraggingTo(adjust(x, y));
864 }
865
866 /**
867 * This method is called to finish the drag session by calling
868 * finishDraggingTo.
869 *
870 * @param e The MouseEvent.
871 */
872 protected void completeDrag(MouseEvent e)
873 {
874 finishDraggingTo(positionForMouseEvent(e));
875 }
876
877 /**
878 * This is a helper method that includes the offset in the needed
879 * location.
880 *
881 * @param x The x coordinate of the MouseEvent.
882 * @param y The y coordinate of the MouseEvent.
883 *
884 * @return The needed location adjusted by the offsets.
885 */
886 int adjust(int x, int y)
887 {
888 return getNeededLocation(x, y) + getX() - offset;
889 }
890 }
891
892 /**
893 * This is a helper class that controls dragging when the orientation is
894 * VERTICAL_SPLIT.
895 */
896 protected class VerticalDragController extends DragController
897 {
898 /**
899 * Creates a new VerticalDragController object.
900 *
901 * @param e The MouseEvent to initialize with.
902 */
903 protected VerticalDragController(MouseEvent e)
904 {
905 super(e);
906 offset = e.getY();
907 }
908
909 /**
910 * This method returns one of the two parameters given the orientation. In
911 * this case, it returns y.
912 *
913 * @param x The x coordinate of the MouseEvent.
914 * @param y The y coordinate of the MouseEvent.
915 *
916 * @return The y coordinate.
917 */
918 protected int getNeededLocation(int x, int y)
919 {
920 return y;
921 }
922
923 /**
924 * This method returns the new location of the divider given a MouseEvent.
925 *
926 * @param e The MouseEvent.
927 *
928 * @return The new location of the divider.
929 */
930 protected int positionForMouseEvent(MouseEvent e)
931 {
932 return e.getY() + getY() - offset;
933 }
934
935 /**
936 * This is a helper method that includes the offset in the needed
937 * location.
938 *
939 * @param x The x coordinate of the MouseEvent.
940 * @param y The y coordinate of the MouseEvent.
941 *
942 * @return The needed location adjusted by the offsets.
943 */
944 int adjust(int x, int y)
945 {
946 return getNeededLocation(x, y) + getY() - offset;
947 }
948 }
949
950 /**
951 * This helper class acts as the Layout Manager for the divider.
952 */
953 protected class DividerLayout implements LayoutManager
954 {
955 /**
956 * Creates a new DividerLayout object.
957 */
958 protected DividerLayout()
959 {
960 // Nothing to do here.
961 }
962
963 /**
964 * This method is called when a Component is added.
965 *
966 * @param string The constraints string.
967 * @param c The Component to add.
968 */
969 public void addLayoutComponent(String string, Component c)
970 {
971 // Do nothing.
972 }
973
974 /**
975 * This method is called to lay out the container.
976 *
977 * @param c The container to lay out.
978 */
979 public void layoutContainer(Container c)
980 {
981 if (leftButton != null && rightButton != null
982 && c == BasicSplitPaneDivider.this)
983 {
984 if (splitPane.isOneTouchExpandable())
985 {
986 Insets insets = getInsets();
987 if (orientation == JSplitPane.HORIZONTAL_SPLIT)
988 {
989 int size = getWidth() - insets.left - insets.right;
990 size = Math.max(size, 0);
991 size = Math.min(size, ONE_TOUCH_SIZE);
992 int x, y;
993 if (centerOneTouchButtons)
994 {
995 y = insets.top;
996 x = (getWidth() - size) / 2;
997 }
998 else
999 {
1000 x = insets.left;
1001 y = 0;
1002 }
1003
1004 leftButton.setBounds(x, y + ONE_TOUCH_OFFSET, size,
1005 size * 2);
1006 rightButton.setBounds(x, y + ONE_TOUCH_OFFSET
1007 + ONE_TOUCH_SIZE * 2, size, size * 2);
1008 }
1009 else
1010 {
1011 int size = getHeight() - insets.top - insets.bottom;
1012 size = Math.max(size, 0);
1013 size = Math.min(size, ONE_TOUCH_SIZE);
1014 int x, y;
1015 if (centerOneTouchButtons)
1016 {
1017 x = insets.left;
1018 y = (getHeight() - size) / 2;
1019 }
1020 else
1021 {
1022 x = 0;
1023 y = insets.top;
1024 }
1025 leftButton.setBounds(x + ONE_TOUCH_OFFSET, y, size * 2,
1026 size);
1027 rightButton.setBounds(x + ONE_TOUCH_OFFSET
1028 + ONE_TOUCH_SIZE * 2, y, size * 2,
1029 size);
1030 }
1031 }
1032 else
1033 {
1034 // The JDK sets this bounds for disabled one touch buttons, so
1035 // do we.
1036 leftButton.setBounds(-5, -5, 1, 1);
1037 rightButton.setBounds(-5, -5, 1, 1);
1038 }
1039 }
1040 }
1041
1042 /**
1043 * This method returns the minimum layout size.
1044 *
1045 * @param c The container to calculate for.
1046 *
1047 * @return The minimum layout size.
1048 */
1049 public Dimension minimumLayoutSize(Container c)
1050 {
1051 return preferredLayoutSize(c);
1052 }
1053
1054 /**
1055 * This method returns the preferred layout size.
1056 *
1057 * @param c The container to calculate for.
1058 *
1059 * @return The preferred layout size.
1060 */
1061 public Dimension preferredLayoutSize(Container c)
1062 {
1063 return new Dimension(dividerSize, dividerSize);
1064 }
1065
1066 /**
1067 * This method is called when a component is removed.
1068 *
1069 * @param c The component to remove.
1070 */
1071 public void removeLayoutComponent(Component c)
1072 {
1073 // Do nothing.
1074 }
1075
1076 }
1077 }