OSDN Git Service

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