KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > plaf > basic > BasicSplitPaneDivider


1 /*
2  * @(#)BasicSplitPaneDivider.java 1.52 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8
9
10 package javax.swing.plaf.basic;
11
12
13
14 import java.awt.*;
15 import java.awt.event.*;
16 import javax.swing.*;
17 import javax.swing.event.*;
18 import javax.swing.plaf.*;
19 import javax.swing.border.Border JavaDoc;
20 import java.beans.*;
21 import sun.swing.DefaultLookup;
22
23
24
25 /**
26  * Divider used by BasicSplitPaneUI. Subclassers may wish to override
27  * paint to do something more interesting.
28  * The border effect is drawn in BasicSplitPaneUI, so if you don't like
29  * that border, reset it there.
30  * To conditionally drag from certain areas subclass mousePressed and
31  * call super when you wish the dragging to begin.
32  * <p>
33  * <strong>Warning:</strong>
34  * Serialized objects of this class will not be compatible with
35  * future Swing releases. The current serialization support is
36  * appropriate for short term storage or RMI between applications running
37  * the same version of Swing. As of 1.4, support for long term storage
38  * of all JavaBeans<sup><font size="-2">TM</font></sup>
39  * has been added to the <code>java.beans</code> package.
40  * Please see {@link java.beans.XMLEncoder}.
41  *
42  * @version 1.52 12/19/03
43  * @author Scott Violet
44  */

45 public class BasicSplitPaneDivider extends Container
46     implements PropertyChangeListener
47 {
48     /**
49      * Width or height of the divider based on orientation
50      * BasicSplitPaneUI adds two to this.
51      */

52     protected static final int ONE_TOUCH_SIZE = 6;
53     protected static final int ONE_TOUCH_OFFSET = 2;
54
55     /**
56      * Handles mouse dragging message to do the actual dragging.
57      */

58     protected DragController dragger;
59
60     /**
61      * UI this instance was created from.
62      */

63     protected BasicSplitPaneUI JavaDoc splitPaneUI;
64
65     /**
66      * Size of the divider.
67      */

68     protected int dividerSize = 0; // default - SET TO 0???
69

70     /**
71      * Divider that is used for noncontinuous layout mode.
72      */

73     protected Component hiddenDivider;
74
75     /**
76      * JSplitPane the receiver is contained in.
77      */

78     protected JSplitPane splitPane;
79
80     /**
81      * Handles mouse events from both this class, and the split pane.
82      * Mouse events are handled for the splitpane since you want to be able
83      * to drag when clicking on the border of the divider, which is not
84      * drawn by the divider.
85      */

86     protected MouseHandler mouseHandler;
87
88     /**
89      * Orientation of the JSplitPane.
90      */

91     protected int orientation;
92
93     /**
94      * Button for quickly toggling the left component.
95      */

96     protected JButton leftButton;
97
98     /**
99      * Button for quickly toggling the right component.
100      */

101     protected JButton rightButton;
102
103     /** Border. */
104     private Border JavaDoc border;
105
106     /**
107      * Is the mouse over the divider?
108      */

109     private boolean mouseOver;
110
111     private int oneTouchSize;
112     private int oneTouchOffset;
113
114     /**
115      * If true the one touch buttons are centered on the divider.
116      */

117     private boolean centerOneTouchButtons;
118
119
120     /**
121      * Creates an instance of BasicSplitPaneDivider. Registers this
122      * instance for mouse events and mouse dragged events.
123      */

124     public BasicSplitPaneDivider(BasicSplitPaneUI JavaDoc ui) {
125         oneTouchSize = DefaultLookup.getInt(ui.getSplitPane(), ui,
126                 "SplitPane.oneTouchButtonSize", ONE_TOUCH_SIZE);
127         oneTouchOffset = DefaultLookup.getInt(ui.getSplitPane(), ui,
128                 "SplitPane.oneTouchButtonOffset", ONE_TOUCH_OFFSET);
129         centerOneTouchButtons = DefaultLookup.getBoolean(ui.getSplitPane(),
130                  ui, "SplitPane.centerOneTouchButtons", true);
131         setLayout(new DividerLayout());
132         setBasicSplitPaneUI(ui);
133         orientation = splitPane.getOrientation();
134         setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ?
135                   Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) :
136                   Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
137         setBackground(UIManager.getColor("SplitPane.background"));
138     }
139
140     private void revalidate() {
141         invalidate();
142         if (splitPane != null) {
143             splitPane.revalidate();
144         }
145     }
146
147     /**
148      * Sets the SplitPaneUI that is using the receiver.
149      */

