KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > java > swing > plaf > windows > XPStyle


1 /*
2  * @(#)XPStyle.java 1.28 07/01/09
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 /*
9  * <p>These classes are designed to be used while the
10  * corresponding <code>LookAndFeel</code> class has been installed
11  * (<code>UIManager.setLookAndFeel(new <i>XXX</i>LookAndFeel())</code>).
12  * Using them while a different <code>LookAndFeel</code> is installed
13  * may produce unexpected results, including exceptions.
14  * Additionally, changing the <code>LookAndFeel</code>
15  * maintained by the <code>UIManager</code> without updating the
16  * corresponding <code>ComponentUI</code> of any
17  * <code>JComponent</code>s may also produce unexpected results,
18  * such as the wrong colors showing up, and is generally not
19  * encouraged.
20  *
21  */

22
23 package com.sun.java.swing.plaf.windows;
24
25 import java.awt.*;
26 import java.awt.image.*;
27 import java.io.*;
28 import java.security.AccessController JavaDoc;
29 import java.util.*;
30 import java.util.prefs.*;
31
32 import javax.swing.*;
33 import javax.swing.border.*;
34 import javax.swing.plaf.*;
35 import javax.swing.text.JTextComponent JavaDoc;
36
37 import sun.awt.windows.ThemeReader;
38 import sun.security.action.GetPropertyAction;
39 import sun.swing.CachedPainter;
40
41 import com.sun.java.swing.plaf.windows.TMSchema.*;
42
43 /**
44  * Implements Windows XP Styles for the Windows Look and Feel.
45  *
46  * @version 1.28 01/09/07
47  * @author Leif Samuelsson
48  */

