History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/plaf/basic/BasicSplitPaneUI.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/plaf/basic/BasicSplitPaneUI.java+2246−0
@@ -0,0 +1,2246 @@
1/*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package javax.swing.plaf.basic;
28
29
30import sun.swing.DefaultLookup;
31import sun.swing.UIAction;
32import javax.swing.*;
33import javax.swing.border.Border;
34import java.awt.*;
35import java.awt.event.*;
36import java.awt.peer.ComponentPeer;
37import java.awt.peer.LightweightPeer;
38import java.beans.*;
39import java.util.*;
40import javax.swing.plaf.SplitPaneUI;
41import javax.swing.plaf.ComponentUI;
42import javax.swing.plaf.UIResource;
43import sun.swing.SwingUtilities2;
44
45
46/**
47 * A Basic L&F implementation of the SplitPaneUI.
48 *
49 * @author Scott Violet
50 * @author Steve Wilson
51 * @author Ralph Kar
52 */
53public class BasicSplitPaneUI extends SplitPaneUI
54{
55 /**
56 * The divider used for non-continuous layout is added to the split pane
57 * with this object.
58 */
59 protected static final String NON_CONTINUOUS_DIVIDER =
60 "nonContinuousDivider";
61
62
63 /**
64 * How far (relative) the divider does move when it is moved around by
65 * the cursor keys on the keyboard.
66 */
67 protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3;
68
69
70 /**
71 * JSplitPane instance this instance is providing
72 * the look and feel for.
73 */
74 protected JSplitPane splitPane;
75
76
77 /**
78 * LayoutManager that is created and placed into the split pane.
79 */
80 protected BasicHorizontalLayoutManager layoutManager;
81
82
83 /**
84 * Instance of the divider for this JSplitPane.
85 */
86 protected BasicSplitPaneDivider divider;
87
88
89 /**
90 * Instance of the PropertyChangeListener for this JSplitPane.
91 */
92 protected PropertyChangeListener propertyChangeListener;
93
94
95 /**
96 * Instance of the FocusListener for this JSplitPane.
97 */
98 protected FocusListener focusListener;
99
100 private Handler handler;
101
102
103 /**
104 * Keys to use for forward focus traversal when the JComponent is
105 * managing focus.
106 */
107 private Set<KeyStroke> managingFocusForwardTraversalKeys;
108
109 /**
110 * Keys to use for backward focus traversal when the JComponent is
111 * managing focus.
112 */
113 private Set<KeyStroke> managingFocusBackwardTraversalKeys;
114
115
116 /**
117 * The size of the divider while the dragging session is valid.
118 */
119 protected int dividerSize;
120
121
122 /**
123 * Instance for the shadow of the divider when non continuous layout
124 * is being used.
125 */
126 protected Component nonContinuousLayoutDivider;
127
128
129 /**
130 * Set to true in startDragging if any of the children
131 * (not including the nonContinuousLayoutDivider) are heavy weights.
132 */
133 protected boolean draggingHW;
134
135
136 /**
137 * Location of the divider when the dragging session began.
138 */
139 protected int beginDragDividerLocation;
140
141
142 /**
143 * As of Java 2 platform v1.3 this previously undocumented field is no
144 * longer used.
145 * Key bindings are now defined by the LookAndFeel, please refer to
146 * the key bindings specification for further details.
147 *
148 * @deprecated As of Java 2 platform v1.3.
149 */
150 @Deprecated
151 protected KeyStroke upKey;
152 /**
153 * As of Java 2 platform v1.3 this previously undocumented field is no
154 * longer used.
155 * Key bindings are now defined by the LookAndFeel, please refer to
156 * the key bindings specification for further details.
157 *
158 * @deprecated As of Java 2 platform v1.3.
159 */
160 @Deprecated
161 protected KeyStroke downKey;
162 /**
163 * As of Java 2 platform v1.3 this previously undocumented field is no
164 * longer used.
165 * Key bindings are now defined by the LookAndFeel, please refer to
166 * the key bindings specification for further details.
167 *
168 * @deprecated As of Java 2 platform v1.3.
169 */
170 @Deprecated
171 protected KeyStroke leftKey;
172 /**
173 * As of Java 2 platform v1.3 this previously undocumented field is no
174 * longer used.
175 * Key bindings are now defined by the LookAndFeel, please refer to
176 * the key bindings specification for further details.
177 *
178 * @deprecated As of Java 2 platform v1.3.
179 */
180 @Deprecated
181 protected KeyStroke rightKey;
182 /**
183 * As of Java 2 platform v1.3 this previously undocumented field is no
184 * longer used.
185 * Key bindings are now defined by the LookAndFeel, please refer to
186 * the key bindings specification for further details.
187 *
188 * @deprecated As of Java 2 platform v1.3.
189 */
190 @Deprecated
191 protected KeyStroke homeKey;
192 /**
193 * As of Java 2 platform v1.3 this previously undocumented field is no
194 * longer used.
195 * Key bindings are now defined by the LookAndFeel, please refer to
196 * the key bindings specification for further details.
197 *
198 * @deprecated As of Java 2 platform v1.3.
199 */
200 @Deprecated
201 protected KeyStroke endKey;
202 /**
203 * As of Java 2 platform v1.3 this previously undocumented field is no
204 * longer used.
205 * Key bindings are now defined by the LookAndFeel, please refer to
206 * the key bindings specification for further details.
207 *
208 * @deprecated As of Java 2 platform v1.3.
209 */
210 @Deprecated
211 protected KeyStroke dividerResizeToggleKey;
212
213 /**
214 * As of Java 2 platform v1.3 this previously undocumented field is no
215 * longer used.
216 * Key bindings are now defined by the LookAndFeel, please refer to
217 * the key bindings specification for further details.
218 *
219 * @deprecated As of Java 2 platform v1.3.
220 */
221 @Deprecated
222 protected ActionListener keyboardUpLeftListener;
223 /**
224 * As of Java 2 platform v1.3 this previously undocumented field is no
225 * longer used.
226 * Key bindings are now defined by the LookAndFeel, please refer to
227 * the key bindings specification for further details.
228 *
229 * @deprecated As of Java 2 platform v1.3.
230 */
231 @Deprecated
232 protected ActionListener keyboardDownRightListener;
233 /**
234 * As of Java 2 platform v1.3 this previously undocumented field is no
235 * longer used.
236 * Key bindings are now defined by the LookAndFeel, please refer to
237 * the key bindings specification for further details.
238 *
239 * @deprecated As of Java 2 platform v1.3.
240 */
241 @Deprecated
242 protected ActionListener keyboardHomeListener;
243 /**
244 * As of Java 2 platform v1.3 this previously undocumented field is no
245 * longer used.
246 * Key bindings are now defined by the LookAndFeel, please refer to
247 * the key bindings specification for further details.
248 *
249 * @deprecated As of Java 2 platform v1.3.
250 */
251 @Deprecated
252 protected ActionListener keyboardEndListener;
253 /**
254 * As of Java 2 platform v1.3 this previously undocumented field is no
255 * longer used.
256 * Key bindings are now defined by the LookAndFeel, please refer to
257 * the key bindings specification for further details.
258 *
259 * @deprecated As of Java 2 platform v1.3.
260 */
261 @Deprecated
262 protected ActionListener keyboardResizeToggleListener;
263
264
265 // Private data of the instance
266 private int orientation;
267 private int lastDragLocation;
268 private boolean continuousLayout;
269 private boolean dividerKeyboardResize;
270 private boolean dividerLocationIsSet; // needed for tracking
271 // the first occurrence of
272 // setDividerLocation()
273 private Color dividerDraggingColor;
274 private boolean rememberPaneSizes;
275
276 // Indicates wether the one of splitpane sides is expanded
277 private boolean keepHidden = false;
278
279 /** Indicates that we have painted once. */
280 // This is used by the LayoutManager to determine when it should use
281 // the divider location provided by the JSplitPane. This is used as there
282 // is no way to determine when the layout process has completed.
283 boolean painted;
284 /** If true, setDividerLocation does nothing. */
285 boolean ignoreDividerLocationChange;
286
287
288 /**
289 * Creates a new BasicSplitPaneUI instance
290 */
291 public static ComponentUI createUI(JComponent x) {
292 return new BasicSplitPaneUI();
293 }
294
295 static void loadActionMap(LazyActionMap map) {
296 map.put(new Actions(Actions.NEGATIVE_INCREMENT));
297 map.put(new Actions(Actions.POSITIVE_INCREMENT));
298 map.put(new Actions(Actions.SELECT_MIN));
299 map.put(new Actions(Actions.SELECT_MAX));
300 map.put(new Actions(Actions.START_RESIZE));
301 map.put(new Actions(Actions.TOGGLE_FOCUS));
302 map.put(new Actions(Actions.FOCUS_OUT_FORWARD));
303 map.put(new Actions(Actions.FOCUS_OUT_BACKWARD));
304 }
305
306
307
308 /**
309 * Installs the UI.
310 */
311 public void installUI(JComponent c) {
312 splitPane = (JSplitPane) c;
313 dividerLocationIsSet = false;
314 dividerKeyboardResize = false;
315 keepHidden = false;
316 installDefaults();
317 installListeners();
318 installKeyboardActions();
319 setLastDragLocation(-1);
320 }
321
322
323 /**
324 * Installs the UI defaults.
325 */
326 protected void installDefaults(){
327 LookAndFeel.installBorder(splitPane, "SplitPane.border");
328 LookAndFeel.installColors(splitPane, "SplitPane.background",
329 "SplitPane.foreground");
330 LookAndFeel.installProperty(splitPane, "opaque", Boolean.TRUE);
331
332 if (divider == null) divider = createDefaultDivider();
333 divider.setBasicSplitPaneUI(this);
334
335 Border b = divider.getBorder();
336
337 if (b == null || !(b instanceof UIResource)) {
338 divider.setBorder(UIManager.getBorder("SplitPaneDivider.border"));
339 }
340
341 dividerDraggingColor = UIManager.getColor("SplitPaneDivider.draggingColor");
342
343 setOrientation(splitPane.getOrientation());
344
345 // note: don't rename this temp variable to dividerSize
346 // since it will conflict with "this.dividerSize" field
347 Integer temp = (Integer)UIManager.get("SplitPane.dividerSize");
348 LookAndFeel.installProperty(splitPane, "dividerSize", temp == null? 10: temp);
349
350 divider.setDividerSize(splitPane.getDividerSize());
351 dividerSize = divider.getDividerSize();
352 splitPane.add(divider, JSplitPane.DIVIDER);
353
354 setContinuousLayout(splitPane.isContinuousLayout());
355
356 resetLayoutManager();
357
358 /* Install the nonContinuousLayoutDivider here to avoid having to
359 add/remove everything later. */
360 if(nonContinuousLayoutDivider == null) {
361 setNonContinuousLayoutDivider(
362 createDefaultNonContinuousLayoutDivider(),
363 true);
364 } else {
365 setNonContinuousLayoutDivider(nonContinuousLayoutDivider, true);
366 }
367
368 // focus forward traversal key
369 if (managingFocusForwardTraversalKeys==null) {
370 managingFocusForwardTraversalKeys = new HashSet<KeyStroke>();
371 managingFocusForwardTraversalKeys.add(
372 KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
373 }
374 splitPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
375 managingFocusForwardTraversalKeys);
376 // focus backward traversal key
377 if (managingFocusBackwardTraversalKeys==null) {
378 managingFocusBackwardTraversalKeys = new HashSet<KeyStroke>();
379 managingFocusBackwardTraversalKeys.add(
380 KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
381 }
382 splitPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
383 managingFocusBackwardTraversalKeys);
384 }
385
386
387 /**
388 * Installs the event listeners for the UI.
389 */
390 protected void installListeners() {
391 if ((propertyChangeListener = createPropertyChangeListener()) !=
392 null) {
393 splitPane.addPropertyChangeListener(propertyChangeListener);
394 }
395
396 if ((focusListener = createFocusListener()) != null) {
397 splitPane.addFocusListener(focusListener);
398 }
399 }
400
401
402 /**
403 * Installs the keyboard actions for the UI.
404 */
405 protected void installKeyboardActions() {
406 InputMap km = getInputMap(JComponent.
407 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
408
409 SwingUtilities.replaceUIInputMap(splitPane, JComponent.
410 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
411 km);
412 LazyActionMap.installLazyActionMap(splitPane, BasicSplitPaneUI.class,
413 "SplitPane.actionMap");
414 }
415
416 InputMap getInputMap(int condition) {
417 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
418 return (InputMap)DefaultLookup.get(splitPane, this,
419 "SplitPane.ancestorInputMap");
420 }
421 return null;
422 }
423
424 /**
425 * Uninstalls the UI.
426 */
427 public void uninstallUI(JComponent c) {
428 uninstallKeyboardActions();
429 uninstallListeners();
430 uninstallDefaults();
431 dividerLocationIsSet = false;
432 dividerKeyboardResize = false;
433 splitPane = null;
434 }
435
436
437 /**
438 * Uninstalls the UI defaults.
439 */
440 protected void uninstallDefaults() {
441 if(splitPane.getLayout() == layoutManager) {
442 splitPane.setLayout(null);
443 }
444
445 if(nonContinuousLayoutDivider != null) {
446 splitPane.remove(nonContinuousLayoutDivider);
447 }
448
449 LookAndFeel.uninstallBorder(splitPane);
450
451 Border b = divider.getBorder();
452
453 if (b instanceof UIResource) {
454 divider.setBorder(null);
455 }
456
457 splitPane.remove(divider);
458 divider.setBasicSplitPaneUI(null);
459 layoutManager = null;
460 divider = null;
461 nonContinuousLayoutDivider = null;
462
463 setNonContinuousLayoutDivider(null);
464
465 // sets the focus forward and backward traversal keys to null
466 // to restore the defaults
467 splitPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
468 splitPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
469 }
470
471
472 /**
473 * Uninstalls the event listeners for the UI.
474 */
475 protected void uninstallListeners() {
476 if (propertyChangeListener != null) {
477 splitPane.removePropertyChangeListener(propertyChangeListener);
478 propertyChangeListener = null;
479 }
480 if (focusListener != null) {
481 splitPane.removeFocusListener(focusListener);
482 focusListener = null;
483 }
484
485 keyboardUpLeftListener = null;
486 keyboardDownRightListener = null;
487 keyboardHomeListener = null;
488 keyboardEndListener = null;
489 keyboardResizeToggleListener = null;
490 handler = null;
491 }
492
493
494 /**
495 * Uninstalls the keyboard actions for the UI.
496 */
497 protected void uninstallKeyboardActions() {
498 SwingUtilities.replaceUIActionMap(splitPane, null);
499 SwingUtilities.replaceUIInputMap(splitPane, JComponent.
500 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
501 null);
502 }
503
504
505 /**
506 * Creates a PropertyChangeListener for the JSplitPane UI.
507 */
508 protected PropertyChangeListener createPropertyChangeListener() {
509 return getHandler();
510 }
511
512 private Handler getHandler() {
513 if (handler == null) {
514 handler = new Handler();
515 }
516 return handler;
517 }
518
519
520 /**
521 * Creates a FocusListener for the JSplitPane UI.
522 */
523 protected FocusListener createFocusListener() {
524 return getHandler();
525 }
526
527
528 /**
529 * As of Java 2 platform v1.3 this method is no
530 * longer used. Subclassers previously using this method should
531 * instead create an Action wrapping the ActionListener, and register
532 * that Action by overriding <code>installKeyboardActions</code> and
533 * placing the Action in the SplitPane's ActionMap. Please refer to
534 * the key bindings specification for further details.
535 * <p>
536 * Creates a ActionListener for the JSplitPane UI that listens for
537 * specific key presses.
538 *
539 * @deprecated As of Java 2 platform v1.3.
540 */
541 @Deprecated
542 protected ActionListener createKeyboardUpLeftListener() {
543 return new KeyboardUpLeftHandler();
544 }
545
546
547 /**
548 * As of Java 2 platform v1.3 this method is no
549 * longer used. Subclassers previously using this method should
550 * instead create an Action wrapping the ActionListener, and register
551 * that Action by overriding <code>installKeyboardActions</code> and
552 * placing the Action in the SplitPane's ActionMap. Please refer to
553 * the key bindings specification for further details.
554 * <p>
555 * Creates a ActionListener for the JSplitPane UI that listens for
556 * specific key presses.
557 *
558 * @deprecated As of Java 2 platform v1.3.
559 */
560 @Deprecated
561 protected ActionListener createKeyboardDownRightListener() {
562 return new KeyboardDownRightHandler();
563 }
564
565
566 /**
567 * As of Java 2 platform v1.3 this method is no
568 * longer used. Subclassers previously using this method should
569 * instead create an Action wrapping the ActionListener, and register
570 * that Action by overriding <code>installKeyboardActions</code> and
571 * placing the Action in the SplitPane's ActionMap. Please refer to
572 * the key bindings specification for further details.
573 * <p>
574 * Creates a ActionListener for the JSplitPane UI that listens for
575 * specific key presses.
576 *
577 * @deprecated As of Java 2 platform v1.3.
578 */
579 @Deprecated
580 protected ActionListener createKeyboardHomeListener() {
581 return new KeyboardHomeHandler();
582 }
583
584
585 /**
586 * As of Java 2 platform v1.3 this method is no
587 * longer used. Subclassers previously using this method should
588 * instead create an Action wrapping the ActionListener, and register
589 * that Action by overriding <code>installKeyboardActions</code> and
590 * placing the Action in the SplitPane's ActionMap. Please refer to
591 * the key bindings specification for further details.
592 * <p>
593 * Creates a ActionListener for the JSplitPane UI that listens for
594 * specific key presses.
595 *
596 * @deprecated As of Java 2 platform v1.3.
597 */
598 @Deprecated
599 protected ActionListener createKeyboardEndListener() {
600 return new KeyboardEndHandler();
601 }
602
603
604 /**
605 * As of Java 2 platform v1.3 this method is no
606 * longer used. Subclassers previously using this method should
607 * instead create an Action wrapping the ActionListener, and register
608 * that Action by overriding <code>installKeyboardActions</code> and
609 * placing the Action in the SplitPane's ActionMap. Please refer to
610 * the key bindings specification for further details.
611 * <p>
612 * Creates a ActionListener for the JSplitPane UI that listens for
613 * specific key presses.
614 *
615 * @deprecated As of Java 2 platform v1.3.
616 */
617 @Deprecated
618 protected ActionListener createKeyboardResizeToggleListener() {
619 return new KeyboardResizeToggleHandler();
620 }
621
622
623 /**
624 * Returns the orientation for the JSplitPane.
625 */
626 public int getOrientation() {
627 return orientation;
628 }
629
630
631 /**
632 * Set the orientation for the JSplitPane.
633 */
634 public void setOrientation(int orientation) {
635 this.orientation = orientation;
636 }
637
638
639 /**
640 * Determines wether the JSplitPane is set to use a continuous layout.
641 */
642 public boolean isContinuousLayout() {
643 return continuousLayout;
644 }
645
646
647 /**
648 * Turn continuous layout on/off.
649 */
650 public void setContinuousLayout(boolean b) {
651 continuousLayout = b;
652 }
653
654
655 /**
656 * Returns the last drag location of the JSplitPane.
657 */
658 public int getLastDragLocation() {
659 return lastDragLocation;
660 }
661
662
663 /**
664 * Set the last drag location of the JSplitPane.
665 */
666 public void setLastDragLocation(int l) {
667 lastDragLocation = l;
668 }
669
670 /**
671 * @return increment via keyboard methods.
672 */
673 int getKeyboardMoveIncrement() {
674 return 3;
675 }
676
677 /**
678 * Implementation of the PropertyChangeListener
679 * that the JSplitPane UI uses.
680 * <p>
681 * This class should be treated as a &quot;protected&quot; inner class.
682 * Instantiate it only within subclasses of BasicSplitPaneUI.
683 */
684 public class PropertyHandler implements PropertyChangeListener
685 {
686 // NOTE: This class exists only for backward compatability. All
687 // its functionality has been moved into Handler. If you need to add
688 // new functionality add it to the Handler, but make sure this
689 // class calls into the Handler.
690
691 /**
692 * Messaged from the <code>JSplitPane</code> the receiver is
693 * contained in. May potentially reset the layout manager and cause a
694 * <code>validate</code> to be sent.
695 */
696 public void propertyChange(PropertyChangeEvent e) {
697 getHandler().propertyChange(e);
698 }
699 }
700
701
702 /**
703 * Implementation of the FocusListener that the JSplitPane UI uses.
704 * <p>
705 * This class should be treated as a &quot;protected&quot; inner class.
706 * Instantiate it only within subclasses of BasicSplitPaneUI.
707 */
708 public class FocusHandler extends FocusAdapter
709 {
710 // NOTE: This class exists only for backward compatability. All
711 // its functionality has been moved into Handler. If you need to add
712 // new functionality add it to the Handler, but make sure this
713 // class calls into the Handler.
714 public void focusGained(FocusEvent ev) {
715 getHandler().focusGained(ev);
716 }
717
718 public void focusLost(FocusEvent ev) {
719 getHandler().focusLost(ev);
720 }
721 }
722
723
724 /**
725 * Implementation of an ActionListener that the JSplitPane UI uses for
726 * handling specific key presses.
727 * <p>
728 * This class should be treated as a &quot;protected&quot; inner class.
729 * Instantiate it only within subclasses of BasicSplitPaneUI.
730 */
731 public class KeyboardUpLeftHandler implements ActionListener
732 {
733 public void actionPerformed(ActionEvent ev) {
734 if (dividerKeyboardResize) {
735 splitPane.setDividerLocation(Math.max(0,getDividerLocation
736 (splitPane) - getKeyboardMoveIncrement()));
737 }
738 }
739 }
740
741 /**
742 * Implementation of an ActionListener that the JSplitPane UI uses for
743 * handling specific key presses.
744 * <p>
745 * This class should be treated as a &quot;protected&quot; inner class.
746 * Instantiate it only within subclasses of BasicSplitPaneUI.
747 */
748 public class KeyboardDownRightHandler implements ActionListener
749 {
750 public void actionPerformed(ActionEvent ev) {
751 if (dividerKeyboardResize) {
752 splitPane.setDividerLocation(getDividerLocation(splitPane) +
753 getKeyboardMoveIncrement());
754 }
755 }
756 }
757
758
759 /**
760 * Implementation of an ActionListener that the JSplitPane UI uses for
761 * handling specific key presses.
762 * <p>
763 * This class should be treated as a &quot;protected&quot; inner class.
764 * Instantiate it only within subclasses of BasicSplitPaneUI.
765 */
766 public class KeyboardHomeHandler implements ActionListener
767 {
768 public void actionPerformed(ActionEvent ev) {
769 if (dividerKeyboardResize) {
770 splitPane.setDividerLocation(0);
771 }
772 }
773 }
774
775
776 /**
777 * Implementation of an ActionListener that the JSplitPane UI uses for
778 * handling specific key presses.
779 * <p>
780 * This class should be treated as a &quot;protected&quot; inner class.
781 * Instantiate it only within subclasses of BasicSplitPaneUI.
782 */
783 public class KeyboardEndHandler implements ActionListener
784 {
785 public void actionPerformed(ActionEvent ev) {
786 if (dividerKeyboardResize) {
787 Insets insets = splitPane.getInsets();
788 int bottomI = (insets != null) ? insets.bottom : 0;
789 int rightI = (insets != null) ? insets.right : 0;
790
791 if (orientation == JSplitPane.VERTICAL_SPLIT) {
792 splitPane.setDividerLocation(splitPane.getHeight() -
793 bottomI);
794 }
795 else {
796 splitPane.setDividerLocation(splitPane.getWidth() -
797 rightI);
798 }
799 }
800 }
801 }
802
803
804 /**
805 * Implementation of an ActionListener that the JSplitPane UI uses for
806 * handling specific key presses.
807 * <p>
808 * This class should be treated as a &quot;protected&quot; inner class.
809 * Instantiate it only within subclasses of BasicSplitPaneUI.
810 */
811 public class KeyboardResizeToggleHandler implements ActionListener
812 {
813 public void actionPerformed(ActionEvent ev) {
814 if (!dividerKeyboardResize) {
815 splitPane.requestFocus();
816 }
817 }
818 }
819
820 /**
821 * Returns the divider between the top Components.
822 */
823 public BasicSplitPaneDivider getDivider() {
824 return divider;
825 }
826
827
828 /**
829 * Returns the default non continuous layout divider, which is an
830 * instance of {@code Canvas} that fills in the background with dark gray.
831 */
832 protected Component createDefaultNonContinuousLayoutDivider() {
833 return new Canvas() {
834 public void paint(Graphics g) {
835 if(!isContinuousLayout() && getLastDragLocation() != -1) {
836 Dimension size = splitPane.getSize();
837
838 g.setColor(dividerDraggingColor);
839 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
840 g.fillRect(0, 0, dividerSize - 1, size.height - 1);
841 } else {
842 g.fillRect(0, 0, size.width - 1, dividerSize - 1);
843 }
844 }
845 }
846 };
847 }
848
849
850 /**
851 * Sets the divider to use when the splitPane is configured to
852 * not continuously layout. This divider will only be used during a
853 * dragging session. It is recommended that the passed in component
854 * be a heavy weight.
855 */
856 protected void setNonContinuousLayoutDivider(Component newDivider) {
857 setNonContinuousLayoutDivider(newDivider, true);
858 }
859
860
861 /**
862 * Sets the divider to use.
863 */
864 protected void setNonContinuousLayoutDivider(Component newDivider,
865 boolean rememberSizes) {
866 rememberPaneSizes = rememberSizes;
867 if(nonContinuousLayoutDivider != null && splitPane != null) {
868 splitPane.remove(nonContinuousLayoutDivider);
869 }
870 nonContinuousLayoutDivider = newDivider;
871 }
872
873 private void addHeavyweightDivider() {
874 if(nonContinuousLayoutDivider != null && splitPane != null) {
875
876 /* Needs to remove all the components and re-add them! YECK! */
877 // This is all done so that the nonContinuousLayoutDivider will
878 // be drawn on top of the other components, without this, one
879 // of the heavyweights will draw over the divider!
880 Component leftC = splitPane.getLeftComponent();
881 Component rightC = splitPane.getRightComponent();
882 int lastLocation = splitPane.
883 getDividerLocation();
884
885 if(leftC != null)
886 splitPane.setLeftComponent(null);
887 if(rightC != null)
888 splitPane.setRightComponent(null);
889 splitPane.remove(divider);
890 splitPane.add(nonContinuousLayoutDivider, BasicSplitPaneUI.
891 NON_CONTINUOUS_DIVIDER,
892 splitPane.getComponentCount());
893 splitPane.setLeftComponent(leftC);
894 splitPane.setRightComponent(rightC);
895 splitPane.add(divider, JSplitPane.DIVIDER);
896 if(rememberPaneSizes) {
897 splitPane.setDividerLocation(lastLocation);
898 }
899 }
900
901 }
902
903
904 /**
905 * Returns the divider to use when the splitPane is configured to
906 * not continuously layout. This divider will only be used during a
907 * dragging session.
908 */
909 public Component getNonContinuousLayoutDivider() {
910 return nonContinuousLayoutDivider;
911 }
912
913
914 /**
915 * Returns the splitpane this instance is currently contained
916 * in.
917 */
918 public JSplitPane getSplitPane() {
919 return splitPane;
920 }
921
922
923 /**
924 * Creates the default divider.
925 */
926 public BasicSplitPaneDivider createDefaultDivider() {
927 return new BasicSplitPaneDivider(this);
928 }
929
930
931 /**
932 * Messaged to reset the preferred sizes.
933 */
934 public void resetToPreferredSizes(JSplitPane jc) {
935 if(splitPane != null) {
936 layoutManager.resetToPreferredSizes();
937 splitPane.revalidate();
938 splitPane.repaint();
939 }
940 }
941
942
943 /**
944 * Sets the location of the divider to location.
945 */
946 public void setDividerLocation(JSplitPane jc, int location) {
947 if (!ignoreDividerLocationChange) {
948 dividerLocationIsSet = true;
949 splitPane.revalidate();
950 splitPane.repaint();
951
952 if (keepHidden) {
953 Insets insets = splitPane.getInsets();
954 int orientation = splitPane.getOrientation();
955 if ((orientation == JSplitPane.VERTICAL_SPLIT &&
956 location != insets.top &&
957 location != splitPane.getHeight()-divider.getHeight()-insets.top) ||
958 (orientation == JSplitPane.HORIZONTAL_SPLIT &&
959 location != insets.left &&
960 location != splitPane.getWidth()-divider.getWidth()-insets.left)) {
961 setKeepHidden(false);
962 }
963 }
964 }
965 else {
966 ignoreDividerLocationChange = false;
967 }
968 }
969
970
971 /**
972 * Returns the location of the divider, which may differ from what
973 * the splitpane thinks the location of the divider is.
974 */
975 public int getDividerLocation(JSplitPane jc) {
976 if(orientation == JSplitPane.HORIZONTAL_SPLIT)
977 return divider.getLocation().x;
978 return divider.getLocation().y;
979 }
980
981
982 /**
983 * Gets the minimum location of the divider.
984 */
985 public int getMinimumDividerLocation(JSplitPane jc) {
986 int minLoc = 0;
987 Component leftC = splitPane.getLeftComponent();
988
989 if ((leftC != null) && (leftC.isVisible())) {
990 Insets insets = splitPane.getInsets();
991 Dimension minSize = leftC.getMinimumSize();
992 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
993 minLoc = minSize.width;
994 } else {
995 minLoc = minSize.height;
996 }
997 if(insets != null) {
998 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
999 minLoc += insets.left;
1000 } else {
1001 minLoc += insets.top;
1002 }
1003 }
1004 }
1005 return minLoc;
1006 }
1007
1008
1009 /**
1010 * Gets the maximum location of the divider.
1011 */
1012 public int getMaximumDividerLocation(JSplitPane jc) {
1013 Dimension splitPaneSize = splitPane.getSize();
1014 int maxLoc = 0;
1015 Component rightC = splitPane.getRightComponent();
1016
1017 if (rightC != null) {
1018 Insets insets = splitPane.getInsets();
1019 Dimension minSize = new Dimension(0, 0);
1020 if (rightC.isVisible()) {
1021 minSize = rightC.getMinimumSize();
1022 }
1023 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
1024 maxLoc = splitPaneSize.width - minSize.width;
1025 } else {
1026 maxLoc = splitPaneSize.height - minSize.height;
1027 }
1028 maxLoc -= dividerSize;
1029 if(insets != null) {
1030 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
1031 maxLoc -= insets.right;
1032 } else {
1033 maxLoc -= insets.top;
1034 }
1035 }
1036 }
1037 return Math.max(getMinimumDividerLocation(splitPane), maxLoc);
1038 }
1039
1040
1041 /**
1042 * Called when the specified split pane has finished painting
1043 * its children.
1044 */
1045 public void finishedPaintingChildren(JSplitPane sp, Graphics g) {
1046 if(sp == splitPane && getLastDragLocation() != -1 &&
1047 !isContinuousLayout() && !draggingHW) {
1048 Dimension size = splitPane.getSize();
1049
1050 g.setColor(dividerDraggingColor);
1051 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
1052 g.fillRect(getLastDragLocation(), 0, dividerSize - 1,
1053 size.height - 1);
1054 } else {
1055 g.fillRect(0, lastDragLocation, size.width - 1,
1056 dividerSize - 1);
1057 }
1058 }
1059 }
1060
1061
1062 /**
1063 * @inheritDoc
1064 */
1065 public void paint(Graphics g, JComponent jc) {
1066 if (!painted && splitPane.getDividerLocation()<0) {
1067 ignoreDividerLocationChange = true;
1068 splitPane.setDividerLocation(getDividerLocation(splitPane));
1069 }
1070 painted = true;
1071 }
1072
1073
1074 /**
1075 * Returns the preferred size for the passed in component,
1076 * This is passed off to the current layoutmanager.
1077 */
1078 public Dimension getPreferredSize(JComponent jc) {
1079 if(splitPane != null)
1080 return layoutManager.preferredLayoutSize(splitPane);
1081 return new Dimension(0, 0);
1082 }
1083
1084
1085 /**
1086 * Returns the minimum size for the passed in component,
1087 * This is passed off to the current layoutmanager.
1088 */
1089 public Dimension getMinimumSize(JComponent jc) {
1090 if(splitPane != null)
1091 return layoutManager.minimumLayoutSize(splitPane);
1092 return new Dimension(0, 0);
1093 }
1094
1095
1096 /**
1097 * Returns the maximum size for the passed in component,
1098 * This is passed off to the current layoutmanager.
1099 */
1100 public Dimension getMaximumSize(JComponent jc) {
1101 if(splitPane != null)
1102 return layoutManager.maximumLayoutSize(splitPane);
1103 return new Dimension(0, 0);
1104 }
1105
1106
1107 /**
1108 * Returns the insets. The insets are returned from the border insets
1109 * of the current border.
1110 */
1111 public Insets getInsets(JComponent jc) {
1112 return null;
1113 }
1114
1115
1116 /**
1117 * Resets the layout manager based on orientation and messages it
1118 * with invalidateLayout to pull in appropriate Components.
1119 */
1120 protected void resetLayoutManager() {
1121 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
1122 layoutManager = new BasicHorizontalLayoutManager(0);
1123 } else {
1124 layoutManager = new BasicHorizontalLayoutManager(1);
1125 }
1126 splitPane.setLayout(layoutManager);
1127 layoutManager.updateComponents();
1128 splitPane.revalidate();
1129 splitPane.repaint();
1130 }
1131
1132 /**
1133 * Set the value to indicate if one of the splitpane sides is expanded.
1134 */
1135 void setKeepHidden(boolean keepHidden) {
1136 this.keepHidden = keepHidden;
1137 }
1138
1139 /**
1140 * The value returned indicates if one of the splitpane sides is expanded.
1141 * @return true if one of the splitpane sides is expanded, false otherwise.
1142 */
1143 private boolean getKeepHidden() {
1144 return keepHidden;
1145 }
1146
1147 /**
1148 * Should be messaged before the dragging session starts, resets
1149 * lastDragLocation and dividerSize.
1150 */
1151 protected void startDragging() {
1152 Component leftC = splitPane.getLeftComponent();
1153 Component rightC = splitPane.getRightComponent();
1154 ComponentPeer cPeer;
1155
1156 beginDragDividerLocation = getDividerLocation(splitPane);
1157 draggingHW = false;
1158 if(leftC != null && (cPeer = leftC.getPeer()) != null &&
1159 !(cPeer instanceof LightweightPeer)) {
1160 draggingHW = true;
1161 } else if(rightC != null && (cPeer = rightC.getPeer()) != null
1162 && !(cPeer instanceof LightweightPeer)) {
1163 draggingHW = true;
1164 }
1165 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
1166 setLastDragLocation(divider.getBounds().x);
1167 dividerSize = divider.getSize().width;
1168 if(!isContinuousLayout() && draggingHW) {
1169 nonContinuousLayoutDivider.setBounds
1170 (getLastDragLocation(), 0, dividerSize,
1171 splitPane.getHeight());
1172 addHeavyweightDivider();
1173 }
1174 } else {
1175 setLastDragLocation(divider.getBounds().y);
1176 dividerSize = divider.getSize().height;
1177 if(!isContinuousLayout() && draggingHW) {
1178 nonContinuousLayoutDivider.setBounds
1179 (0, getLastDragLocation(), splitPane.getWidth(),
1180 dividerSize);
1181 addHeavyweightDivider();
1182 }
1183 }
1184 }
1185
1186
1187 /**
1188 * Messaged during a dragging session to move the divider to the
1189 * passed in location. If continuousLayout is true the location is
1190 * reset and the splitPane validated.
1191 */
1192 protected void dragDividerTo(int location) {
1193 if(getLastDragLocation() != location) {
1194 if(isContinuousLayout()) {
1195 splitPane.setDividerLocation(location);
1196 setLastDragLocation(location);
1197 } else {
1198 int lastLoc = getLastDragLocation();
1199
1200 setLastDragLocation(location);
1201 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
1202 if(draggingHW) {
1203 nonContinuousLayoutDivider.setLocation(
1204 getLastDragLocation(), 0);
1205 } else {
1206 int splitHeight = splitPane.getHeight();
1207 splitPane.repaint(lastLoc, 0, dividerSize,
1208 splitHeight);
1209 splitPane.repaint(location, 0, dividerSize,
1210 splitHeight);
1211 }
1212 } else {
1213 if(draggingHW) {
1214 nonContinuousLayoutDivider.setLocation(0,
1215 getLastDragLocation());
1216 } else {
1217 int splitWidth = splitPane.getWidth();
1218
1219 splitPane.repaint(0, lastLoc, splitWidth,
1220 dividerSize);
1221 splitPane.repaint(0, location, splitWidth,
1222 dividerSize);
1223 }
1224 }
1225 }
1226 }
1227 }
1228
1229
1230 /**
1231 * Messaged to finish the dragging session. If not continuous display
1232 * the dividers location will be reset.
1233 */
1234 protected void finishDraggingTo(int location) {
1235 dragDividerTo(location);
1236 setLastDragLocation(-1);
1237 if(!isContinuousLayout()) {
1238 Component leftC = splitPane.getLeftComponent();
1239 Rectangle leftBounds = leftC.getBounds();
1240
1241 if (draggingHW) {
1242 if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
1243 nonContinuousLayoutDivider.setLocation(-dividerSize, 0);
1244 }
1245 else {
1246 nonContinuousLayoutDivider.setLocation(0, -dividerSize);
1247 }
1248 splitPane.remove(nonContinuousLayoutDivider);
1249 }
1250 splitPane.setDividerLocation(location);
1251 }
1252 }
1253
1254
1255 /**
1256 * As of Java 2 platform v1.3 this method is no longer used. Instead
1257 * you should set the border on the divider.
1258 * <p>
1259 * Returns the width of one side of the divider border.
1260 *
1261 * @deprecated As of Java 2 platform v1.3, instead set the border on the
1262 * divider.
1263 */
1264 @Deprecated
1265 protected int getDividerBorderSize() {
1266 return 1;
1267 }
1268
1269
1270 /**
1271 * LayoutManager for JSplitPanes that have an orientation of
1272 * HORIZONTAL_SPLIT.
1273 */
1274 public class BasicHorizontalLayoutManager implements LayoutManager2
1275 {
1276 /* left, right, divider. (in this exact order) */
1277 protected int[] sizes;
1278 protected Component[] components;
1279 /** Size of the splitpane the last time laid out. */
1280 private int lastSplitPaneSize;
1281 /** True if resetToPreferredSizes has been invoked. */
1282 private boolean doReset;
1283 /** Axis, 0 for horizontal, or 1 for veritcal. */
1284 private int axis;
1285
1286
1287 BasicHorizontalLayoutManager() {
1288 this(0);
1289 }
1290
1291 BasicHorizontalLayoutManager(int axis) {
1292 this.axis = axis;
1293 components = new Component[3];
1294 components[0] = components[1] = components[2] = null;
1295 sizes = new int[3];
1296 }
1297
1298 //
1299 // LayoutManager
1300 //
1301
1302 /**
1303 * Does the actual layout.
1304 */
1305 public void layoutContainer(Container container) {
1306 Dimension containerSize = container.getSize();
1307
1308 // If the splitpane has a zero size then no op out of here.
1309 // If we execute this function now, we're going to cause ourselves
1310 // much grief.
1311 if (containerSize.height <= 0 || containerSize.width <= 0 ) {
1312 lastSplitPaneSize = 0;
1313 return;
1314 }
1315
1316 int spDividerLocation = splitPane.getDividerLocation();
1317 Insets insets = splitPane.getInsets();
1318 int availableSize = getAvailableSize(containerSize,
1319 insets);
1320 int newSize = getSizeForPrimaryAxis(containerSize);
1321 int beginLocation = getDividerLocation(splitPane);
1322 int dOffset = getSizeForPrimaryAxis(insets, true);
1323 Dimension dSize = (components[2] == null) ? null :
1324 components[2].getPreferredSize();
1325
1326 if ((doReset && !dividerLocationIsSet) || spDividerLocation < 0) {
1327 resetToPreferredSizes(availableSize);
1328 }
1329 else if (lastSplitPaneSize <= 0 ||
1330 availableSize == lastSplitPaneSize || !painted ||
1331 (dSize != null &&
1332 getSizeForPrimaryAxis(dSize) != sizes[2])) {
1333 if (dSize != null) {
1334 sizes[2] = getSizeForPrimaryAxis(dSize);
1335 }
1336 else {
1337 sizes[2] = 0;
1338 }
1339 setDividerLocation(spDividerLocation - dOffset, availableSize);
1340 dividerLocationIsSet = false;
1341 }
1342 else if (availableSize != lastSplitPaneSize) {
1343 distributeSpace(availableSize - lastSplitPaneSize,
1344 getKeepHidden());
1345 }
1346 doReset = false;
1347 dividerLocationIsSet = false;
1348 lastSplitPaneSize = availableSize;
1349
1350 // Reset the bounds of each component
1351 int nextLocation = getInitialLocation(insets);
1352 int counter = 0;
1353
1354 while (counter < 3) {
1355 if (components[counter] != null &&
1356 components[counter].isVisible()) {
1357 setComponentToSize(components[counter], sizes[counter],
1358 nextLocation, insets, containerSize);
1359 nextLocation += sizes[counter];
1360 }
1361 switch (counter) {
1362 case 0:
1363 counter = 2;
1364 break;
1365 case 2:
1366 counter = 1;
1367 break;
1368 case 1:
1369 counter = 3;
1370 break;
1371 }
1372 }
1373 if (painted) {
1374 // This is tricky, there is never a good time for us
1375 // to push the value to the splitpane, painted appears to
1376 // the best time to do it. What is really needed is
1377 // notification that layout has completed.
1378 int newLocation = getDividerLocation(splitPane);
1379
1380 if (newLocation != (spDividerLocation - dOffset)) {
1381 int lastLocation = splitPane.getLastDividerLocation();
1382
1383 ignoreDividerLocationChange = true;
1384 try {
1385 splitPane.setDividerLocation(newLocation);
1386 // This is not always needed, but is rather tricky
1387 // to determine when... The case this is needed for
1388 // is if the user sets the divider location to some
1389 // bogus value, say 0, and the actual value is 1, the
1390 // call to setDividerLocation(1) will preserve the
1391 // old value of 0, when we really want the divider
1392 // location value before the call. This is needed for
1393 // the one touch buttons.
1394 splitPane.setLastDividerLocation(lastLocation);
1395 } finally {
1396 ignoreDividerLocationChange = false;
1397 }
1398 }
1399 }
1400 }
1401
1402
1403 /**
1404 * Adds the component at place. Place must be one of
1405 * JSplitPane.LEFT, RIGHT, TOP, BOTTOM, or null (for the
1406 * divider).
1407 */
1408 public void addLayoutComponent(String place, Component component) {
1409 boolean isValid = true;
1410
1411 if(place != null) {
1412 if(place.equals(JSplitPane.DIVIDER)) {
1413 /* Divider. */
1414 components[2] = component;
1415 sizes[2] = getSizeForPrimaryAxis(component.
1416 getPreferredSize());
1417 } else if(place.equals(JSplitPane.LEFT) ||
1418 place.equals(JSplitPane.TOP)) {
1419 components[0] = component;
1420 sizes[0] = 0;
1421 } else if(place.equals(JSplitPane.RIGHT) ||
1422 place.equals(JSplitPane.BOTTOM)) {
1423 components[1] = component;
1424 sizes[1] = 0;
1425 } else if(!place.equals(
1426 BasicSplitPaneUI.NON_CONTINUOUS_DIVIDER))
1427 isValid = false;
1428 } else {
1429 isValid = false;
1430 }
1431 if(!isValid)
1432 throw new IllegalArgumentException("cannot add to layout: " +
1433 "unknown constraint: " +
1434 place);
1435 doReset = true;
1436 }
1437
1438
1439 /**
1440 * Returns the minimum size needed to contain the children.
1441 * The width is the sum of all the childrens min widths and
1442 * the height is the largest of the childrens minimum heights.
1443 */
1444 public Dimension minimumLayoutSize(Container container) {
1445 int minPrimary = 0;
1446 int minSecondary = 0;
1447 Insets insets = splitPane.getInsets();
1448
1449 for (int counter=0; counter<3; counter++) {
1450 if(components[counter] != null) {
1451 Dimension minSize = components[counter].getMinimumSize();
1452 int secSize = getSizeForSecondaryAxis(minSize);
1453
1454 minPrimary += getSizeForPrimaryAxis(minSize);
1455 if(secSize > minSecondary)
1456 minSecondary = secSize;
1457 }
1458 }
1459 if(insets != null) {
1460 minPrimary += getSizeForPrimaryAxis(insets, true) +
1461 getSizeForPrimaryAxis(insets, false);
1462 minSecondary += getSizeForSecondaryAxis(insets, true) +
1463 getSizeForSecondaryAxis(insets, false);
1464 }
1465 if (axis == 0) {
1466 return new Dimension(minPrimary, minSecondary);
1467 }
1468 return new Dimension(minSecondary, minPrimary);
1469 }
1470
1471
1472 /**
1473 * Returns the preferred size needed to contain the children.
1474 * The width is the sum of all the childrens preferred widths and
1475 * the height is the largest of the childrens preferred heights.
1476 */
1477 public Dimension preferredLayoutSize(Container container) {
1478 int prePrimary = 0;
1479 int preSecondary = 0;
1480 Insets insets = splitPane.getInsets();
1481
1482 for(int counter = 0; counter < 3; counter++) {
1483 if(components[counter] != null) {
1484 Dimension preSize = components[counter].
1485 getPreferredSize();
1486 int secSize = getSizeForSecondaryAxis(preSize);
1487
1488 prePrimary += getSizeForPrimaryAxis(preSize);
1489 if(secSize > preSecondary)
1490 preSecondary = secSize;
1491 }
1492 }
1493 if(insets != null) {
1494 prePrimary += getSizeForPrimaryAxis(insets, true) +
1495 getSizeForPrimaryAxis(insets, false);
1496 preSecondary += getSizeForSecondaryAxis(insets, true) +
1497 getSizeForSecondaryAxis(insets, false);
1498 }
1499 if (axis == 0) {
1500 return new Dimension(prePrimary, preSecondary);
1501 }
1502 return new Dimension(preSecondary, prePrimary);
1503 }
1504
1505
1506 /**
1507 * Removes the specified component from our knowledge.
1508 */
1509 public void removeLayoutComponent(Component component) {
1510 for(int counter = 0; counter < 3; counter++) {
1511 if(components[counter] == component) {
1512 components[counter] = null;
1513 sizes[counter] = 0;
1514 doReset = true;
1515 }
1516 }
1517 }
1518
1519
1520 //
1521 // LayoutManager2
1522 //
1523
1524
1525 /**
1526 * Adds the specified component to the layout, using the specified
1527 * constraint object.
1528 * @param comp the component to be added
1529 * @param constraints where/how the component is added to the layout.
1530 */
1531 public void addLayoutComponent(Component comp, Object constraints) {
1532 if ((constraints == null) || (constraints instanceof String)) {
1533 addLayoutComponent((String)constraints, comp);
1534 } else {
1535 throw new IllegalArgumentException("cannot add to layout: " +
1536 "constraint must be a " +
1537 "string (or null)");
1538 }
1539 }
1540
1541
1542 /**
1543 * Returns the alignment along the x axis. This specifies how
1544 * the component would like to be aligned relative to other
1545 * components. The value should be a number between 0 and 1
1546 * where 0 represents alignment along the origin, 1 is aligned
1547 * the furthest away from the origin, 0.5 is centered, etc.
1548 */
1549 public float getLayoutAlignmentX(Container target) {
1550 return 0.0f;
1551 }
1552
1553
1554 /**
1555 * Returns the alignment along the y axis. This specifies how
1556 * the component would like to be aligned relative to other
1557 * components. The value should be a number between 0 and 1
1558 * where 0 represents alignment along the origin, 1 is aligned
1559 * the furthest away from the origin, 0.5 is centered, etc.
1560 */
1561 public float getLayoutAlignmentY(Container target) {
1562 return 0.0f;
1563 }
1564
1565
1566 /**
1567 * Does nothing. If the developer really wants to change the
1568 * size of one of the views JSplitPane.resetToPreferredSizes should
1569 * be messaged.
1570 */
1571 public void invalidateLayout(Container c) {
1572 }
1573
1574
1575 /**
1576 * Returns the maximum layout size, which is Integer.MAX_VALUE
1577 * in both directions.
1578 */
1579 public Dimension maximumLayoutSize(Container target) {
1580 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
1581 }
1582
1583
1584 //
1585 // New methods.
1586 //
1587
1588 /**
1589 * Marks the receiver so that the next time this instance is
1590 * laid out it'll ask for the preferred sizes.
1591 */
1592 public void resetToPreferredSizes() {
1593 doReset = true;
1594 }
1595
1596 /**
1597 * Resets the size of the Component at the passed in location.
1598 */
1599 protected void resetSizeAt(int index) {
1600 sizes[index] = 0;
1601 doReset = true;
1602 }
1603
1604
1605 /**
1606 * Sets the sizes to <code>newSizes</code>.
1607 */
1608 protected void setSizes(int[] newSizes) {
1609 System.arraycopy(newSizes, 0, sizes, 0, 3);
1610 }
1611
1612
1613 /**
1614 * Returns the sizes of the components.
1615 */
1616 protected int[] getSizes() {
1617 int[] retSizes = new int[3];
1618
1619 System.arraycopy(sizes, 0, retSizes, 0, 3);
1620 return retSizes;
1621 }
1622
1623
1624 /**
1625 * Returns the width of the passed in Components preferred size.
1626 */
1627 protected int getPreferredSizeOfComponent(Component c) {
1628 return getSizeForPrimaryAxis(c.getPreferredSize());
1629 }
1630
1631
1632 /**
1633 * Returns the width of the passed in Components minimum size.
1634 */
1635 int getMinimumSizeOfComponent(Component c) {
1636 return getSizeForPrimaryAxis(c.getMinimumSize());
1637 }
1638
1639
1640 /**
1641 * Returns the width of the passed in component.
1642 */
1643 protected int getSizeOfComponent(Component c) {
1644 return getSizeForPrimaryAxis(c.getSize());
1645 }
1646
1647
1648 /**
1649 * Returns the available width based on the container size and
1650 * Insets.
1651 */
1652 protected int getAvailableSize(Dimension containerSize,
1653 Insets insets) {
1654 if(insets == null)
1655 return getSizeForPrimaryAxis(containerSize);
1656 return (getSizeForPrimaryAxis(containerSize) -
1657 (getSizeForPrimaryAxis(insets, true) +
1658 getSizeForPrimaryAxis(insets, false)));
1659 }
1660
1661
1662 /**
1663 * Returns the left inset, unless the Insets are null in which case
1664 * 0 is returned.
1665 */
1666 protected int getInitialLocation(Insets insets) {
1667 if(insets != null)
1668 return getSizeForPrimaryAxis(insets, true);
1669 return 0;
1670 }
1671
1672
1673 /**
1674 * Sets the width of the component c to be size, placing its
1675 * x location at location, y to the insets.top and height
1676 * to the containersize.height less the top and bottom insets.
1677 */
1678 protected void setComponentToSize(Component c, int size,
1679 int location, Insets insets,
1680 Dimension containerSize) {
1681 if(insets != null) {
1682 if (axis == 0) {
1683 c.setBounds(location, insets.top, size,
1684 containerSize.height -
1685 (insets.top + insets.bottom));
1686 }
1687 else {
1688 c.setBounds(insets.left, location, containerSize.width -
1689 (insets.left + insets.right), size);
1690 }
1691 }
1692 else {
1693 if (axis == 0) {
1694 c.setBounds(location, 0, size, containerSize.height);
1695 }
1696 else {
1697 c.setBounds(0, location, containerSize.width, size);
1698 }
1699 }
1700 }
1701
1702 /**
1703 * If the axis == 0, the width is returned, otherwise the height.
1704 */
1705 int getSizeForPrimaryAxis(Dimension size) {
1706 if (axis == 0) {
1707 return size.width;
1708 }
1709 return size.height;
1710 }
1711
1712 /**
1713 * If the axis == 0, the width is returned, otherwise the height.
1714 */
1715 int getSizeForSecondaryAxis(Dimension size) {
1716 if (axis == 0) {
1717 return size.height;
1718 }
1719 return size.width;
1720 }
1721
1722 /**
1723 * Returns a particular value of the inset identified by the
1724 * axis and <code>isTop</code><p>
1725 * axis isTop
1726 * 0 true - left
1727 * 0 false - right
1728 * 1 true - top
1729 * 1 false - bottom
1730 */
1731 int getSizeForPrimaryAxis(Insets insets, boolean isTop) {
1732 if (axis == 0) {
1733 if (isTop) {
1734 return insets.left;
1735 }
1736 return insets.right;
1737 }
1738 if (isTop) {
1739 return insets.top;
1740 }
1741 return insets.bottom;
1742 }
1743
1744 /**
1745 * Returns a particular value of the inset identified by the
1746 * axis and <code>isTop</code><p>
1747 * axis isTop
1748 * 0 true - left
1749 * 0 false - right
1750 * 1 true - top
1751 * 1 false - bottom
1752 */
1753 int getSizeForSecondaryAxis(Insets insets, boolean isTop) {
1754 if (axis == 0) {
1755 if (isTop) {
1756 return insets.top;
1757 }
1758 return insets.bottom;
1759 }
1760 if (isTop) {
1761 return insets.left;
1762 }
1763 return insets.right;
1764 }
1765
1766 /**
1767 * Determines the components. This should be called whenever
1768 * a new instance of this is installed into an existing
1769 * SplitPane.
1770 */
1771 protected void updateComponents() {
1772 Component comp;
1773
1774 comp = splitPane.getLeftComponent();
1775 if(components[0] != comp) {
1776 components[0] = comp;
1777 if(comp == null) {
1778 sizes[0] = 0;
1779 } else {
1780 sizes[0] = -1;
1781 }
1782 }
1783
1784 comp = splitPane.getRightComponent();
1785 if(components[1] != comp) {
1786 components[1] = comp;
1787 if(comp == null) {
1788 sizes[1] = 0;
1789 } else {
1790 sizes[1] = -1;
1791 }
1792 }
1793
1794 /* Find the divider. */
1795 Component[] children = splitPane.getComponents();
1796 Component oldDivider = components[2];
1797
1798 components[2] = null;
1799 for(int counter = children.length - 1; counter >= 0; counter--) {
1800 if(children[counter] != components[0] &&
1801 children[counter] != components[1] &&
1802 children[counter] != nonContinuousLayoutDivider) {
1803 if(oldDivider != children[counter]) {
1804 components[2] = children[counter];
1805 } else {
1806 components[2] = oldDivider;
1807 }
1808 break;
1809 }
1810 }
1811 if(components[2] == null) {
1812 sizes[2] = 0;
1813 }
1814 else {
1815 sizes[2] = getSizeForPrimaryAxis(components[2].getPreferredSize());
1816 }
1817 }
1818
1819 /**
1820 * Resets the size of the first component to <code>leftSize</code>,
1821 * and the right component to the remainder of the space.
1822 */
1823 void setDividerLocation(int leftSize, int availableSize) {
1824 boolean lValid = (components[0] != null &&
1825 components[0].isVisible());
1826 boolean rValid = (components[1] != null &&
1827 components[1].isVisible());
1828 boolean dValid = (components[2] != null &&
1829 components[2].isVisible());
1830 int max = availableSize;
1831
1832 if (dValid) {
1833 max -= sizes[2];
1834 }
1835 leftSize = Math.max(0, Math.min(leftSize, max));
1836 if (lValid) {
1837 if (rValid) {
1838 sizes[0] = leftSize;
1839 sizes[1] = max - leftSize;
1840 }
1841 else {
1842 sizes[0] = max;
1843 sizes[1] = 0;
1844 }
1845 }
1846 else if (rValid) {
1847 sizes[1] = max;
1848 sizes[0] = 0;
1849 }
1850 }
1851
1852 /**
1853 * Returns an array of the minimum sizes of the components.
1854 */
1855 int[] getPreferredSizes() {
1856 int[] retValue = new int[3];
1857
1858 for (int counter = 0; counter < 3; counter++) {
1859 if (components[counter] != null &&
1860 components[counter].isVisible()) {
1861 retValue[counter] = getPreferredSizeOfComponent
1862 (components[counter]);
1863 }
1864 else {
1865 retValue[counter] = -1;
1866 }
1867 }
1868 return retValue;
1869 }
1870
1871 /**
1872 * Returns an array of the minimum sizes of the components.
1873 */
1874 int[] getMinimumSizes() {
1875 int[] retValue = new int[3];
1876
1877 for (int counter = 0; counter < 2; counter++) {
1878 if (components[counter] != null &&
1879 components[counter].isVisible()) {
1880 retValue[counter] = getMinimumSizeOfComponent
1881 (components[counter]);
1882 }
1883 else {
1884 retValue[counter] = -1;
1885 }
1886 }
1887 retValue[2] = (components[2] != null) ?
1888 getMinimumSizeOfComponent(components[2]) : -1;
1889 return retValue;
1890 }
1891
1892 /**
1893 * Resets the components to their preferred sizes.
1894 */
1895 void resetToPreferredSizes(int availableSize) {
1896 // Set the sizes to the preferred sizes (if fits), otherwise
1897 // set to min sizes and distribute any extra space.
1898 int[] testSizes = getPreferredSizes();
1899 int totalSize = 0;
1900
1901 for (int counter = 0; counter < 3; counter++) {
1902 if (testSizes[counter] != -1) {
1903 totalSize += testSizes[counter];
1904 }
1905 }
1906 if (totalSize > availableSize) {
1907 testSizes = getMinimumSizes();
1908
1909 totalSize = 0;
1910 for (int counter = 0; counter < 3; counter++) {
1911 if (testSizes[counter] != -1) {
1912 totalSize += testSizes[counter];
1913 }
1914 }
1915 }
1916 setSizes(testSizes);
1917 distributeSpace(availableSize - totalSize, false);
1918 }
1919
1920 /**
1921 * Distributes <code>space</code> between the two components
1922 * (divider won't get any extra space) based on the weighting. This
1923 * attempts to honor the min size of the components.
1924 *
1925 * @param keepHidden if true and one of the components is 0x0
1926 * it gets none of the extra space
1927 */
1928 void distributeSpace(int space, boolean keepHidden) {
1929 boolean lValid = (components[0] != null &&
1930 components[0].isVisible());
1931 boolean rValid = (components[1] != null &&
1932 components[1].isVisible());
1933
1934 if (keepHidden) {
1935 if (lValid && getSizeForPrimaryAxis(
1936 components[0].getSize()) == 0) {
1937 lValid = false;
1938 if (rValid && getSizeForPrimaryAxis(
1939 components[1].getSize()) == 0) {
1940 // Both aren't valid, force them both to be valid
1941 lValid = true;
1942 }
1943 }
1944 else if (rValid && getSizeForPrimaryAxis(
1945 components[1].getSize()) == 0) {
1946 rValid = false;
1947 }
1948 }
1949 if (lValid && rValid) {
1950 double weight = splitPane.getResizeWeight();
1951 int lExtra = (int)(weight * (double)space);
1952 int rExtra = (space - lExtra);
1953
1954 sizes[0] += lExtra;
1955 sizes[1] += rExtra;
1956
1957 int lMin = getMinimumSizeOfComponent(components[0]);
1958 int rMin = getMinimumSizeOfComponent(components[1]);
1959 boolean lMinValid = (sizes[0] >= lMin);
1960 boolean rMinValid = (sizes[1] >= rMin);
1961
1962 if (!lMinValid && !rMinValid) {
1963 if (sizes[0] < 0) {
1964 sizes[1] += sizes[0];
1965 sizes[0] = 0;
1966 }
1967 else if (sizes[1] < 0) {
1968 sizes[0] += sizes[1];
1969 sizes[1] = 0;
1970 }
1971 }
1972 else if (!lMinValid) {
1973 if (sizes[1] - (lMin - sizes[0]) < rMin) {
1974 // both below min, just make sure > 0
1975 if (sizes[0] < 0) {
1976 sizes[1] += sizes[0];
1977 sizes[0] = 0;
1978 }
1979 }
1980 else {
1981 sizes[1] -= (lMin - sizes[0]);
1982 sizes[0] = lMin;
1983 }
1984 }
1985 else if (!rMinValid) {
1986 if (sizes[0] - (rMin - sizes[1]) < lMin) {
1987 // both below min, just make sure > 0
1988 if (sizes[1] < 0) {
1989 sizes[0] += sizes[1];
1990 sizes[1] = 0;
1991 }
1992 }
1993 else {
1994 sizes[0] -= (rMin - sizes[1]);
1995 sizes[1] = rMin;
1996 }
1997 }
1998 if (sizes[0] < 0) {
1999 sizes[0] = 0;
2000 }
2001 if (sizes[1] < 0) {
2002 sizes[1] = 0;
2003 }
2004 }
2005 else if (lValid) {
2006 sizes[0] = Math.max(0, sizes[0] + space);
2007 }
2008 else if (rValid) {
2009 sizes[1] = Math.max(0, sizes[1] + space);
2010 }
2011 }
2012 }
2013
2014
2015 /**
2016 * LayoutManager used for JSplitPanes with an orientation of
2017 * VERTICAL_SPLIT.
2018 * <p>
2019 */
2020 public class BasicVerticalLayoutManager extends
2021 BasicHorizontalLayoutManager
2022 {
2023 public BasicVerticalLayoutManager() {
2024 super(1);
2025 }
2026 }
2027
2028
2029 private class Handler implements FocusListener, PropertyChangeListener {
2030 //
2031 // PropertyChangeListener
2032 //
2033 /**
2034 * Messaged from the <code>JSplitPane</code> the receiver is
2035 * contained in. May potentially reset the layout manager and cause a
2036 * <code>validate</code> to be sent.
2037 */
2038 public void propertyChange(PropertyChangeEvent e) {
2039 if(e.getSource() == splitPane) {
2040 String changeName = e.getPropertyName();
2041
2042 if(changeName == JSplitPane.ORIENTATION_PROPERTY) {
2043 orientation = splitPane.getOrientation();
2044 resetLayoutManager();
2045 } else if(changeName == JSplitPane.CONTINUOUS_LAYOUT_PROPERTY){
2046 setContinuousLayout(splitPane.isContinuousLayout());
2047 if(!isContinuousLayout()) {
2048 if(nonContinuousLayoutDivider == null) {
2049 setNonContinuousLayoutDivider(
2050 createDefaultNonContinuousLayoutDivider(),
2051 true);
2052 } else if(nonContinuousLayoutDivider.getParent() ==
2053 null) {
2054 setNonContinuousLayoutDivider(
2055 nonContinuousLayoutDivider,
2056 true);
2057 }
2058 }
2059 } else if(changeName == JSplitPane.DIVIDER_SIZE_PROPERTY){
2060 divider.setDividerSize(splitPane.getDividerSize());
2061 dividerSize = divider.getDividerSize();
2062 splitPane.revalidate();
2063 splitPane.repaint();
2064 }
2065 }
2066 }
2067
2068 //
2069 // FocusListener
2070 //
2071 public void focusGained(FocusEvent ev) {
2072 dividerKeyboardResize = true;
2073 splitPane.repaint();
2074 }
2075
2076 public void focusLost(FocusEvent ev) {
2077 dividerKeyboardResize = false;
2078 splitPane.repaint();
2079 }
2080 }
2081
2082
2083 private static class Actions extends UIAction {
2084 private static final String NEGATIVE_INCREMENT = "negativeIncrement";
2085 private static final String POSITIVE_INCREMENT = "positiveIncrement";
2086 private static final String SELECT_MIN = "selectMin";
2087 private static final String SELECT_MAX = "selectMax";
2088 private static final String START_RESIZE = "startResize";
2089 private static final String TOGGLE_FOCUS = "toggleFocus";
2090 private static final String FOCUS_OUT_FORWARD = "focusOutForward";
2091 private static final String FOCUS_OUT_BACKWARD = "focusOutBackward";
2092
2093 Actions(String key) {
2094 super(key);
2095 }
2096
2097 public void actionPerformed(ActionEvent ev) {
2098 JSplitPane splitPane = (JSplitPane)ev.getSource();
2099 BasicSplitPaneUI ui = (BasicSplitPaneUI)BasicLookAndFeel.
2100 getUIOfType(splitPane.getUI(), BasicSplitPaneUI.class);
2101
2102 if (ui == null) {
2103 return;
2104 }
2105 String key = getName();
2106 if (key == NEGATIVE_INCREMENT) {
2107 if (ui.dividerKeyboardResize) {
2108 splitPane.setDividerLocation(Math.max(
2109 0, ui.getDividerLocation
2110 (splitPane) - ui.getKeyboardMoveIncrement()));
2111 }
2112 }
2113 else if (key == POSITIVE_INCREMENT) {
2114 if (ui.dividerKeyboardResize) {
2115 splitPane.setDividerLocation(
2116 ui.getDividerLocation(splitPane) +
2117 ui.getKeyboardMoveIncrement());
2118 }
2119 }
2120 else if (key == SELECT_MIN) {
2121 if (ui.dividerKeyboardResize) {
2122 splitPane.setDividerLocation(0);
2123 }
2124 }
2125 else if (key == SELECT_MAX) {
2126 if (ui.dividerKeyboardResize) {
2127 Insets insets = splitPane.getInsets();
2128 int bottomI = (insets != null) ? insets.bottom : 0;
2129 int rightI = (insets != null) ? insets.right : 0;
2130
2131 if (ui.orientation == JSplitPane.VERTICAL_SPLIT) {
2132 splitPane.setDividerLocation(splitPane.getHeight() -
2133 bottomI);
2134 }
2135 else {
2136 splitPane.setDividerLocation(splitPane.getWidth() -
2137 rightI);
2138 }
2139 }
2140 }
2141 else if (key == START_RESIZE) {
2142 if (!ui.dividerKeyboardResize) {
2143 splitPane.requestFocus();
2144 } else {
2145 JSplitPane parentSplitPane =
2146 (JSplitPane)SwingUtilities.getAncestorOfClass(
2147 JSplitPane.class, splitPane);
2148 if (parentSplitPane!=null) {
2149 parentSplitPane.requestFocus();
2150 }
2151 }
2152 }
2153 else if (key == TOGGLE_FOCUS) {
2154 toggleFocus(splitPane);
2155 }
2156 else if (key == FOCUS_OUT_FORWARD) {
2157 moveFocus(splitPane, 1);
2158 }
2159 else if (key == FOCUS_OUT_BACKWARD) {
2160 moveFocus(splitPane, -1);
2161 }
2162 }
2163
2164 private void moveFocus(JSplitPane splitPane, int direction) {
2165 Container rootAncestor = splitPane.getFocusCycleRootAncestor();
2166 FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy();
2167 Component focusOn = (direction > 0) ?
2168 policy.getComponentAfter(rootAncestor, splitPane) :
2169 policy.getComponentBefore(rootAncestor, splitPane);
2170 HashSet<Component> focusFrom = new HashSet<Component>();
2171 if (splitPane.isAncestorOf(focusOn)) {
2172 do {
2173 focusFrom.add(focusOn);
2174 rootAncestor = focusOn.getFocusCycleRootAncestor();
2175 policy = rootAncestor.getFocusTraversalPolicy();
2176 focusOn = (direction > 0) ?
2177 policy.getComponentAfter(rootAncestor, focusOn) :
2178 policy.getComponentBefore(rootAncestor, focusOn);
2179 } while (splitPane.isAncestorOf(focusOn) &&
2180 !focusFrom.contains(focusOn));
2181 }
2182 if ( focusOn!=null && !splitPane.isAncestorOf(focusOn) ) {
2183 focusOn.requestFocus();
2184 }
2185 }
2186
2187 private void toggleFocus(JSplitPane splitPane) {
2188 Component left = splitPane.getLeftComponent();
2189 Component right = splitPane.getRightComponent();
2190
2191 KeyboardFocusManager manager =
2192 KeyboardFocusManager.getCurrentKeyboardFocusManager();
2193 Component focus = manager.getFocusOwner();
2194 Component focusOn = getNextSide(splitPane, focus);
2195 if (focusOn != null) {
2196 // don't change the focus if the new focused component belongs
2197 // to the same splitpane and the same side
2198 if ( focus!=null &&
2199 ( (SwingUtilities.isDescendingFrom(focus, left) &&
2200 SwingUtilities.isDescendingFrom(focusOn, left)) ||
2201 (SwingUtilities.isDescendingFrom(focus, right) &&
2202 SwingUtilities.isDescendingFrom(focusOn, right)) ) ) {
2203 return;
2204 }
2205 SwingUtilities2.compositeRequestFocus(focusOn);
2206 }
2207 }
2208
2209 private Component getNextSide(JSplitPane splitPane, Component focus) {
2210 Component left = splitPane.getLeftComponent();
2211 Component right = splitPane.getRightComponent();
2212 Component next;
2213 if (focus!=null && SwingUtilities.isDescendingFrom(focus, left) &&
2214 right!=null) {
2215 next = getFirstAvailableComponent(right);
2216 if (next != null) {
2217 return next;
2218 }
2219 }
2220 JSplitPane parentSplitPane = (JSplitPane)SwingUtilities.getAncestorOfClass(JSplitPane.class, splitPane);
2221 if (parentSplitPane!=null) {
2222 // focus next side of the parent split pane
2223 next = getNextSide(parentSplitPane, focus);
2224 } else {
2225 next = getFirstAvailableComponent(left);
2226 if (next == null) {
2227 next = getFirstAvailableComponent(right);
2228 }
2229 }
2230 return next;
2231 }
2232
2233 private Component getFirstAvailableComponent(Component c) {
2234 if (c!=null && c instanceof JSplitPane) {
2235 JSplitPane sp = (JSplitPane)c;
2236 Component left = getFirstAvailableComponent(sp.getLeftComponent());
2237 if (left != null) {
2238 c = left;
2239 } else {
2240 c = getFirstAvailableComponent(sp.getRightComponent());
2241 }
2242 }
2243 return c;
2244 }
2245 }
2246}