150     public void setBasicSplitPaneUI(BasicSplitPaneUI JavaDoc newUI) {
151         if (splitPane != null) {
152             splitPane.removePropertyChangeListener(this);
153            if (mouseHandler != null) {
154                splitPane.removeMouseListener(mouseHandler);
155                splitPane.removeMouseMotionListener(mouseHandler);
156            removeMouseListener(mouseHandler);
157            removeMouseMotionListener(mouseHandler);
158                mouseHandler = null;
159            }
160         }
161         splitPaneUI = newUI;
162         if (newUI != null) {
163             splitPane = newUI.getSplitPane();
164             if (splitPane != null) {
165                 if (mouseHandler == null) mouseHandler = new MouseHandler();
166                 splitPane.addMouseListener(mouseHandler);
167                 splitPane.addMouseMotionListener(mouseHandler);
168         addMouseListener(mouseHandler);
169         addMouseMotionListener(mouseHandler);
170                 splitPane.addPropertyChangeListener(this);
171                 if (splitPane.isOneTouchExpandable()) {
172                     oneTouchExpandableChanged();
173                 }
174             }
175         }
176         else {
177             splitPane = null;
178         }
179     }
180
181
182     /**
183      * Returns the <code>SplitPaneUI</code> the receiver is currently
184      * in.
185      */

186     public BasicSplitPaneUI JavaDoc getBasicSplitPaneUI() {
187         return splitPaneUI;
188     }
189
190
191     /**
192      * Sets the size of the divider to <code>newSize</code>. That is
193      * the width if the splitpane is <code>HORIZONTAL_SPLIT</code>, or
194      * the height of <code>VERTICAL_SPLIT</code>.
195      */

196     public void setDividerSize(int newSize) {
197         dividerSize = newSize;
198     }
199
200
201     /**
202      * Returns the size of the divider, that is the width if the splitpane
203      * is HORIZONTAL_SPLIT, or the height of VERTICAL_SPLIT.
204      */

205     public int getDividerSize() {
206         return dividerSize;
207     }
208
209
210     /**
211      * Sets the border of this component.
212      * @since 1.3
213      */

214     public void setBorder(Border JavaDoc border) {
215         Border JavaDoc oldBorder = this.border;
216
217         this.border = border;
218     }
219
220     /**
221      * Returns the border of this component or null if no border is
222      * currently set.
223      *
224      * @return the border object for this component
225      * @see #setBorder
226      * @since 1.3
227      */

228     public Border JavaDoc getBorder() {
229         return border;
230     }
231
232     /**
233      * If a border has been set on this component, returns the
234      * border's insets, else calls super.getInsets.
235      *
236      * @return the value of the insets property.
237      * @see #setBorder
238      */

239     public Insets getInsets() {
240     Border JavaDoc border = getBorder();
241
242         if (border != null) {
243             return border.getBorderInsets(this);
244         }
245         return super.getInsets();
246     }
247
248     /**
249      * Sets whether or not the mouse is currently over the divider.
250      *
251      * @param mouseOver whether or not the mouse is currently over the divider
252      * @since 1.5
253      */

254     protected void setMouseOver(boolean mouseOver) {
255         this.mouseOver = mouseOver;
256     }
257
258     /**
259      * Returns whether or not the mouse is currently over the divider
260      *
261      * @param Returns whether or not the mouse is currently over the divider
262      */

263     public boolean isMouseOver() {
264         return mouseOver;
265     }
266
267     /**
268      * Returns dividerSize x dividerSize
269      */

270     public Dimension getPreferredSize() {
271         // Ideally this would return the size from the layout manager,
272
// but that could result in the layed out size being different from
273
// the dividerSize, which may break developers as well as
274
// BasicSplitPaneUI.
275
if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
276             return new Dimension(getDividerSize(), 1);
277         }
278         return new Dimension(1, getDividerSize());
279     }
280
281     /**
282      * Returns dividerSize x dividerSize
283      */

