001 /*
002 * Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.swing.plaf.synth;
027
028 import java.awt.*;
029 import java.awt.event.*;
030 import java.io.Serializable;
031 import javax.swing.*;
032 import javax.swing.border.*;
033 import java.awt.*;
034 import java.awt.event.*;
035 import java.beans.*;
036 import javax.swing.plaf.*;
037 import javax.swing.plaf.basic.BasicButtonUI;
038 import javax.swing.plaf.basic.BasicHTML;
039 import javax.swing.text.View;
040 import sun.swing.plaf.synth.SynthUI;
041 import sun.swing.plaf.synth.DefaultSynthStyle;
042
043 /**
044 * Synth's ButtonUI implementation.
045 *
046 * @version 1.34, 05/05/07
047 * @author Scott Violet
048 */
049 class SynthButtonUI extends BasicButtonUI implements
050 PropertyChangeListener, SynthUI {
051 private SynthStyle style;
052
053 public static ComponentUI createUI(JComponent c) {
054 return new SynthButtonUI();
055 }
056
057 protected void installDefaults(AbstractButton b) {
058 updateStyle(b);
059
060 LookAndFeel.installProperty(b, "rolloverEnabled", Boolean.TRUE);
061 }
062
063 protected void installListeners(AbstractButton b) {
064 super .installListeners(b);
065 b.addPropertyChangeListener(this );
066 }
067
068 void updateStyle(AbstractButton b) {
069 SynthContext context = getContext(b, SynthConstants.ENABLED);
070 SynthStyle oldStyle = style;
071 style = SynthLookAndFeel.updateStyle(context, this );
072 if (style != oldStyle) {
073 if (b.getMargin() == null
074 || (b.getMargin() instanceof UIResource)) {
075 Insets margin = (Insets) style.get(context,
076 getPropertyPrefix() + "margin");
077
078 if (margin == null) {
079 // Some places assume margins are non-null.
080 margin = SynthLookAndFeel.EMPTY_UIRESOURCE_INSETS;
081 }
082 b.setMargin(margin);
083 }
084
085 Object value = style.get(context, getPropertyPrefix()
086 + "iconTextGap");
087 if (value != null) {
088 LookAndFeel.installProperty(b, "iconTextGap", value);
089 }
090
091 value = style.get(context, getPropertyPrefix()
092 + "contentAreaFilled");
093 LookAndFeel.installProperty(b, "contentAreaFilled",
094 value != null ? value : Boolean.TRUE);
095
096 if (oldStyle != null) {
097 uninstallKeyboardActions(b);
098 installKeyboardActions(b);
099 }
100
101 }
102 context.dispose();
103 }
104
105 protected void uninstallListeners(AbstractButton b) {
106 super .uninstallListeners(b);
107 b.removePropertyChangeListener(this );
108 }
109
110 protected void uninstallDefaults(AbstractButton b) {
111 SynthContext context = getContext(b, ENABLED);
112
113 style.uninstallDefaults(context);
114 context.dispose();
115 style = null;
116 }
117
118 public SynthContext getContext(JComponent c) {
119 return getContext(c, getComponentState(c));
120 }
121
122 SynthContext getContext(JComponent c, int state) {
123 Region region = getRegion(c);
124 return SynthContext.getContext(SynthContext.class, c, region,
125 style, state);
126 }
127
128 private Region getRegion(JComponent c) {
129 return SynthLookAndFeel.getRegion(c);
130 }
131
132 /**
133 * Returns the current state of the passed in <code>AbstractButton</code>.
134 */
135 private int getComponentState(JComponent c) {
136 int state = ENABLED;
137
138 if (!c.isEnabled()) {
139 state = DISABLED;
140 }
141 if (SynthLookAndFeel.selectedUI == this ) {
142 return SynthLookAndFeel.selectedUIState
143 | SynthConstants.ENABLED;
144 }
145 AbstractButton button = (AbstractButton) c;
146 ButtonModel model = button.getModel();
147
148 if (model.isPressed()) {
149 if (model.isArmed()) {
150 state = PRESSED;
151 } else {
152 state = MOUSE_OVER;
153 }
154 }
155 if (model.isRollover()) {
156 state |= MOUSE_OVER;
157 }
158 if (model.isSelected()) {
159 state |= SELECTED;
160 }
161 if (c.isFocusOwner() && button.isFocusPainted()) {
162 state |= FOCUSED;
163 }
164 if ((c instanceof JButton) && ((JButton) c).isDefaultButton()) {
165 state |= DEFAULT;
166 }
167 return state;
168 }
169
170 public int getBaseline(JComponent c, int width, int height) {
171 if (c == null) {
172 throw new NullPointerException("Component must be non-null");
173 }
174 if (width < 0 || height < 0) {
175 throw new IllegalArgumentException(
176 "Width and height must be >= 0");
177 }
178 AbstractButton b = (AbstractButton) c;
179 String text = b.getText();
180 if (text == null || "".equals(text)) {
181 return -1;
182 }
183 Insets i = b.getInsets();
184 Rectangle viewRect = new Rectangle();
185 Rectangle textRect = new Rectangle();
186 Rectangle iconRect = new Rectangle();
187 viewRect.x = i.left;
188 viewRect.y = i.top;
189 viewRect.width = width - (i.right + viewRect.x);
190 viewRect.height = height - (i.bottom + viewRect.y);
191
192 // layout the text and icon
193 SynthContext context = getContext(b);
194 FontMetrics fm = context.getComponent().getFontMetrics(
195 context.getStyle().getFont(context));
196 context.getStyle().getGraphicsUtils(context).layoutText(
197 context, fm, b.getText(), b.getIcon(),
198 b.getHorizontalAlignment(), b.getVerticalAlignment(),
199 b.getHorizontalTextPosition(),
200 b.getVerticalTextPosition(), viewRect, iconRect,
201 textRect, b.getIconTextGap());
202 View view = (View) b.getClientProperty(BasicHTML.propertyKey);
203 int baseline;
204 if (view != null) {
205 baseline = BasicHTML.getHTMLBaseline(view, textRect.width,
206 textRect.height);
207 if (baseline >= 0) {
208 baseline += textRect.y;
209 }
210 } else {
211 baseline = textRect.y + fm.getAscent();
212 }
213 context.dispose();
214 return baseline;
215 }
216
217 // ********************************
218 // Paint Methods
219 // ********************************
220
221 public void update(Graphics g, JComponent c) {
222 SynthContext context = getContext(c);
223
224 SynthLookAndFeel.update(context, g);
225 paintBackground(context, g, c);
226 paint(context, g);
227 context.dispose();
228 }
229
230 public void paint(Graphics g, JComponent c) {
231 SynthContext context = getContext(c);
232
233 paint(context, g);
234 context.dispose();
235 }
236
237 protected void paint(SynthContext context, Graphics g) {
238 AbstractButton b = (AbstractButton) context.getComponent();
239
240 g.setColor(context.getStyle().getColor(context,
241 ColorType.TEXT_FOREGROUND));
242 g.setFont(style.getFont(context));
243 context.getStyle().getGraphicsUtils(context).paintText(context,
244 g, b.getText(), getIcon(b), b.getHorizontalAlignment(),
245 b.getVerticalAlignment(),
246 b.getHorizontalTextPosition(),
247 b.getVerticalTextPosition(), b.getIconTextGap(),
248 b.getDisplayedMnemonicIndex(),
249 getTextShiftOffset(context));
250 }
251
252 void paintBackground(SynthContext context, Graphics g, JComponent c) {
253 if (((AbstractButton) c).isContentAreaFilled()) {
254 context.getPainter().paintButtonBackground(context, g, 0,
255 0, c.getWidth(), c.getHeight());
256 }
257 }
258
259 public void paintBorder(SynthContext context, Graphics g, int x,
260 int y, int w, int h) {
261 context.getPainter().paintButtonBorder(context, g, x, y, w, h);
262 }
263
264 /**
265 * Returns the default icon. This should NOT callback
266 * to the JComponent.
267 *
268 * @param b AbstractButton the iocn is associated with
269 * @return default icon
270 */
271
272 protected Icon getDefaultIcon(AbstractButton b) {
273 SynthContext context = getContext(b);
274 Icon icon = context.getStyle().getIcon(context,
275 getPropertyPrefix() + "icon");
276 context.dispose();
277 return icon;
278 }
279
280 /**
281 * Returns the Icon to use in painting the button.
282 */
283 protected Icon getIcon(AbstractButton b) {
284 Icon icon = b.getIcon();
285 ButtonModel model = b.getModel();
286
287 if (!model.isEnabled()) {
288 icon = getSynthDisabledIcon(b, icon);
289 } else if (model.isPressed() && model.isArmed()) {
290 icon = getPressedIcon(b, getSelectedIcon(b, icon));
291 } else if (b.isRolloverEnabled() && model.isRollover()) {
292 icon = getRolloverIcon(b, getSelectedIcon(b, icon));
293 } else if (model.isSelected()) {
294 icon = getSelectedIcon(b, icon);
295 } else {
296 icon = getEnabledIcon(b, icon);
297 }
298 if (icon == null) {
299 return getDefaultIcon(b);
300 }
301 return icon;
302 }
303
304 /**
305 * This method will return the icon that should be used for a button. We
306 * only want to use the synth icon defined by the style if the specific
307 * icon has not been defined for the button state and the backup icon is a
308 * UIResource (we set it, not the developer).
309 *
310 * @param b button
311 * @param specificIcon icon returned from the button for the specific state
312 * @param defaultIcon fallback icon
313 * @param state the synth state of the button
314 */
315 private Icon getIcon(AbstractButton b, Icon specificIcon,
316 Icon defaultIcon, int state) {
317 Icon icon = specificIcon;
318 if (icon == null) {
319 if (defaultIcon instanceof UIResource) {
320 icon = getSynthIcon(b, state);
321 if (icon == null) {
322 icon = defaultIcon;
323 }
324 } else {
325 icon = defaultIcon;
326 }
327 }
328 return icon;
329 }
330
331 private Icon getSynthIcon(AbstractButton b, int synthConstant) {
332 return style.getIcon(getContext(b, synthConstant),
333 getPropertyPrefix() + "icon");
334 }
335
336 private Icon getEnabledIcon(AbstractButton b, Icon defaultIcon) {
337 if (defaultIcon == null) {
338 defaultIcon = getSynthIcon(b, SynthConstants.ENABLED);
339 }
340 return defaultIcon;
341 }
342
343 private Icon getSelectedIcon(AbstractButton b, Icon defaultIcon) {
344 return getIcon(b, b.getSelectedIcon(), defaultIcon,
345 SynthConstants.SELECTED);
346 }
347
348 private Icon getRolloverIcon(AbstractButton b, Icon defaultIcon) {
349 ButtonModel model = b.getModel();
350 Icon icon;
351 if (model.isSelected()) {
352 icon = getIcon(b, b.getRolloverSelectedIcon(), defaultIcon,
353 SynthConstants.MOUSE_OVER | SynthConstants.SELECTED);
354 } else {
355 icon = getIcon(b, b.getRolloverIcon(), defaultIcon,
356 SynthConstants.MOUSE_OVER);
357 }
358 return icon;
359 }
360
361 private Icon getPressedIcon(AbstractButton b, Icon defaultIcon) {
362 return getIcon(b, b.getPressedIcon(), defaultIcon,
363 SynthConstants.PRESSED);
364 }
365
366 private Icon getSynthDisabledIcon(AbstractButton b, Icon defaultIcon) {
367 ButtonModel model = b.getModel();
368 Icon icon;
369 if (model.isSelected()) {
370 icon = getIcon(b, b.getDisabledSelectedIcon(), defaultIcon,
371 SynthConstants.DISABLED | SynthConstants.SELECTED);
372 } else {
373 icon = getIcon(b, b.getDisabledIcon(), defaultIcon,
374 SynthConstants.DISABLED);
375 }
376 return icon;
377 }
378
379 /**
380 * Returns the amount to shift the text/icon when painting.
381 */
382 protected int getTextShiftOffset(SynthContext state) {
383 AbstractButton button = (AbstractButton) state.getComponent();
384 ButtonModel model = button.getModel();
385
386 if (model.isArmed() && model.isPressed()
387 && button.getPressedIcon() == null) {
388 return state.getStyle().getInt(state,
389 getPropertyPrefix() + "textShiftOffset", 0);
390 }
391 return 0;
392 }
393
394 // ********************************
395 // Layout Methods
396 // ********************************
397 public Dimension getMinimumSize(JComponent c) {
398 if (c.getComponentCount() > 0 && c.getLayout() != null) {
399 return null;
400 }
401 AbstractButton b = (AbstractButton) c;
402 SynthContext ss = getContext(c);
403 Dimension size = ss.getStyle().getGraphicsUtils(ss)
404 .getMinimumSize(ss, ss.getStyle().getFont(ss),
405 b.getText(), getSizingIcon(b),
406 b.getHorizontalAlignment(),
407 b.getVerticalAlignment(),
408 b.getHorizontalTextPosition(),
409 b.getVerticalTextPosition(),
410 b.getIconTextGap(),
411 b.getDisplayedMnemonicIndex());
412
413 ss.dispose();
414 return size;
415 }
416
417 public Dimension getPreferredSize(JComponent c) {
418 if (c.getComponentCount() > 0 && c.getLayout() != null) {
419 return null;
420 }
421 AbstractButton b = (AbstractButton) c;
422 SynthContext ss = getContext(c);
423 Dimension size = ss.getStyle().getGraphicsUtils(ss)
424 .getPreferredSize(ss, ss.getStyle().getFont(ss),
425 b.getText(), getSizingIcon(b),
426 b.getHorizontalAlignment(),
427 b.getVerticalAlignment(),
428 b.getHorizontalTextPosition(),
429 b.getVerticalTextPosition(),
430 b.getIconTextGap(),
431 b.getDisplayedMnemonicIndex());
432
433 ss.dispose();
434 return size;
435 }
436
437 public Dimension getMaximumSize(JComponent c) {
438 if (c.getComponentCount() > 0 && c.getLayout() != null) {
439 return null;
440 }
441
442 AbstractButton b = (AbstractButton) c;
443 SynthContext ss = getContext(c);
444 Dimension size = ss.getStyle().getGraphicsUtils(ss)
445 .getMaximumSize(ss, ss.getStyle().getFont(ss),
446 b.getText(), getSizingIcon(b),
447 b.getHorizontalAlignment(),
448 b.getVerticalAlignment(),
449 b.getHorizontalTextPosition(),
450 b.getVerticalTextPosition(),
451 b.getIconTextGap(),
452 b.getDisplayedMnemonicIndex());
453
454 ss.dispose();
455 return size;
456 }
457
458 /**
459 * Returns the Icon used in calculating the pref/min/max size.
460 */
461 protected Icon getSizingIcon(AbstractButton b) {
462 // NOTE: this is slightly different than BasicButtonUI, where it
463 // would just use getIcon, but this should be ok.
464 Icon icon = (b.isEnabled()) ? b.getIcon() : b.getDisabledIcon();
465 if (icon == null) {
466 icon = getDefaultIcon(b);
467 }
468 return icon;
469 }
470
471 public void propertyChange(PropertyChangeEvent e) {
472 if (SynthLookAndFeel.shouldUpdateStyle(e)) {
473 updateStyle((AbstractButton) e.getSource());
474 }
475 }
476 }
|