OSDN Git Service

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