284     public Dimension getMinimumSize() {
285         return getPreferredSize();
286     }
287
288
289     /**
290      * Property change event, presumably from the JSplitPane, will message
291      * updateOrientation if necessary.
292      */

293     public void propertyChange(PropertyChangeEvent e) {
294         if (e.getSource() == splitPane) {
295             if (e.getPropertyName() == JSplitPane.ORIENTATION_PROPERTY) {
296                 orientation = splitPane.getOrientation();
297                 setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ?
298                           Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) :
299                           Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
300                 revalidate();
301             }
302             else if (e.getPropertyName() == JSplitPane.
303                       ONE_TOUCH_EXPANDABLE_PROPERTY) {
304                 oneTouchExpandableChanged();
305             }
306         }
307     }
308
309
310     /**
311      * Paints the divider.
312      */

313     public void paint(Graphics g) {
314       super.paint(g);
315
316       // Paint the border.
317
Border JavaDoc border = getBorder();
318
319       if (border != null) {
320       Dimension size = getSize();
321
322       border.paintBorder(this, g, 0, 0, size.width, size.height);
323       }
324     }
325
326
327     /**
328      * Messaged when the oneTouchExpandable value of the JSplitPane the
329      * receiver is contained in changes. Will create the
330      * <code>leftButton</code> and <code>rightButton</code> if they
331      * are null. invalidates the receiver as well.
332      */

333     protected void oneTouchExpandableChanged() {
334         if (!DefaultLookup.getBoolean(splitPane, splitPaneUI,
335                            "SplitPane.supportsOneTouchButtons", true)) {
336             // Look and feel doesn't want to support one touch buttons, bail.
337
return;
338         }
339         if (splitPane.isOneTouchExpandable() &&
340             leftButton == null &&
341             rightButton == null) {
342             /* Create the left button and add an action listener to
343                expand/collapse it. */

344             leftButton = createLeftOneTouchButton();
345             if (leftButton != null)
346                 leftButton.addActionListener(new OneTouchActionHandler(true));
347
348
349             /* Create the right button and add an action listener to
350                expand/collapse it. */

351             rightButton = createRightOneTouchButton();
352             if (rightButton != null)
353                 rightButton.addActionListener(new OneTouchActionHandler
354             (false));
355
356             if (leftButton != null && rightButton != null) {
357                 add(leftButton);
358                 add(rightButton);
359             }
360         }
361         revalidate();
362     }
363
364
365     /**
366      * Creates and return an instance of JButton that can be used to
367      * collapse the left component in the split pane.
368      */

369     protected JButton createLeftOneTouchButton() {
370         JButton b = new JButton() {
371             public void setBorder(Border JavaDoc b) {
372             }
373             public void paint(Graphics g) {
374                 if (splitPane != null) {
375                     int[] xs = new int[3];
376                     int[] ys = new int[3];
377                     int blockSize;
378
379                     // Fill the background first ...
380
g.setColor(this.getBackground());
381                     g.fillRect(0, 0, this.getWidth(),
382                                this.getHeight());
383
384                     // ... then draw the arrow.
385
g.setColor(Color.black);
386                     if (orientation == JSplitPane.VERTICAL_SPLIT) {
387                         blockSize = Math.min(getHeight(), oneTouchSize);
388                         xs[0] = blockSize;
389                         xs[1] = 0;
390                         xs[2] = blockSize << 1;
391                         ys[0] = 0;
392                         ys[1] = ys[2] = blockSize;
393                         g.drawPolygon(xs, ys, 3); // Little trick to make the
394
// arrows of equal size
395
}
396                     else {
397                         blockSize = Math.min(getWidth(), oneTouchSize);
398                         xs[0] = xs[2] = blockSize;
399                         xs[1] = 0;
400                         ys[0] = 0;
401                         ys[1] = blockSize;
402                         ys[2] = blockSize << 1;
403                     }
404                     g.fillPolygon(xs, ys, 3);
405                 }
406             }
407         // Don't want the button to participate in focus traversable.
408
public boolean isFocusTraversable() {
409         return false;
410         }
411         };
412         b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
413     b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
414         b.setFocusPainted(false);
415         b.setBorderPainted(false);
416         b.setRequestFocusEnabled(false);
417         return b;
418     }
419
420
421     /**
422      * Creates and return an instance of JButton that can be used to
423      * collapse the right component in the split pane.
424      */

