1. /*
  2. * @(#)MetalToolBarUI.java 1.39 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.metal;
  8. import javax.swing.*;
  9. import java.awt.Color;
  10. import java.awt.Component;
  11. import java.awt.Container;
  12. import java.awt.Dimension;
  13. import java.awt.Frame;
  14. import java.awt.Graphics;
  15. import java.awt.GraphicsEnvironment;
  16. import java.awt.Insets;
  17. import java.awt.Point;
  18. import java.awt.Rectangle;
  19. import java.awt.event.*;
  20. import java.lang.ref.WeakReference;
  21. import java.util.*;
  22. import java.beans.PropertyChangeListener;
  23. import javax.swing.event.*;
  24. import javax.swing.border.*;
  25. import javax.swing.plaf.*;
  26. import javax.swing.plaf.basic.*;
  27. /**
  28. * A Metal Look and Feel implementation of ToolBarUI. This implementation
  29. * is a "combined" view/controller.
  30. * <p>
  31. *
  32. * @version 1.39 12/19/03
  33. * @author Jeff Shapiro
  34. */
  35. public class MetalToolBarUI extends BasicToolBarUI
  36. {
  37. /**
  38. * An array of WeakReferences that point to JComponents. This will contain
  39. * instances of JToolBars and JMenuBars and is used to find
  40. * JToolBars/JMenuBars that border each other.
  41. */
  42. private static java.util.List components = new ArrayList();
  43. /**
  44. * This protected field is implemenation specific. Do not access directly
  45. * or override. Use the create method instead.
  46. *
  47. * @see #createContainerListener
  48. */
  49. protected ContainerListener contListener;
  50. /**
  51. * This protected field is implemenation specific. Do not access directly
  52. * or override. Use the create method instead.
  53. *
  54. * @see #createRolloverListener
  55. */
  56. protected PropertyChangeListener rolloverListener;
  57. private static Border nonRolloverBorder;
  58. /**
  59. * Registers the specified component.
  60. */
  61. synchronized static void register(JComponent c) {
  62. if (c == null) {
  63. // Exception is thrown as convenience for callers that are
  64. // typed to throw an NPE.
  65. throw new NullPointerException("JComponent must be non-null");
  66. }
  67. components.add(new WeakReference(c));
  68. }
  69. /**
  70. * Unregisters the specified component.
  71. */
  72. synchronized static void unregister(JComponent c) {
  73. for (int counter = components.size() - 1; counter >= 0; counter--) {
  74. // Search for the component, removing any flushed references
  75. // along the way.
  76. WeakReference ref = (WeakReference)components.get(counter);
  77. Object target = ((WeakReference)components.get(counter)).get();
  78. if (target == c || target == null) {
  79. components.remove(counter);
  80. }
  81. }
  82. }
  83. /**
  84. * Finds a previously registered component of class <code>target</code>
  85. * that shares the JRootPane ancestor of <code>from</code>.
  86. */
  87. synchronized static Object findRegisteredComponentOfType(JComponent from,
  88. Class target) {
  89. JRootPane rp = SwingUtilities.getRootPane(from);
  90. if (rp != null) {
  91. for (int counter = components.size() - 1; counter >= 0; counter--){
  92. Object component = ((WeakReference)components.get(counter)).
  93. get();
  94. if (component == null) {
  95. // WeakReference has gone away, remove the WeakReference
  96. components.remove(counter);
  97. }
  98. else if (target.isInstance(component) && SwingUtilities.
  99. getRootPane((Component)component) == rp) {
  100. return component;
  101. }
  102. }
  103. }
  104. return null;
  105. }
  106. /**
  107. * Returns true if the passed in JMenuBar is above a horizontal
  108. * JToolBar.
  109. */
  110. static boolean doesMenuBarBorderToolBar(JMenuBar c) {
  111. JToolBar tb = (JToolBar)MetalToolBarUI.
  112. findRegisteredComponentOfType(c, JToolBar.class);
  113. if (tb != null && tb.getOrientation() == JToolBar.HORIZONTAL) {
  114. JRootPane rp = SwingUtilities.getRootPane(c);
  115. Point point = new Point(0, 0);
  116. point = SwingUtilities.convertPoint(c, point, rp);
  117. int menuX = point.x;
  118. int menuY = point.y;
  119. point.x = point.y = 0;
  120. point = SwingUtilities.convertPoint(tb, point, rp);
  121. return (point.x == menuX && menuY + c.getHeight() == point.y &&
  122. c.getWidth() == tb.getWidth());
  123. }
  124. return false;
  125. }
  126. public static ComponentUI createUI( JComponent c )
  127. {
  128. return new MetalToolBarUI();
  129. }
  130. public void installUI( JComponent c )
  131. {
  132. super.installUI( c );
  133. register(c);
  134. }
  135. public void uninstallUI( JComponent c )
  136. {
  137. super.uninstallUI( c );
  138. nonRolloverBorder = null;
  139. unregister(c);
  140. }
  141. protected void installListeners() {
  142. super.installListeners();
  143. contListener = createContainerListener();
  144. if (contListener != null) {
  145. toolBar.addContainerListener(contListener);
  146. }
  147. rolloverListener = createRolloverListener();
  148. if (rolloverListener != null) {
  149. toolBar.addPropertyChangeListener(rolloverListener);
  150. }
  151. }
  152. protected void uninstallListeners() {
  153. super.uninstallListeners();
  154. if (contListener != null) {
  155. toolBar.removeContainerListener(contListener);
  156. }
  157. rolloverListener = createRolloverListener();
  158. if (rolloverListener != null) {
  159. toolBar.removePropertyChangeListener(rolloverListener);
  160. }
  161. }
  162. protected Border createRolloverBorder() {
  163. return super.createRolloverBorder();
  164. }
  165. protected Border createNonRolloverBorder() {
  166. return super.createNonRolloverBorder();
  167. }
  168. /**
  169. * Creates a non rollover border for Toggle buttons in the toolbar.
  170. */
  171. private Border createNonRolloverToggleBorder() {
  172. return createNonRolloverBorder();
  173. }
  174. protected void setBorderToNonRollover(Component c) {
  175. if (c instanceof JToggleButton && !(c instanceof JCheckBox)) {
  176. // 4735514, 4886944: The method createNonRolloverToggleBorder() is
  177. // private in BasicToolBarUI so we can't override it. We still need
  178. // to call super from this method so that it can save away the
  179. // original border and then we install ours.
  180. // Before calling super we get a handle to the old border, because
  181. // super will install a non-UIResource border that we can't
  182. // distinguish from one provided by an application.
  183. JToggleButton b = (JToggleButton)c;
  184. Border border = b.getBorder();
  185. super.setBorderToNonRollover(c);
  186. if (border instanceof UIResource) {
  187. if (nonRolloverBorder == null) {
  188. nonRolloverBorder = createNonRolloverToggleBorder();
  189. }
  190. b.setBorder(nonRolloverBorder);
  191. }
  192. } else {
  193. super.setBorderToNonRollover(c);
  194. }
  195. }
  196. /**
  197. * Creates a container listener that will be added to the JToolBar.
  198. * If this method returns null then it will not be added to the
  199. * toolbar.
  200. *
  201. * @return an instance of a <code>ContainerListener</code> or null
  202. */
  203. protected ContainerListener createContainerListener() {
  204. return null;
  205. }
  206. /**
  207. * Creates a property change listener that will be added to the JToolBar.
  208. * If this method returns null then it will not be added to the
  209. * toolbar.
  210. *
  211. * @return an instance of a <code>PropertyChangeListener</code> or null
  212. */
  213. protected PropertyChangeListener createRolloverListener() {
  214. return null;
  215. }
  216. protected MouseInputListener createDockingListener( )
  217. {
  218. return new MetalDockingListener( toolBar );
  219. }
  220. protected void setDragOffset(Point p) {
  221. if (!GraphicsEnvironment.isHeadless()) {
  222. if (dragWindow == null) {
  223. dragWindow = createDragWindow(toolBar);
  224. }
  225. dragWindow.setOffset(p);
  226. }
  227. }
  228. /**
  229. * If necessary paints the background of the component, then invokes
  230. * <code>paint</code>.
  231. *
  232. * @param g Graphics to paint to
  233. * @param c JComponent painting on
  234. * @throws NullPointerException if <code>g</code> or <code>c</code> is
  235. * null
  236. * @see javax.swing.plaf.ComponentUI#update
  237. * @see javax.swing.plaf.ComponentUI#paint
  238. * @since 1.5
  239. */
  240. public void update(Graphics g, JComponent c) {
  241. if (c.isOpaque() && (c.getBackground() instanceof UIResource) &&
  242. ((JToolBar)c).getOrientation() ==
  243. JToolBar.HORIZONTAL && UIManager.get(
  244. "MenuBar.gradient") != null) {
  245. JRootPane rp = SwingUtilities.getRootPane(c);
  246. JMenuBar mb = (JMenuBar)findRegisteredComponentOfType(
  247. c, JMenuBar.class);
  248. if (mb != null && mb.isOpaque() &&
  249. (mb.getBackground() instanceof UIResource)) {
  250. Point point = new Point(0, 0);
  251. point = SwingUtilities.convertPoint(c, point, rp);
  252. int x = point.x;
  253. int y = point.y;
  254. point.x = point.y = 0;
  255. point = SwingUtilities.convertPoint(mb, point, rp);
  256. if (point.x == x && y == point.y + mb.getHeight() &&
  257. mb.getWidth() == c.getWidth() &&
  258. MetalUtils.drawGradient(c, g, "MenuBar.gradient",
  259. 0, -mb.getHeight(), c.getWidth(), c.getHeight() +
  260. mb.getHeight(), true)) {
  261. paint(g, c);
  262. return;
  263. }
  264. }
  265. if (MetalUtils.drawGradient(c, g, "MenuBar.gradient",
  266. 0, 0, c.getWidth(), c.getHeight(), true)) {
  267. paint(g, c);
  268. return;
  269. }
  270. }
  271. super.update(g, c);
  272. }
  273. // No longer used. Cannot remove for compatibility reasons
  274. protected class MetalContainerListener
  275. extends BasicToolBarUI.ToolBarContListener {}
  276. // No longer used. Cannot remove for compatibility reasons
  277. protected class MetalRolloverListener
  278. extends BasicToolBarUI.PropertyListener {}
  279. protected class MetalDockingListener extends DockingListener {
  280. private boolean pressedInBumps = false;
  281. public MetalDockingListener(JToolBar t) {
  282. super(t);
  283. }
  284. public void mousePressed(MouseEvent e) {
  285. super.mousePressed(e);
  286. if (!toolBar.isEnabled()) {
  287. return;
  288. }
  289. pressedInBumps = false;
  290. Rectangle bumpRect = new Rectangle();
  291. if (toolBar.getOrientation() == JToolBar.HORIZONTAL) {
  292. int x = MetalUtils.isLeftToRight(toolBar) ? 0 : toolBar.getSize().width-14;
  293. bumpRect.setBounds(x, 0, 14, toolBar.getSize().height);
  294. } else { // vertical
  295. bumpRect.setBounds(0, 0, toolBar.getSize().width, 14);
  296. }
  297. if (bumpRect.contains(e.getPoint())) {
  298. pressedInBumps = true;
  299. Point dragOffset = e.getPoint();
  300. if (!MetalUtils.isLeftToRight(toolBar)) {
  301. dragOffset.x -= (toolBar.getSize().width
  302. - toolBar.getPreferredSize().width);
  303. }
  304. setDragOffset(dragOffset);
  305. }
  306. }
  307. public void mouseDragged(MouseEvent e) {
  308. if (pressedInBumps) {
  309. super.mouseDragged(e);
  310. }
  311. }
  312. } // end class MetalDockingListener
  313. }