1 /* BasicToolBarUI.java -- 2 Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package javax.swing.plaf.basic; 40 41 import java.awt.BorderLayout; 42 import java.awt.Color; 43 import java.awt.Component; 44 import java.awt.Container; 45 import java.awt.Dimension; 46 import java.awt.Graphics; 47 import java.awt.Insets; 48 import java.awt.Point; 49 import java.awt.Rectangle; 50 import java.awt.Window; 51 import java.awt.event.ActionEvent; 52 import java.awt.event.ContainerEvent; 53 import java.awt.event.ContainerListener; 54 import java.awt.event.FocusEvent; 55 import java.awt.event.FocusListener; 56 import java.awt.event.MouseEvent; 57 import java.awt.event.WindowAdapter; 58 import java.awt.event.WindowEvent; 59 import java.awt.event.WindowListener; 60 import java.beans.PropertyChangeEvent; 61 import java.beans.PropertyChangeListener; 62 import java.util.Hashtable; 63 64 import javax.swing.AbstractAction; 65 import javax.swing.AbstractButton; 66 import javax.swing.Action; 67 import javax.swing.ActionMap; 68 import javax.swing.InputMap; 69 import javax.swing.JButton; 70 import javax.swing.JComponent; 71 import javax.swing.JDialog; 72 import javax.swing.JFrame; 73 import javax.swing.JToolBar; 74 import javax.swing.KeyStroke; 75 import javax.swing.LookAndFeel; 76 import javax.swing.RootPaneContainer; 77 import javax.swing.SwingConstants; 78 import javax.swing.SwingUtilities; 79 import javax.swing.UIManager; 80 import javax.swing.border.Border; 81 import javax.swing.border.CompoundBorder; 82 import javax.swing.event.MouseInputListener; 83 import javax.swing.plaf.ActionMapUIResource; 84 import javax.swing.plaf.ComponentUI; 85 import javax.swing.plaf.ToolBarUI; 86 import javax.swing.plaf.UIResource; 87 import javax.swing.plaf.basic.BasicBorders.ButtonBorder; 88 89 /** 90 * This is the Basic Look and Feel UI class for JToolBar. 91 */ 92 public class BasicToolBarUI extends ToolBarUI implements SwingConstants 93 { 94 95 /** 96 * Implements the keyboard actions for JToolBar. 97 */ 98 static class ToolBarAction 99 extends AbstractAction 100 { 101 /** 102 * Performs the action. 103 */ actionPerformed(ActionEvent event)104 public void actionPerformed(ActionEvent event) 105 { 106 Object cmd = getValue("__command__"); 107 JToolBar toolBar = (JToolBar) event.getSource(); 108 BasicToolBarUI ui = (BasicToolBarUI) toolBar.getUI(); 109 110 if (cmd.equals("navigateRight")) 111 ui.navigateFocusedComp(EAST); 112 else if (cmd.equals("navigateLeft")) 113 ui.navigateFocusedComp(WEST); 114 else if (cmd.equals("navigateUp")) 115 ui.navigateFocusedComp(NORTH); 116 else if (cmd.equals("navigateDown")) 117 ui.navigateFocusedComp(SOUTH); 118 else 119 assert false : "Shouldn't reach here"; 120 } 121 } 122 123 /** Static owner of all DragWindows. 124 * This is package-private to avoid an accessor method. */ 125 static JFrame owner = new JFrame(); 126 127 /** The border used when the JToolBar is in nonrollover mode. */ 128 private static Border nonRolloverBorder; 129 130 /** The border used when the JToolBar is in rollover mode. */ 131 private static Border rolloverBorder; 132 133 /** The last known BorderLayout constraint before floating. */ 134 protected String constraintBeforeFloating; 135 136 /** The last known orientation of the JToolBar before floating. 137 * This is package-private to avoid an accessor method. */ 138 int lastGoodOrientation; 139 140 /** The color of the border when it is dockable. */ 141 protected Color dockingBorderColor; 142 143 /** The background color of the JToolBar when it is dockable. */ 144 protected Color dockingColor; 145 146 /** The docking listener responsible for mouse events on the JToolBar. */ 147 protected MouseInputListener dockingListener; 148 149 /** The window used for dragging the JToolBar. */ 150 protected BasicToolBarUI.DragWindow dragWindow; 151 152 /** The color of the border when it is not dockable. */ 153 protected Color floatingBorderColor; 154 155 /** The background color of the JToolBar when it is not dockable. */ 156 protected Color floatingColor; 157 158 /** The index of the focused component. */ 159 protected int focusedCompIndex; 160 161 /** The PropertyChangeListener for the JToolBar. */ 162 protected PropertyChangeListener propertyListener; 163 164 /** The JToolBar this UI delegate is responsible for. */ 165 protected JToolBar toolBar; 166 167 /** The Container listener for the JToolBar. */ 168 protected ContainerListener toolBarContListener; 169 170 /** The Focus listener for the JToolBar. */ 171 protected FocusListener toolBarFocusListener; 172 173 /** 174 * @deprecated since JDK1.3. 175 */ 176 protected KeyStroke leftKey; 177 178 /** 179 * @deprecated since JDK1.3. 180 */ 181 protected KeyStroke rightKey; 182 183 /** 184 * @deprecated since JDK1.3. 185 */ 186 protected KeyStroke upKey; 187 188 /** 189 * @deprecated since JDK1.3. 190 */ 191 protected KeyStroke downKey; 192 193 /** 194 * The floating window that is responsible for holding the JToolBar when it 195 * is dragged outside of its original parent. 196 */ 197 private transient Window floatFrame; 198 199 /** The original parent of the JToolBar. 200 * This is package-private to avoid an accessor method. */ 201 transient Container origParent; 202 203 /** A hashtable of components and their original borders. 204 * This is package-private to avoid an accessor method. */ 205 transient Hashtable borders; 206 207 /** A window listener for the floatable frame. */ 208 private transient WindowListener windowListener; 209 210 /** A set of cached bounds of the JToolBar. 211 * This is package-private to avoid an accessor method. */ 212 transient Dimension cachedBounds; 213 214 /** The cached orientation of the JToolBar. 215 * This is package-private to avoid an accessor method. */ 216 transient int cachedOrientation; 217 218 /** 219 * This method creates a new <code>BasicToolBarUI</code> object for the given JToolBar. 220 */ BasicToolBarUI()221 public BasicToolBarUI() 222 { 223 // Do nothing here. 224 } 225 226 /** 227 * This method returns whether the JToolBar can dock at the given position. 228 * 229 * @param c The component to try to dock in. 230 * @param p The position of the mouse cursor relative to the given 231 * component. 232 * 233 * @return Whether the JToolBar can dock. 234 */ canDock(Component c, Point p)235 public boolean canDock(Component c, Point p) 236 { 237 return areaOfClick(c, p) != -1; 238 } 239 240 /** 241 * This helper method returns the position of the JToolBar if it can dock. 242 * 243 * @param c The component to try to dock in. 244 * @param p The position of the mouse cursor relative to the given 245 * component. 246 * 247 * @return One of the SwingConstants directions or -1 if the JToolBar can't 248 * dock. 249 */ areaOfClick(Component c, Point p)250 private int areaOfClick(Component c, Point p) 251 { 252 // Has to dock in immediate parent, not eventual root container. 253 Rectangle pBounds = c.getBounds(); 254 255 // XXX: In Sun's implementation, the space the toolbar has to dock is dependent on the size it had last. 256 Dimension d = toolBar.getSize(); 257 int limit = Math.min(d.width, d.height); 258 259 // The order of checking is 1. top 2. bottom 3. left 4. right 260 if (! pBounds.contains(p)) 261 return -1; 262 263 if (p.y < limit) 264 return SwingConstants.NORTH; 265 266 if (p.y > (pBounds.height - limit)) 267 return SwingConstants.SOUTH; 268 269 if (p.x < limit) 270 return SwingConstants.WEST; 271 272 if (p.x > (pBounds.width - limit)) 273 return SwingConstants.EAST; 274 275 return -1; 276 } 277 278 /** 279 * This method creates a new DockingListener for the JToolBar. 280 * 281 * @return A new DockingListener for the JToolBar. 282 */ createDockingListener()283 protected MouseInputListener createDockingListener() 284 { 285 return new DockingListener(toolBar); 286 } 287 288 /** 289 * This method creates a new DragWindow for the given JToolBar. 290 * 291 * @param toolbar The JToolBar to create a DragWindow for. 292 * 293 * @return A new DragWindow. 294 */ createDragWindow(JToolBar toolbar)295 protected BasicToolBarUI.DragWindow createDragWindow(JToolBar toolbar) 296 { 297 return new DragWindow(); 298 } 299 300 /** 301 * This method creates a new floating frame for the JToolBar. By default, 302 * this UI uses createFloatingWindow instead. This method of creating a 303 * floating frame is deprecated. 304 * 305 * @param toolbar The JToolBar to create a floating frame for. 306 * 307 * @return A new floating frame. 308 */ createFloatingFrame(JToolBar toolbar)309 protected JFrame createFloatingFrame(JToolBar toolbar) 310 { 311 // FIXME: Though deprecated, this should still work. 312 return null; 313 } 314 315 /** 316 * This method creates a new floating window for the JToolBar. This is the 317 * method used by default to create a floating container for the JToolBar. 318 * 319 * @param toolbar The JToolBar to create a floating window for. 320 * 321 * @return A new floating window. 322 */ createFloatingWindow(JToolBar toolbar)323 protected RootPaneContainer createFloatingWindow(JToolBar toolbar) 324 { 325 // This one is used by default though. 326 return new ToolBarDialog(); 327 } 328 329 /** 330 * This method creates a new WindowListener for the JToolBar. 331 * 332 * @return A new WindowListener. 333 */ createFrameListener()334 protected WindowListener createFrameListener() 335 { 336 return new FrameListener(); 337 } 338 339 /** 340 * This method creates a new nonRolloverBorder for JButtons when the 341 * JToolBar's rollover property is set to false. 342 * 343 * @return A new NonRolloverBorder. 344 */ createNonRolloverBorder()345 protected Border createNonRolloverBorder() 346 { 347 Border b = UIManager.getBorder("ToolBar.nonrolloverBorder"); 348 349 if (b == null) 350 { 351 b = new CompoundBorder( 352 new ButtonBorder(UIManager.getColor("Button.shadow"), 353 UIManager.getColor("Button.darkShadow"), 354 UIManager.getColor("Button.light"), 355 UIManager.getColor("Button.highlight")), 356 BasicBorders.getMarginBorder()); 357 } 358 359 return b; } 360 361 /** 362 * This method creates a new PropertyChangeListener for the JToolBar. 363 * 364 * @return A new PropertyChangeListener. 365 */ createPropertyListener()366 protected PropertyChangeListener createPropertyListener() 367 { 368 return new PropertyListener(); 369 } 370 371 /** 372 * This method creates a new rollover border for JButtons when the 373 * JToolBar's rollover property is set to true. 374 * 375 * @return A new rollover border. 376 */ createRolloverBorder()377 protected Border createRolloverBorder() 378 { 379 Border b = UIManager.getBorder("ToolBar.rolloverBorder"); 380 381 if (b == null) 382 { 383 b = new CompoundBorder( 384 new ButtonBorder(UIManager.getColor("Button.shadow"), 385 UIManager.getColor("Button.darkShadow"), 386 UIManager.getColor("Button.light"), 387 UIManager.getColor("Button.highlight")), 388 BasicBorders.getMarginBorder()); 389 } 390 391 return b; 392 } 393 394 /** 395 * This method creates a new Container listener for the JToolBar. 396 * 397 * @return A new Container listener. 398 */ createToolBarContListener()399 protected ContainerListener createToolBarContListener() 400 { 401 return new ToolBarContListener(); 402 } 403 404 /** 405 * This method creates a new FocusListener for the JToolBar. 406 * 407 * @return A new FocusListener for the JToolBar. 408 */ createToolBarFocusListener()409 protected FocusListener createToolBarFocusListener() 410 { 411 return new ToolBarFocusListener(); 412 } 413 414 /** 415 * This method creates a new UI delegate for the given JComponent. 416 * 417 * @param c The JComponent to create a UI delegate for. 418 * 419 * @return A new UI delegate. 420 */ createUI(JComponent c)421 public static ComponentUI createUI(JComponent c) 422 { 423 return new BasicToolBarUI(); 424 } 425 426 /** 427 * This method is called to drag the DragWindow around when the JToolBar is 428 * being dragged around. 429 * 430 * @param position The mouse cursor coordinates relative to the JToolBar. 431 * @param origin The screen position of the JToolBar. 432 */ dragTo(Point position, Point origin)433 protected void dragTo(Point position, Point origin) 434 { 435 int loc = areaOfClick(origParent, 436 SwingUtilities.convertPoint(toolBar, position, 437 origParent)); 438 439 if (loc != -1) 440 { 441 dragWindow.setBorderColor(dockingBorderColor); 442 dragWindow.setBackground(dockingColor); 443 } 444 else 445 { 446 dragWindow.setBorderColor(floatingBorderColor); 447 dragWindow.setBackground(floatingColor); 448 } 449 450 int w = 0; 451 int h = 0; 452 453 boolean tmp = (loc == SwingConstants.NORTH) 454 || (loc == SwingConstants.SOUTH) || (loc == -1); 455 456 cachedOrientation = toolBar.getOrientation(); 457 cachedBounds = toolBar.getSize(); 458 if (((cachedOrientation == SwingConstants.HORIZONTAL) && tmp) 459 || ((cachedOrientation == VERTICAL) && ! tmp)) 460 { 461 w = cachedBounds.width; 462 h = cachedBounds.height; 463 } 464 else 465 { 466 w = cachedBounds.height; 467 h = cachedBounds.width; 468 } 469 470 Point p = dragWindow.getOffset(); 471 Insets insets = toolBar.getInsets(); 472 473 dragWindow.setBounds((origin.x + position.x) - p.x 474 - ((insets.left + insets.right) / 2), 475 (origin.y + position.y) - p.y 476 - ((insets.top + insets.bottom) / 2), w, h); 477 478 if (! dragWindow.isVisible()) 479 dragWindow.show(); 480 } 481 482 /** 483 * This method is used at the end of a drag session to place the frame in 484 * either its original parent as a docked JToolBar or in its floating 485 * frame. 486 * 487 * @param position The position of the mouse cursor relative to the 488 * JToolBar. 489 * @param origin The screen position of the JToolBar before the drag session 490 * started. 491 */ floatAt(Point position, Point origin)492 protected void floatAt(Point position, Point origin) 493 { 494 Point p = new Point(position); 495 int aoc = areaOfClick(origParent, 496 SwingUtilities.convertPoint(toolBar, p, origParent)); 497 498 Container oldParent = toolBar.getParent(); 499 500 oldParent.remove(toolBar); 501 oldParent.doLayout(); 502 oldParent.repaint(); 503 504 Container newParent; 505 506 if (aoc == -1) 507 newParent = ((RootPaneContainer) floatFrame).getContentPane(); 508 else 509 { 510 floatFrame.hide(); 511 newParent = origParent; 512 } 513 514 String constraint; 515 switch (aoc) 516 { 517 case SwingConstants.EAST: 518 constraint = BorderLayout.EAST; 519 break; 520 case SwingConstants.NORTH: 521 constraint = BorderLayout.NORTH; 522 break; 523 case SwingConstants.SOUTH: 524 constraint = BorderLayout.SOUTH; 525 break; 526 case SwingConstants.WEST: 527 constraint = BorderLayout.WEST; 528 break; 529 default: 530 constraint = BorderLayout.CENTER; 531 break; 532 } 533 534 int newOrientation = SwingConstants.HORIZONTAL; 535 if ((aoc != -1) 536 && ((aoc == SwingConstants.EAST) || (aoc == SwingConstants.WEST))) 537 newOrientation = SwingConstants.VERTICAL; 538 539 if (aoc != -1) 540 { 541 constraintBeforeFloating = constraint; 542 lastGoodOrientation = newOrientation; 543 } 544 545 newParent.add(toolBar, constraint); 546 547 setFloating(aoc == -1, null); 548 toolBar.setOrientation(newOrientation); 549 550 Insets insets = floatFrame.getInsets(); 551 Dimension dims = toolBar.getPreferredSize(); 552 p = dragWindow.getOffset(); 553 setFloatingLocation((position.x + origin.x) - p.x 554 - ((insets.left + insets.right) / 2), 555 (position.y + origin.y) - p.y 556 - ((insets.top + insets.bottom) / 2)); 557 558 if (aoc == -1) 559 { 560 floatFrame.pack(); 561 floatFrame.setSize(dims.width + insets.left + insets.right, 562 dims.height + insets.top + insets.bottom); 563 floatFrame.show(); 564 } 565 566 newParent.invalidate(); 567 newParent.validate(); 568 newParent.repaint(); 569 } 570 571 /** 572 * This method returns the docking color. 573 * 574 * @return The docking color. 575 */ getDockingColor()576 public Color getDockingColor() 577 { 578 return dockingColor; 579 } 580 581 /** 582 * This method returns the Color which is displayed when over a floating 583 * area. 584 * 585 * @return The color which is displayed when over a floating area. 586 */ getFloatingColor()587 public Color getFloatingColor() 588 { 589 return floatingColor; 590 } 591 592 /** 593 * This method returns the maximum size of the given JComponent for this UI. 594 * 595 * @param c The JComponent to find the maximum size for. 596 * 597 * @return The maximum size for this UI. 598 */ getMaximumSize(JComponent c)599 public Dimension getMaximumSize(JComponent c) 600 { 601 return getPreferredSize(c); 602 } 603 604 /** 605 * This method returns the minimum size of the given JComponent for this UI. 606 * 607 * @param c The JComponent to find a minimum size for. 608 * 609 * @return The minimum size for this UI. 610 */ getMinimumSize(JComponent c)611 public Dimension getMinimumSize(JComponent c) 612 { 613 return getPreferredSize(c); 614 } 615 616 /** 617 * This method installs the needed components for the JToolBar. 618 */ installComponents()619 protected void installComponents() 620 { 621 floatFrame = (Window) createFloatingWindow(toolBar); 622 623 dragWindow = createDragWindow(toolBar); 624 625 nonRolloverBorder = createNonRolloverBorder(); 626 rolloverBorder = createRolloverBorder(); 627 628 borders = new Hashtable(); 629 setRolloverBorders(toolBar.isRollover()); 630 631 fillHashtable(); 632 } 633 634 /** 635 * This method installs the defaults as specified by the look and feel. 636 */ installDefaults()637 protected void installDefaults() 638 { 639 LookAndFeel.installBorder(toolBar, "ToolBar.border"); 640 LookAndFeel.installColorsAndFont(toolBar, "ToolBar.background", 641 "ToolBar.foreground", "ToolBar.font"); 642 643 dockingBorderColor = UIManager.getColor("ToolBar.dockingForeground"); 644 dockingColor = UIManager.getColor("ToolBar.dockingBackground"); 645 646 floatingBorderColor = UIManager.getColor("ToolBar.floatingForeground"); 647 floatingColor = UIManager.getColor("ToolBar.floatingBackground"); 648 } 649 650 /** 651 * This method installs the keyboard actions for the JToolBar as specified 652 * by the look and feel. 653 */ installKeyboardActions()654 protected void installKeyboardActions() 655 { 656 // Install the input map. 657 InputMap inputMap = 658 (InputMap) SharedUIDefaults.get("ToolBar.ancestorInputMap"); 659 SwingUtilities.replaceUIInputMap(toolBar, 660 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, 661 inputMap); 662 663 // FIXME: The JDK uses a LazyActionMap for parentActionMap 664 SwingUtilities.replaceUIActionMap(toolBar, getActionMap()); 665 } 666 667 /** 668 * Fetches the action map from the UI defaults, or create a new one 669 * if the action map hasn't been initialized. 670 * 671 * @return the action map 672 */ getActionMap()673 private ActionMap getActionMap() 674 { 675 ActionMap am = (ActionMap) UIManager.get("ToolBar.actionMap"); 676 if (am == null) 677 { 678 am = createDefaultActions(); 679 UIManager.getLookAndFeelDefaults().put("ToolBar.actionMap", am); 680 } 681 return am; 682 } 683 createDefaultActions()684 private ActionMap createDefaultActions() 685 { 686 ActionMapUIResource am = new ActionMapUIResource(); 687 Action action = new ToolBarAction(); 688 689 am.put("navigateLeft", action); 690 am.put("navigateRight", action); 691 am.put("navigateUp", action); 692 am.put("navigateDown", action); 693 694 return am; 695 } 696 697 /** 698 * This method installs listeners for the JToolBar. 699 */ installListeners()700 protected void installListeners() 701 { 702 dockingListener = createDockingListener(); 703 toolBar.addMouseListener(dockingListener); 704 toolBar.addMouseMotionListener(dockingListener); 705 706 propertyListener = createPropertyListener(); 707 toolBar.addPropertyChangeListener(propertyListener); 708 709 toolBarContListener = createToolBarContListener(); 710 toolBar.addContainerListener(toolBarContListener); 711 712 windowListener = createFrameListener(); 713 floatFrame.addWindowListener(windowListener); 714 715 toolBarFocusListener = createToolBarFocusListener(); 716 if (toolBarFocusListener != null) 717 { 718 int count = toolBar.getComponentCount(); 719 for (int i = 0; i < count; i++) 720 toolBar.getComponent(i).addFocusListener(toolBarFocusListener); 721 } 722 } 723 724 /** 725 * This method installs non rollover borders for each component inside the 726 * given JComponent. 727 * 728 * @param c The JComponent whose children need to have non rollover borders 729 * installed. 730 */ installNonRolloverBorders(JComponent c)731 protected void installNonRolloverBorders(JComponent c) 732 { 733 Component[] components = toolBar.getComponents(); 734 735 for (int i = 0; i < components.length; i++) 736 setBorderToNonRollover(components[i]); 737 } 738 739 /** 740 * This method installs normal (or their original) borders for each 741 * component inside the given JComponent. 742 * 743 * @param c The JComponent whose children need to have their original 744 * borders installed. 745 */ installNormalBorders(JComponent c)746 protected void installNormalBorders(JComponent c) 747 { 748 Component[] components = toolBar.getComponents(); 749 750 for (int i = 0; i < components.length; i++) 751 setBorderToNormal(components[i]); 752 } 753 754 /** 755 * This method install rollover borders for each component inside the given 756 * JComponent. 757 * 758 * @param c The JComponent whose children need to have rollover borders 759 * installed. 760 */ installRolloverBorders(JComponent c)761 protected void installRolloverBorders(JComponent c) 762 { 763 Component[] components = toolBar.getComponents(); 764 765 for (int i = 0; i < components.length; i++) 766 setBorderToRollover(components[i]); 767 } 768 769 /** 770 * This method fills the borders hashtable with a list of components that 771 * are JButtons and their borders. 772 */ fillHashtable()773 private void fillHashtable() 774 { 775 Component[] c = toolBar.getComponents(); 776 777 for (int i = 0; i < c.length; i++) 778 { 779 if (c[i] instanceof JButton) 780 { 781 // Don't really care about anything other than JButtons 782 JButton b = (JButton) c[i]; 783 784 if (b.getBorder() != null) 785 borders.put(b, b.getBorder()); 786 } 787 } 788 } 789 790 /** 791 * This method installs the UI for the given JComponent. 792 * 793 * @param c The JComponent to install a UI for. 794 */ installUI(JComponent c)795 public void installUI(JComponent c) 796 { 797 super.installUI(c); 798 799 if (c instanceof JToolBar) 800 { 801 toolBar = (JToolBar) c; 802 installDefaults(); 803 installComponents(); 804 installListeners(); 805 installKeyboardActions(); 806 } 807 } 808 809 /** 810 * This method returns whether the JToolBar is floating. 811 * 812 * @return Whether the JToolBar is floating. 813 */ isFloating()814 public boolean isFloating() 815 { 816 return floatFrame.isVisible(); 817 } 818 819 /** 820 * This method returns whether rollover borders have been set. 821 * 822 * @return Whether rollover borders have been set. 823 */ isRolloverBorders()824 public boolean isRolloverBorders() 825 { 826 return toolBar.isRollover(); 827 } 828 829 /** 830 * This method navigates in the given direction giving focus to the next 831 * component in the given direction. 832 * 833 * @param direction The direction to give focus to. 834 */ navigateFocusedComp(int direction)835 protected void navigateFocusedComp(int direction) 836 { 837 int count = toolBar.getComponentCount(); 838 switch (direction) 839 { 840 case EAST: 841 case SOUTH: 842 if (focusedCompIndex >= 0 && focusedCompIndex < count) 843 { 844 int i = focusedCompIndex + 1; 845 boolean focusRequested = false; 846 // Find component to focus and request focus on it. 847 while (i != focusedCompIndex && ! focusRequested) 848 { 849 if (i >= count) 850 i = 0; 851 Component comp = toolBar.getComponentAtIndex(i++); 852 if (comp != null && comp.isFocusable() 853 && comp.isEnabled()) 854 { 855 comp.requestFocus(); 856 focusRequested = true; 857 } 858 } 859 } 860 break; 861 case WEST: 862 case NORTH: 863 if (focusedCompIndex >= 0 && focusedCompIndex < count) 864 { 865 int i = focusedCompIndex - 1; 866 boolean focusRequested = false; 867 // Find component to focus and request focus on it. 868 while (i != focusedCompIndex && ! focusRequested) 869 { 870 if (i < 0) 871 i = count - 1; 872 Component comp = toolBar.getComponentAtIndex(i--); 873 if (comp != null && comp.isFocusable() 874 && comp.isEnabled()) 875 { 876 comp.requestFocus(); 877 focusRequested = true; 878 } 879 } 880 } 881 break; 882 default: 883 break; 884 } 885 } 886 887 /** 888 * This method sets the border of the given component to a non rollover 889 * border. 890 * 891 * @param c The Component whose border needs to be set. 892 */ setBorderToNonRollover(Component c)893 protected void setBorderToNonRollover(Component c) 894 { 895 if (c instanceof AbstractButton) 896 { 897 AbstractButton b = (AbstractButton) c; 898 b.setRolloverEnabled(false); 899 900 // Save old border in hashtable. 901 if (b.getBorder() != null) 902 borders.put(b, b.getBorder()); 903 904 b.setBorder(nonRolloverBorder); 905 } 906 } 907 908 /** 909 * This method sets the border of the given component to its original value. 910 * 911 * @param c The Component whose border needs to be set. 912 */ setBorderToNormal(Component c)913 protected void setBorderToNormal(Component c) 914 { 915 if (c instanceof AbstractButton) 916 { 917 AbstractButton b = (AbstractButton) c; 918 b.setRolloverEnabled(true); 919 b.setBorder((Border) borders.remove(b)); 920 } 921 } 922 923 /** 924 * This method sets the border of the given component to a rollover border. 925 * 926 * @param c The Component whose border needs to be set. 927 */ setBorderToRollover(Component c)928 protected void setBorderToRollover(Component c) 929 { 930 if (c instanceof AbstractButton) 931 { 932 AbstractButton b = (AbstractButton) c; 933 b.setRolloverEnabled(false); 934 935 // Save old border in hashtable. 936 if (b.getBorder() != null) 937 borders.put(b, b.getBorder()); 938 939 b.setBorder(rolloverBorder); 940 } 941 } 942 943 /** 944 * This method sets the docking color. 945 * 946 * @param c The docking color. 947 */ setDockingColor(Color c)948 public void setDockingColor(Color c) 949 { 950 dockingColor = c; 951 } 952 953 /** 954 * This method sets the floating property for the JToolBar. 955 * 956 * @param b Whether the JToolBar is floating. 957 * @param p FIXME 958 */ setFloating(boolean b, Point p)959 public void setFloating(boolean b, Point p) 960 { 961 // FIXME: use p for something. It's not location 962 // since we already have setFloatingLocation. 963 floatFrame.setVisible(b); 964 } 965 966 /** 967 * This method sets the color displayed when the JToolBar is not in a 968 * dockable area. 969 * 970 * @param c The floating color. 971 */ setFloatingColor(Color c)972 public void setFloatingColor(Color c) 973 { 974 floatingColor = c; 975 } 976 977 /** 978 * This method sets the floating location of the JToolBar. 979 * 980 * @param x The x coordinate for the floating frame. 981 * @param y The y coordinate for the floating frame. 982 */ setFloatingLocation(int x, int y)983 public void setFloatingLocation(int x, int y) 984 { 985 // x,y are the coordinates of the new JFrame created to store the toolbar 986 // XXX: The floating location is bogus is not floating. 987 floatFrame.setLocation(x, y); 988 floatFrame.invalidate(); 989 floatFrame.validate(); 990 floatFrame.repaint(); 991 } 992 993 /** 994 * This is a convenience method for changing the orientation of the 995 * JToolBar. 996 * 997 * @param orientation The new orientation. 998 */ setOrientation(int orientation)999 public void setOrientation(int orientation) 1000 { 1001 toolBar.setOrientation(orientation); 1002 } 1003 1004 /** 1005 * This method changes the child components to have rollover borders if the 1006 * given parameter is true. Otherwise, the components are set to have non 1007 * rollover borders. 1008 * 1009 * @param rollover Whether the children will have rollover borders. 1010 */ setRolloverBorders(boolean rollover)1011 public void setRolloverBorders(boolean rollover) 1012 { 1013 if (rollover) 1014 installRolloverBorders(toolBar); 1015 else 1016 installNonRolloverBorders(toolBar); 1017 } 1018 1019 /** 1020 * This method uninstall UI installed components from the JToolBar. 1021 */ uninstallComponents()1022 protected void uninstallComponents() 1023 { 1024 installNormalBorders(toolBar); 1025 borders = null; 1026 cachedBounds = null; 1027 1028 floatFrame = null; 1029 dragWindow = null; 1030 } 1031 1032 /** 1033 * This method removes the defaults installed by the Look and Feel. 1034 */ uninstallDefaults()1035 protected void uninstallDefaults() 1036 { 1037 toolBar.setBackground(null); 1038 toolBar.setForeground(null); 1039 toolBar.setFont(null); 1040 1041 dockingBorderColor = null; 1042 dockingColor = null; 1043 floatingBorderColor = null; 1044 floatingColor = null; 1045 } 1046 1047 /** 1048 * This method uninstalls keyboard actions installed by the UI. 1049 */ uninstallKeyboardActions()1050 protected void uninstallKeyboardActions() 1051 { 1052 SwingUtilities.replaceUIInputMap(toolBar, JComponent. 1053 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null); 1054 SwingUtilities.replaceUIActionMap(toolBar, null); 1055 } 1056 1057 /** 1058 * This method uninstalls listeners installed by the UI. 1059 */ uninstallListeners()1060 protected void uninstallListeners() 1061 { 1062 if (toolBarFocusListener != null) 1063 { 1064 int count = toolBar.getComponentCount(); 1065 for (int i = 0; i < count; i++) 1066 toolBar.getComponent(i).removeFocusListener(toolBarFocusListener); 1067 toolBarFocusListener = null; 1068 } 1069 1070 floatFrame.removeWindowListener(windowListener); 1071 windowListener = null; 1072 1073 toolBar.removeContainerListener(toolBarContListener); 1074 toolBarContListener = null; 1075 1076 toolBar.removeMouseMotionListener(dockingListener); 1077 toolBar.removeMouseListener(dockingListener); 1078 dockingListener = null; 1079 } 1080 1081 /** 1082 * This method uninstalls the UI. 1083 * 1084 * @param c The JComponent that is having this UI removed. 1085 */ uninstallUI(JComponent c)1086 public void uninstallUI(JComponent c) 1087 { 1088 uninstallKeyboardActions(); 1089 uninstallListeners(); 1090 uninstallComponents(); 1091 uninstallDefaults(); 1092 toolBar = null; 1093 } 1094 1095 /** 1096 * This is the MouseHandler class that allows the user to drag the JToolBar 1097 * in and out of the parent and dock it if it can. 1098 */ 1099 public class DockingListener implements MouseInputListener 1100 { 1101 /** Whether the JToolBar is being dragged. */ 1102 protected boolean isDragging; 1103 1104 /** 1105 * The origin point. This point is saved from the beginning press and is 1106 * used until the end of the drag session. 1107 */ 1108 protected Point origin; 1109 1110 /** The JToolBar being dragged. */ 1111 protected JToolBar toolBar; 1112 1113 /** 1114 * Creates a new DockingListener object. 1115 * 1116 * @param t The JToolBar this DockingListener is being used for. 1117 */ DockingListener(JToolBar t)1118 public DockingListener(JToolBar t) 1119 { 1120 toolBar = t; 1121 } 1122 1123 /** 1124 * This method is called when the mouse is clicked. 1125 * 1126 * @param e The MouseEvent. 1127 */ mouseClicked(MouseEvent e)1128 public void mouseClicked(MouseEvent e) 1129 { 1130 // Nothing to do here. 1131 } 1132 1133 /** 1134 * This method is called when the mouse is dragged. It delegates the drag 1135 * painting to the dragTo method. 1136 * 1137 * @param e The MouseEvent. 1138 */ mouseDragged(MouseEvent e)1139 public void mouseDragged(MouseEvent e) 1140 { 1141 if (isDragging) 1142 dragTo(e.getPoint(), origin); 1143 } 1144 1145 /** 1146 * This method is called when the mouse enters the JToolBar. 1147 * 1148 * @param e The MouseEvent. 1149 */ mouseEntered(MouseEvent e)1150 public void mouseEntered(MouseEvent e) 1151 { 1152 // Nothing to do here. 1153 } 1154 1155 /** 1156 * This method is called when the mouse exits the JToolBar. 1157 * 1158 * @param e The MouseEvent. 1159 */ mouseExited(MouseEvent e)1160 public void mouseExited(MouseEvent e) 1161 { 1162 // Nothing to do here. 1163 } 1164 1165 /** 1166 * This method is called when the mouse is moved in the JToolBar. 1167 * 1168 * @param e The MouseEvent. 1169 */ mouseMoved(MouseEvent e)1170 public void mouseMoved(MouseEvent e) 1171 { 1172 // Nothing to do here. 1173 } 1174 1175 /** 1176 * This method is called when the mouse is pressed in the JToolBar. If the 1177 * press doesn't occur in a place where it causes the JToolBar to be 1178 * dragged, it returns. Otherwise, it starts a drag session. 1179 * 1180 * @param e The MouseEvent. 1181 */ mousePressed(MouseEvent e)1182 public void mousePressed(MouseEvent e) 1183 { 1184 if (! toolBar.isFloatable()) 1185 return; 1186 1187 Point ssd = e.getPoint(); 1188 Insets insets = toolBar.getInsets(); 1189 1190 // Verify that this click occurs in the top inset. 1191 if (toolBar.getOrientation() == SwingConstants.HORIZONTAL) 1192 { 1193 if (e.getX() > insets.left) 1194 return; 1195 } 1196 else 1197 { 1198 if (e.getY() > insets.top) 1199 return; 1200 } 1201 1202 origin = new Point(0, 0); 1203 if (toolBar.isShowing()) 1204 SwingUtilities.convertPointToScreen(ssd, toolBar); 1205 1206 if (! (SwingUtilities.getAncestorOfClass(Window.class, toolBar) instanceof UIResource)) 1207 // Need to know who keeps the toolBar if it gets dragged back into it. 1208 origParent = toolBar.getParent(); 1209 1210 if (toolBar.isShowing()) 1211 SwingUtilities.convertPointToScreen(origin, toolBar); 1212 1213 isDragging = true; 1214 1215 if (dragWindow != null) 1216 dragWindow.setOffset(new Point(cachedBounds.width / 2, 1217 cachedBounds.height / 2)); 1218 1219 dragTo(e.getPoint(), origin); 1220 } 1221 1222 /** 1223 * This method is called when the mouse is released from the JToolBar. 1224 * 1225 * @param e The MouseEvent. 1226 */ mouseReleased(MouseEvent e)1227 public void mouseReleased(MouseEvent e) 1228 { 1229 if (! isDragging || ! toolBar.isFloatable()) 1230 return; 1231 1232 isDragging = false; 1233 floatAt(e.getPoint(), origin); 1234 dragWindow.hide(); 1235 } 1236 } 1237 1238 /** 1239 * This is the window that appears when the JToolBar is being dragged 1240 * around. 1241 */ 1242 protected class DragWindow extends Window 1243 { 1244 /** 1245 * The current border color. It changes depending on whether the JToolBar 1246 * is over a place that allows it to dock. 1247 */ 1248 private Color borderColor; 1249 1250 /** The between the mouse and the top left corner of the window. */ 1251 private Point offset; 1252 1253 /** 1254 * Creates a new DragWindow object. 1255 * This is package-private to avoid an accessor method. 1256 */ DragWindow()1257 DragWindow() 1258 { 1259 super(owner); 1260 } 1261 1262 /** 1263 * The color that the border should be. 1264 * 1265 * @return The border color. 1266 */ getBorderColor()1267 public Color getBorderColor() 1268 { 1269 if (borderColor == null) 1270 return Color.BLACK; 1271 1272 return borderColor; 1273 } 1274 1275 /** 1276 * This method returns the insets for the DragWindow. 1277 * 1278 * @return The insets for the DragWindow. 1279 */ getInsets()1280 public Insets getInsets() 1281 { 1282 // This window has no decorations, so insets are empty. 1283 return new Insets(0, 0, 0, 0); 1284 } 1285 1286 /** 1287 * This method returns the mouse offset from the top left corner of the 1288 * DragWindow. 1289 * 1290 * @return The mouse offset. 1291 */ getOffset()1292 public Point getOffset() 1293 { 1294 return offset; 1295 } 1296 1297 /** 1298 * This method paints the DragWindow. 1299 * 1300 * @param g The Graphics object to paint with. 1301 */ paint(Graphics g)1302 public void paint(Graphics g) 1303 { 1304 // No visiting children necessary. 1305 Color saved = g.getColor(); 1306 Rectangle b = getBounds(); 1307 1308 g.setColor(getBorderColor()); 1309 g.drawRect(0, 0, b.width - 1, b.height - 1); 1310 1311 g.setColor(saved); 1312 } 1313 1314 /** 1315 * This method changes the border color. 1316 * 1317 * @param c The new border color. 1318 */ setBorderColor(Color c)1319 public void setBorderColor(Color c) 1320 { 1321 borderColor = c; 1322 } 1323 1324 /** 1325 * This method changes the mouse offset. 1326 * 1327 * @param p The new mouse offset. 1328 */ setOffset(Point p)1329 public void setOffset(Point p) 1330 { 1331 offset = p; 1332 } 1333 1334 /** 1335 * Sets the orientation of the toolbar and the 1336 * drag window. 1337 * 1338 * @param o - the new orientation of the toolbar and drag 1339 * window. 1340 */ setOrientation(int o)1341 public void setOrientation(int o) 1342 { 1343 toolBar.setOrientation(o); 1344 if (dragWindow != null) 1345 dragWindow.setOrientation(o); 1346 } 1347 } 1348 1349 /** 1350 * This helper class listens for Window events from the floatable window and 1351 * if it is closed, returns the JToolBar to the last known good location. 1352 */ 1353 protected class FrameListener extends WindowAdapter 1354 { 1355 /** 1356 * This method is called when the floating window is closed. 1357 * 1358 * @param e The WindowEvent. 1359 */ windowClosing(WindowEvent e)1360 public void windowClosing(WindowEvent e) 1361 { 1362 Container parent = toolBar.getParent(); 1363 parent.remove(toolBar); 1364 1365 if (origParent != null) 1366 { 1367 origParent.add(toolBar, 1368 (constraintBeforeFloating != null) 1369 ? constraintBeforeFloating : BorderLayout.NORTH); 1370 toolBar.setOrientation(lastGoodOrientation); 1371 } 1372 1373 origParent.invalidate(); 1374 origParent.validate(); 1375 origParent.repaint(); 1376 } 1377 } 1378 1379 /** 1380 * This helper class listens for PropertyChangeEvents from the JToolBar. 1381 */ 1382 protected class PropertyListener implements PropertyChangeListener 1383 { 1384 /** 1385 * This method is called when a property from the JToolBar is changed. 1386 * 1387 * @param e The PropertyChangeEvent. 1388 */ propertyChange(PropertyChangeEvent e)1389 public void propertyChange(PropertyChangeEvent e) 1390 { 1391 // FIXME: need name properties so can change floatFrame title. 1392 if (e.getPropertyName().equals("rollover") && toolBar != null) 1393 setRolloverBorders(toolBar.isRollover()); 1394 } 1395 } 1396 1397 /** 1398 * This helper class listens for components added to and removed from the 1399 * JToolBar. 1400 */ 1401 protected class ToolBarContListener implements ContainerListener 1402 { 1403 /** 1404 * This method is responsible for setting rollover or non rollover for new 1405 * buttons added to the JToolBar. 1406 * 1407 * @param e The ContainerEvent. 1408 */ componentAdded(ContainerEvent e)1409 public void componentAdded(ContainerEvent e) 1410 { 1411 if (e.getChild() instanceof JButton) 1412 { 1413 JButton b = (JButton) e.getChild(); 1414 1415 if (b.getBorder() != null) 1416 borders.put(b, b.getBorder()); 1417 } 1418 1419 if (isRolloverBorders()) 1420 setBorderToRollover(e.getChild()); 1421 else 1422 setBorderToNonRollover(e.getChild()); 1423 1424 cachedBounds = toolBar.getPreferredSize(); 1425 cachedOrientation = toolBar.getOrientation(); 1426 1427 Component c = e.getChild(); 1428 if (toolBarFocusListener != null) 1429 c.addFocusListener(toolBarFocusListener); 1430 } 1431 1432 /** 1433 * This method is responsible for giving the child components their 1434 * original borders when they are removed. 1435 * 1436 * @param e The ContainerEvent. 1437 */ componentRemoved(ContainerEvent e)1438 public void componentRemoved(ContainerEvent e) 1439 { 1440 setBorderToNormal(e.getChild()); 1441 cachedBounds = toolBar.getPreferredSize(); 1442 cachedOrientation = toolBar.getOrientation(); 1443 1444 Component c = e.getChild(); 1445 if (toolBarFocusListener != null) 1446 c.removeFocusListener(toolBarFocusListener); 1447 } 1448 } 1449 1450 /** 1451 * This is the floating window that is returned when getFloatingWindow is 1452 * called. 1453 */ 1454 private class ToolBarDialog extends JDialog implements UIResource 1455 { 1456 /** 1457 * Creates a new ToolBarDialog object with the name given by the JToolBar. 1458 */ ToolBarDialog()1459 public ToolBarDialog() 1460 { 1461 super(); 1462 setName((toolBar.getName() != null) ? toolBar.getName() : ""); 1463 } 1464 } 1465 1466 /** 1467 * DOCUMENT ME! 1468 */ 1469 protected class ToolBarFocusListener implements FocusListener 1470 { 1471 /** 1472 * Creates a new ToolBarFocusListener object. 1473 */ ToolBarFocusListener()1474 protected ToolBarFocusListener() 1475 { 1476 // Nothing to do here. 1477 } 1478 1479 /** 1480 * Receives notification when the toolbar or one of it's component 1481 * receives the keyboard input focus. 1482 * 1483 * @param e the focus event 1484 */ focusGained(FocusEvent e)1485 public void focusGained(FocusEvent e) 1486 { 1487 Component c = e.getComponent(); 1488 focusedCompIndex = toolBar.getComponentIndex(c); 1489 } 1490 1491 /** 1492 * Receives notification when the toolbar or one of it's component 1493 * looses the keyboard input focus. 1494 * 1495 * @param e the focus event 1496 */ focusLost(FocusEvent e)1497 public void focusLost(FocusEvent e) 1498 { 1499 // Do nothing here. 1500 } 1501 } 1502 1503 /** 1504 * This helper class acts as the border for the JToolBar. 1505 */ 1506 private static class ToolBarBorder implements Border 1507 { 1508 /** The size of the larger, draggable side of the border. */ 1509 private static final int offset = 10; 1510 1511 /** The other sides. */ 1512 private static final int regular = 2; 1513 1514 /** 1515 * This method returns the border insets for the JToolBar. 1516 * 1517 * @param c The Component to find insets for. 1518 * 1519 * @return The border insets. 1520 */ getBorderInsets(Component c)1521 public Insets getBorderInsets(Component c) 1522 { 1523 if (c instanceof JToolBar) 1524 { 1525 JToolBar tb = (JToolBar) c; 1526 int orientation = tb.getOrientation(); 1527 1528 if (! tb.isFloatable()) 1529 return new Insets(regular, regular, regular, regular); 1530 else if (orientation == SwingConstants.HORIZONTAL) 1531 return new Insets(regular, offset, regular, regular); 1532 else 1533 return new Insets(offset, regular, regular, regular); 1534 } 1535 1536 return new Insets(0, 0, 0, 0); 1537 } 1538 1539 /** 1540 * This method returns whether the border is opaque. 1541 * 1542 * @return Whether the border is opaque. 1543 */ isBorderOpaque()1544 public boolean isBorderOpaque() 1545 { 1546 return false; 1547 } 1548 1549 /** 1550 * This method paints the ribbed area of the border. 1551 * 1552 * @param g The Graphics object to paint with. 1553 * @param x The x coordinate of the area. 1554 * @param y The y coordinate of the area. 1555 * @param w The width of the area. 1556 * @param h The height of the area. 1557 * @param size The size of the bump. 1558 * @param c The color of the bumps. 1559 */ paintBumps(Graphics g, int x, int y, int w, int h, int size, Color c)1560 private void paintBumps(Graphics g, int x, int y, int w, int h, int size, 1561 Color c) 1562 { 1563 Color saved = g.getColor(); 1564 g.setColor(c); 1565 1566 int hgap = 2 * size; 1567 int vgap = 4 * size; 1568 int count = 0; 1569 1570 for (int i = x; i < (w + x); i += hgap) 1571 for (int j = ((count++ % 2) == 0) ? y : (y + (2 * size)); j < (h + y); 1572 j += vgap) 1573 g.fillRect(i, j, size, size); 1574 1575 g.setColor(saved); 1576 } 1577 1578 /** 1579 * This method paints the border around the given Component. 1580 * 1581 * @param c The Component whose border is being painted. 1582 * @param g The Graphics object to paint with. 1583 * @param x The x coordinate of the component. 1584 * @param y The y coordinate of the component. 1585 * @param width The width of the component. 1586 * @param height The height of the component. 1587 */ paintBorder(Component c, Graphics g, int x, int y, int width, int height)1588 public void paintBorder(Component c, Graphics g, int x, int y, int width, 1589 int height) 1590 { 1591 if (c instanceof JToolBar) 1592 { 1593 JToolBar tb = (JToolBar) c; 1594 1595 int orientation = tb.getOrientation(); 1596 1597 if (orientation == SwingConstants.HORIZONTAL) 1598 { 1599 paintBumps(g, x, y, offset, height, 1, Color.WHITE); 1600 paintBumps(g, x + 1, y + 1, offset - 1, height - 1, 1, Color.GRAY); 1601 } 1602 else 1603 { 1604 paintBumps(g, x, y, width, offset, 1, Color.WHITE); 1605 paintBumps(g, x + 1, y + 1, width - 1, offset - 1, 1, Color.GRAY); 1606 } 1607 } 1608 } 1609 } 1610 } 1611