425     protected JButton createRightOneTouchButton() {
426         JButton b = new JButton() {
427             public void setBorder(Border JavaDoc border) {
428             }
429             public void paint(Graphics g) {
430                 if (splitPane != null) {
431                     int[] xs = new int[3];
432                     int[] ys = new int[3];
433                     int blockSize;
434
435                     // Fill the background first ...
436
g.setColor(this.getBackground());
437                     g.fillRect(0, 0, this.getWidth(),
438                                this.getHeight());
439
440                     // ... then draw the arrow.
441
if (orientation == JSplitPane.VERTICAL_SPLIT) {
442                         blockSize = Math.min(getHeight(), oneTouchSize);
443                         xs[0] = blockSize;
444                         xs[1] = blockSize << 1;
445                         xs[2] = 0;
446                         ys[0] = blockSize;
447                         ys[1] = ys[2] = 0;
448                     }
449                     else {
450                         blockSize = Math.min(getWidth(), oneTouchSize);
451                         xs[0] = xs[2] = 0;
452                         xs[1] = blockSize;
453                         ys[0] = 0;
454                         ys[1] = blockSize;
455                         ys[2] = blockSize << 1;
456                     }
457                     g.setColor(Color.black);
458                     g.fillPolygon(xs, ys, 3);
459                 }
460             }
461         // Don't want the button to participate in focus traversable.
462
public boolean isFocusTraversable() {
463         return false;
464         }
465         };
466         b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
467     b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
468         b.setFocusPainted(false);
469         b.setBorderPainted(false);
470         b.setRequestFocusEnabled(false);
471         return b;
472     }
473
474
475     /**
476      * Message to prepare for dragging. This messages the BasicSplitPaneUI
477      * with startDragging.
478      */

479     protected void prepareForDragging() {
480         splitPaneUI.startDragging();
481     }
482
483
484     /**
485      * Messages the BasicSplitPaneUI with dragDividerTo that this instance
486      * is contained in.
487      */

488     protected void dragDividerTo(int location) {
489         splitPaneUI.dragDividerTo(location);
490     }
491
492
493     /**
494      * Messages the BasicSplitPaneUI with finishDraggingTo that this instance
495      * is contained in.
496      */

497     protected void finishDraggingTo(int location) {
498         splitPaneUI.finishDraggingTo(location);
499     }
500
501
502     /**
503      * MouseHandler is responsible for converting mouse events
504      * (released, dragged...) into the appropriate DragController
505      * methods.
506      * <p>
507      */

508     protected class MouseHandler extends MouseAdapter
509             implements MouseMotionListener
510     {
511         /**
512          * Starts the dragging session by creating the appropriate instance
513          * of DragController.
514          */

515         public void mousePressed(MouseEvent e) {
516             if ((e.getSource() == BasicSplitPaneDivider.this ||
517          e.getSource() == splitPane) &&
518         dragger == null &&splitPane.isEnabled()) {
519                 Component newHiddenDivider = splitPaneUI.
520                                      getNonContinuousLayoutDivider();
521
522                 if (hiddenDivider != newHiddenDivider) {
523                     if (hiddenDivider != null) {
524                         hiddenDivider.removeMouseListener(this);
525                         hiddenDivider.removeMouseMotionListener(this);
526                     }
527                     hiddenDivider = newHiddenDivider;
528                     if (hiddenDivider != null) {
529                         hiddenDivider.addMouseMotionListener(this);
530                         hiddenDivider.addMouseListener(this);
531                     }
532                 }
533                 if (splitPane.getLeftComponent() != null &&
534                     splitPane.getRightComponent() != null) {
535                     if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
536                         dragger = new DragController(e);
537                     }
538                     else {
539                         dragger = new VerticalDragController(e);
540                     }
541                     if (!dragger.isValid()) {
542                         dragger = null;
543                     }
544                     else {
545                         prepareForDragging();
546                         dragger.continueDrag(e);
547                     }
548                 }
549                 e.consume();
550             }
551         }
552
553
554         /**
555          * If dragger is not null it is messaged with completeDrag.
556          */

