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