001 /* JToolBar.java -- 002 Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package javax.swing; 040 041 import java.awt.Component; 042 import java.awt.Container; 043 import java.awt.Dimension; 044 import java.awt.Graphics; 045 import java.awt.Insets; 046 import java.awt.LayoutManager; 047 import java.beans.PropertyChangeListener; 048 049 import javax.accessibility.Accessible; 050 import javax.accessibility.AccessibleContext; 051 import javax.accessibility.AccessibleRole; 052 import javax.accessibility.AccessibleStateSet; 053 import javax.swing.plaf.ToolBarUI; 054 055 /** 056 * JToolBar is a component that provides a toolbar to Swing programs. Users 057 * can add buttons (or actions that will be represented by JButtons) as well 058 * as other components to the JToolBar. JToolBars can be dragged in and out 059 * of their parent components. If the JToolBar is dragged out of the parent, 060 * then it will be displayed in its own RootPaneContainer. For dragging to 061 * work properly, JToolBars need to be placed in a Container that has a 062 * BorderLayout. That parent Container cannot have components in the NORTH, 063 * EAST, SOUTH, or WEST components (that is not the JToolBar). 064 */ 065 public class JToolBar extends JComponent implements SwingConstants, Accessible 066 { 067 /** 068 * Provides the accessibility features for the <code>JToolBar</code> 069 * component. 070 */ 071 protected class AccessibleJToolBar extends AccessibleJComponent 072 { 073 private static final long serialVersionUID = -5516888265903814215L; 074 075 /** 076 * Creates a new <code>AccessibleJToolBar</code> instance. 077 */ 078 protected AccessibleJToolBar() 079 { 080 // Nothing to do here. 081 } 082 083 /** 084 * Returns a set containing the current state of the {@link JToolBar} 085 * component. The current implementation simply calls the superclass. 086 * 087 * @return The accessible state set. 088 */ 089 public AccessibleStateSet getAccessibleStateSet() 090 { 091 // running tests against the reference implementation, I was unable 092 // to find any state information that is set specifically by the 093 // tool bar... 094 return super.getAccessibleStateSet(); 095 } 096 097 /** 098 * Returns the accessible role for the <code>JToolBar</code> component. 099 * 100 * @return {@link AccessibleRole#TOOL_BAR}. 101 */ 102 public AccessibleRole getAccessibleRole() 103 { 104 return AccessibleRole.TOOL_BAR; 105 } 106 } 107 108 /** 109 * This is the private JToolBar layout manager. 110 */ 111 private class DefaultToolBarLayout implements LayoutManager 112 { 113 /** 114 * This method is called when a new component is added to the container. 115 * 116 * @param name The name of the component added. 117 * @param comp The component that was added. 118 */ 119 public void addLayoutComponent(String name, Component comp) 120 { 121 // Do nothing. 122 } 123 124 /** 125 * This method is called to lay out the given container to position and 126 * size the child components. 127 * 128 * @param c The container to lay out. 129 * 130 * @throws Error DOCUMENT ME! 131 */ 132 public void layoutContainer(Container c) 133 { 134 if (! (c instanceof JToolBar)) 135 throw new Error("DefaultToolBarLayout can only be used on JToolBars."); 136 Insets insets = getInsets(); 137 Insets margin = getMargin(); 138 int middle; 139 if (margin != null) 140 { 141 insets.left += margin.left; 142 insets.top += margin.top; 143 insets.bottom += margin.bottom; 144 insets.right += margin.right; 145 } 146 Component[] components = c.getComponents(); 147 Dimension tdims = c.getSize(); 148 int start = 0; 149 Dimension pref; 150 151 if (getOrientation() == SwingUtilities.HORIZONTAL) 152 { 153 start += insets.left; 154 for (int i = 0; i < components.length; i++) 155 { 156 if (components[i] != null && components[i].isVisible()) 157 { 158 pref = components[i].getPreferredSize(); 159 if (pref != null) 160 { 161 middle = (tdims.height - pref.height) / 2; 162 components[i].setBounds(start, middle, pref.width, 163 pref.height); 164 start += pref.width; 165 } 166 } 167 } 168 } 169 else 170 { 171 start += insets.top; 172 for (int i = 0; i < components.length; i++) 173 { 174 if (components[i] != null && components[i].isVisible()) 175 { 176 pref = components[i].getPreferredSize(); 177 if (pref != null) 178 { 179 middle = (tdims.width - pref.width) / 2; 180 components[i].setBounds(middle, start, pref.width, 181 pref.height); 182 start += pref.height; 183 } 184 } 185 } 186 } 187 } 188 189 /** 190 * This method returns the minimum size of the given container given the 191 * child components. 192 * 193 * @param parent The container to measure. 194 * 195 * @return The minimum size of the given container. 196 */ 197 public Dimension minimumLayoutSize(Container parent) 198 { 199 return preferredLayoutSize(parent); 200 } 201 202 /** 203 * This method returns the preferred size of the given container given the 204 * child components. 205 * 206 * @param parent The container to measure. 207 * 208 * @return The preferred size of the given container. 209 */ 210 public Dimension preferredLayoutSize(Container parent) 211 { 212 int orientation = getOrientation(); 213 Component[] components = getComponents(); 214 215 int limit = 0; 216 int total = 0; 217 Dimension dims; 218 219 int w = 0; 220 int h = 0; 221 222 if (orientation == SwingConstants.HORIZONTAL) 223 { 224 for (int i = 0; i < components.length; i++) 225 { 226 dims = components[i].getPreferredSize(); 227 if (dims != null) 228 { 229 if (dims.height > limit) 230 limit = dims.height; 231 total += dims.width; 232 } 233 } 234 w = total; 235 h = limit; 236 } 237 else 238 { 239 for (int i = 0; i < components.length; i++) 240 { 241 dims = components[i].getPreferredSize(); 242 if (dims != null) 243 { 244 if (dims.width > limit) 245 limit = dims.width; 246 total += dims.height; 247 } 248 } 249 w = limit; 250 h = total; 251 } 252 253 Insets insets = getInsets(); 254 w += insets.left + insets.right; 255 h += insets.top + insets.bottom; 256 257 Insets margin = getMargin(); 258 if (margin != null) 259 { 260 w += margin.left + margin.right; 261 h += margin.top + margin.bottom; 262 } 263 264 return new Dimension(w, h); 265 } 266 267 /** 268 * This method is called when the given component is removed from the 269 * container. 270 * 271 * @param comp The component removed. 272 */ 273 public void removeLayoutComponent(Component comp) 274 { 275 // Do nothing. 276 } 277 } 278 279 /** 280 * This is an extension of JSeparator used in toolbars. Unlike JSeparator, 281 * nothing is painted for this Separator, it is only blank space that 282 * separates components. 283 */ 284 public static class Separator extends JSeparator 285 { 286 /** DOCUMENT ME! */ 287 private static final long serialVersionUID = -1656745644823105219L; 288 289 /** 290 * Creates a new Separator object. 291 */ 292 public Separator() 293 { 294 super(); 295 } // Separator() 296 297 /** 298 * Creates a new Separator object with the given size. 299 * 300 * @param size The size of the separator. 301 */ 302 public Separator(Dimension size) 303 { 304 setPreferredSize(size); 305 } // Separator() 306 307 /** 308 * This method returns the String ID of the UI class of Separator. 309 * 310 * @return The UI class' String ID. 311 */ 312 public String getUIClassID() 313 { 314 return "ToolBarSeparatorUI"; 315 } // getUIClassID() 316 317 /** 318 * This method returns the preferred size of the Separator. 319 * 320 * @return The preferred size of the Separator. 321 */ 322 public Dimension getPreferredSize() 323 { 324 return super.getPreferredSize(); 325 } // getPreferredSize() 326 327 /** 328 * This method returns the maximum size of the Separator. 329 * 330 * @return The maximum size of the Separator. 331 */ 332 public Dimension getMaximumSize() 333 { 334 return super.getPreferredSize(); 335 } // getMaximumSize() 336 337 /** 338 * This method returns the minimum size of the Separator. 339 * 340 * @return The minimum size of the Separator. 341 */ 342 public Dimension getMinimumSize() 343 { 344 return super.getPreferredSize(); 345 } // getMinimumSize() 346 347 /** 348 * This method returns the size of the Separator. 349 * 350 * @return The size of the Separator. 351 */ 352 public Dimension getSeparatorSize() 353 { 354 return super.getPreferredSize(); 355 } // getSeparatorSize() 356 357 /** 358 * This method sets the size of the Separator. 359 * 360 * @param size The new size of the Separator. 361 */ 362 public void setSeparatorSize(Dimension size) 363 { 364 setPreferredSize(size); 365 } // setSeparatorSize() 366 } // Separator 367 368 /** DOCUMENT ME! */ 369 private static final long serialVersionUID = -1269915519555129643L; 370 371 /** Whether the JToolBar paints its border. */ 372 private transient boolean paintBorder = true; 373 374 /** The extra insets around the JToolBar. */ 375 private transient Insets margin; 376 377 /** Whether the JToolBar can float (and be dragged around). */ 378 private transient boolean floatable = true; 379 380 /** Whether the buttons will have rollover borders. */ 381 private transient boolean rollover; 382 383 /** The orientation of the JToolBar. */ 384 private int orientation = HORIZONTAL; 385 386 /** 387 * This method creates a new JToolBar object with horizontal orientation 388 * and no name. 389 */ 390 public JToolBar() 391 { 392 this(null, HORIZONTAL); 393 } // JToolBar() 394 395 /** 396 * This method creates a new JToolBar with the given orientation and no 397 * name. 398 * 399 * @param orientation JToolBar orientation (HORIZONTAL or VERTICAL) 400 */ 401 public JToolBar(int orientation) 402 { 403 this(null, orientation); 404 } // JToolBar() 405 406 /** 407 * This method creates a new JToolBar object with the given name and 408 * horizontal orientation. 409 * 410 * @param name Name assigned to undocked tool bar. 411 */ 412 public JToolBar(String name) 413 { 414 this(name, HORIZONTAL); 415 } // JToolBar() 416 417 /** 418 * This method creates a new JToolBar object with the given name and 419 * orientation. 420 * 421 * @param name Name assigned to undocked tool bar. 422 * @param orientation JToolBar orientation (HORIZONTAL or VERTICAL) 423 */ 424 public JToolBar(String name, int orientation) 425 { 426 setName(name); 427 setOrientation(orientation); 428 setLayout(new DefaultToolBarLayout()); 429 revalidate(); 430 setOpaque(true); 431 updateUI(); 432 } 433 434 /** 435 * This method adds a new JButton that performs the given Action to the 436 * JToolBar. 437 * 438 * @param action The Action to add to the JToolBar. 439 * 440 * @return The JButton that wraps the Action. 441 */ 442 public JButton add(Action action) 443 { 444 JButton b = createActionComponent(action); 445 add(b); 446 return b; 447 } // add() 448 449 /** 450 * This method paints the border if the borderPainted property is true. 451 * 452 * @param graphics The graphics object to paint with. 453 */ 454 protected void paintBorder(Graphics graphics) 455 { 456 if (paintBorder && isFloatable()) 457 super.paintBorder(graphics); 458 } // paintBorder() 459 460 /** 461 * This method returns the UI class used to paint this JToolBar. 462 * 463 * @return The UI class for this JToolBar. 464 */ 465 public ToolBarUI getUI() 466 { 467 return (ToolBarUI) ui; 468 } // getUI() 469 470 /** 471 * This method sets the UI used with the JToolBar. 472 * 473 * @param ui The UI used with the JToolBar. 474 */ 475 public void setUI(ToolBarUI ui) 476 { 477 super.setUI(ui); 478 } // setUI() 479 480 /** 481 * This method resets the UI used to the Look and Feel defaults. 482 */ 483 public void updateUI() 484 { 485 setUI((ToolBarUI) UIManager.getUI(this)); 486 } 487 488 /** 489 * This method returns the String identifier for the UI class to the used 490 * with the JToolBar. 491 * 492 * @return The String identifier for the UI class. 493 */ 494 public String getUIClassID() 495 { 496 return "ToolBarUI"; 497 } // getUIClassID() 498 499 /** 500 * This method sets the rollover property for the JToolBar. In rollover 501 * mode, JButtons inside the JToolBar will only display their borders when 502 * the mouse is moving over them. 503 * 504 * @param b The new rollover property. 505 */ 506 public void setRollover(boolean b) 507 { 508 if (b != rollover) 509 { 510 rollover = b; 511 firePropertyChange("rollover", ! rollover, rollover); 512 revalidate(); 513 repaint(); 514 } 515 } 516 517 /** 518 * This method returns the rollover property. 519 * 520 * @return The rollover property. 521 */ 522 public boolean isRollover() 523 { 524 return rollover; 525 } 526 527 /** 528 * This method returns the index of the given component. 529 * 530 * @param component The component to find. 531 * 532 * @return The index of the given component. 533 */ 534 public int getComponentIndex(Component component) 535 { 536 Component[] components = getComponents(); 537 if (components == null) 538 return -1; 539 540 for (int i = 0; i < components.length; i++) 541 if (components[i] == component) 542 return i; 543 544 return -1; 545 } // getComponentIndex() 546 547 /** 548 * This method returns the component at the given index. 549 * 550 * @param index The index of the component. 551 * 552 * @return The component at the given index. 553 */ 554 public Component getComponentAtIndex(int index) 555 { 556 return getComponent(index); 557 } // getComponentAtIndex() 558 559 /** 560 * This method returns the margin property. 561 * 562 * @return The margin property. 563 */ 564 public Insets getMargin() 565 { 566 return margin; 567 } // getMargin() 568 569 /** 570 * This method sets the margin property. The margin property determines the 571 * extra space between the children components of the JToolBar and the 572 * border. 573 * 574 * @param margin The margin property. 575 */ 576 public void setMargin(Insets margin) 577 { 578 if ((this.margin != null && margin == null) 579 || (this.margin == null && margin != null) 580 || (margin != null && this.margin != null 581 && (margin.left != this.margin.left 582 || margin.right != this.margin.right || margin.top != this.margin.top 583 || margin.bottom != this.margin.bottom))) 584 { 585 Insets oldMargin = this.margin; 586 this.margin = margin; 587 firePropertyChange("margin", oldMargin, this.margin); 588 revalidate(); 589 repaint(); 590 } 591 } // setMargin() 592 593 /** 594 * This method returns the borderPainted property. 595 * 596 * @return The borderPainted property. 597 */ 598 public boolean isBorderPainted() 599 { 600 return paintBorder; 601 } // isBorderPainted() 602 603 /** 604 * This method sets the borderPainted property. If set to false, the border 605 * will not be painted. 606 * 607 * @param painted Whether the border will be painted. 608 */ 609 public void setBorderPainted(boolean painted) 610 { 611 if (painted != paintBorder) 612 { 613 paintBorder = painted; 614 firePropertyChange("borderPainted", ! paintBorder, 615 paintBorder); 616 repaint(); 617 } 618 } // setBorderPainted() 619 620 /** 621 * This method returns the floatable property. 622 * 623 * @return The floatable property. 624 */ 625 public boolean isFloatable() 626 { 627 return floatable; 628 } // isFloatable() 629 630 /** 631 * This method sets the floatable property. If set to false, the JToolBar 632 * cannot be dragged. 633 * 634 * @param floatable Whether the JToolBar can be dragged. 635 */ 636 public void setFloatable(boolean floatable) 637 { 638 if (floatable != this.floatable) 639 { 640 this.floatable = floatable; 641 firePropertyChange("floatable", ! floatable, floatable); 642 } 643 } // setFloatable() 644 645 /** 646 * This method returns the orientation of the JToolBar. 647 * 648 * @return The orientation of the JToolBar. 649 */ 650 public int getOrientation() 651 { 652 return orientation; 653 } // getOrientation() 654 655 /** 656 * This method sets the layout manager to be used with the JToolBar. 657 * 658 * @param mgr The Layout Manager used with the JToolBar. 659 */ 660 public void setLayout(LayoutManager mgr) 661 { 662 super.setLayout(mgr); 663 revalidate(); 664 repaint(); 665 } // setLayout() 666 667 /** 668 * This method sets the orientation property for JToolBar. 669 * 670 * @param orientation The new orientation for JToolBar. 671 * 672 * @throws IllegalArgumentException If the orientation is not HORIZONTAL or 673 * VERTICAL. 674 */ 675 public void setOrientation(int orientation) 676 { 677 if (orientation != HORIZONTAL && orientation != VERTICAL) 678 throw new IllegalArgumentException(orientation 679 + " is not a legal orientation"); 680 if (orientation != this.orientation) 681 { 682 int oldOrientation = this.orientation; 683 this.orientation = orientation; 684 firePropertyChange("orientation", oldOrientation, this.orientation); 685 revalidate(); 686 repaint(); 687 } 688 } // setOrientation() 689 690 /** 691 * This method adds a Separator of default size to the JToolBar. 692 */ 693 public void addSeparator() 694 { 695 add(new Separator()); 696 } // addSeparator() 697 698 /** 699 * This method adds a Separator with the given size to the JToolBar. 700 * 701 * @param size The size of the Separator. 702 */ 703 public void addSeparator(Dimension size) 704 { 705 add(new Separator(size)); 706 } // addSeparator() 707 708 /** 709 * This method is used to create JButtons which can be added to the JToolBar 710 * for the given action. 711 * 712 * @param action The action to create a JButton for. 713 * 714 * @return The JButton created from the action. 715 */ 716 protected JButton createActionComponent(Action action) 717 { 718 return new JButton(action); 719 } // createActionComponent() 720 721 /** 722 * This method creates a pre-configured PropertyChangeListener which updates 723 * the control as changes are made to the Action. However, this is no 724 * longer the recommended way of adding Actions to Containers. As such, 725 * this method returns null. 726 * 727 * @param button The JButton to configure a PropertyChangeListener for. 728 * 729 * @return null. 730 */ 731 protected PropertyChangeListener createActionChangeListener(JButton button) 732 { 733 // XXX: As specified, this returns null. But seems kind of strange, usually deprecated methods don't just return null, verify! 734 return null; 735 } // createActionChangeListener() 736 737 /** 738 * This method overrides Container's addImpl method. If a JButton is added, 739 * it is disabled. 740 * 741 * @param component The Component to add. 742 * @param constraints The Constraints placed on the component. 743 * @param index The index to place the Component at. 744 */ 745 protected void addImpl(Component component, Object constraints, int index) 746 { 747 // XXX: Sun says disable button but test cases show otherwise. 748 super.addImpl(component, constraints, index); 749 750 // if we added a Swing Button then adjust this a little 751 if (component instanceof AbstractButton) 752 { 753 AbstractButton b = (AbstractButton) component; 754 b.setRolloverEnabled(rollover); 755 } 756 757 } // addImpl() 758 759 /** 760 * Returns a string describing the attributes for the <code>JToolBar</code> 761 * component, for use in debugging. The return value is guaranteed to be 762 * non-<code>null</code>, but the format of the string may vary between 763 * implementations. 764 * 765 * @return A string describing the attributes of the <code>JToolBar</code>. 766 */ 767 protected String paramString() 768 { 769 StringBuffer sb = new StringBuffer(super.paramString()); 770 sb.append(",floatable=").append(floatable); 771 sb.append(",margin="); 772 if (margin != null) 773 sb.append(margin); 774 sb.append(",orientation="); 775 if (orientation == HORIZONTAL) 776 sb.append("HORIZONTAL"); 777 else 778 sb.append(VERTICAL); 779 sb.append(",paintBorder=").append(paintBorder); 780 return sb.toString(); 781 } 782 783 /** 784 * Returns the object that provides accessibility features for this 785 * <code>JToolBar</code> component. 786 * 787 * @return The accessible context (an instance of {@link AccessibleJToolBar}). 788 */ 789 public AccessibleContext getAccessibleContext() 790 { 791 if (accessibleContext == null) 792 accessibleContext = new AccessibleJToolBar(); 793 794 return accessibleContext; 795 } 796 }