557         public void mouseReleased(MouseEvent e) {
558             if (dragger != null) {
559                 if (e.getSource() == splitPane) {
560                     dragger.completeDrag(e.getX(), e.getY());
561                 }
562         else if (e.getSource() == BasicSplitPaneDivider.this) {
563                     Point ourLoc = getLocation();
564
565             dragger.completeDrag(e.getX() + ourLoc.x,
566                      e.getY() + ourLoc.y);
567         }
568                 else if (e.getSource() == hiddenDivider) {
569                     Point hDividerLoc = hiddenDivider.getLocation();
570                     int ourX = e.getX() + hDividerLoc.x;
571                     int ourY = e.getY() + hDividerLoc.y;
572                     
573                     dragger.completeDrag(ourX, ourY);
574                 }
575                 dragger = null;
576                 e.consume();
577             }
578         }
579
580
581         //
582
// MouseMotionListener
583
//
584

585         /**
586          * If dragger is not null it is messaged with continueDrag.
587          */

588         public void mouseDragged(MouseEvent e) {
589             if (dragger != null) {
590                 if (e.getSource() == splitPane) {
591                     dragger.continueDrag(e.getX(), e.getY());
592                 }
593         else if (e.getSource() == BasicSplitPaneDivider.this) {
594                     Point ourLoc = getLocation();
595                     
596                     dragger.continueDrag(e.getX() + ourLoc.x,
597                      e.getY() + ourLoc.y);
598         }
599                 else if (e.getSource() == hiddenDivider) {
600                     Point hDividerLoc = hiddenDivider.getLocation();
601                     int ourX = e.getX() + hDividerLoc.x;
602                     int ourY = e.getY() + hDividerLoc.y;
603                     
604                     dragger.continueDrag(ourX, ourY);
605                 }
606                 e.consume();
607             }
608         }
609
610
611         /**
612          * Resets the cursor based on the orientation.
613          */

614         public void mouseMoved(MouseEvent e) {
615         }
616
617         /**
618          * Invoked when the mouse enters a component.
619          *
620          * @param e MouseEvent describing the details of the enter event.
621          * @since 1.5
622          */

623         public void mouseEntered(MouseEvent e) {
624             if (e.getSource() == BasicSplitPaneDivider.this) {
625                 setMouseOver(true);
626             }
627         }
628
629         /**
630          * Invoked when the mouse exits a component.
631          *
632          * @param e MouseEvent describing the details of the exit event.
633          * @since 1.5
634          */

635         public void mouseExited(MouseEvent e) {
636             if (e.getSource() == BasicSplitPaneDivider.this) {
637                 setMouseOver(false);
638             }
639         }
640     }
641
642
643     /**
644      * Handles the events during a dragging session for a
645      * HORIZONTAL_SPLIT oriented split pane. This continually
646      * messages <code>dragDividerTo</code> and then when done messages
647      * <code>finishDraggingTo</code>. When an instance is created it should be
648      * messaged with <code>isValid</code> to insure that dragging can happen
649      * (dragging won't be allowed if the two views can not be resized).
650      * <p>
651      * <strong>Warning:</strong>
652      * Serialized objects of this class will not be compatible with
653      * future Swing releases. The current serialization support is
654      * appropriate for short term storage or RMI between applications running
655      * the same version of Swing. As of 1.4, support for long term storage
656      * of all JavaBeans<sup><font size="-2">TM</font></sup>
657      * has been added to the <code>java.beans</code> package.
658      * Please see {@link java.beans.XMLEncoder}.
659      */

