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