blob: eed7d630351623cfba47eabbd2476802029cc234 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.swing.plaf.metal;
27
28import javax.swing.*;
29import java.awt.Color;
30import java.awt.Component;
31import java.awt.Container;
32import java.awt.Dimension;
33import java.awt.Frame;
34import java.awt.Graphics;
35import java.awt.GraphicsEnvironment;
36import java.awt.Insets;
37import java.awt.Point;
38import java.awt.Rectangle;
39import java.awt.event.*;
40import java.lang.ref.WeakReference;
41import java.util.*;
42
43import java.beans.PropertyChangeListener;
44
45import javax.swing.event.*;
46import javax.swing.border.*;
47import javax.swing.plaf.*;
48import javax.swing.plaf.basic.*;
49
50/**
51 * A Metal Look and Feel implementation of ToolBarUI. This implementation
52 * is a "combined" view/controller.
53 * <p>
54 *
55 * @author Jeff Shapiro
56 */
57public class MetalToolBarUI extends BasicToolBarUI
58{
59 /**
60 * An array of WeakReferences that point to JComponents. This will contain
61 * instances of JToolBars and JMenuBars and is used to find
62 * JToolBars/JMenuBars that border each other.
63 */
64 private static java.util.List components = new ArrayList();
65
66 /**
67 * This protected field is implemenation specific. Do not access directly
68 * or override. Use the create method instead.
69 *
70 * @see #createContainerListener
71 */
72 protected ContainerListener contListener;
73
74 /**
75 * This protected field is implemenation specific. Do not access directly
76 * or override. Use the create method instead.
77 *
78 * @see #createRolloverListener
79 */
80 protected PropertyChangeListener rolloverListener;
81
82 private static Border nonRolloverBorder;
83
84 /**
85 * Last menubar the toolbar touched. This is only useful for ocean.
86 */
87 private JMenuBar lastMenuBar;
88
89 /**
90 * Registers the specified component.
91 */
92 synchronized static void register(JComponent c) {
93 if (c == null) {
94 // Exception is thrown as convenience for callers that are
95 // typed to throw an NPE.
96 throw new NullPointerException("JComponent must be non-null");
97 }
98 components.add(new WeakReference(c));
99 }
100
101 /**
102 * Unregisters the specified component.
103 */
104 synchronized static void unregister(JComponent c) {
105 for (int counter = components.size() - 1; counter >= 0; counter--) {
106 // Search for the component, removing any flushed references
107 // along the way.
108 WeakReference ref = (WeakReference)components.get(counter);
109 Object target = ((WeakReference)components.get(counter)).get();
110
111 if (target == c || target == null) {
112 components.remove(counter);
113 }
114 }
115 }
116
117 /**
118 * Finds a previously registered component of class <code>target</code>
119 * that shares the JRootPane ancestor of <code>from</code>.
120 */
121 synchronized static Object findRegisteredComponentOfType(JComponent from,
122 Class target) {
123 JRootPane rp = SwingUtilities.getRootPane(from);
124 if (rp != null) {
125 for (int counter = components.size() - 1; counter >= 0; counter--){
126 Object component = ((WeakReference)components.get(counter)).
127 get();
128
129 if (component == null) {
130 // WeakReference has gone away, remove the WeakReference
131 components.remove(counter);
132 }
133 else if (target.isInstance(component) && SwingUtilities.
134 getRootPane((Component)component) == rp) {
135 return component;
136 }
137 }
138 }
139 return null;
140 }
141
142 /**
143 * Returns true if the passed in JMenuBar is above a horizontal
144 * JToolBar.
145 */
146 static boolean doesMenuBarBorderToolBar(JMenuBar c) {
147 JToolBar tb = (JToolBar)MetalToolBarUI.
148 findRegisteredComponentOfType(c, JToolBar.class);
149 if (tb != null && tb.getOrientation() == JToolBar.HORIZONTAL) {
150 JRootPane rp = SwingUtilities.getRootPane(c);
151 Point point = new Point(0, 0);
152 point = SwingUtilities.convertPoint(c, point, rp);
153 int menuX = point.x;
154 int menuY = point.y;
155 point.x = point.y = 0;
156 point = SwingUtilities.convertPoint(tb, point, rp);
157 return (point.x == menuX && menuY + c.getHeight() == point.y &&
158 c.getWidth() == tb.getWidth());
159 }
160 return false;
161 }
162
163 public static ComponentUI createUI( JComponent c )
164 {
165 return new MetalToolBarUI();
166 }
167
168 public void installUI( JComponent c )
169 {
170 super.installUI( c );
171 register(c);
172 }
173
174 public void uninstallUI( JComponent c )
175 {
176 super.uninstallUI( c );
177 nonRolloverBorder = null;
178 unregister(c);
179 }
180
181 protected void installListeners() {
182 super.installListeners();
183
184 contListener = createContainerListener();
185 if (contListener != null) {
186 toolBar.addContainerListener(contListener);
187 }
188 rolloverListener = createRolloverListener();
189 if (rolloverListener != null) {
190 toolBar.addPropertyChangeListener(rolloverListener);
191 }
192 }
193
194 protected void uninstallListeners() {
195 super.uninstallListeners();
196
197 if (contListener != null) {
198 toolBar.removeContainerListener(contListener);
199 }
200 rolloverListener = createRolloverListener();
201 if (rolloverListener != null) {
202 toolBar.removePropertyChangeListener(rolloverListener);
203 }
204 }
205
206 protected Border createRolloverBorder() {
207 return super.createRolloverBorder();
208 }
209
210 protected Border createNonRolloverBorder() {
211 return super.createNonRolloverBorder();
212 }
213
214
215 /**
216 * Creates a non rollover border for Toggle buttons in the toolbar.
217 */
218 private Border createNonRolloverToggleBorder() {
219 return createNonRolloverBorder();
220 }
221
222 protected void setBorderToNonRollover(Component c) {
223 if (c instanceof JToggleButton && !(c instanceof JCheckBox)) {
224 // 4735514, 4886944: The method createNonRolloverToggleBorder() is
225 // private in BasicToolBarUI so we can't override it. We still need
226 // to call super from this method so that it can save away the
227 // original border and then we install ours.
228
229 // Before calling super we get a handle to the old border, because
230 // super will install a non-UIResource border that we can't
231 // distinguish from one provided by an application.
232 JToggleButton b = (JToggleButton)c;
233 Border border = b.getBorder();
234 super.setBorderToNonRollover(c);
235 if (border instanceof UIResource) {
236 if (nonRolloverBorder == null) {
237 nonRolloverBorder = createNonRolloverToggleBorder();
238 }
239 b.setBorder(nonRolloverBorder);
240 }
241 } else {
242 super.setBorderToNonRollover(c);
243 }
244 }
245
246
247 /**
248 * Creates a container listener that will be added to the JToolBar.
249 * If this method returns null then it will not be added to the
250 * toolbar.
251 *
252 * @return an instance of a <code>ContainerListener</code> or null
253 */
254 protected ContainerListener createContainerListener() {
255 return null;
256 }
257
258 /**
259 * Creates a property change listener that will be added to the JToolBar.
260 * If this method returns null then it will not be added to the
261 * toolbar.
262 *
263 * @return an instance of a <code>PropertyChangeListener</code> or null
264 */
265 protected PropertyChangeListener createRolloverListener() {
266 return null;
267 }
268
269 protected MouseInputListener createDockingListener( )
270 {
271 return new MetalDockingListener( toolBar );
272 }
273
274 protected void setDragOffset(Point p) {
275 if (!GraphicsEnvironment.isHeadless()) {
276 if (dragWindow == null) {
277 dragWindow = createDragWindow(toolBar);
278 }
279 dragWindow.setOffset(p);
280 }
281 }
282
283 /**
284 * If necessary paints the background of the component, then invokes
285 * <code>paint</code>.
286 *
287 * @param g Graphics to paint to
288 * @param c JComponent painting on
289 * @throws NullPointerException if <code>g</code> or <code>c</code> is
290 * null
291 * @see javax.swing.plaf.ComponentUI#update
292 * @see javax.swing.plaf.ComponentUI#paint
293 * @since 1.5
294 */
295 public void update(Graphics g, JComponent c) {
296 if (g == null) {
297 throw new NullPointerException("graphics must be non-null");
298 }
299 if (c.isOpaque() && (c.getBackground() instanceof UIResource) &&
300 ((JToolBar)c).getOrientation() ==
301 JToolBar.HORIZONTAL && UIManager.get(
302 "MenuBar.gradient") != null) {
303 JRootPane rp = SwingUtilities.getRootPane(c);
304 JMenuBar mb = (JMenuBar)findRegisteredComponentOfType(
305 c, JMenuBar.class);
306 if (mb != null && mb.isOpaque() &&
307 (mb.getBackground() instanceof UIResource)) {
308 Point point = new Point(0, 0);
309 point = SwingUtilities.convertPoint(c, point, rp);
310 int x = point.x;
311 int y = point.y;
312 point.x = point.y = 0;
313 point = SwingUtilities.convertPoint(mb, point, rp);
314 if (point.x == x && y == point.y + mb.getHeight() &&
315 mb.getWidth() == c.getWidth() &&
316 MetalUtils.drawGradient(c, g, "MenuBar.gradient",
317 0, -mb.getHeight(), c.getWidth(), c.getHeight() +
318 mb.getHeight(), true)) {
319 setLastMenuBar(mb);
320 paint(g, c);
321 return;
322 }
323 }
324 if (MetalUtils.drawGradient(c, g, "MenuBar.gradient",
325 0, 0, c.getWidth(), c.getHeight(), true)) {
326 setLastMenuBar(null);
327 paint(g, c);
328 return;
329 }
330 }
331 setLastMenuBar(null);
332 super.update(g, c);
333 }
334
335 private void setLastMenuBar(JMenuBar lastMenuBar) {
336 if (MetalLookAndFeel.usingOcean()) {
337 if (this.lastMenuBar != lastMenuBar) {
338 // The menubar we previously touched has changed, force it
339 // to repaint.
340 if (this.lastMenuBar != null) {
341 this.lastMenuBar.repaint();
342 }
343 if (lastMenuBar != null) {
344 lastMenuBar.repaint();
345 }
346 this.lastMenuBar = lastMenuBar;
347 }
348 }
349 }
350
351 // No longer used. Cannot remove for compatibility reasons
352 protected class MetalContainerListener
353 extends BasicToolBarUI.ToolBarContListener {}
354
355 // No longer used. Cannot remove for compatibility reasons
356 protected class MetalRolloverListener
357 extends BasicToolBarUI.PropertyListener {}
358
359 protected class MetalDockingListener extends DockingListener {
360 private boolean pressedInBumps = false;
361
362 public MetalDockingListener(JToolBar t) {
363 super(t);
364 }
365
366 public void mousePressed(MouseEvent e) {
367 super.mousePressed(e);
368 if (!toolBar.isEnabled()) {
369 return;
370 }
371 pressedInBumps = false;
372 Rectangle bumpRect = new Rectangle();
373
374 if (toolBar.getOrientation() == JToolBar.HORIZONTAL) {
375 int x = MetalUtils.isLeftToRight(toolBar) ? 0 : toolBar.getSize().width-14;
376 bumpRect.setBounds(x, 0, 14, toolBar.getSize().height);
377 } else { // vertical
378 bumpRect.setBounds(0, 0, toolBar.getSize().width, 14);
379 }
380 if (bumpRect.contains(e.getPoint())) {
381 pressedInBumps = true;
382 Point dragOffset = e.getPoint();
383 if (!MetalUtils.isLeftToRight(toolBar)) {
384 dragOffset.x -= (toolBar.getSize().width
385 - toolBar.getPreferredSize().width);
386 }
387 setDragOffset(dragOffset);
388 }
389 }
390
391 public void mouseDragged(MouseEvent e) {
392 if (pressedInBumps) {
393 super.mouseDragged(e);
394 }
395 }
396 } // end class MetalDockingListener
397}