660     protected class DragController
661     {
662         /**
663          * Initial location of the divider.
664          */

665         int initialX;
666
667         /**
668          * Maximum and minimum positions to drag to.
669          */

670         int maxX, minX;
671
672         /**
673          * Initial location the mouse down happened at.
674          */

675         int offset;
676
677
678         protected DragController(MouseEvent e) {
679             JSplitPane splitPane = splitPaneUI.getSplitPane();
680             Component leftC = splitPane.getLeftComponent();
681         Component rightC = splitPane.getRightComponent();
682
683             initialX = getLocation().x;
684         if (e.getSource() == BasicSplitPaneDivider.this) {
685         offset = e.getX();
686         }
687         else { // splitPane
688
offset = e.getX() - initialX;
689         }
690         if (leftC == null || rightC == null || offset < -1 ||
691         offset >= getSize().width) {
692         // Don't allow dragging.
693
maxX = -1;
694         }
695         else {
696         Insets insets = splitPane.getInsets();
697
698                 if (leftC.isVisible()) {
699                     minX = leftC.getMinimumSize().width;
700             if (insets != null) {
701             minX += insets.left;
702             }
703                 }
704                 else {
705                     minX = 0;
706                 }
707                 if (rightC.isVisible()) {
708             int right = (insets != null) ? insets.right : 0;
709                     maxX = Math.max(0, splitPane.getSize().width -
710                                     (getSize().width + right) -
711                                     rightC.getMinimumSize().width);
712                 }
713                 else {
714             int right = (insets != null) ? insets.right : 0;
715                     maxX = Math.max(0, splitPane.getSize().width -
716                                     (getSize().width + right));
717                 }
718                 if (maxX < minX) minX = maxX = 0;
719             }
720         }
721
722
723         /**
724          * Returns true if the dragging session is valid.
725          */

726         protected boolean isValid() {
727             return (maxX > 0);
728         }
729
730
731         /**
732          * Returns the new position to put the divider at based on
733          * the passed in MouseEvent.
734          */

735         protected int positionForMouseEvent(MouseEvent e) {
736         int newX = (e.getSource() == BasicSplitPaneDivider.this) ?
737                 (e.getX() + getLocation().x) : e.getX();
738
739             newX = Math.min(maxX, Math.max(minX, newX - offset));
740             return newX;
741         }
742
743
744         /**
745          * Returns the x argument, since this is used for horizontal
746          * splits.
747          */

748         protected int getNeededLocation(int x, int y) {
749             int newX;
750
751             newX = Math.min(maxX, Math.max(minX, x - offset));
752             return newX;
753         }
754
755
756         protected void continueDrag(int newX, int newY) {
757             dragDividerTo(getNeededLocation(newX, newY));
758         }
759
760
761         /**
762          * Messages dragDividerTo with the new location for the mouse
763          * event.
764          */

765         protected void continueDrag(MouseEvent e) {
766             dragDividerTo(positionForMouseEvent(e));
767         }
768
769
770         protected void completeDrag(int x, int y) {
771             finishDraggingTo(getNeededLocation(x, y));
772         }
773
774
775         /**
776          * Messages finishDraggingTo with the new location for the mouse
777          * event.
778          */

779         protected void completeDrag(MouseEvent e) {
780             finishDraggingTo(positionForMouseEvent(e));
781         }
782     } // End of BasicSplitPaneDivider.DragController
783

784
785     /**
786      * Handles the events during a dragging session for a
787      * VERTICAL_SPLIT oriented split pane. This continually
788      * messages <code>dragDividerTo</code> and then when done messages
789      * <code>finishDraggingTo</code>. When an instance is created it should be
790      * messaged with <code>isValid</code> to insure that dragging can happen
791      * (dragging won't be allowed if the two views can not be resized).
792      */

793     protected class VerticalDragController extends DragController
794     {
795         /* DragControllers ivars are now in terms of y, not x. */
796         protected VerticalDragController(MouseEvent e) {
797             super(e);
798             JSplitPane splitPane = splitPaneUI.getSplitPane();
799             Component leftC = splitPane.getLeftComponent();
800         Component rightC = splitPane.getRightComponent();
801
802             initialX = getLocation().y;
803         if (e.getSource() == BasicSplitPaneDivider.this) {
804         offset = e.getY();
805         }
806         else {
807         offset = e.getY() - initialX;
808         }
809         if (leftC == null || rightC == null || offset < -1 ||
810         offset > getSize().height) {
811         // Don't allow dragging.
812
maxX = -1;
813         }
814         else {
815         Insets insets = splitPane.getInsets();
816
817                 if (leftC.isVisible()) {
818                     minX = leftC.getMinimumSize().height;
819             if (insets != null) {
820             minX += insets.top;
821             }
822                 }
823                 else {
824                     minX = 0;
825                 }
826                 if (rightC.isVisible()) {
827             int bottom = (insets != null) ? insets.bottom : 0;
828
829                     maxX = Math.max(0, splitPane.getSize().height -
830                                     (getSize().height + bottom) -
831                                     rightC.getMinimumSize().height);
832                 }
833                 else {
834             int bottom = (insets != null) ? insets.bottom : 0;
835
836                     maxX = Math.max(0, splitPane.getSize().height -
837                                     (getSize().height + bottom));
838                 }
839                 if (maxX < minX) minX = maxX = 0;
840             }
841         }
842
843
844         /**
845          * Returns the y argument, since this is used for vertical
846          * splits.
847          */

848         protected int getNeededLocation(int x, int y) {
849             int newY;
850
851             newY = Math.min(maxX, Math.max(minX, y - offset));
852             return newY;
853         }
854
855
856         /**
857          * Returns the new position to put the divider at based on
858          * the passed in MouseEvent.
859          */

860         protected int positionForMouseEvent(MouseEvent e) {
861         int newY = (e.getSource() == BasicSplitPaneDivider.this) ?
862                 (e.getY() + getLocation().y) : e.getY();
863
864
865             newY = Math.min(maxX, Math.max(minX, newY - offset));
866             return newY;
867         }
868     } // End of BasicSplitPaneDividier.VerticalDragController
869

