001: /*
002: * Copyright 2002-2007 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: /*
027: * <p>These classes are designed to be used while the
028: * corresponding <code>LookAndFeel</code> class has been installed
029: * (<code>UIManager.setLookAndFeel(new <i>XXX</i>LookAndFeel())</code>).
030: * Using them while a different <code>LookAndFeel</code> is installed
031: * may produce unexpected results, including exceptions.
032: * Additionally, changing the <code>LookAndFeel</code>
033: * maintained by the <code>UIManager</code> without updating the
034: * corresponding <code>ComponentUI</code> of any
035: * <code>JComponent</code>s may also produce unexpected results,
036: * such as the wrong colors showing up, and is generally not
037: * encouraged.
038: *
039: */
040:
041: package com.sun.java.swing.plaf.windows;
042:
043: import java.awt.*;
044: import java.awt.image.*;
045: import java.security.AccessController;
046: import java.util.*;
047:
048: import javax.swing.*;
049: import javax.swing.border.*;
050: import javax.swing.plaf.*;
051: import javax.swing.text.JTextComponent;
052:
053: import sun.awt.image.SunWritableRaster;
054: import sun.awt.windows.ThemeReader;
055: import sun.security.action.GetPropertyAction;
056: import sun.swing.CachedPainter;
057:
058: import static com.sun.java.swing.plaf.windows.TMSchema.*;
059:
060: /**
061: * Implements Windows XP Styles for the Windows Look and Feel.
062: *
063: * @version 1.34 07/13/06
064: * @author Leif Samuelsson
065: */
066: class XPStyle {
067: // Singleton instance of this class
068: private static XPStyle xp;
069:
070: // Singleton instance of SkinPainter
071: private static SkinPainter skinPainter = new SkinPainter();
072:
073: private static Boolean themeActive = null;
074:
075: private HashMap<String, Border> borderMap;
076: private HashMap<String, Color> colorMap;
077:
078: private boolean flatMenus;
079:
080: static {
081: invalidateStyle();
082: }
083:
084: /** Static method for clearing the hashmap and loading the
085: * current XP style and theme
086: */
087: static synchronized void invalidateStyle() {
088: xp = null;
089: themeActive = null;
090: skinPainter.flush();
091: }
092:
093: /** Get the singleton instance of this class
094: *
095: * @return the singleton instance of this class or null if XP styles
096: * are not active or if this is not Windows XP
097: */
098: static synchronized XPStyle getXP() {
099: if (themeActive == null) {
100: Toolkit toolkit = Toolkit.getDefaultToolkit();
101: themeActive = (Boolean) toolkit
102: .getDesktopProperty("win.xpstyle.themeActive");
103: if (themeActive == null) {
104: themeActive = Boolean.FALSE;
105: }
106: if (themeActive.booleanValue()) {
107: GetPropertyAction propertyAction = new GetPropertyAction(
108: "swing.noxp");
109: if (AccessController.doPrivileged(propertyAction) == null
110: && ThemeReader.isThemed()
111: && !(UIManager.getLookAndFeel() instanceof WindowsClassicLookAndFeel)) {
112:
113: xp = new XPStyle();
114: }
115: }
116: }
117: return xp;
118: }
119:
120: static boolean isVista() {
121: XPStyle xp = XPStyle.getXP();
122: return (xp != null && xp.isSkinDefined(null,
123: Part.CP_DROPDOWNBUTTONRIGHT));
124: }
125:
126: /** Get a named <code>String</code> value from the current style
127: *
128: * @param part a <code>Part</code>
129: * @param state a <code>String</code>
130: * @param attributeKey a <code>String</code>
131: * @return a <code>String</code> or null if key is not found
132: * in the current style
133: *
134: * This is currently only used by WindowsInternalFrameTitlePane for painting
135: * title foregound and can be removed when no longer needed
136: */
137: String getString(Component c, Part part, State state, Prop prop) {
138: return getTypeEnumName(c, part, state, prop);
139: }
140:
141: TypeEnum getTypeEnum(Component c, Part part, State state, Prop prop) {
142: int enumValue = ThemeReader.getEnum(part.getControlName(c),
143: part.getValue(), State.getValue(part, state), prop
144: .getValue());
145: return TypeEnum.getTypeEnum(prop, enumValue);
146: }
147:
148: private static String getTypeEnumName(Component c, Part part,
149: State state, Prop prop) {
150: int enumValue = ThemeReader.getEnum(part.getControlName(c),
151: part.getValue(), State.getValue(part, state), prop
152: .getValue());
153: if (enumValue == -1) {
154: return null;
155: }
156: return TypeEnum.getTypeEnum(prop, enumValue).getName();
157: }
158:
159: /** Get a named <code>int</code> value from the current style
160: *
161: * @param part a <code>Part</code>
162: * @return an <code>int</code> or null if key is not found
163: * in the current style
164: */
165: int getInt(Component c, Part part, State state, Prop prop,
166: int fallback) {
167: return ThemeReader.getInt(part.getControlName(c), part
168: .getValue(), State.getValue(part, state), prop
169: .getValue());
170: }
171:
172: /** Get a named <code>Dimension</code> value from the current style
173: *
174: * @param key a <code>String</code>
175: * @return a <code>Dimension</code> or null if key is not found
176: * in the current style
177: *
178: * This is currently only used by WindowsProgressBarUI and the value
179: * should probably be cached there instead of here.
180: */
181: Dimension getDimension(Component c, Part part, State state,
182: Prop prop) {
183: return ThemeReader.getPosition(part.getControlName(c), part
184: .getValue(), State.getValue(part, state), prop
185: .getValue());
186: }
187:
188: /** Get a named <code>Point</code> (e.g. a location or an offset) value
189: * from the current style
190: *
191: * @param key a <code>String</code>
192: * @return a <code>Point</code> or null if key is not found
193: * in the current style
194: *
195: * This is currently only used by WindowsInternalFrameTitlePane for painting
196: * title foregound and can be removed when no longer needed
197: */
198: Point getPoint(Component c, Part part, State state, Prop prop) {
199: Dimension d = ThemeReader.getPosition(part.getControlName(c),
200: part.getValue(), State.getValue(part, state), prop
201: .getValue());
202: if (d != null) {
203: return new Point(d.width, d.height);
204: } else {
205: return null;
206: }
207: }
208:
209: /** Get a named <code>Insets</code> value from the current style
210: *
211: * @param key a <code>String</code>
212: * @return an <code>Insets</code> object or null if key is not found
213: * in the current style
214: *
215: * This is currently only used to create borders and by
216: * WindowsInternalFrameTitlePane for painting title foregound.
217: * The return value is already cached in those places.
218: */
219: Insets getMargin(Component c, Part part, State state, Prop prop) {
220: return ThemeReader.getThemeMargins(part.getControlName(c), part
221: .getValue(), State.getValue(part, state), prop
222: .getValue());
223: }
224:
225: /** Get a named <code>Color</code> value from the current style
226: *
227: * @param part a <code>Part</code>
228: * @return a <code>Color</code> or null if key is not found
229: * in the current style
230: */
231: synchronized Color getColor(Skin skin, Prop prop, Color fallback) {
232: String key = skin.toString() + "." + prop.name();
233: Part part = skin.part;
234: Color color = colorMap.get(key);
235: if (color == null) {
236: color = ThemeReader.getColor(part.getControlName(null),
237: part.getValue(), State.getValue(part, skin.state),
238: prop.getValue());
239: if (color != null) {
240: color = new ColorUIResource(color);
241: colorMap.put(key, color);
242: }
243: }
244: return (color != null) ? color : fallback;
245: }
246:
247: Color getColor(Component c, Part part, State state, Prop prop,
248: Color fallback) {
249: return getColor(new Skin(c, part, state), prop, fallback);
250: }
251:
252: /** Get a named <code>Border</code> value from the current style
253: *
254: * @param part a <code>Part</code>
255: * @return a <code>Border</code> or null if key is not found
256: * in the current style or if the style for the particular
257: * part is not defined as "borderfill".
258: */
259: synchronized Border getBorder(Component c, Part part) {
260: if (part == Part.MENU) {
261: // Special case because XP has no skin for menus
262: if (flatMenus) {
263: // TODO: The classic border uses this color, but we should
264: // create a new UI property called "PopupMenu.borderColor"
265: // instead.
266: return new XPFillBorder(UIManager
267: .getColor("InternalFrame.borderShadow"), 1);
268: } else {
269: return null; // Will cause L&F to use classic border
270: }
271: }
272: Skin skin = new Skin(c, part, null);
273: Border border = borderMap.get(skin.string);
274: if (border == null) {
275: String bgType = getTypeEnumName(c, part, null, Prop.BGTYPE);
276: if ("borderfill".equalsIgnoreCase(bgType)) {
277: int thickness = getInt(c, part, null, Prop.BORDERSIZE,
278: 1);
279: Color color = getColor(skin, Prop.BORDERCOLOR,
280: Color.black);
281: border = new XPFillBorder(color, thickness);
282: if (part == Part.CP_COMBOBOX) {
283: border = new XPStatefulFillBorder(color, thickness,
284: part, Prop.BORDERCOLOR);
285: }
286: } else if ("imagefile".equalsIgnoreCase(bgType)) {
287: Insets m = getMargin(c, part, null, Prop.SIZINGMARGINS);
288: if (m != null) {
289: if (getBoolean(c, part, null, Prop.BORDERONLY)) {
290: border = new XPImageBorder(c, part);
291: } else if (part == Part.CP_COMBOBOX) {
292: border = new EmptyBorder(1, 1, 1, 1);
293: } else {
294: if (part == Part.TP_BUTTON) {
295: border = new XPEmptyBorder(new Insets(3, 3,
296: 3, 3));
297: } else {
298: border = new XPEmptyBorder(m);
299: }
300: }
301: }
302: }
303: if (border != null) {
304: borderMap.put(skin.string, border);
305: }
306: }
307: return border;
308: }
309:
310: private class XPFillBorder extends LineBorder implements UIResource {
311: XPFillBorder(Color color, int thickness) {
312: super (color, thickness);
313: }
314:
315: public Insets getBorderInsets(Component c) {
316: return getBorderInsets(c, new Insets(0, 0, 0, 0));
317: }
318:
319: public Insets getBorderInsets(Component c, Insets insets) {
320: Insets margin = null;
321: //
322: // Ideally we'd have an interface defined for classes which
323: // support margins (to avoid this hackery), but we've
324: // decided against it for simplicity
325: //
326: if (c instanceof AbstractButton) {
327: margin = ((AbstractButton) c).getMargin();
328: } else if (c instanceof JToolBar) {
329: margin = ((JToolBar) c).getMargin();
330: } else if (c instanceof JTextComponent) {
331: margin = ((JTextComponent) c).getMargin();
332: }
333: insets.top = (margin != null ? margin.top : 0) + thickness;
334: insets.left = (margin != null ? margin.left : 0)
335: + thickness;
336: insets.bottom = (margin != null ? margin.bottom : 0)
337: + thickness;
338: insets.right = (margin != null ? margin.right : 0)
339: + thickness;
340:
341: return insets;
342: }
343: }
344:
345: private class XPStatefulFillBorder extends XPFillBorder {
346: private final Part part;
347: private final Prop prop;
348:
349: XPStatefulFillBorder(Color color, int thickness, Part part,
350: Prop prop) {
351: super (color, thickness);
352: this .part = part;
353: this .prop = prop;
354: }
355:
356: public void paintBorder(Component c, Graphics g, int x, int y,
357: int width, int height) {
358: State state = State.NORMAL;
359: // special casing for comboboxes.
360: // there may be more special cases in the future
361: if (c instanceof JComboBox) {
362: JComboBox cb = (JComboBox) c;
363: // note. in the future this should be replaced with a call
364: // to BasicLookAndFeel.getUIOfType()
365: if (cb.getUI() instanceof WindowsComboBoxUI) {
366: WindowsComboBoxUI wcb = (WindowsComboBoxUI) cb
367: .getUI();
368: state = wcb.getXPComboBoxState(cb);
369: }
370: }
371: lineColor = getColor(c, part, state, prop, Color.black);
372: super .paintBorder(c, g, x, y, width, height);
373: }
374: }
375:
376: private class XPImageBorder extends AbstractBorder implements
377: UIResource {
378: Skin skin;
379:
380: XPImageBorder(Component c, Part part) {
381: this .skin = getSkin(c, part);
382: }
383:
384: public void paintBorder(Component c, Graphics g, int x, int y,
385: int width, int height) {
386: skin.paintSkin(g, x, y, width, height, null);
387: }
388:
389: public Insets getBorderInsets(Component c) {
390: return getBorderInsets(c, new Insets(0, 0, 0, 0));
391: }
392:
393: public Insets getBorderInsets(Component c, Insets insets) {
394: Insets margin = null;
395: Insets borderInsets = skin.getContentMargin();
396: if (borderInsets == null) {
397: borderInsets = new Insets(0, 0, 0, 0);
398: }
399: //
400: // Ideally we'd have an interface defined for classes which
401: // support margins (to avoid this hackery), but we've
402: // decided against it for simplicity
403: //
404: if (c instanceof AbstractButton) {
405: margin = ((AbstractButton) c).getMargin();
406: } else if (c instanceof JToolBar) {
407: margin = ((JToolBar) c).getMargin();
408: } else if (c instanceof JTextComponent) {
409: margin = ((JTextComponent) c).getMargin();
410: }
411: insets.top = (margin != null ? margin.top : 0)
412: + borderInsets.top;
413: insets.left = (margin != null ? margin.left : 0)
414: + borderInsets.left;
415: insets.bottom = (margin != null ? margin.bottom : 0)
416: + borderInsets.bottom;
417: insets.right = (margin != null ? margin.right : 0)
418: + borderInsets.right;
419:
420: return insets;
421: }
422: }
423:
424: private class XPEmptyBorder extends EmptyBorder implements
425: UIResource {
426: XPEmptyBorder(Insets m) {
427: super (m.top + 2, m.left + 2, m.bottom + 2, m.right + 2);
428: }
429:
430: public Insets getBorderInsets(Component c) {
431: return getBorderInsets(c, getBorderInsets());
432: }
433:
434: public Insets getBorderInsets(Component c, Insets insets) {
435: insets = super .getBorderInsets(c, insets);
436:
437: Insets margin = null;
438: if (c instanceof AbstractButton) {
439: Insets m = ((AbstractButton) c).getMargin();
440: // if this is a toolbar button then ignore getMargin()
441: // and subtract the padding added by the constructor
442: if (c.getParent() instanceof JToolBar
443: && !(c instanceof JRadioButton)
444: && !(c instanceof JCheckBox)
445: && m instanceof InsetsUIResource) {
446: insets.top -= 2;
447: insets.left -= 2;
448: insets.bottom -= 2;
449: insets.right -= 2;
450: } else {
451: margin = m;
452: }
453: } else if (c instanceof JToolBar) {
454: margin = ((JToolBar) c).getMargin();
455: } else if (c instanceof JTextComponent) {
456: margin = ((JTextComponent) c).getMargin();
457: }
458: if (margin != null) {
459: insets.top = margin.top + 2;
460: insets.left = margin.left + 2;
461: insets.bottom = margin.bottom + 2;
462: insets.right = margin.right + 2;
463: }
464: return insets;
465: }
466: }
467:
468: boolean isSkinDefined(Component c, Part part) {
469: return (part.getValue() == 0)
470: || ThemeReader.isThemePartDefined(part
471: .getControlName(c), part.getValue(), 0);
472: }
473:
474: /** Get a <code>Skin</code> object from the current style
475: * for a named part (component type)
476: *
477: * @param part a <code>Part</code>
478: * @return a <code>Skin</code> object
479: */
480: synchronized Skin getSkin(Component c, Part part) {
481: assert isSkinDefined(c, part) : "part " + part
482: + " is not defined";
483: return new Skin(c, part, null);
484: }
485:
486: long getThemeTransitionDuration(Component c, Part part,
487: State stateFrom, State stateTo, Prop prop) {
488: return ThemeReader.getThemeTransitionDuration(part
489: .getControlName(c), part.getValue(), State.getValue(
490: part, stateFrom), State.getValue(part, stateTo),
491: (prop != null) ? prop.getValue() : 0);
492: }
493:
494: /** A class which encapsulates attributes for a given part
495: * (component type) and which provides methods for painting backgrounds
496: * and glyphs
497: */
498: static class Skin {
499: final Component component;
500: final Part part;
501: final State state;
502:
503: private final String string;
504: private Dimension size = null;
505:
506: Skin(Component component, Part part) {
507: this (component, part, null);
508: }
509:
510: Skin(Part part, State state) {
511: this (null, part, state);
512: }
513:
514: Skin(Component component, Part part, State state) {
515: this .component = component;
516: this .part = part;
517: this .state = state;
518:
519: String str = part.getControlName(component) + "."
520: + part.name();
521: if (state != null) {
522: str += "(" + state.name() + ")";
523: }
524: string = str;
525: }
526:
527: Insets getContentMargin() {
528: // This is only called by WindowsTableHeaderUI so far.
529: return ThemeReader.getThemeMargins(part
530: .getControlName(null), part.getValue(), 0,
531: Prop.SIZINGMARGINS.getValue());
532: }
533:
534: private int getWidth(State state) {
535: if (size == null) {
536: size = getPartSize(part, state);
537: }
538: return size.width;
539: }
540:
541: int getWidth() {
542: return getWidth((state != null) ? state : State.NORMAL);
543: }
544:
545: private int getHeight(State state) {
546: if (size == null) {
547: size = getPartSize(part, state);
548: }
549: return size.height;
550: }
551:
552: int getHeight() {
553: return getHeight((state != null) ? state : State.NORMAL);
554: }
555:
556: public String toString() {
557: return string;
558: }
559:
560: public boolean equals(Object obj) {
561: return (obj instanceof Skin && ((Skin) obj).string
562: .equals(string));
563: }
564:
565: public int hashCode() {
566: return string.hashCode();
567: }
568:
569: /** Paint a skin at x, y.
570: *
571: * @param g the graphics context to use for painting
572: * @param dx the destination <i>x</i> coordinate
573: * @param dy the destination <i>y</i> coordinate
574: * @param state which state to paint
575: */
576: void paintSkin(Graphics g, int dx, int dy, State state) {
577: if (state == null) {
578: state = this .state;
579: }
580: paintSkin(g, dx, dy, getWidth(state), getHeight(state),
581: state);
582: }
583:
584: /** Paint a skin in an area defined by a rectangle.
585: *
586: * @param g the graphics context to use for painting
587: * @param r a <code>Rectangle</code> defining the area to fill,
588: * may cause the image to be stretched or tiled
589: * @param state which state to paint
590: */
591: void paintSkin(Graphics g, Rectangle r, State state) {
592: paintSkin(g, r.x, r.y, r.width, r.height, state);
593: }
594:
595: /** Paint a skin at a defined position and size
596: * This method supports animation.
597: *
598: * @param g the graphics context to use for painting
599: * @param dx the destination <i>x</i> coordinate
600: * @param dy the destination <i>y</i> coordinate
601: * @param dw the width of the area to fill, may cause
602: * the image to be stretched or tiled
603: * @param dh the height of the area to fill, may cause
604: * the image to be stretched or tiled
605: * @param state which state to paint
606: */
607: void paintSkin(Graphics g, int dx, int dy, int dw, int dh,
608: State state) {
609: if (ThemeReader.isGetThemeTransitionDurationDefined()
610: && component instanceof JComponent
611: && SwingUtilities.getAncestorOfClass(
612: CellRendererPane.class, component) == null) {
613: AnimationController.paintSkin((JComponent) component,
614: this , g, dx, dy, dw, dh, state);
615: } else {
616: paintSkinRaw(g, dx, dy, dw, dh, state);
617: }
618: }
619:
620: /** Paint a skin at a defined position and size. This method
621: * does not trigger animation. It is needed for the animation
622: * support.
623: *
624: * @param g the graphics context to use for painting
625: * @param dx the destination <i>x</i> coordinate.
626: * @param dy the destination <i>y</i> coordinate.
627: * @param dw the width of the area to fill, may cause
628: * the image to be stretched or tiled
629: * @param dh the height of the area to fill, may cause
630: * the image to be stretched or tiled
631: * @param state which state to paint
632: */
633: void paintSkinRaw(Graphics g, int dx, int dy, int dw, int dh,
634: State state) {
635: skinPainter.paint(null, g, dx, dy, dw, dh, this , state);
636: }
637:
638: /** Paint a skin at a defined position and size
639: *
640: * @param g the graphics context to use for painting
641: * @param dx the destination <i>x</i> coordinate
642: * @param dy the destination <i>y</i> coordinate
643: * @param dw the width of the area to fill, may cause
644: * the image to be stretched or tiled
645: * @param dh the height of the area to fill, may cause
646: * the image to be stretched or tiled
647: * @param state which state to paint
648: * @param borderFill should test if the component uses a border fill
649: and skip painting if it is
650: */
651: void paintSkin(Graphics g, int dx, int dy, int dw, int dh,
652: State state, boolean borderFill) {
653: if (borderFill
654: && "borderfill".equals(getTypeEnumName(component,
655: part, state, Prop.BGTYPE))) {
656: return;
657: }
658: skinPainter.paint(null, g, dx, dy, dw, dh, this , state);
659: }
660: }
661:
662: private static class SkinPainter extends CachedPainter {
663: SkinPainter() {
664: super (30);
665: flush();
666: }
667:
668: public void flush() {
669: super .flush();
670: }
671:
672: protected void paintToImage(Component c, Image image,
673: Graphics g, int w, int h, Object[] args) {
674: boolean accEnabled = false;
675: Skin skin = (Skin) args[0];
676: Part part = skin.part;
677: State state = (State) args[1];
678: if (state == null) {
679: state = skin.state;
680: }
681: if (c == null) {
682: c = skin.component;
683: }
684: BufferedImage bi = (BufferedImage) image;
685:
686: WritableRaster raster = bi.getRaster();
687: DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
688: // Note that stealData() requires a markDirty() afterwards
689: // since we modify the data in it.
690: ThemeReader.paintBackground(SunWritableRaster.stealData(
691: dbi, 0), part.getControlName(c), part.getValue(),
692: State.getValue(part, state), 0, 0, w, h, w);
693: SunWritableRaster.markDirty(dbi);
694: }
695:
696: protected Image createImage(Component c, int w, int h,
697: GraphicsConfiguration config, Object[] args) {
698: return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
699: }
700: }
701:
702: static class GlyphButton extends JButton {
703: private Skin skin;
704:
705: public GlyphButton(Component parent, Part part) {
706: XPStyle xp = getXP();
707: skin = xp.getSkin(parent, part);
708: setBorder(null);
709: setContentAreaFilled(false);
710: setMinimumSize(new Dimension(5, 5));
711: setPreferredSize(new Dimension(16, 16));
712: setMaximumSize(new Dimension(Integer.MAX_VALUE,
713: Integer.MAX_VALUE));
714: }
715:
716: public boolean isFocusTraversable() {
717: return false;
718: }
719:
720: protected State getState() {
721: State state = State.NORMAL;
722: if (!isEnabled()) {
723: state = State.DISABLED;
724: } else if (getModel().isPressed()) {
725: state = State.PRESSED;
726: } else if (getModel().isRollover()) {
727: state = State.HOT;
728: }
729: return state;
730: }
731:
732: public void paintComponent(Graphics g) {
733: Dimension d = getSize();
734: skin.paintSkin(g, 0, 0, d.width, d.height, getState());
735: }
736:
737: public void setPart(Component parent, Part part) {
738: XPStyle xp = getXP();
739: skin = xp.getSkin(parent, part);
740: revalidate();
741: repaint();
742: }
743:
744: protected void paintBorder(Graphics g) {
745: }
746:
747: }
748:
749: // Private constructor
750: private XPStyle() {
751: flatMenus = getSysBoolean(Prop.FLATMENUS);
752:
753: colorMap = new HashMap<String, Color>();
754: borderMap = new HashMap<String, Border>();
755: // Note: All further access to the maps must be synchronized
756: }
757:
758: private boolean getBoolean(Component c, Part part, State state,
759: Prop prop) {
760: return ThemeReader.getBoolean(part.getControlName(c), part
761: .getValue(), State.getValue(part, state), prop
762: .getValue());
763: }
764:
765: static Dimension getPartSize(Part part, State state) {
766: return ThemeReader.getPartSize(part.getControlName(null), part
767: .getValue(), State.getValue(part, state));
768: }
769:
770: private static boolean getSysBoolean(Prop prop) {
771: // We can use any widget name here, I guess.
772: return ThemeReader.getSysBoolean("window", prop.getValue());
773: }
774: }
|