1 /*
2 * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package javax.swing.plaf.basic;
27
28 import javax.swing;
29 import javax.swing.event;
30 import java.awt;
31 import java.awt.event;
32
33 import java.beans;
34
35 import java.util.Hashtable;
36 import java.util.HashMap;
37
38 import javax.swing.border;
39 import javax.swing.plaf;
40 import sun.swing.DefaultLookup;
41 import sun.swing.UIAction;
42
43
44 /**
45 * A Basic L&F implementation of ToolBarUI. This implementation
46 * is a "combined" view/controller.
47 * <p>
48 *
49 * @author Georges Saab
50 * @author Jeff Shapiro
51 */
52 public class BasicToolBarUI extends ToolBarUI implements SwingConstants
53 {
54 protected JToolBar toolBar;
55 private boolean floating;
56 private int floatingX;
57 private int floatingY;
58 private JFrame floatingFrame;
59 private RootPaneContainer floatingToolBar;
60 protected DragWindow dragWindow;
61 private Container dockingSource;
62 private int dockingSensitivity = 0;
63 protected int focusedCompIndex = -1;
64
65 protected Color dockingColor = null;
66 protected Color floatingColor = null;
67 protected Color dockingBorderColor = null;
68 protected Color floatingBorderColor = null;
69
70 protected MouseInputListener dockingListener;
71 protected PropertyChangeListener propertyListener;
72
73 protected ContainerListener toolBarContListener;
74 protected FocusListener toolBarFocusListener;
75 private Handler handler;
76
77 protected String constraintBeforeFloating = BorderLayout.NORTH;
78
79 // Rollover button implementation.
80 private static String IS_ROLLOVER = "JToolBar.isRollover";
81 private static Border rolloverBorder;
82 private static Border nonRolloverBorder;
83 private static Border nonRolloverToggleBorder;
84 private boolean rolloverBorders = false;
85
86 private HashMap borderTable = new HashMap();
87 private Hashtable rolloverTable = new Hashtable();
88
89
90 /**
91 * As of Java 2 platform v1.3 this previously undocumented field is no
92 * longer used.
93 * Key bindings are now defined by the LookAndFeel, please refer to
94 * the key bindings specification for further details.
95 *
96 * @deprecated As of Java 2 platform v1.3.
97 */
98 @Deprecated
99 protected KeyStroke upKey;
100 /**
101 * As of Java 2 platform v1.3 this previously undocumented field is no
102 * longer used.
103 * Key bindings are now defined by the LookAndFeel, please refer to
104 * the key bindings specification for further details.
105 *
106 * @deprecated As of Java 2 platform v1.3.
107 */
108 @Deprecated
109 protected KeyStroke downKey;
110 /**
111 * As of Java 2 platform v1.3 this previously undocumented field is no
112 * longer used.
113 * Key bindings are now defined by the LookAndFeel, please refer to
114 * the key bindings specification for further details.
115 *
116 * @deprecated As of Java 2 platform v1.3.
117 */
118 @Deprecated
119 protected KeyStroke leftKey;
120 /**
121 * As of Java 2 platform v1.3 this previously undocumented field is no
122 * longer used.
123 * Key bindings are now defined by the LookAndFeel, please refer to
124 * the key bindings specification for further details.
125 *
126 * @deprecated As of Java 2 platform v1.3.
127 */
128 @Deprecated
129 protected KeyStroke rightKey;
130
131
132 private static String FOCUSED_COMP_INDEX = "JToolBar.focusedCompIndex";
133
134 public static ComponentUI createUI( JComponent c )
135 {
136 return new BasicToolBarUI();
137 }
138
139 public void installUI( JComponent c )
140 {
141 toolBar = (JToolBar) c;
142
143 // Set defaults
144 installDefaults();
145 installComponents();
146 installListeners();
147 installKeyboardActions();
148
149 // Initialize instance vars
150 dockingSensitivity = 0;
151 floating = false;
152 floatingX = floatingY = 0;
153 floatingToolBar = null;
154
155 setOrientation( toolBar.getOrientation() );
156 LookAndFeel.installProperty(c, "opaque", Boolean.TRUE);
157
158 if ( c.getClientProperty( FOCUSED_COMP_INDEX ) != null )
159 {
160 focusedCompIndex = ( (Integer) ( c.getClientProperty( FOCUSED_COMP_INDEX ) ) ).intValue();
161 }
162 }
163
164 public void uninstallUI( JComponent c )
165 {
166
167 // Clear defaults
168 uninstallDefaults();
169 uninstallComponents();
170 uninstallListeners();
171 uninstallKeyboardActions();
172
173 // Clear instance vars
174 if (isFloating() == true)
175 setFloating(false, null);
176
177 floatingToolBar = null;
178 dragWindow = null;
179 dockingSource = null;
180
181 c.putClientProperty( FOCUSED_COMP_INDEX, Integer.valueOf( focusedCompIndex ) );
182 }
183
184 protected void installDefaults( )
185 {
186 LookAndFeel.installBorder(toolBar,"ToolBar.border");
187 LookAndFeel.installColorsAndFont(toolBar,
188 "ToolBar.background",
189 "ToolBar.foreground",
190 "ToolBar.font");
191 // Toolbar specific defaults
192 if ( dockingColor == null || dockingColor instanceof UIResource )
193 dockingColor = UIManager.getColor("ToolBar.dockingBackground");
194 if ( floatingColor == null || floatingColor instanceof UIResource )
195 floatingColor = UIManager.getColor("ToolBar.floatingBackground");
196 if ( dockingBorderColor == null ||
197 dockingBorderColor instanceof UIResource )
198 dockingBorderColor = UIManager.getColor("ToolBar.dockingForeground");
199 if ( floatingBorderColor == null ||
200 floatingBorderColor instanceof UIResource )
201 floatingBorderColor = UIManager.getColor("ToolBar.floatingForeground");
202
203 // ToolBar rollover button borders
204 Object rolloverProp = toolBar.getClientProperty( IS_ROLLOVER );
205 if (rolloverProp == null) {
206 rolloverProp = UIManager.get("ToolBar.isRollover");
207 }
208 if ( rolloverProp != null ) {
209 rolloverBorders = ((Boolean)rolloverProp).booleanValue();
210 }
211
212 if (rolloverBorder == null) {
213 rolloverBorder = createRolloverBorder();
214 }
215 if (nonRolloverBorder == null) {
216 nonRolloverBorder = createNonRolloverBorder();
217 }
218 if (nonRolloverToggleBorder == null) {
219 nonRolloverToggleBorder = createNonRolloverToggleBorder();
220 }
221
222
223 setRolloverBorders( isRolloverBorders() );
224 }
225
226 protected void uninstallDefaults( )
227 {
228 LookAndFeel.uninstallBorder(toolBar);
229 dockingColor = null;
230 floatingColor = null;
231 dockingBorderColor = null;
232 floatingBorderColor = null;
233
234 installNormalBorders(toolBar);
235
236 rolloverBorder = null;
237 nonRolloverBorder = null;
238 nonRolloverToggleBorder = null;
239 }
240
241 protected void installComponents( )
242 {
243 }
244
245 protected void uninstallComponents( )
246 {
247 }
248
249 protected void installListeners( )
250 {
251 dockingListener = createDockingListener( );
252
253 if ( dockingListener != null )
254 {
255 toolBar.addMouseMotionListener( dockingListener );
256 toolBar.addMouseListener( dockingListener );
257 }
258
259 propertyListener = createPropertyListener(); // added in setFloating
260 if (propertyListener != null) {
261 toolBar.addPropertyChangeListener(propertyListener);
262 }
263
264 toolBarContListener = createToolBarContListener();
265 if ( toolBarContListener != null ) {
266 toolBar.addContainerListener( toolBarContListener );
267 }
268
269 toolBarFocusListener = createToolBarFocusListener();
270
271 if ( toolBarFocusListener != null )
272 {
273 // Put focus listener on all components in toolbar
274 Component[] components = toolBar.getComponents();
275
276 for ( int i = 0; i < components.length; ++i )
277 {
278 components[ i ].addFocusListener( toolBarFocusListener );
279 }
280 }
281 }
282
283 protected void uninstallListeners( )
284 {
285 if ( dockingListener != null )
286 {
287 toolBar.removeMouseMotionListener(dockingListener);
288 toolBar.removeMouseListener(dockingListener);
289
290 dockingListener = null;
291 }
292
293 if ( propertyListener != null )
294 {
295 toolBar.removePropertyChangeListener(propertyListener);
296 propertyListener = null; // removed in setFloating
297 }
298
299 if ( toolBarContListener != null )
300 {
301 toolBar.removeContainerListener( toolBarContListener );
302 toolBarContListener = null;
303 }
304
305 if ( toolBarFocusListener != null )
306 {
307 // Remove focus listener from all components in toolbar
308 Component[] components = toolBar.getComponents();
309
310 for ( int i = 0; i < components.length; ++i )
311 {
312 components[ i ].removeFocusListener( toolBarFocusListener );
313 }
314
315 toolBarFocusListener = null;
316 }
317 handler = null;
318 }
319
320 protected void installKeyboardActions( )
321 {
322 InputMap km = getInputMap(JComponent.
323 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
324
325 SwingUtilities.replaceUIInputMap(toolBar, JComponent.
326 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
327 km);
328
329 LazyActionMap.installLazyActionMap(toolBar, BasicToolBarUI.class,
330 "ToolBar.actionMap");
331 }
332
333 InputMap getInputMap(int condition) {
334 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
335 return (InputMap)DefaultLookup.get(toolBar, this,
336 "ToolBar.ancestorInputMap");
337 }
338 return null;
339 }
340
341 static void loadActionMap(LazyActionMap map) {
342 map.put(new Actions(Actions.NAVIGATE_RIGHT));
343 map.put(new Actions(Actions.NAVIGATE_LEFT));
344 map.put(new Actions(Actions.NAVIGATE_UP));
345 map.put(new Actions(Actions.NAVIGATE_DOWN));
346 }
347
348 protected void uninstallKeyboardActions( )
349 {
350 SwingUtilities.replaceUIActionMap(toolBar, null);
351 SwingUtilities.replaceUIInputMap(toolBar, JComponent.
352 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
353 null);
354 }
355
356 protected void navigateFocusedComp( int direction )
357 {
358 int nComp = toolBar.getComponentCount();
359 int j;
360
361 switch ( direction )
362 {
363 case EAST:
364 case SOUTH:
365
366 if ( focusedCompIndex < 0 || focusedCompIndex >= nComp ) break;
367
368 j = focusedCompIndex + 1;
369
370 while ( j != focusedCompIndex )
371 {
372 if ( j >= nComp ) j = 0;
373 Component comp = toolBar.getComponentAtIndex( j++ );
374
375 if ( comp != null && comp.isFocusTraversable() && comp.isEnabled() )
376 {
377 comp.requestFocus();
378 break;
379 }
380 }
381
382 break;
383
384 case WEST:
385 case NORTH:
386
387 if ( focusedCompIndex < 0 || focusedCompIndex >= nComp ) break;
388
389 j = focusedCompIndex - 1;
390
391 while ( j != focusedCompIndex )
392 {
393 if ( j < 0 ) j = nComp - 1;
394 Component comp = toolBar.getComponentAtIndex( j-- );
395
396 if ( comp != null && comp.isFocusTraversable() && comp.isEnabled() )
397 {
398 comp.requestFocus();
399 break;
400 }
401 }
402
403 break;
404
405 default:
406 break;
407 }
408 }
409
410 /**
411 * Creates a rollover border for toolbar components. The
412 * rollover border will be installed if rollover borders are
413 * enabled.
414 * <p>
415 * Override this method to provide an alternate rollover border.
416 *
417 * @since 1.4
418 */
419 protected Border createRolloverBorder() {
420 Object border = UIManager.get("ToolBar.rolloverBorder");
421 if (border != null) {
422 return (Border)border;
423 }
424 UIDefaults table = UIManager.getLookAndFeelDefaults();
425 return new CompoundBorder(new BasicBorders.RolloverButtonBorder(
426 table.getColor("controlShadow"),
427 table.getColor("controlDkShadow"),
428 table.getColor("controlHighlight"),
429 table.getColor("controlLtHighlight")),
430 new BasicBorders.RolloverMarginBorder());
431 }
432
433 /**
434 * Creates the non rollover border for toolbar components. This
435 * border will be installed as the border for components added
436 * to the toolbar if rollover borders are not enabled.
437 * <p>
438 * Override this method to provide an alternate rollover border.
439 *
440 * @since 1.4
441 */
442 protected Border createNonRolloverBorder() {
443 Object border = UIManager.get("ToolBar.nonrolloverBorder");
444 if (border != null) {
445 return (Border)border;
446 }
447 UIDefaults table = UIManager.getLookAndFeelDefaults();
448 return new CompoundBorder(new BasicBorders.ButtonBorder(
449 table.getColor("Button.shadow"),
450 table.getColor("Button.darkShadow"),
451 table.getColor("Button.light"),
452 table.getColor("Button.highlight")),
453 new BasicBorders.RolloverMarginBorder());
454 }
455
456 /**
457 * Creates a non rollover border for Toggle buttons in the toolbar.
458 */
459 private Border createNonRolloverToggleBorder() {
460 UIDefaults table = UIManager.getLookAndFeelDefaults();
461 return new CompoundBorder(new BasicBorders.RadioButtonBorder(
462 table.getColor("ToggleButton.shadow"),
463 table.getColor("ToggleButton.darkShadow"),
464 table.getColor("ToggleButton.light"),
465 table.getColor("ToggleButton.highlight")),
466 new BasicBorders.RolloverMarginBorder());
467 }
468
469 /**
470 * No longer used, use BasicToolBarUI.createFloatingWindow(JToolBar)
471 * @see #createFloatingWindow
472 */
473 protected JFrame createFloatingFrame(JToolBar toolbar) {
474 Window window = SwingUtilities.getWindowAncestor(toolbar);
475 JFrame frame = new JFrame(toolbar.getName(),
476 (window != null) ? window.getGraphicsConfiguration() : null) {
477 // Override createRootPane() to automatically resize
478 // the frame when contents change
479 protected JRootPane createRootPane() {
480 JRootPane rootPane = new JRootPane() {
481 private boolean packing = false;
482
483 public void validate() {
484 super.validate();
485 if (!packing) {
486 packing = true;
487 pack();
488 packing = false;
489 }
490 }
491 };
492 rootPane.setOpaque(true);
493 return rootPane;
494 }
495 };
496 frame.getRootPane().setName("ToolBar.FloatingFrame");
497 frame.setResizable(false);
498 WindowListener wl = createFrameListener();
499 frame.addWindowListener(wl);
500 return frame;
501 }
502
503 /**
504 * Creates a window which contains the toolbar after it has been
505 * dragged out from its container
506 * @return a <code>RootPaneContainer</code> object, containing the toolbar.
507 * @since 1.4
508 */
509 protected RootPaneContainer createFloatingWindow(JToolBar toolbar) {
510 class ToolBarDialog extends JDialog {
511 public ToolBarDialog(Frame owner, String title, boolean modal) {
512 super(owner, title, modal);
513 }
514
515 public ToolBarDialog(Dialog owner, String title, boolean modal) {
516 super(owner, title, modal);
517 }
518
519 // Override createRootPane() to automatically resize
520 // the frame when contents change
521 protected JRootPane createRootPane() {
522 JRootPane rootPane = new JRootPane() {
523 private boolean packing = false;
524
525 public void validate() {
526 super.validate();
527 if (!packing) {
528 packing = true;
529 pack();
530 packing = false;
531 }
532 }
533 };
534 rootPane.setOpaque(true);
535 return rootPane;
536 }
537 }
538
539 JDialog dialog;
540 Window window = SwingUtilities.getWindowAncestor(toolbar);
541 if (window instanceof Frame) {
542 dialog = new ToolBarDialog((Frame)window, toolbar.getName(), false);
543 } else if (window instanceof Dialog) {
544 dialog = new ToolBarDialog((Dialog)window, toolbar.getName(), false);
545 } else {
546 dialog = new ToolBarDialog((Frame)null, toolbar.getName(), false);
547 }
548
549 dialog.getRootPane().setName("ToolBar.FloatingWindow");
550 dialog.setTitle(toolbar.getName());
551 dialog.setResizable(false);
552 WindowListener wl = createFrameListener();
553 dialog.addWindowListener(wl);
554 return dialog;
555 }
556
557 protected DragWindow createDragWindow(JToolBar toolbar) {
558 Window frame = null;
559 if(toolBar != null) {
560 Container p;
561 for(p = toolBar.getParent() ; p != null && !(p instanceof Window) ;
562 p = p.getParent());
563 if(p != null && p instanceof Window)
564 frame = (Window) p;
565 }
566 if(floatingToolBar == null) {
567 floatingToolBar = createFloatingWindow(toolBar);
568 }
569 if (floatingToolBar instanceof Window) frame = (Window) floatingToolBar;
570 DragWindow dragWindow = new DragWindow(frame);
571 return dragWindow;
572 }
573
574 /**
575 * Returns a flag to determine whether rollover button borders
576 * are enabled.
577 *
578 * @return true if rollover borders are enabled; false otherwise
579 * @see #setRolloverBorders
580 * @since 1.4
581 */
582 public boolean isRolloverBorders() {
583 return rolloverBorders;
584 }
585
586 /**
587 * Sets the flag for enabling rollover borders on the toolbar and it will
588 * also install the apropriate border depending on the state of the flag.
589 *
590 * @param rollover if true, rollover borders are installed.
591 * Otherwise non-rollover borders are installed
592 * @see #isRolloverBorders
593 * @since 1.4
594 */
595 public void setRolloverBorders( boolean rollover ) {
596 rolloverBorders = rollover;
597
598 if ( rolloverBorders ) {
599 installRolloverBorders( toolBar );
600 } else {
601 installNonRolloverBorders( toolBar );
602 }
603 }
604
605 /**
606 * Installs rollover borders on all the child components of the JComponent.
607 * <p>
608 * This is a convenience method to call <code>setBorderToRollover</code>
609 * for each child component.
610 *
611 * @param c container which holds the child components (usally a JToolBar)
612 * @see #setBorderToRollover
613 * @since 1.4
614 */
615 protected void installRolloverBorders ( JComponent c ) {
616 // Put rollover borders on buttons
617 Component[] components = c.getComponents();
618
619 for ( int i = 0; i < components.length; ++i ) {
620 if ( components[ i ] instanceof JComponent ) {
621 ( (JComponent)components[ i ] ).updateUI();
622 setBorderToRollover( components[ i ] );
623 }
624 }
625 }
626
627 /**
628 * Installs non-rollover borders on all the child components of the JComponent.
629 * A non-rollover border is the border that is installed on the child component
630 * while it is in the toolbar.
631 * <p>
632 * This is a convenience method to call <code>setBorderToNonRollover</code>
633 * for each child component.
634 *
635 * @param c container which holds the child components (usally a JToolBar)
636 * @see #setBorderToNonRollover
637 * @since 1.4
638 */
639 protected void installNonRolloverBorders ( JComponent c ) {
640 // Put non-rollover borders on buttons. These borders reduce the margin.
641 Component[] components = c.getComponents();
642
643 for ( int i = 0; i < components.length; ++i ) {
644 if ( components[ i ] instanceof JComponent ) {
645 ( (JComponent)components[ i ] ).updateUI();
646 setBorderToNonRollover( components[ i ] );
647 }
648 }
649 }
650
651 /**
652 * Installs normal borders on all the child components of the JComponent.
653 * A normal border is the original border that was installed on the child
654 * component before it was added to the toolbar.
655 * <p>
656 * This is a convenience method to call <code>setBorderNormal</code>
657 * for each child component.
658 *
659 * @param c container which holds the child components (usally a JToolBar)
660 * @see #setBorderToNonRollover
661 * @since 1.4
662 */
663 protected void installNormalBorders ( JComponent c ) {
664 // Put back the normal borders on buttons
665 Component[] components = c.getComponents();
666
667 for ( int i = 0; i < components.length; ++i ) {
668 setBorderToNormal( components[ i ] );
669 }
670 }
671
672 /**
673 * Sets the border of the component to have a rollover border which
674 * was created by <code>createRolloverBorder</code>.
675 *
676 * @param c component which will have a rollover border installed
677 * @see #createRolloverBorder
678 * @since 1.4
679 */
680 protected void setBorderToRollover(Component c) {
681 if (c instanceof AbstractButton) {
682 AbstractButton b = (AbstractButton)c;
683
684 Border border = (Border)borderTable.get(b);
685 if (border == null || border instanceof UIResource) {
686 borderTable.put(b, b.getBorder());
687 }
688
689 // Only set the border if its the default border
690 if (b.getBorder() instanceof UIResource) {
691 b.setBorder(getRolloverBorder(b));
692 }
693
694 rolloverTable.put(b, b.isRolloverEnabled()?
695 Boolean.TRUE: Boolean.FALSE);
696 b.setRolloverEnabled(true);
697 }
698 }
699
700 /**
701 * Returns a rollover border for the button.
702 *
703 * @param b the button to calculate the rollover border for
704 * @return the rollover border
705 * @see #setBorderToRollover
706 * @since 1.6
707 */
708 protected Border getRolloverBorder(AbstractButton b) {
709 return rolloverBorder;
710 }
711
712 /**
713 * Sets the border of the component to have a non-rollover border which
714 * was created by <code>createNonRolloverBorder</code>.
715 *
716 * @param c component which will have a non-rollover border installed
717 * @see #createNonRolloverBorder
718 * @since 1.4
719 */
720 protected void setBorderToNonRollover(Component c) {
721 if (c instanceof AbstractButton) {
722 AbstractButton b = (AbstractButton)c;
723
724 Border border = (Border)borderTable.get(b);
725 if (border == null || border instanceof UIResource) {
726 borderTable.put(b, b.getBorder());
727 }
728
729 // Only set the border if its the default border
730 if (b.getBorder() instanceof UIResource) {
731 b.setBorder(getNonRolloverBorder(b));
732 }
733 rolloverTable.put(b, b.isRolloverEnabled()?
734 Boolean.TRUE: Boolean.FALSE);
735 b.setRolloverEnabled(false);
736 }
737 }
738
739 /**
740 * Returns a non-rollover border for the button.
741 *
742 * @param b the button to calculate the non-rollover border for
743 * @return the non-rollover border
744 * @see #setBorderToNonRollover
745 * @since 1.6
746 */
747 protected Border getNonRolloverBorder(AbstractButton b) {
748 if (b instanceof JToggleButton) {
749 return nonRolloverToggleBorder;
750 } else {
751 return nonRolloverBorder;
752 }
753 }
754
755 /**
756 * Sets the border of the component to have a normal border.
757 * A normal border is the original border that was installed on the child
758 * component before it was added to the toolbar.
759 *
760 * @param c component which will have a normal border re-installed
761 * @see #createNonRolloverBorder
762 * @since 1.4
763 */
764 protected void setBorderToNormal(Component c) {
765 if (c instanceof AbstractButton) {
766 AbstractButton b = (AbstractButton)c;
767
768 Border border = (Border)borderTable.remove(b);
769 b.setBorder(border);
770
771 Boolean value = (Boolean)rolloverTable.remove(b);
772 if (value != null) {
773 b.setRolloverEnabled(value.booleanValue());
774 }
775 }
776 }
777
778 public void setFloatingLocation(int x, int y) {
779 floatingX = x;
780 floatingY = y;
781 }
782
783 public boolean isFloating() {
784 return floating;
785 }
786
787 public void setFloating(boolean b, Point p) {
788 if (toolBar.isFloatable() == true) {
789 boolean visible = false;
790 Window ancestor = SwingUtilities.getWindowAncestor(toolBar);
791 if (ancestor != null) {
792 visible = ancestor.isVisible();
793 }
794 if (dragWindow != null)
795 dragWindow.setVisible(false);
796 this.floating = b;
797 if (floatingToolBar == null) {
798 floatingToolBar = createFloatingWindow(toolBar);
799 }
800 if (b == true)
801 {
802 if (dockingSource == null)
803 {
804 dockingSource = toolBar.getParent();
805 dockingSource.remove(toolBar);
806 }
807 constraintBeforeFloating = calculateConstraint();
808 if ( propertyListener != null )
809 UIManager.addPropertyChangeListener( propertyListener );
810 floatingToolBar.getContentPane().add(toolBar,BorderLayout.CENTER);
811 if (floatingToolBar instanceof Window) {
812 ((Window)floatingToolBar).pack();
813 ((Window)floatingToolBar).setLocation(floatingX, floatingY);
814 if (visible) {
815 ((Window)floatingToolBar).show();
816 } else {
817 ancestor.addWindowListener(new WindowAdapter() {
818 public void windowOpened(WindowEvent e) {
819 ((Window)floatingToolBar).show();
820 }
821 });
822 }
823 }
824 } else {
825 if (floatingToolBar == null)
826 floatingToolBar = createFloatingWindow(toolBar);
827 if (floatingToolBar instanceof Window) ((Window)floatingToolBar).setVisible(false);
828 floatingToolBar.getContentPane().remove(toolBar);
829 String constraint = getDockingConstraint(dockingSource,
830 p);
831 if (constraint == null) {
832 constraint = BorderLayout.NORTH;
833 }
834 int orientation = mapConstraintToOrientation(constraint);
835 setOrientation(orientation);
836 if (dockingSource== null)
837 dockingSource = toolBar.getParent();
838 if ( propertyListener != null )
839 UIManager.removePropertyChangeListener( propertyListener );
840 dockingSource.add(constraint, toolBar);
841 }
842 dockingSource.invalidate();
843 Container dockingSourceParent = dockingSource.getParent();
844 if (dockingSourceParent != null)
845 dockingSourceParent.validate();
846 dockingSource.repaint();
847 }
848 }
849
850 private int mapConstraintToOrientation(String constraint)
851 {
852 int orientation = toolBar.getOrientation();
853
854 if ( constraint != null )
855 {
856 if ( constraint.equals(BorderLayout.EAST) || constraint.equals(BorderLayout.WEST) )
857 orientation = JToolBar.VERTICAL;
858 else if ( constraint.equals(BorderLayout.NORTH) || constraint.equals(BorderLayout.SOUTH) )
859 orientation = JToolBar.HORIZONTAL;
860 }
861
862 return orientation;
863 }
864
865 public void setOrientation(int orientation)
866 {
867 toolBar.setOrientation( orientation );
868
869 if (dragWindow !=null)
870 dragWindow.setOrientation(orientation);
871 }
872
873 /**
874 * Gets the color displayed when over a docking area
875 */
876 public Color getDockingColor() {
877 return dockingColor;
878 }
879
880 /**
881 * Sets the color displayed when over a docking area
882 */
883 public void setDockingColor(Color c) {
884 this.dockingColor = c;
885 }
886
887 /**
888 * Gets the color displayed when over a floating area
889 */
890 public Color getFloatingColor() {
891 return floatingColor;
892 }
893
894 /**
895 * Sets the color displayed when over a floating area
896 */
897 public void setFloatingColor(Color c) {
898 this.floatingColor = c;
899 }
900
901 private boolean isBlocked(Component comp, Object constraint) {
902 if (comp instanceof Container) {
903 Container cont = (Container)comp;
904 LayoutManager lm = cont.getLayout();
905 if (lm instanceof BorderLayout) {
906 BorderLayout blm = (BorderLayout)lm;
907 Component c = blm.getLayoutComponent(cont, constraint);
908 return (c != null && c != toolBar);
909 }
910 }
911 return false;
912 }
913
914 public boolean canDock(Component c, Point p) {
915 return (p != null && getDockingConstraint(c, p) != null);
916 }
917
918 private String calculateConstraint() {
919 String constraint = null;
920 LayoutManager lm = dockingSource.getLayout();
921 if (lm instanceof BorderLayout) {
922 constraint = (String)((BorderLayout)lm).getConstraints(toolBar);
923 }
924 return (constraint != null) ? constraint : constraintBeforeFloating;
925 }
926
927
928
929 private String getDockingConstraint(Component c, Point p) {
930 if (p == null) return constraintBeforeFloating;
931 if (c.contains(p)) {
932 dockingSensitivity = (toolBar.getOrientation() == JToolBar.HORIZONTAL)
933 ? toolBar.getSize().height
934 : toolBar.getSize().width;
935 // North (Base distance on height for now!)
936 if (p.y < dockingSensitivity && !isBlocked(c, BorderLayout.NORTH)) {
937 return BorderLayout.NORTH;
938 }
939 // East (Base distance on height for now!)
940 if (p.x >= c.getWidth() - dockingSensitivity && !isBlocked(c, BorderLayout.EAST)) {
941 return BorderLayout.EAST;
942 }
943 // West (Base distance on height for now!)
944 if (p.x < dockingSensitivity && !isBlocked(c, BorderLayout.WEST)) {
945 return BorderLayout.WEST;
946 }
947 if (p.y >= c.getHeight() - dockingSensitivity && !isBlocked(c, BorderLayout.SOUTH)) {
948 return BorderLayout.SOUTH;
949 }
950 }
951 return null;
952 }
953
954 protected void dragTo(Point position, Point origin)
955 {
956 if (toolBar.isFloatable() == true)
957 {
958 try
959 {
960 if (dragWindow == null)
961 dragWindow = createDragWindow(toolBar);
962 Point offset = dragWindow.getOffset();
963 if (offset == null) {
964 Dimension size = toolBar.getPreferredSize();
965 offset = new Point(size.width/2, size.height/2);
966 dragWindow.setOffset(offset);
967 }
968 Point global = new Point(origin.x+ position.x,
969 origin.y+position.y);
970 Point dragPoint = new Point(global.x- offset.x,
971 global.y- offset.y);
972 if (dockingSource == null)
973 dockingSource = toolBar.getParent();
974 constraintBeforeFloating = calculateConstraint();
975 Point dockingPosition = dockingSource.getLocationOnScreen();
976 Point comparisonPoint = new Point(global.x-dockingPosition.x,
977 global.y-dockingPosition.y);
978 if (canDock(dockingSource, comparisonPoint)) {
979 dragWindow.setBackground(getDockingColor());
980 String constraint = getDockingConstraint(dockingSource,
981 comparisonPoint);
982 int orientation = mapConstraintToOrientation(constraint);
983 dragWindow.setOrientation(orientation);
984 dragWindow.setBorderColor(dockingBorderColor);
985 } else {
986 dragWindow.setBackground(getFloatingColor());
987 dragWindow.setBorderColor(floatingBorderColor);
988 dragWindow.setOrientation(toolBar.getOrientation());
989 }
990
991 dragWindow.setLocation(dragPoint.x, dragPoint.y);
992 if (dragWindow.isVisible() == false) {
993 Dimension size = toolBar.getPreferredSize();
994 dragWindow.setSize(size.width, size.height);
995 dragWindow.show();
996 }
997 }
998 catch ( IllegalComponentStateException e )
999 {
1000 }
1001 }
1002 }
1003
1004 protected void floatAt(Point position, Point origin)
1005 {
1006 if(toolBar.isFloatable() == true)
1007 {
1008 try
1009 {
1010 Point offset = dragWindow.getOffset();
1011 if (offset == null) {
1012 offset = position;
1013 dragWindow.setOffset(offset);
1014 }
1015 Point global = new Point(origin.x+ position.x,
1016 origin.y+position.y);
1017 setFloatingLocation(global.x-offset.x,
1018 global.y-offset.y);
1019 if (dockingSource != null) {
1020 Point dockingPosition = dockingSource.getLocationOnScreen();
1021 Point comparisonPoint = new Point(global.x-dockingPosition.x,
1022 global.y-dockingPosition.y);
1023 if (canDock(dockingSource, comparisonPoint)) {
1024 setFloating(false, comparisonPoint);
1025 } else {
1026 setFloating(true, null);
1027 }
1028 } else {
1029 setFloating(true, null);
1030 }
1031 dragWindow.setOffset(null);
1032 }
1033 catch ( IllegalComponentStateException e )
1034 {
1035 }
1036 }
1037 }
1038
1039 private Handler getHandler() {
1040 if (handler == null) {
1041 handler = new Handler();
1042 }
1043 return handler;
1044 }
1045
1046 protected ContainerListener createToolBarContListener( )
1047 {
1048 return getHandler();
1049 }
1050
1051 protected FocusListener createToolBarFocusListener( )
1052 {
1053 return getHandler();
1054 }
1055
1056 protected PropertyChangeListener createPropertyListener()
1057 {
1058 return getHandler();
1059 }
1060
1061 protected MouseInputListener createDockingListener( ) {
1062 getHandler().tb = toolBar;
1063 return getHandler();
1064 }
1065
1066 protected WindowListener createFrameListener() {
1067 return new FrameListener();
1068 }
1069
1070 /**
1071 * Paints the contents of the window used for dragging.
1072 *
1073 * @param g Graphics to paint to.
1074 * @throws NullPointerException is <code>g</code> is null
1075 * @since 1.5
1076 */
1077 protected void paintDragWindow(Graphics g) {
1078 g.setColor(dragWindow.getBackground());
1079 int w = dragWindow.getWidth();
1080 int h = dragWindow.getHeight();
1081 g.fillRect(0, 0, w, h);
1082 g.setColor(dragWindow.getBorderColor());
1083 g.drawRect(0, 0, w - 1, h - 1);
1084 }
1085
1086
1087 private static class Actions extends UIAction {
1088 private static final String NAVIGATE_RIGHT = "navigateRight";
1089 private static final String NAVIGATE_LEFT = "navigateLeft";
1090 private static final String NAVIGATE_UP = "navigateUp";
1091 private static final String NAVIGATE_DOWN = "navigateDown";
1092
1093 public Actions(String name) {
1094 super(name);
1095 }
1096
1097 public void actionPerformed(ActionEvent evt) {
1098 String key = getName();
1099 JToolBar toolBar = (JToolBar)evt.getSource();
1100 BasicToolBarUI ui = (BasicToolBarUI)BasicLookAndFeel.getUIOfType(
1101 toolBar.getUI(), BasicToolBarUI.class);
1102
1103 if (NAVIGATE_RIGHT == key) {
1104 ui.navigateFocusedComp(EAST);
1105 } else if (NAVIGATE_LEFT == key) {
1106 ui.navigateFocusedComp(WEST);
1107 } else if (NAVIGATE_UP == key) {
1108 ui.navigateFocusedComp(NORTH);
1109 } else if (NAVIGATE_DOWN == key) {
1110 ui.navigateFocusedComp(SOUTH);
1111 }
1112 }
1113 }
1114
1115
1116 private class Handler implements ContainerListener,
1117 FocusListener, MouseInputListener, PropertyChangeListener {
1118
1119 //
1120 // ContainerListener
1121 //
1122 public void componentAdded(ContainerEvent evt) {
1123 Component c = evt.getChild();
1124
1125 if (toolBarFocusListener != null) {
1126 c.addFocusListener(toolBarFocusListener);
1127 }
1128
1129 if (isRolloverBorders()) {
1130 setBorderToRollover(c);
1131 } else {
1132 setBorderToNonRollover(c);
1133 }
1134 }
1135
1136 public void componentRemoved(ContainerEvent evt) {
1137 Component c = evt.getChild();
1138
1139 if (toolBarFocusListener != null) {
1140 c.removeFocusListener(toolBarFocusListener);
1141 }
1142
1143 // Revert the button border
1144 setBorderToNormal(c);
1145 }
1146
1147
1148 //
1149 // FocusListener
1150 //
1151 public void focusGained(FocusEvent evt) {
1152 Component c = evt.getComponent();
1153 focusedCompIndex = toolBar.getComponentIndex(c);
1154 }
1155
1156 public void focusLost(FocusEvent evt) { }
1157
1158
1159 //
1160 // MouseInputListener (DockingListener)
1161 //
1162 JToolBar tb;
1163 boolean isDragging = false;
1164 Point origin = null;
1165
1166 public void mousePressed(MouseEvent evt) {
1167 if (!tb.isEnabled()) {
1168 return;
1169 }
1170 isDragging = false;
1171 }
1172
1173 public void mouseReleased(MouseEvent evt) {
1174 if (!tb.isEnabled()) {
1175 return;
1176 }
1177 if (isDragging == true) {
1178 Point position = evt.getPoint();
1179 if (origin == null)
1180 origin = evt.getComponent().getLocationOnScreen();
1181 floatAt(position, origin);
1182 }
1183 origin = null;
1184 isDragging = false;
1185 }
1186
1187 public void mouseDragged(MouseEvent evt) {
1188 if (!tb.isEnabled()) {
1189 return;
1190 }
1191 isDragging = true;
1192 Point position = evt.getPoint();
1193 if (origin == null) {
1194 origin = evt.getComponent().getLocationOnScreen();
1195 }
1196 dragTo(position, origin);
1197 }
1198
1199 public void mouseClicked(MouseEvent evt) {}
1200 public void mouseEntered(MouseEvent evt) {}
1201 public void mouseExited(MouseEvent evt) {}
1202 public void mouseMoved(MouseEvent evt) {}
1203
1204
1205 //
1206 // PropertyChangeListener
1207 //
1208 public void propertyChange(PropertyChangeEvent evt) {
1209 String propertyName = evt.getPropertyName();
1210 if (propertyName == "lookAndFeel") {
1211 toolBar.updateUI();
1212 } else if (propertyName == "orientation") {
1213 // Search for JSeparator components and change it's orientation
1214 // to match the toolbar and flip it's orientation.
1215 Component[] components = toolBar.getComponents();
1216 int orientation = ((Integer)evt.getNewValue()).intValue();
1217 JToolBar.Separator separator;
1218
1219 for (int i = 0; i < components.length; ++i) {
1220 if (components[i] instanceof JToolBar.Separator) {
1221 separator = (JToolBar.Separator)components[i];
1222 if ((orientation == JToolBar.HORIZONTAL)) {
1223 separator.setOrientation(JSeparator.VERTICAL);
1224 } else {
1225 separator.setOrientation(JSeparator.HORIZONTAL);
1226 }
1227 Dimension size = separator.getSeparatorSize();
1228 if (size != null && size.width != size.height) {
1229 // Flip the orientation.
1230 Dimension newSize =
1231 new Dimension(size.height, size.width);
1232 separator.setSeparatorSize(newSize);
1233 }
1234 }
1235 }
1236 } else if (propertyName == IS_ROLLOVER) {
1237 installNormalBorders(toolBar);
1238 setRolloverBorders(((Boolean)evt.getNewValue()).booleanValue());
1239 }
1240 }
1241 }
1242
1243 protected class FrameListener extends WindowAdapter {
1244 public void windowClosing(WindowEvent w) {
1245 if (toolBar.isFloatable() == true) {
1246 if (dragWindow != null)
1247 dragWindow.setVisible(false);
1248 floating = false;
1249 if (floatingToolBar == null)
1250 floatingToolBar = createFloatingWindow(toolBar);
1251 if (floatingToolBar instanceof Window) ((Window)floatingToolBar).setVisible(false);
1252 floatingToolBar.getContentPane().remove(toolBar);
1253 String constraint = constraintBeforeFloating;
1254 if (toolBar.getOrientation() == JToolBar.HORIZONTAL) {
1255 if (constraint == "West" || constraint == "East") {
1256 constraint = "North";
1257 }
1258 } else {
1259 if (constraint == "North" || constraint == "South") {
1260 constraint = "West";
1261 }
1262 }
1263 if (dockingSource == null)
1264 dockingSource = toolBar.getParent();
1265 if (propertyListener != null)
1266 UIManager.removePropertyChangeListener(propertyListener);
1267 dockingSource.add(toolBar, constraint);
1268 dockingSource.invalidate();
1269 Container dockingSourceParent = dockingSource.getParent();
1270 if (dockingSourceParent != null)
1271 dockingSourceParent.validate();
1272 dockingSource.repaint();
1273 }
1274 }
1275
1276 }
1277
1278 protected class ToolBarContListener implements ContainerListener {
1279 // NOTE: This class exists only for backward compatability. All
1280 // its functionality has been moved into Handler. If you need to add
1281 // new functionality add it to the Handler, but make sure this
1282 // class calls into the Handler.
1283 public void componentAdded( ContainerEvent e ) {
1284 getHandler().componentAdded(e);
1285 }
1286
1287 public void componentRemoved( ContainerEvent e ) {
1288 getHandler().componentRemoved(e);
1289 }
1290
1291 }
1292
1293 protected class ToolBarFocusListener implements FocusListener {
1294 // NOTE: This class exists only for backward compatability. All
1295 // its functionality has been moved into Handler. If you need to add
1296 // new functionality add it to the Handler, but make sure this
1297 // class calls into the Handler.
1298 public void focusGained( FocusEvent e ) {
1299 getHandler().focusGained(e);
1300 }
1301
1302 public void focusLost( FocusEvent e ) {
1303 getHandler().focusLost(e);
1304 }
1305 }
1306
1307 protected class PropertyListener implements PropertyChangeListener {
1308 // NOTE: This class exists only for backward compatability. All
1309 // its functionality has been moved into Handler. If you need to add
1310 // new functionality add it to the Handler, but make sure this
1311 // class calls into the Handler.
1312 public void propertyChange( PropertyChangeEvent e ) {
1313 getHandler().propertyChange(e);
1314 }
1315 }
1316
1317 /**
1318 * This class should be treated as a "protected" inner class.
1319 * Instantiate it only within subclasses of BasicToolBarUI.
1320 */
1321 public class DockingListener implements MouseInputListener {
1322 // NOTE: This class exists only for backward compatability. All
1323 // its functionality has been moved into Handler. If you need to add
1324 // new functionality add it to the Handler, but make sure this
1325 // class calls into the Handler.
1326 protected JToolBar toolBar;
1327 protected boolean isDragging = false;
1328 protected Point origin = null;
1329
1330 public DockingListener(JToolBar t) {
1331 this.toolBar = t;
1332 getHandler().tb = t;
1333 }
1334
1335 public void mouseClicked(MouseEvent e) {
1336 getHandler().mouseClicked(e);
1337 }
1338
1339 public void mousePressed(MouseEvent e) {
1340 getHandler().tb = toolBar;
1341 getHandler().mousePressed(e);
1342 isDragging = getHandler().isDragging;
1343 }
1344
1345 public void mouseReleased(MouseEvent e) {
1346 getHandler().tb = toolBar;
1347 getHandler().isDragging = isDragging;
1348 getHandler().origin = origin;
1349 getHandler().mouseReleased(e);
1350 isDragging = getHandler().isDragging;
1351 origin = getHandler().origin;
1352 }
1353
1354 public void mouseEntered(MouseEvent e) {
1355 getHandler().mouseEntered(e);
1356 }
1357
1358 public void mouseExited(MouseEvent e) {
1359 getHandler().mouseExited(e);
1360 }
1361
1362 public void mouseDragged(MouseEvent e) {
1363 getHandler().tb = toolBar;
1364 getHandler().origin = origin;
1365 getHandler().mouseDragged(e);
1366 isDragging = getHandler().isDragging;
1367 origin = getHandler().origin;
1368 }
1369
1370 public void mouseMoved(MouseEvent e) {
1371 getHandler().mouseMoved(e);
1372 }
1373 }
1374
1375 protected class DragWindow extends Window
1376 {
1377 Color borderColor = Color.gray;
1378 int orientation = toolBar.getOrientation();
1379 Point offset; // offset of the mouse cursor inside the DragWindow
1380
1381 DragWindow(Window w) {
1382 super(w);
1383 }
1384
1385 /**
1386 * Returns the orientation of the toolbar window when the toolbar is
1387 * floating. The orientation is either one of <code>JToolBar.HORIZONTAL</code>
1388 * or <code>JToolBar.VERTICAL</code>.
1389 *
1390 * @return the orientation of the toolbar window
1391 * @since 1.6
1392 */
1393 public int getOrientation() {
1394 return orientation;
1395 }
1396
1397 public void setOrientation(int o) {
1398 if(isShowing()) {
1399 if (o == this.orientation)
1400 return;
1401 this.orientation = o;
1402 Dimension size = getSize();
1403 setSize(new Dimension(size.height, size.width));
1404 if (offset!=null) {
1405 if( BasicGraphicsUtils.isLeftToRight(toolBar) ) {
1406 setOffset(new Point(offset.y, offset.x));
1407 } else if( o == JToolBar.HORIZONTAL ) {
1408 setOffset(new Point( size.height-offset.y, offset.x));
1409 } else {
1410 setOffset(new Point(offset.y, size.width-offset.x));
1411 }
1412 }
1413 repaint();
1414 }
1415 }
1416
1417 public Point getOffset() {
1418 return offset;
1419 }
1420
1421 public void setOffset(Point p) {
1422 this.offset = p;
1423 }
1424
1425 public void setBorderColor(Color c) {
1426 if (this.borderColor == c)
1427 return;
1428 this.borderColor = c;
1429 repaint();
1430 }
1431
1432 public Color getBorderColor() {
1433 return this.borderColor;
1434 }
1435
1436 public void paint(Graphics g) {
1437 paintDragWindow(g);
1438 // Paint the children
1439 super.paint(g);
1440 }
1441 public Insets getInsets() {
1442 return new Insets(1,1,1,1);
1443 }
1444 }
1445 }