870
871     /**
872      * Used to layout a <code>BasicSplitPaneDivider</code>.
873      * Layout for the divider
874      * involves appropriately moving the left/right buttons around.
875      * <p>
876      */

877     protected class DividerLayout implements LayoutManager
878     {
879         public void layoutContainer(Container c) {
880             if (leftButton != null && rightButton != null &&
881                 c == BasicSplitPaneDivider.this) {
882                 if (splitPane.isOneTouchExpandable()) {
883             Insets insets = getInsets();
884
885                     if (orientation == JSplitPane.VERTICAL_SPLIT) {
886             int extraX = (insets != null) ? insets.left : 0;
887             int blockSize = getHeight();
888
889             if (insets != null) {
890                 blockSize -= (insets.top + insets.bottom);
891                             blockSize = Math.max(blockSize, 0);
892             }
893                         blockSize = Math.min(blockSize, oneTouchSize);
894
895                         int y = (c.getSize().height - blockSize) / 2;
896
897                         if (!centerOneTouchButtons) {
898                             y = (insets != null) ? insets.top : 0;
899                             extraX = 0;
900                         }
901                         leftButton.setBounds(extraX + oneTouchOffset, y,
902                                              blockSize * 2, blockSize);
903                         rightButton.setBounds(extraX + oneTouchOffset +
904                                               oneTouchSize * 2, y,
905                                               blockSize * 2, blockSize);
906                     }
907                     else {
908             int extraY = (insets != null) ? insets.top : 0;
909             int blockSize = getWidth();
910
911             if (insets != null) {
912                 blockSize -= (insets.left + insets.right);
913                             blockSize = Math.max(blockSize, 0);
914             }
915                         blockSize = Math.min(blockSize, oneTouchSize);
916
917                         int x = (c.getSize().width - blockSize) / 2;
918
919                         if (!centerOneTouchButtons) {
920                             x = (insets != null) ? insets.left : 0;
921                             extraY = 0;
922                         }
923
924                         leftButton.setBounds(x, extraY + oneTouchOffset,
925                                              blockSize, blockSize * 2);
926                         rightButton.setBounds(x, extraY + oneTouchOffset +
927                                               oneTouchSize * 2, blockSize,
928                                               blockSize * 2);
929                     }
930                 }
931                 else {
932                     leftButton.setBounds(-5, -5, 1, 1);
933                     rightButton.setBounds(-5, -5, 1, 1);
934                 }
935             }
936         }
937
938
939         public Dimension minimumLayoutSize(Container c) {
940             // NOTE: This isn't really used, refer to
941
// BasicSplitPaneDivider.getPreferredSize for the reason.
942
// I leave it in hopes of having this used at some point.
943
if (c != BasicSplitPaneDivider.this || splitPane == null) {
944                 return new Dimension(0,0);
945             }
946             Dimension buttonMinSize = null;
947
948             if (splitPane.isOneTouchExpandable() && leftButton != null) {
949                 buttonMinSize = leftButton.getMinimumSize();
950             }
951
952             Insets insets = getInsets();
953             int width = getDividerSize();
954             int height = width;
955
956             if (orientation == JSplitPane.VERTICAL_SPLIT) {
957                 if (buttonMinSize != null) {
958                     int size = buttonMinSize.height;
959                     if (insets != null) {
960                         size += insets.top + insets.bottom;
961                     }
962                     height = Math.max(height, size);
963                 }
964                 width = 1;
965             }
966             else {
967                 if (buttonMinSize != null) {
968                     int size = buttonMinSize.width;
969                     if (insets != null) {
970                         size += insets.left + insets.right;
971                     }
972                     width = Math.max(width, size);
973                 }
974                 height = 1;
975             }
976             return new Dimension(width, height);
977         }
978
979
980         public Dimension preferredLayoutSize(Container c) {
981             return minimumLayoutSize(c);
982         }
983
984
985         public void removeLayoutComponent(Component c) {}
986
987         public void addLayoutComponent(String JavaDoc string, Component c) {}
988     } // End of class BasicSplitPaneDivider.DividerLayout
989

