KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * @(#)BasicSplitPaneUI.java 1.80 04/05/18
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8
9 package javax.swing.plaf.basic;
10
11
12 import sun.swing.DefaultLookup;
13 import sun.swing.UIAction;
14 import javax.swing.*;
15 import javax.swing.border.Border JavaDoc;
16 import javax.swing.event.*;
17 import java.awt.*;
18 import java.awt.event.*;
19 import java.awt.peer.ComponentPeer;
20 import java.awt.peer.LightweightPeer;
21 import java.beans.*;
22 import java.util.*;
23 import javax.swing.plaf.ActionMapUIResource JavaDoc;
24 import javax.swing.plaf.SplitPaneUI JavaDoc;
25 import javax.swing.plaf.ComponentUI JavaDoc;
26 import javax.swing.plaf.UIResource JavaDoc;
27
28
29 /**
30  * A Basic L&F implementation of the SplitPaneUI.
31  *
32  * @version 1.80 05/18/04
33  * @author Scott Violet
34  * @author Steve Wilson
35  * @author Ralph Kar
36  */

37 public class BasicSplitPaneUI extends SplitPaneUI JavaDoc
38 {
39     /**
40      * The divider used for non-continuous layout is added to the split pane
41      * with this object.
42      */

43     protected static final String JavaDoc NON_CONTINUOUS_DIVIDER =
44         "nonContinuousDivider";
45
46
47     /**
48      * How far (relative) the divider does move when it is moved around by
49      * the cursor keys on the keyboard.
50      */

51     protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3;
52
53
54     /**
55      * JSplitPane instance this instance is providing
56      * the look and feel for.
57      */

58     protected JSplitPane splitPane;
59
60
61     /**
62      * LayoutManager that is created and placed into the split pane.
63      */

64     protected BasicHorizontalLayoutManager layoutManager;
65
66
67     /**
68      * Instance of the divider for this JSplitPane.
69      */

70     protected BasicSplitPaneDivider JavaDoc divider;
71
72
73     /**
74      * Instance of the PropertyChangeListener for this JSplitPane.
75      */

76     protected PropertyChangeListener propertyChangeListener;
77
78
79     /**
80      * Instance of the FocusListener for this JSplitPane.
81      */

82     protected FocusListener focusListener;
83
84     private Handler handler;
85
86
87     /**
88      * Keys to use for forward focus traversal when the JComponent is
89      * managing focus.
90      */

91     private static Set managingFocusForwardTraversalKeys;
92
93     /**
94      * Keys to use for backward focus traversal when the JComponent is
95      * managing focus.
96      */

97     private static Set managingFocusBackwardTraversalKeys;
98
99
100     /**
101      * The size of the divider while the dragging session is valid.
102      */

103     protected int dividerSize;
104
105
106     /**
107      * Instance for the shadow of the divider when non continuous layout
108      * is being used.
109      */

110     protected Component nonContinuousLayoutDivider;
111
112
113     /**
114      * Set to true in startDragging if any of the children
115      * (not including the nonContinuousLayoutDivider) are heavy weights.
116      */

117     protected boolean draggingHW;
118
119
120     /**
121      * Location of the divider when the dragging session began.
122      */

123     protected int beginDragDividerLocation;
124
125
126     /**
127      * As of Java 2 platform v1.3 this previously undocumented field is no
128      * longer used.
129      * Key bindings are now defined by the LookAndFeel, please refer to
130      * the key bindings specification for further details.
131      *
132      * @deprecated As of Java 2 platform v1.3.
133      */

134     @Deprecated JavaDoc
135     protected KeyStroke upKey;
136     /**
137      * As of Java 2 platform v1.3 this previously undocumented field is no
138      * longer used.
139      * Key bindings are now defined by the LookAndFeel, please refer to
140      * the key bindings specification for further details.
141      *
142      * @deprecated As of Java 2 platform v1.3.
143      */

144     @Deprecated JavaDoc
145     protected KeyStroke downKey;
146     /**
147      * As of Java 2 platform v1.3 this previously undocumented field is no
148      * longer used.
149      * Key bindings are now defined by the LookAndFeel, please refer to
150      * the key bindings specification for further details.
151      *
152      * @deprecated As of Java 2 platform v1.3.
153      */

154     @Deprecated JavaDoc
155     protected KeyStroke leftKey;
156     /**
157      * As of Java 2 platform v1.3 this previously undocumented field is no
158      * longer used.
159      * Key bindings are now defined by the LookAndFeel, please refer to
160      * the key bindings specification for further details.
161      *
162      * @deprecated As of Java 2 platform v1.3.
163      */

164     @Deprecated JavaDoc
165     protected KeyStroke rightKey;
166     /**
167      * As of Java 2 platform v1.3 this previously undocumented field is no
168      * longer used.
169      * Key bindings are now defined by the LookAndFeel, please refer to
170      * the key bindings specification for further details.
171      *
172      * @deprecated As of Java 2 platform v1.3.
173      */

174     @Deprecated JavaDoc
175     protected KeyStroke homeKey;
176     /**
177      * As of Java 2 platform v1.3 this previously undocumented field is no
178      * longer used.
179      * Key bindings are now defined by the LookAndFeel, please refer to
180      * the key bindings specification for further details.
181      *
182      * @deprecated As of Java 2 platform v1.3.
183      */

184     @Deprecated JavaDoc
185     protected KeyStroke endKey;
186     /**
187      * As of Java 2 platform v1.3 this previously undocumented field is no
188      * longer used.
189      * Key bindings are now defined by the LookAndFeel, please refer to
190      * the key bindings specification for further details.
191      *
192      * @deprecated As of Java 2 platform v1.3.
193      */

194     @Deprecated JavaDoc
195     protected KeyStroke dividerResizeToggleKey;
196
197     /**
198      * As of Java 2 platform v1.3 this previously undocumented field is no
199      * longer used.
200      * Key bindings are now defined by the LookAndFeel, please refer to
201      * the key bindings specification for further details.
202      *
203      * @deprecated As of Java 2 platform v1.3.
204      */

205     @Deprecated JavaDoc
206     protected ActionListener keyboardUpLeftListener;
207     /**
208      * As of Java 2 platform v1.3 this previously undocumented field is no
209      * longer used.
210      * Key bindings are now defined by the LookAndFeel, please refer to
211      * the key bindings specification for further details.
212      *
213      * @deprecated As of Java 2 platform v1.3.
214      */

215     @Deprecated JavaDoc
216     protected ActionListener keyboardDownRightListener;
217     /**
218      * As of Java 2 platform v1.3 this previously undocumented field is no
219      * longer used.
220      * Key bindings are now defined by the LookAndFeel, please refer to
221      * the key bindings specification for further details.
222      *
223      * @deprecated As of Java 2 platform v1.3.
224      */

225     @Deprecated JavaDoc
226     protected ActionListener keyboardHomeListener;
227     /**
228      * As of Java 2 platform v1.3 this previously undocumented field is no
229      * longer used.
230      * Key bindings are now defined by the LookAndFeel, please refer to
231      * the key bindings specification for further details.
232      *
233      * @deprecated As of Java 2 platform v1.3.
234      */

235     @Deprecated JavaDoc
236     protected ActionListener keyboardEndListener;
237     /**
238      * As of Java 2 platform v1.3 this previously undocumented field is no
239      * longer used.
240      * Key bindings are now defined by the LookAndFeel, please refer to
241      * the key bindings specification for further details.
242      *
243      * @deprecated As of Java 2 platform v1.3.
244      */

245     @Deprecated JavaDoc
246     protected ActionListener keyboardResizeToggleListener;
247
248
249     // Private data of the instance
250
private int orientation;
251     private int lastDragLocation;
252     private boolean continuousLayout;
253     private boolean dividerKeyboardResize;
254     private boolean dividerLocationIsSet; // needed for tracking
255
// the first occurrence of
256
// setDividerLocation()
257
private Color dividerDraggingColor;
258     private boolean rememberPaneSizes;
259
260     // Indicates wether the one of splitpane sides is expanded
261
private boolean keepHidden = false;
262
263     /** Indicates that we have painted once. */
264     // This is used by the LayoutManager to determine when it should use
265
// the divider location provided by the JSplitPane. This is used as there
266
// is no way to determine when the layout process has completed.
267
boolean painted;
268     /** If true, setDividerLocation does nothing. */
269     boolean ignoreDividerLocationChange;
270
271
272     /**
273      * Creates a new BasicSplitPaneUI instance
274      */

275     public static ComponentUI JavaDoc createUI(JComponent x) {
276         return new BasicSplitPaneUI JavaDoc();
277     }
278
279     static void loadActionMap(LazyActionMap JavaDoc map) {
280         map.put(new Actions(Actions.NEGATIVE_INCREMENT));
281     map.put(new Actions(Actions.POSITIVE_INCREMENT));
282     map.put(new Actions(Actions.SELECT_MIN));
283     map.put(new Actions(Actions.SELECT_MAX));
284     map.put(new Actions(Actions.START_RESIZE));
285     map.put(new Actions(Actions.TOGGLE_FOCUS));
286     map.put(new Actions(Actions.FOCUS_OUT_FORWARD));
287     map.put(new Actions(Actions.FOCUS_OUT_BACKWARD));
288     }
289
290
291
292     /**
293      * Installs the UI.
294      */

295     public void installUI(JComponent c) {
296         splitPane = (JSplitPane) c;
297         dividerLocationIsSet = false;
298         dividerKeyboardResize = false;
299         keepHidden = false;
300         installDefaults();
301         installListeners();
302         installKeyboardActions();
303         setLastDragLocation(-1);
304     }
305
306
307     /**
308      * Installs the UI defaults.
309      */

310     protected void installDefaults(){
311         LookAndFeel.installBorder(splitPane, "SplitPane.border");
312         LookAndFeel.installColors(splitPane, "SplitPane.background",
313                                   "SplitPane.foreground");
314         LookAndFeel.installProperty(splitPane, "opaque", Boolean.TRUE);
315
316         if (divider == null) divider = createDefaultDivider();
317         divider.setBasicSplitPaneUI(this);
318
319     Border JavaDoc b = divider.getBorder();
320
321     if (b == null || !(b instanceof UIResource JavaDoc)) {
322         divider.setBorder(UIManager.getBorder("SplitPaneDivider.border"));
323     }
324
325     dividerDraggingColor = UIManager.getColor("SplitPaneDivider.draggingColor");
326
327         setOrientation(splitPane.getOrientation());
328
329     // This plus 2 here is to provide backwards consistancy. Previously,
330
// the old size did not include the 2 pixel border around the divider,
331
// it now does.
332
LookAndFeel.installProperty(splitPane, "dividerSize",
333                     UIManager.get("SplitPane.dividerSize"));
334
335         divider.setDividerSize(splitPane.getDividerSize());
336     dividerSize = divider.getDividerSize();
337         splitPane.add(divider, JSplitPane.DIVIDER);
338
339         setContinuousLayout(splitPane.isContinuousLayout());
340
341         resetLayoutManager();
342
343         /* Install the nonContinuousLayoutDivider here to avoid having to
344         add/remove everything later. */

345         if(nonContinuousLayoutDivider == null) {
346             setNonContinuousLayoutDivider(
347                                 createDefaultNonContinuousLayoutDivider(),
348                                 true);
349         } else {
350             setNonContinuousLayoutDivider(nonContinuousLayoutDivider, true);
351         }
352
353     // focus forward traversal key
354
if (managingFocusForwardTraversalKeys==null) {
355         managingFocusForwardTraversalKeys = new TreeSet();
356         managingFocusForwardTraversalKeys.add(
357         KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
358     }
359     splitPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
360                     managingFocusForwardTraversalKeys);
361     // focus backward traversal key
362
if (managingFocusBackwardTraversalKeys==null) {
363         managingFocusBackwardTraversalKeys = new TreeSet();
364         managingFocusBackwardTraversalKeys.add(
365         KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
366     }
367     splitPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
368                     managingFocusBackwardTraversalKeys);
369     }
370
371
372     /**
373      * Installs the event listeners for the UI.
374      */

375     protected void installListeners() {
376         if ((propertyChangeListener = createPropertyChangeListener()) !=
377             null) {
378             splitPane.addPropertyChangeListener(propertyChangeListener);
379         }
380
381         if ((focusListener = createFocusListener()) != null) {
382             splitPane.addFocusListener(focusListener);
383         }
384     }
385
386
387     /**
388      * Installs the keyboard actions for the UI.
389      */

390     protected void installKeyboardActions() {
391     InputMap km = getInputMap(JComponent.
392                   WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
393
394     SwingUtilities.replaceUIInputMap(splitPane, JComponent.
395                        WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
396                        km);
397         LazyActionMap.installLazyActionMap(splitPane, BasicSplitPaneUI JavaDoc.class,
398                                            "SplitPane.actionMap");
399     }
400
401     InputMap getInputMap(int condition) {
402     if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
403         return (InputMap)DefaultLookup.get(splitPane, this,
404                                                "SplitPane.ancestorInputMap");
405     }
406     return null;
407     }
408
409     /**
410      * Uninstalls the UI.
411      */

412     public void uninstallUI(JComponent c) {
413         uninstallKeyboardActions();
414         uninstallListeners();
415         uninstallDefaults();
416         dividerLocationIsSet = false;
417         dividerKeyboardResize = false;
418         splitPane = null;
419     }
420
421
422     /**
423      * Uninstalls the UI defaults.
424      */

425     protected void uninstallDefaults() {
426         if(splitPane.getLayout() == layoutManager) {
427             splitPane.setLayout(null);
428         }
429
430         if(nonContinuousLayoutDivider != null) {
431             splitPane.remove(nonContinuousLayoutDivider);
432         }
433
434         LookAndFeel.uninstallBorder(splitPane);
435
436     Border JavaDoc b = divider.getBorder();
437
438     if (b instanceof UIResource JavaDoc) {
439         divider.setBorder(null);
440     }
441
442         splitPane.remove(divider);
443         divider.setBasicSplitPaneUI(null);
444         layoutManager = null;
445         divider = null;
446         nonContinuousLayoutDivider = null;
447
448         setNonContinuousLayoutDivider(null);
449
450     // sets the focus forward and backward traversal keys to null
451
// to restore the defaults
452
splitPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
453     splitPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
454     }
455
456
457     /**
458      * Uninstalls the event listeners for the UI.
459      */

460     protected void uninstallListeners() {
461         if (propertyChangeListener != null) {
462             splitPane.removePropertyChangeListener(propertyChangeListener);
463             propertyChangeListener = null;
464         }
465         if (focusListener != null) {
466             splitPane.removeFocusListener(focusListener);
467             focusListener = null;
468         }
469
470         keyboardUpLeftListener = null;
471         keyboardDownRightListener = null;
472         keyboardHomeListener = null;
473         keyboardEndListener = null;
474         keyboardResizeToggleListener = null;
475         handler = null;
476     }
477
478
479     /**
480      * Uninstalls the keyboard actions for the UI.
481      */

482     protected void uninstallKeyboardActions() {
483     SwingUtilities.replaceUIActionMap(splitPane, null);
484     SwingUtilities.replaceUIInputMap(splitPane, JComponent.
485                       WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
486                       null);
487     }
488
489
490     /**
491      * Creates a PropertyChangeListener for the JSplitPane UI.
492      */

493     protected PropertyChangeListener createPropertyChangeListener() {
494         return getHandler();
495     }
496
497     private Handler getHandler() {
498         if (handler == null) {
499             handler = new Handler();
500         }
501         return handler;
502     }
503
504
505     /**
506      * Creates a FocusListener for the JSplitPane UI.
507      */

508     protected FocusListener createFocusListener() {
509         return getHandler();
510     }
511
512
513     /**
514      * As of Java 2 platform v1.3 this method is no
515      * longer used. Subclassers previously using this method should
516      * instead create an Action wrapping the ActionListener, and register
517      * that Action by overriding <code>installKeyboardActions</code> and
518      * placing the Action in the SplitPane's ActionMap. Please refer to
519      * the key bindings specification for further details.
520      * <p>
521      * Creates a ActionListener for the JSplitPane UI that listens for
522      * specific key presses.
523      *
524      * @deprecated As of Java 2 platform v1.3.
525      */

526     @Deprecated JavaDoc
527     protected ActionListener createKeyboardUpLeftListener() {
528         return new KeyboardUpLeftHandler();
529     }
530
531
532     /**
533      * As of Java 2 platform v1.3 this method is no
534      * longer used. Subclassers previously using this method should
535      * instead create an Action wrapping the ActionListener, and register
536      * that Action by overriding <code>installKeyboardActions</code> and
537      * placing the Action in the SplitPane's ActionMap. Please refer to
538      * the key bindings specification for further details.
539      * <p>
540      * Creates a ActionListener for the JSplitPane UI that listens for
541      * specific key presses.
542      *
543      * @deprecated As of Java 2 platform v1.3.
544      */

545     @Deprecated JavaDoc
546     protected ActionListener createKeyboardDownRightListener() {
547         return new KeyboardDownRightHandler();
548     }
549
550
551     /**
552      * As of Java 2 platform v1.3 this method is no
553      * longer used. Subclassers previously using this method should
554      * instead create an Action wrapping the ActionListener, and register
555      * that Action by overriding <code>installKeyboardActions</code> and
556      * placing the Action in the SplitPane's ActionMap. Please refer to
557      * the key bindings specification for further details.
558      * <p>
559      * Creates a ActionListener for the JSplitPane UI that listens for
560      * specific key presses.
561      *
562      * @deprecated As of Java 2 platform v1.3.
563      */

564     @Deprecated JavaDoc
565     protected ActionListener createKeyboardHomeListener() {
566         return new KeyboardHomeHandler();
567     }
568
569
570     /**
571      * As of Java 2 platform v1.3 this method is no
572      * longer used. Subclassers previously using this method should
573      * instead create an Action wrapping the ActionListener, and register
574      * that Action by overriding <code>installKeyboardActions</code> and
575      * placing the Action in the SplitPane's ActionMap. Please refer to
576      * the key bindings specification for further details.
577      * <p>
578      * Creates a ActionListener for the JSplitPane UI that listens for
579      * specific key presses.
580      *
581      * @deprecated As of Java 2 platform v1.3.
582      */

583     @Deprecated JavaDoc
584     protected ActionListener createKeyboardEndListener() {
585         return new KeyboardEndHandler();
586     }
587
588
589     /**
590      * As of Java 2 platform v1.3 this method is no
591      * longer used. Subclassers previously using this method should
592      * instead create an Action wrapping the ActionListener, and register
593      * that Action by overriding <code>installKeyboardActions</code> and
594      * placing the Action in the SplitPane's ActionMap. Please refer to
595      * the key bindings specification for further details.
596      * <p>
597      * Creates a ActionListener for the JSplitPane UI that listens for
598      * specific key presses.
599      *
600      * @deprecated As of Java 2 platform v1.3.
601      */

602     @Deprecated JavaDoc
603     protected ActionListener createKeyboardResizeToggleListener() {
604         return new KeyboardResizeToggleHandler();
605     }
606
607
608     /**
609      * Returns the orientation for the JSplitPane.
610      */

611     public int getOrientation() {
612         return orientation;
613     }
614
615
616     /**
617      * Set the orientation for the JSplitPane.
618      */

619     public void setOrientation(int orientation) {
620         this.orientation = orientation;
621     }
622
623
624     /**
625      * Determines wether the JSplitPane is set to use a continuous layout.
626      */

627     public boolean isContinuousLayout() {
628         return continuousLayout;
629     }
630
631
632     /**
633      * Turn continuous layout on/off.
634      */

635     public void setContinuousLayout(boolean b) {
636         continuousLayout = b;
637     }
638
639
640     /**
641      * Returns the last drag location of the JSplitPane.
642      */

643     public int getLastDragLocation() {
644         return lastDragLocation;
645     }
646
647
648     /**
649      * Set the last drag location of the JSplitPane.
650      */

651     public void setLastDragLocation(int l) {
652         lastDragLocation = l;
653     }
654
655     /**
656      * @return increment via keyboard methods.
657      */

658     int getKeyboardMoveIncrement() {
659     return KEYBOARD_DIVIDER_MOVE_OFFSET;
660     }
661
662     /**
663      * Implementation of the PropertyChangeListener
664      * that the JSplitPane UI uses.
665      * <p>
666      * This class should be treated as a &quot;protected&quot; inner class.
667      * Instantiate it only within subclasses of BasicSplitPaneUI.
668      */

669     public class PropertyHandler implements PropertyChangeListener
670     {
671         // NOTE: This class exists only for backward compatability. All
672
// its functionality has been moved into Handler. If you need to add
673
// new functionality add it to the Handler, but make sure this
674
// class calls into the Handler.
675

676         /**
677          * Messaged from the <code>JSplitPane</code> the receiver is
678          * contained in. May potentially reset the layout manager and cause a
679          * <code>validate</code> to be sent.
680          */

681         public void propertyChange(PropertyChangeEvent e) {
682             getHandler().propertyChange(e);
683         }
684     }
685
686
687     /**
688      * Implementation of the FocusListener that the JSplitPane UI uses.
689      * <p>
690      * This class should be treated as a &quot;protected&quot; inner class.
691      * Instantiate it only within subclasses of BasicSplitPaneUI.
692      */

693     public class FocusHandler extends FocusAdapter
694     {
695         // NOTE: This class exists only for backward compatability. All
696
// its functionality has been moved into Handler. If you need to add
697
// new functionality add it to the Handler, but make sure this
698
// class calls into the Handler.
699
public void focusGained(FocusEvent ev) {
700             getHandler().focusGained(ev);
701         }
702
703         public void focusLost(FocusEvent ev) {
704             getHandler().focusLost(ev);
705         }
706     }
707     
708
709     /**
710      * Implementation of an ActionListener that the JSplitPane UI uses for
711      * handling specific key presses.
712      * <p>
713      * This class should be treated as a &quot;protected&quot; inner class.
714      * Instantiate it only within subclasses of BasicSplitPaneUI.
715      */

716     public class KeyboardUpLeftHandler implements ActionListener
717     {
718         public void actionPerformed(ActionEvent ev) {
719             if (dividerKeyboardResize) {
720         splitPane.setDividerLocation(Math.max(0,getDividerLocation
721                   (splitPane) - getKeyboardMoveIncrement()));
722             }
723         }
724     }
725
726     /**
727      * Implementation of an ActionListener that the JSplitPane UI uses for
728      * handling specific key presses.
729      * <p>
730      * This class should be treated as a &quot;protected&quot; inner class.
731      * Instantiate it only within subclasses of BasicSplitPaneUI.
732      */

733     public class KeyboardDownRightHandler implements ActionListener
734     {
735         public void actionPerformed(ActionEvent ev) {
736             if (dividerKeyboardResize) {
737                 splitPane.setDividerLocation(getDividerLocation(splitPane) +
738                          getKeyboardMoveIncrement());
739             }
740         }
741     }
742
743
744     /**
745      * Implementation of an ActionListener that the JSplitPane UI uses for
746      * handling specific key presses.
747      * <p>
748      * This class should be treated as a &quot;protected&quot; inner class.
749      * Instantiate it only within subclasses of BasicSplitPaneUI.
750      */

751     public class KeyboardHomeHandler implements ActionListener
752     {
753         public void actionPerformed(ActionEvent ev) {
754             if (dividerKeyboardResize) {
755                 splitPane.setDividerLocation(0);
756             }
757         }
758     }
759     
760
761     /**
762      * Implementation of an ActionListener that the JSplitPane UI uses for
763      * handling specific key presses.
764      * <p>
765      * This class should be treated as a &quot;protected&quot; inner class.
766      * Instantiate it only within subclasses of BasicSplitPaneUI.
767      */

768     public class KeyboardEndHandler implements ActionListener
769     {
770         public void actionPerformed(ActionEvent ev) {
771             if (dividerKeyboardResize) {
772         Insets insets = splitPane.getInsets();
773         int bottomI = (insets != null) ? insets.bottom : 0;
774         int rightI = (insets != null) ? insets.right : 0;
775
776                 if (orientation == JSplitPane.VERTICAL_SPLIT) {
777                     splitPane.setDividerLocation(splitPane.getHeight() -
778                                        bottomI);
779                 }
780                 else {
781                     splitPane.setDividerLocation(splitPane.getWidth() -
782                          rightI);
783                 }
784             }
785         }
786     }
787
788
789     /**
790      * Implementation of an ActionListener that the JSplitPane UI uses for
791      * handling specific key presses.
792      * <p>
793      * This class should be treated as a &quot;protected&quot; inner class.
794      * Instantiate it only within subclasses of BasicSplitPaneUI.
795      */

796     public class KeyboardResizeToggleHandler implements ActionListener
797     {
798         public void actionPerformed(ActionEvent ev) {
799             if (!dividerKeyboardResize) {
800                 splitPane.requestFocus();
801             }
802         }
803     }
804
805     /**
806      * Returns the divider between the top Components.
807      */

808     public BasicSplitPaneDivider JavaDoc getDivider() {
809         return divider;
810     }
811
812
813     /**
814      * Returns the default non continuous layout divider, which is an
815      * instanceof Canvas that fills the background in dark gray.
816      */

817     protected Component createDefaultNonContinuousLayoutDivider() {
818         return new Canvas() {
819             public void paint(Graphics g) {
820                 if(!isContinuousLayout() && getLastDragLocation() != -1) {
821                     Dimension size = splitPane.getSize();
822
823                     g.setColor(dividerDraggingColor);
824                     if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
825                         g.fillRect(0, 0, dividerSize - 1, size.height - 1);
826                     } else {
827                         g.fillRect(0, 0, size.width - 1, dividerSize - 1);
828                     }
829                 }
830             }
831         };
832     }
833
834
835     /**
836      * Sets the divider to use when the splitPane is configured to
837      * not continuously layout. This divider will only be used during a
838      * dragging session. It is recommended that the passed in component
839      * be a heavy weight.
840      */

841     protected void setNonContinuousLayoutDivider(Component newDivider) {
842         setNonContinuousLayoutDivider(newDivider, true);
843     }
844
845
846     /**
847      * Sets the divider to use.
848      */

849     protected void setNonContinuousLayoutDivider(Component newDivider,
850         boolean rememberSizes) {
851         rememberPaneSizes = rememberSizes;
852         if(nonContinuousLayoutDivider != null && splitPane != null) {
853             splitPane.remove(nonContinuousLayoutDivider);
854         }
855         nonContinuousLayoutDivider = newDivider;
856     }
857
858     private void addHeavyweightDivider() {
859         if(nonContinuousLayoutDivider != null && splitPane != null) {
860
861             /* Needs to remove all the components and re-add them! YECK! */
862         // This is all done so that the nonContinuousLayoutDivider will
863
// be drawn on top of the other components, without this, one
864
// of the heavyweights will draw over the divider!
865
Component leftC = splitPane.getLeftComponent();
866             Component rightC = splitPane.getRightComponent();
867         int lastLocation = splitPane.
868                                       getDividerLocation();
869
870             if(leftC != null)
871                 splitPane.setLeftComponent(null);
872             if(rightC != null)
873                 splitPane.setRightComponent(null);
874             splitPane.remove(divider);
875             splitPane.add(nonContinuousLayoutDivider, BasicSplitPaneUI.
876                           NON_CONTINUOUS_DIVIDER,
877                           splitPane.getComponentCount());
878             splitPane.setLeftComponent(leftC);
879             splitPane.setRightComponent(rightC);
880             splitPane.add(divider, JSplitPane.DIVIDER);
881             if(rememberPaneSizes) {
882         splitPane.setDividerLocation(lastLocation);
883         }
884         }
885  
886     }
887
888
889     /**
890      * Returns the divider to use when the splitPane is configured to
891      * not continuously layout. This divider will only be used during a
892      * dragging session.
893      */

894     public Component getNonContinuousLayoutDivider() {
895         return nonContinuousLayoutDivider;
896     }
897
898
899     /**
900      * Returns the splitpane this instance is currently contained
901      * in.
902      */

903     public JSplitPane getSplitPane() {
904         return splitPane;
905     }
906
907
908     /**
909      * Creates the default divider.
910      */

911     public BasicSplitPaneDivider JavaDoc createDefaultDivider() {
912         return new BasicSplitPaneDivider JavaDoc(this);
913     }
914
915
916     /**
917      * Messaged to reset the preferred sizes.
918      */

919     public void resetToPreferredSizes(JSplitPane jc) {
920         if(splitPane != null) {
921             layoutManager.resetToPreferredSizes();
922             splitPane.revalidate();
923         splitPane.repaint();
924         }
925     }
926
927
928     /**
929      * Sets the location of the divider to location.
930      */

931     public void setDividerLocation(JSplitPane jc, int location) {
932     if (!ignoreDividerLocationChange) {
933         dividerLocationIsSet = true;
934         splitPane.revalidate();
935         splitPane.repaint();
936
937             if (keepHidden) {
938         Insets insets = splitPane.getInsets();
939         int orientation = splitPane.getOrientation();
940         if ((orientation == JSplitPane.VERTICAL_SPLIT &&
941              location != insets.top &&
942              location != splitPane.getHeight()-divider.getHeight()-insets.top) ||
943             (orientation == JSplitPane.HORIZONTAL_SPLIT &&
944              location != insets.left &&
945              location != splitPane.getWidth()-divider.getWidth()-insets.left)) {
946             setKeepHidden(false);
947         }
948         }
949     }
950     else {
951         ignoreDividerLocationChange = false;
952     }
953     }
954
955
956     /**
957      * Returns the location of the divider, which may differ from what
958      * the splitpane thinks the location of the divider is.
959      */

960     public int getDividerLocation(JSplitPane jc) {
961         if(orientation == JSplitPane.HORIZONTAL_SPLIT)
962             return divider.getLocation().x;
963         return divider.getLocation().y;
964     }
965
966
967     /**
968      * Gets the minimum location of the divider.
969      */

970     public int getMinimumDividerLocation(JSplitPane jc) {
971         int minLoc = 0;
972         Component leftC = splitPane.getLeftComponent();
973
974         if ((leftC != null) && (leftC.isVisible())) {
975             Insets insets = splitPane.getInsets();
976             Dimension minSize = leftC.getMinimumSize();
977             if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
978                 minLoc = minSize.width;
979             } else {
980                 minLoc = minSize.height;
981             }
982             if(insets != null) {
983                 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
984                     minLoc += insets.left;
985                 } else {
986                     minLoc += insets.top;
987                 }
988             }
989         }
990         return minLoc;
991     }
992
993
994     /**
995      * Gets the maximum location of the divider.
996      */

997     public int getMaximumDividerLocation(JSplitPane jc) {
998         Dimension splitPaneSize = splitPane.getSize();
999         int maxLoc = 0;
1000        Component rightC = splitPane.getRightComponent();
1001
1002        if (rightC != null) {
1003            Insets insets = splitPane.getInsets();
1004            Dimension minSize = new Dimension(0, 0);
1005            if (rightC.isVisible()) {
1006                minSize = rightC.getMinimumSize();
1007            }
1008            if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
1009                maxLoc = splitPaneSize.width - minSize.width;
1010            } else {
1011                maxLoc = splitPaneSize.height - minSize.height;
1012            }
1013            maxLoc -= dividerSize;
1014            if(insets != null) {
1015                if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
1016                    maxLoc -= insets.right;
1017                } else {
1018                    maxLoc -= insets.top;
1019                }
1020            }
1021        }
1022        return Math.max(getMinimumDividerLocation(splitPane), maxLoc);
1023    }
1024