49 class XPStyle {
50     // Singleton instance of this class
51
private static XPStyle xp;
52
53     // Singleton instance of SkinPainter
54
private static SkinPainter skinPainter = new SkinPainter();
55
56     private static Boolean JavaDoc themeActive = null;
57
58     private HashMap<String JavaDoc, Border> borderMap;
59     private HashMap<String JavaDoc, Color> colorMap;
60
61     private boolean flatMenus;
62
63     static {
64         invalidateStyle();
65     }
66
67     /** Static method for clearing the hashmap and loading the
68      * current XP style and theme
69      */

70     static synchronized void invalidateStyle() {
71         xp = null;
72         themeActive = null;
73     }
74
75     /** Get the singleton instance of this class
76      *
77      * @return the singleton instance of this class or null if XP styles
78      * are not active or if this is not Windows XP
79      */

80     static synchronized XPStyle getXP() {
81         if (themeActive == null) {
82             Toolkit toolkit = Toolkit.getDefaultToolkit();
83             themeActive =
84                 (Boolean JavaDoc)toolkit.getDesktopProperty("win.xpstyle.themeActive");
85             if (themeActive == null) {
86                 themeActive = Boolean.FALSE;
87             }
88             if (themeActive.booleanValue()) {
89                 GetPropertyAction propertyAction =
90                     new GetPropertyAction("swing.noxp");
91                 if (AccessController.doPrivileged(propertyAction) == null &&
92                     ThemeReader.isThemed() &&
93                     !(UIManager.getLookAndFeel()
94                       instanceof WindowsClassicLookAndFeel)) {
95
96                     xp = new XPStyle();
97                 }
98             }
99         }
100         return xp;
101     }
102
103
104
105     /** Get a named <code>String</code> value from the current style
106      *
107      * @param part a <code>Part</code>
108      * @param state a <code>String</code>
109      * @param attributeKey a <code>String</code>
110      * @return a <code>String</code> or null if key is not found
111      * in the current style
112      *
113      * This is currently only used by WindowsInternalFrameTitlePane for painting
114      * title foregound and can be removed when no longer needed
115      */

116     String JavaDoc getString(Component JavaDoc c, Part part, State state, Prop prop) {
117         return getTypeEnumName(c, part, state, prop);
118     }
119
120     private static String JavaDoc getTypeEnumName(Component JavaDoc c, Part part, State state, Prop prop) {
121         int enumValue = ThemeReader.getEnum(part.getControlName(c), part.getValue(),
122                                             State.getValue(part, state),
123                                             prop.getValue());
124         if (enumValue == -1) {
125             return null;
126         }
127         return TypeEnum.getTypeEnum(prop, enumValue).getName();
128     }
129
130
131
132
133     /** Get a named <code>int</code> value from the current style
134      *
135      * @param part a <code>Part</code>
136      * @return an <code>int</code> or null if key is not found
137      * in the current style
138      */

139     int getInt(Component JavaDoc c, Part part, State state, Prop prop, int fallback) {
140         return ThemeReader.getInt(part.getControlName(c), part.getValue(),
141                                   State.getValue(part, state),
142                                   prop.getValue());
143     }
144
145     /** Get a named <code>Dimension</code> value from the current style
146      *
147      * @param key a <code>String</code>
148      * @return a <code>Dimension</code> or null if key is not found
149      * in the current style
150      *
151      * This is currently only used by WindowsProgressBarUI and the value
152      * should probably be cached there instead of here.
153      */

154     Dimension getDimension(Component JavaDoc c, Part part, State state, Prop prop) {
155         return ThemeReader.getPosition(part.getControlName(c), part.getValue(),
156                                        State.getValue(part, state),
157                                        prop.getValue());
158     }
159
160     /** Get a named <code>Point</code> (e.g. a location or an offset) value
161      * from the current style
162      *
163      * @param key a <code>String</code>
164      * @return a <code>Point</code> or null if key is not found
165      * in the current style
166      *
167      * This is currently only used by WindowsInternalFrameTitlePane for painting
168      * title foregound and can be removed when no longer needed
169      */

170     Point getPoint(Component JavaDoc c, Part part, State state, Prop prop) {
171         Dimension d = ThemeReader.getPosition(part.getControlName(c), part.getValue(),
172                                               State.getValue(part, state),
173                                               prop.getValue());
174         if (d != null) {
175             return new Point(d.width, d.height);
176         } else {
177             return null;
178         }
179     }
180
181     /** Get a named <code>Insets</code> value from the current style
182      *
183      * @param key a <code>String</code>
184      * @return an <code>Insets</code> object or null if key is not found
185      * in the current style
186      *
187      * This is currently only used to create borders and by
188      * WindowsInternalFrameTitlePane for painting title foregound.
189      * The return value is already cached in those places.
190      */

191     Insets getMargin(Component JavaDoc c, Part part, State state, Prop prop) {
192         return ThemeReader.getThemeMargins(part.getControlName(c), part.getValue(),
193                                            State.getValue(part, state),
194                                            prop.getValue());
195     }
196
197
198     /** Get a named <code>Color</code> value from the current style
199      *
200      * @param part a <code>Part</code>
201      * @return a <code>Color</code> or null if key is not found
202      * in the current style
203      */

204     synchronized Color getColor(Skin skin, Prop prop, Color fallback) {
205         String JavaDoc key = skin.toString() + "." + prop.name();
206         Part part = skin.part;
207         Color color = colorMap.get(key);
208         if (color == null) {
209             color = ThemeReader.getColor(part.getControlName(null), part.getValue(),
210                                          State.getValue(part, skin.state),
211                                          prop.getValue());
212             if (color != null) {
213                 color = new ColorUIResource(color);
214                 colorMap.put(key, color);
215             }
216         }
217         return (color != null) ? color : fallback;
218     }
219
220     Color getColor(Component JavaDoc c, Part part, State state, Prop prop, Color fallback) {
221         return getColor(new Skin(c, part, state), prop, fallback);
222     }
223
224
225
226     /** Get a named <code>Border</code> value from the current style
227      *
228      * @param part a <code>Part</code>
229      * @return a <code>Border</code> or null if key is not found
230      * in the current style or if the style for the particular
231      * part is not defined as "borderfill".
232      */

233     synchronized Border getBorder(Component JavaDoc c, Part part) {
234         if (part == Part.MENU) {
235             // Special case because XP has no skin for menus
236
if (flatMenus) {
237                 // TODO: The classic border uses this color, but we should
238
// create a new UI property called "PopupMenu.borderColor"
239
// instead.
240
return new XPFillBorder(UIManager.getColor("InternalFrame.borderShadow"),
241                                         1);
242             } else {
243                 return null; // Will cause L&F to use classic border
244
}
245         }
246         Skin skin = new Skin(c, part, null);
247         Border border = borderMap.get(skin.string);
248         if (border == null) {
249             String JavaDoc bgType = getTypeEnumName(c, part, null, Prop.BGTYPE);
250             if ("borderfill".equalsIgnoreCase(bgType)) {
251                 int thickness = getInt(c, part, null, Prop.BORDERSIZE, 1);
252                 Color color = getColor(skin, Prop.BORDERCOLOR, Color.black);
253                 border = new XPFillBorder(color, thickness);
254             } else if ("imagefile".equalsIgnoreCase(bgType)) {
255                 Insets m = getMargin(c, part, null, Prop.SIZINGMARGINS);
256                 if (m != null) {
257                     if (getBoolean(c, part, null, Prop.BORDERONLY)) {
258                         border = new XPImageBorder(c, part);
259                     } else {
260                         if(part == Part.TP_BUTTON) {
261                             border = new XPEmptyBorder(new Insets(3,3,3,3));
262                         } else {
263                             border = new XPEmptyBorder(m);
264                         }
265                     }
266                 }
267             }
268             if (border != null) {
269                 borderMap.put(skin.string, border);
270             }
271         }
272         return border;
273     }
274
275     private class XPFillBorder extends LineBorder implements UIResource {
276         XPFillBorder(Color color, int thickness) {
277             super(color, thickness);
278         }
279
280         public Insets getBorderInsets(Component JavaDoc c) {
281             return getBorderInsets(c, new Insets(0,0,0,0));
282         }
283
284         public Insets getBorderInsets(Component JavaDoc c, Insets insets) {
285             Insets margin = null;
286             //
287
// Ideally we'd have an interface defined for classes which
288
// support margins (to avoid this hackery), but we've
289
// decided against it for simplicity
290
//
291
if (c instanceof AbstractButton) {
292                margin = ((AbstractButton)c).getMargin();
293            } else if (c instanceof JToolBar) {
294                margin = ((JToolBar)c).getMargin();
295            } else if (c instanceof JTextComponent JavaDoc) {
296                margin = ((JTextComponent JavaDoc)c).getMargin();
297            }
298            insets.top = (margin != null? margin.top : 0) + thickness;
299            insets.left = (margin != null? margin.left : 0) + thickness;
300            insets.bottom = (margin != null? margin.bottom : 0) + thickness;
301            insets.right = (margin != null? margin.right : 0) + thickness;
302                
303            return insets;
304         }
305     }
306
307     private class XPImageBorder extends AbstractBorder implements UIResource {
308         Skin skin;
309
310         XPImageBorder(Component JavaDoc c, Part part) {
311             this.skin = getSkin(c, part);
312         }
313
314         public void paintBorder(Component JavaDoc c, Graphics g,
315                                 int x, int y, int width, int height) {
316             skin.paintSkin(g, x, y, width, height, null);
317         }
318
319         public Insets getBorderInsets(Component JavaDoc c) {
320             return getBorderInsets(c, new Insets(0,0,0,0));
321         }
322
323         public Insets getBorderInsets(Component JavaDoc c, Insets insets) {
324             Insets margin = null;
325             Insets borderInsets = skin.getContentMargin();
326             //
327
// Ideally we'd have an interface defined for classes which
328
// support margins (to avoid this hackery), but we've
329
// decided against it for simplicity
330
//
331
if (c instanceof AbstractButton) {
332                margin = ((AbstractButton)c).getMargin();
333            } else if (c instanceof JToolBar) {
334                margin = ((JToolBar)c).getMargin();
335            } else if (c instanceof JTextComponent JavaDoc) {
336                margin = ((JTextComponent JavaDoc)c).getMargin();
337            }
338            insets.top = (margin != null? margin.top : 0) + borderInsets.top;
339            insets.left = (margin != null? margin.left : 0) + borderInsets.left;
340            insets.bottom = (margin != null? margin.bottom : 0) + borderInsets.bottom;
341            insets.right = (margin != null? margin.right : 0) + borderInsets.right;
342                
343            return insets;
344         }
345     }
346
347     private class XPEmptyBorder extends EmptyBorder implements UIResource {
348         XPEmptyBorder(Insets m) {
349             super(m.top+2, m.left+2, m.bottom+2, m.right+2);
350         }
351
352         public Insets getBorderInsets(Component JavaDoc c) {
353             return getBorderInsets(c, getBorderInsets());
354         }
355
356         public Insets getBorderInsets(Component JavaDoc c, Insets insets) {
357             insets = super.getBorderInsets(c, insets);
358                 
359             Insets margin = null;
360             if (c instanceof AbstractButton) {
361                 Insets m = ((AbstractButton)c).getMargin();
362                 // if this is a toolbar button then ignore getMargin()
363
// and subtract the padding added by the constructor
364
if(c.getParent() instanceof JToolBar
365                    && ! (c instanceof JRadioButton)
366                    && ! (c instanceof JCheckBox)
367                    && m instanceof InsetsUIResource) {
368                     insets.top -= 2;
369                     insets.left -= 2;
370                     insets.bottom -= 2;
371                     insets.right -= 2;
372                 } else {
373                     margin = m;
374                 }
375             } else if (c instanceof JToolBar) {
376                 margin = ((JToolBar)c).getMargin();
377             } else if (c instanceof JTextComponent JavaDoc) {
378                 margin = ((JTextComponent JavaDoc)c).getMargin();
379             }
380             if (margin != null) {
381                 insets.top = margin.top + 2;
382                 insets.left = margin.left + 2;
383                 insets.bottom = margin.bottom + 2;
384                 insets.right = margin.right + 2;
385             }
386             return insets;
387         }
388     }
389
390     boolean isSkinDefined(Component JavaDoc c, Part part) {
391         return (part.getValue() == 0)
392             || ThemeReader.isThemePartDefined(
393                    part.getControlName(c), part.getValue(), 0);
394     }
395
396     /** Get a <code>Skin</code> object from the current style
397      * for a named part (component type)
398      *
399      * @param part a <code>Part</code>
400      * @return a <code>Skin</code> object
401      */

402     synchronized Skin getSkin(Component JavaDoc c, Part part) {
403         assert isSkinDefined(c, part) : "part " + part + " is not defined";
404         return new Skin(c, part, null);
405     }
406
407
408
409
410     /** A class which encapsulates attributes for a given part
411      * (component type) and which provides methods for painting backgrounds
412      * and glyphs
413      */

414     static class Skin {
415         final Component JavaDoc component;
416         final Part part;
417         final State state;
418
419         private final String JavaDoc string;
420         private Dimension size = null;
421
422         Skin(Component JavaDoc component, Part part) {
423             this(component, part, null);
424         }
425
426         Skin(Part part, State state) {
427             this(null, part, state);
428         }
429
430         Skin(Component JavaDoc component, Part part, State state) {
431             this.component = component;
432             this.part = part;
433             this.state = state;
434
435             String JavaDoc str = part.getControlName(component) +"." + part.name();
436             if (state != null) {
437                 str += "("+state.name()+")";
438             }
439             string = str;
440         }
441
442         Insets getContentMargin() {
443             // This is only called by WindowsTableHeaderUI so far.
444
return ThemeReader.getThemeMargins(part.getControlName(null), part.getValue(),
445                                                0, Prop.SIZINGMARGINS.getValue());
446         }
447
448         private int getWidth(State state) {
449             if (size == null) {
450                 size = getPartSize(part, state);
451             }
452             return size.width;
453         }
454
455         int getWidth() {
456             return getWidth((state != null) ? state : State.NORMAL);
457         }
458
459         private int getHeight(State state) {
460             if (size == null) {
461                 size = getPartSize(part, state);
462             }
463             return size.height;
464         }
465
466         int getHeight() {
467             return getHeight((state != null) ? state : State.NORMAL);
468         }
469
470         public String JavaDoc toString() {
471             return string;
472         }
473
474         public boolean equals(Object JavaDoc obj) {
475             return (obj instanceof Skin && ((Skin)obj).string.equals(string));
476         }
477
478         public int hashCode() {
479             return string.hashCode();
480         }
481
482         /** Paint a skin at x, y.
483          *
484          * @param g the graphics context to use for painting
485          * @param dx the destination <i>x</i> coordinate.
486          * @param dy the destination <i>y</i> coordinate.
487          * @param state which state to paint
488          */

489         void paintSkin(Graphics g, int dx, int dy, State state) {
490             if (state == null) {
491                 state = this.state;
492             }
493             paintSkin(g, dx, dy, getWidth(state), getHeight(state), state);
494         }
495
496         /** Paint a skin in an area defined by a rectangle.
497          *
498          * @param g the graphics context to use for painting
499          * @param r a <code>Rectangle</code> defining the area to fill,
500          * may cause the image to be stretched or tiled
501          * @param state which state to paint
502          */

503         void paintSkin(Graphics g, Rectangle r, State state) {
504             paintSkin(g, r.x, r.y, r.width, r.height, state);
505         }
506
507         /** Paint a skin at a defined position and size
508          *
509          * @param g the graphics context to use for painting
510          * @param dx the destination <i>x</i> coordinate.
511          * @param dy the destination <i>y</i> coordinate.
512          * @param dw the width of the area to fill, may cause
513          * the image to be stretched or tiled
514          * @param dh the height of the area to fill, may cause
515          * the image to be stretched or tiled
516          * @param state which state to paint
517          */

518         void paintSkin(Graphics g, int dx, int dy, int dw, int dh, State state) {
519             skinPainter.paint(null, g, dx, dy, dw, dh, this, state);
520         }
521         /**
522          * Paint a skin at a defined position and size
523          *
524          * @param g the graphics context to use for painting
525          * @param dx the destination <i>x</i> coordinate
526          * @param dy the destination <i>y</i> coordinate
527          * @param dw the width of the area to fill, may cause
528          * the image to be stretched or tiled
529          * @param dh the height of the area to fill, may cause
530          * the image to be stretched or tiled
531          * @param state which state to paint
532          * @param borderFill should test if the component uses a border fill
533          * and skip painting if it is
534          */

535         void paintSkin(Graphics g, int dx, int dy, int dw, int dh, State state,
536                 boolean borderFill) {
537             if(borderFill && "borderfill".equals(getTypeEnumName(component, part,
538                     state, Prop.BGTYPE))) {
539                 return;
540             }
541             skinPainter.paint(null, g, dx, dy, dw, dh, this, state);
542         }
543     }
544
545     private static class SkinPainter extends CachedPainter {
546         SkinPainter() {
547             super(30);
548             flush();
549         }
550
551         protected void paintToImage(Component JavaDoc c, Image image, Graphics g,
552                                     int w, int h, Object JavaDoc[] args) {
553             Skin skin = (Skin)args[0];
554             Part part = skin.part;
555             State state = (State)args[1];
556             if (state == null) {
557                 state = skin.state;
558             }
559             if (c == null) {
560                 c = skin.component;
561             }
562             WritableRaster raster = ((BufferedImage)image).getRaster();
563             DataBufferInt buffer = (DataBufferInt)raster.getDataBuffer();
564             ThemeReader.paintBackground(buffer.getData(),
565                                         part.getControlName(c), part.getValue(),
566                                         State.getValue(part, state),
567                                         0, 0, w, h, w);
568         }
569
570         protected Image createImage(Component JavaDoc c, int w, int h,
571                                     GraphicsConfiguration config, Object JavaDoc[] args) {
572             return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
573         }
574     }
575
576     static class GlyphButton extends JButton {
577         private Skin skin;
578
579         public GlyphButton(Component JavaDoc parent, Part part) {
580             XPStyle xp = getXP();
581             skin = xp.getSkin(parent, part);
582             setBorder(null);
583             setContentAreaFilled(false);
584         }
585
586         public boolean isFocusTraversable() {
587             return false;
588         }
589
590         protected State getState() {
591             State state = State.NORMAL;
592             if (!isEnabled()) {
593                 state = State.DISABLED;
594             } else if (getModel().isPressed()) {
595                 state = State.PRESSED;
596             } else if (getModel().isRollover()) {
597                 state = State.HOT;
598             }
599             return state;
600         }
601
602         public void paintComponent(Graphics g) {
603             Dimension d = getSize();
604             skin.paintSkin(g, 0, 0, d.width, d.height, getState());
605         }
606
607         public void setPart(Component JavaDoc parent, Part part) {
608             XPStyle xp = getXP();
609             skin = xp.getSkin(parent, part);
610             revalidate();
611             repaint();
612         }
613
614         protected void paintBorder(Graphics g) {
615         }
616
617         public Dimension getPreferredSize() {
618             return new Dimension(16, 16);
619         }
620
621         public Dimension getMinimumSize() {
622             return new Dimension(5, 5);
623         }
624
625         public Dimension getMaximumSize() {
626             return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
627         }
628     }
629
630     // Private constructor
631
private XPStyle() {
632         flatMenus = getSysBoolean(Prop.FLATMENUS);
633
634         colorMap = new HashMap<String JavaDoc, Color>();
635         borderMap = new HashMap<String JavaDoc, Border>();
636         // Note: All further access to the maps must be synchronized
637
}
638
639
640     private boolean getBoolean(Component JavaDoc c, Part part, State state, Prop prop) {
641         return ThemeReader.getBoolean(part.getControlName(c), part.getValue(),
642                                       State.getValue(part, state),
643                                       prop.getValue());
644     }
645
646     private static Dimension getPartSize(Part part, State state) {
647         return ThemeReader.getPartSize(part.getControlName(null), part.getValue(),
648                                        State.getValue(part, state));
649     }
650
651     private static boolean getSysBoolean(Prop prop) {
652          // We can use any widget name here, I guess.
653
return ThemeReader.getSysBoolean("window", prop.getValue());
654     }
655 }
656
Popular Tags