990
991     /**
992      * Listeners installed on the one touch expandable buttons.
993      */

994     private class OneTouchActionHandler implements ActionListener {
995     /** True indicates the resize should go the minimum (top or left)
996      * vs false which indicates the resize should go to the maximum.
997      */

998     private boolean toMinimum;
999
1000    OneTouchActionHandler(boolean toMinimum) {
1001        this.toMinimum = toMinimum;
1002    }
1003
1004        public void actionPerformed(ActionEvent e) {
1005            Insets insets = splitPane.getInsets();
1006        int lastLoc = splitPane.getLastDividerLocation();
1007            int currentLoc = splitPaneUI.getDividerLocation(splitPane);
1008        int newLoc;
1009
1010        // We use the location from the UI directly, as the location the
1011
// JSplitPane itself maintains is not necessarly correct.
1012
if (toMinimum) {
1013        if (orientation == JSplitPane.VERTICAL_SPLIT) {
1014            if (currentLoc >= (splitPane.getHeight() -
1015                       insets.bottom - getHeight())) {
1016            int maxLoc = splitPane.getMaximumDividerLocation();
1017            newLoc = Math.min(lastLoc, maxLoc);
1018            splitPaneUI.setKeepHidden(false);
1019                    }
1020            else {
1021            newLoc = insets.top;
1022            splitPaneUI.setKeepHidden(true);
1023                    }
1024        }
1025        else {
1026            if (currentLoc >= (splitPane.getWidth() -
1027                       insets.right - getWidth())) {
1028            int maxLoc = splitPane.getMaximumDividerLocation();
1029            newLoc = Math.min(lastLoc, maxLoc);
1030            splitPaneUI.setKeepHidden(false);
1031                    }
1032            else {
1033            newLoc = insets.left;
1034            splitPaneUI.setKeepHidden(true);
1035                    }
1036        }
1037        }
1038        else {
1039        if (orientation == JSplitPane.VERTICAL_SPLIT) {
1040            if (currentLoc == insets.top) {
1041            int maxLoc = splitPane.getMaximumDividerLocation();
1042            newLoc = Math.min(lastLoc, maxLoc);
1043            splitPaneUI.setKeepHidden(false);
1044                    }
1045            else {
1046            newLoc = splitPane.getHeight() - getHeight() -
1047                     insets.top;
1048            splitPaneUI.setKeepHidden(true);
1049                    }
1050        }
1051        else {
1052            if (currentLoc == insets.left) {
1053            int maxLoc = splitPane.getMaximumDividerLocation();
1054            newLoc = Math.min(lastLoc, maxLoc);
1055            splitPaneUI.setKeepHidden(false);
1056                    }
1057            else {
1058            newLoc = splitPane.getWidth() - getWidth() -
1059                     insets.left;
1060            splitPaneUI.setKeepHidden(true);
1061            }
1062        }
1063        }
1064        if (currentLoc != newLoc) {
1065        splitPane.setDividerLocation(newLoc);
1066        // We do this in case the dividers notion of the location
1067
// differs from the real location.
1068
splitPane.setLastDividerLocation(currentLoc);
1069        }
1070        }
1071    } // End of class BasicSplitPaneDivider.LeftActionListener
1072
}
1073
Popular Tags