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