KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > java > swing > plaf > gtk > GTKStyle


1 /*
2  * @(#)GTKStyle.java 1.116 04/06/24
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package com.sun.java.swing.plaf.gtk;
8
9 import com.sun.java.swing.SwingUtilities2;
10 import javax.swing.plaf.synth.*;
11 import java.awt.*;
12 import java.awt.image.BufferedImage JavaDoc;
13 import java.awt.image.RescaleOp JavaDoc;
14 import java.lang.reflect.*;
15 import javax.swing.*;
16 import javax.swing.plaf.*;
17 import java.util.*;
18 import java.security.*;
19
20 import sun.swing.plaf.synth.*;
21 import sun.awt.AppContext;
22
23 /**
24  * SynthStyle implementation used in GTK. All painting is mapped to
25  * a <code>GTKEngine</code>.
26  *
27  * @version 1.116, 06/24/04
28  * @author Scott Violet
29  */

30 public class GTKStyle extends DefaultSynthStyle implements GTKConstants {
31     private static final String JavaDoc ICON_PROPERTY_PREFIX = "gtk.icon.";
32
33     static final Color BLACK_COLOR = new ColorUIResource(Color.BLACK);
34     static final Color WHITE_COLOR = new ColorUIResource(Color.WHITE);
35
36     private static final Color[][] DEFAULT_COLORS;
37     /**
38      * State the color array at an particular index in DEFAULT_COLORS
39      * represents.
40      */

41     private static final int[] DEFAULT_COLOR_MAP;
42     // NOTE: This will only be used if you weren't using GTKLookAndFeel
43
// to create a GTKStyle, otherwise the default comes from GTKLookAndFeel.
44
private static final Font DEFAULT_FONT = new FontUIResource(
45                                          "sansserif", Font.PLAIN, 10);
46     /**
47      * Backing style properties that are used if the style does not
48      * defined the property.
49      */

50     // PENDING: This needs to be massaged so that it does not need to
51
// be AppContext specific. In particular some of the Map values are
52
// exposed and mutable and could effect other applets.
53
private static final HashMap DATA = new HashMap();
54
55     /**
56      * Maps from a key that is passed to Style.get to the equivalent class
57      * specific key.
58      */

59     private static final HashMap CLASS_SPECIFIC_MAP;
60
61     private static final GTKGraphicsUtils GTK_GRAPHICS =new GTKGraphicsUtils();
62
63     /**
64      * Indicates the thickness has not been set.
65      */

66     static final int UNDEFINED_THICKNESS = -1;
67
68     // NOTE: If you add a new field to this class you will need to update
69
// addto, and possibly the clone and GTKStyle(GTKStyle) constructors.
70
private int xThickness = 2;
71     private int yThickness = 2;
72
73     /**
74      * Represents the values that are specific to a particular class.
75      * This is a CircularIdentityList of CircularIdentityLists, where the
76      * first level entries are gtk class names, and the second
77      * CircularIdentityLists contains the actual key/value pairs.
78      */

79     private CircularIdentityList classSpecificValues;
80     
81     /**
82      * Icons.
83      */

84     private GTKStockIconInfo[] icons;
85
86     /**
87      * Calculates the LIGHT color from the background color.
88      */

89     static Color calculateLightColor(Color bg) {
90         return GTKColorType.adjustColor(bg, 1.0f, 1.3f, 1.3f);
91     }
92
93     /**
94      * Calculates the DARK color from the background color.
95      */

96     static Color calculateDarkColor(Color bg) {
97         return GTKColorType.adjustColor(bg, 1.0f, .7f, .7f);
98     }
99
100     /**
101      * Calculates the MID color from the light and dark colors.
102      */

103     static Color calculateMidColor(Color lightColor, Color darkColor) {
104         int light = lightColor.getRGB();
105         int dark = darkColor.getRGB();
106         int rLight = (light & 0xFF0000) >> 16;
107         int rDark = (dark & 0xFF0000) >> 16;
108         int gLight = (light & 0x00FF00) >> 8;
109         int gDark = (dark & 0x00FF00) >> 8;
110         int bLight = (light & 0xFF);
111         int bDark = (dark & 0xFF);
112         return new ColorUIResource((((rLight + rDark) / 2) << 16) |
113                                    (((gLight + gDark) / 2) << 8) |
114                                    ((bLight + bDark) / 2));
115     }
116
117     /**
118      * Calculates the MID color from the background color.
119      */

120     static Color calculateMidColor(Color bg) {
121         return calculateMidColor(calculateLightColor(bg),
122                                  calculateDarkColor(bg));
123     }
124
125     /**
126      * Creates an array of colors populated based on the passed in
127      * the background color. Specifically this sets the
128      * BACKGROUND, LIGHT, DARK, MID, BLACK, WHITE and FOCUS colors
129      * from that of color, which is assumed to be the background.
130      */

131     static Color[] getColorsFrom(Color bg, Color fg) {
132         Color lightColor = calculateLightColor(bg);
133         Color darkColor = calculateDarkColor(bg);
134         Color midColor = calculateMidColor(lightColor, darkColor);
135         Color[] colors = new Color[GTKColorType.MAX_COUNT];
136         colors[GTKColorType.BACKGROUND.getID()] = bg;
137         colors[GTKColorType.LIGHT.getID()] = lightColor;
138         colors[GTKColorType.DARK.getID()] = darkColor;
139         colors[GTKColorType.MID.getID()] = midColor;
140         colors[GTKColorType.BLACK.getID()] = BLACK_COLOR;
141         colors[GTKColorType.WHITE.getID()] = WHITE_COLOR;
142         colors[GTKColorType.FOCUS.getID()] = BLACK_COLOR;
143         colors[GTKColorType.FOREGROUND.getID()] = fg;
144         colors[GTKColorType.TEXT_FOREGROUND.getID()] = fg;
145         colors[GTKColorType.TEXT_BACKGROUND.getID()] = WHITE_COLOR;
146         return colors;
147     }
148
149     /**
150      * Creates a new GTKStyle that is a copy of the passed in style.
151      */

152     public GTKStyle(DefaultSynthStyle style) {
153         super(style);
154         if (style instanceof GTKStyle) {
155             GTKStyle gStyle = (GTKStyle)style;
156             xThickness = gStyle.xThickness;
157             yThickness = gStyle.yThickness;
158             icons = gStyle.icons;
159             classSpecificValues = cloneClassSpecificValues(
160                                        gStyle.classSpecificValues);
161         }
162     }
163
164     /**
165      * Creates an empty GTKStyle.
166      */

167     public GTKStyle() {
168         super(new Insets(-1, -1, -1, -1), true, null, null);
169     }
170
171     /**
172      * Creates a GTKStyle with the specified font.
173      *
174      * @param font Font to use in GTK.
175      */

176     public GTKStyle(Font font) {
177         this();
178         setFont(font);
179     }
180
181     /**
182      * Creates a GTKStyle with the specified parameters.
183      *
184      * @param states StateInfo specifying the colors and fonts to use for
185      * a particular state.
186      * @param classSpecificValues Values that are specific to a particular
187      * class
188      * @param font to use.
189      * @param xThickness X thickness
190      * @param yThickness Y thickness
191      * @param GTKStockIconInfo stock icons for this style.
192      */

193     GTKStyle(StateInfo[] states,
194                     CircularIdentityList classSpecificValues,
195                     Font font,
196                     int xThickness, int yThickness,
197                     GTKStockIconInfo[] icons) {
198         super(new Insets(-1, -1, -1, -1), true, states, null);
199         setFont(font);
200         this.xThickness = xThickness;
201         this.yThickness = yThickness;
202         this.icons = icons;
203         this.classSpecificValues = classSpecificValues;
204     }
205
206     /**
207      * {@inheritDoc}
208      */

209     public void installDefaults(SynthContext context) {
210         super.installDefaults(context);
211         if (!context.getRegion().isSubregion()) {
212             context.getComponent().putClientProperty(
213                 SwingUtilities2.AA_TEXT_PROPERTY_KEY,
214                 GTKLookAndFeel.aaText);
215         }
216     }
217
218     public SynthGraphicsUtils getGraphicsUtils(SynthContext context) {
219         return GTK_GRAPHICS;
220     }
221
222     /**
223      * Returns the object used to renderer the look.
224      *
225      * @param context SynthContext indentifying requestor
226      * @return GTKEngine used to provide the look
227      */

228     public GTKEngine getEngine(SynthContext context) {
229         GTKEngine engine = (GTKEngine)get(context, "engine");
230
231         if (engine == null) {
232             return GTKEngine.INSTANCE;
233         }
234         return engine;
235     }
236
237     /**
238      * Returns a <code>SynthPainter</code> that will route the appropriate
239      * calls to a <code>GTKEngine</code>.
240      *
241      * @param state SynthContext indentifying requestor
242      * @return SynthPainter
243      */

244     public SynthPainter getPainter(SynthContext state) {
245         return GTKPainter.INSTANCE;
246     }
247
248     /**
249      * Returns the Insets. If <code>to</code> is non-null the resulting
250      * insets will be placed in it, otherwise a new Insets object will be
251      * created and returned.
252      *
253      * @param context SynthContext indentifying requestor
254      * @param to Where to place Insets
255      * @return Insets.
256      */

257     public Insets getInsets(SynthContext state, Insets insets) {
258         insets = super.getInsets(state, insets);
259
260         if (insets.top == -1) {
261             insets.left = insets.right = insets.top = insets.bottom = 0;
262             insets = GTKPainter.INSTANCE.getInsets(state, insets);
263         }
264         return insets;
265     }
266
267     /**
268      * Returns the value for a class specific property. A class specific value
269      * is a value that will be picked up based on class hierarchy.
270      * For example, a value specified for JComponent would be inherited on
271      * JButtons and JTrees, but not Button.
272      * <p>
273      * Note, the key used here should only contain the letters A-Z, a-z, the
274      * digits 0-9, and the '-' character. If you need to request a value for
275      * a key having characters outside this list, replace any other characters
276      * with '-'. (ie. "default_border" should be "default-border").
277      *
278      * @param region Region requesting class specific value
279      * @param key Key identifying class specific value
280      * @return Value, or null if one has not been defined.
281      */

282     public Object JavaDoc getClassSpecificValue(Region region, String JavaDoc key) {
283         if (classSpecificValues != null) {
284             String JavaDoc gtkClass = GTKStyleFactory.gtkClassFor(region);
285
286             while (gtkClass != null) {
287                 CircularIdentityList classValues = (CircularIdentityList)
288                                 classSpecificValues.get(gtkClass);
289
290                 if (classValues != null) {
291                     Object JavaDoc value = classValues.get(key);
292
293                     if (value != null) {
294                         return value;
295                     }
296                 }
297                 gtkClass = GTKStyleFactory.gtkSuperclass(gtkClass);
298             }
299         }
300         return null;
301     }
302
303     /**
304      * Returns the value for a class specific property. A class specific value
305      * is a value that will be picked up based on class hierarchy.
306      * For example, a value specified for JComponent would be inherited on
307      * JButtons and JTrees, but not Button.
308      * <p>
309      * Note, the key used here should only contain the letters A-Z, a-z, the
310      * digits 0-9, and the '-' character. If you need to request a value for
311      * a key having characters outside this list, replace any other characters
312      * with '-'. (ie. "default_border" should be "default-border").
313      *
314      * @param context SynthContext indentifying requestor
315      * @param key Key identifying class specific value
316      * @return Value, or null if one has not been defined.
317      */

318     public Object JavaDoc getClassSpecificValue(SynthContext context, String JavaDoc key) {
319         return getClassSpecificValue(context.getRegion(), key);
320     }
321     
322     /**
323      * Convenience method to get a class specific integer value.
324      *
325      * @param context SynthContext indentifying requestor
326      * @param key Key identifying class specific value
327      * @param defaultValue Returned if there is no value for the specified
328      * type
329      * @return Value, or defaultValue if <code>key</code> is not defined
330      */

331     public int getClassSpecificIntValue(SynthContext context, String JavaDoc key,
332                                            int defaultValue) {
333         Object JavaDoc value = getClassSpecificValue(context, key);
334
335         if (value instanceof Number JavaDoc) {
336             return ((Number JavaDoc)value).intValue();
337         }
338         return defaultValue;
339     }
340
341     /**
342      * Convenience method to get a class specific Insets value.
343      *
344      * @param context SynthContext indentifying requestor
345      * @param key Key identifying class specific value
346      * @param defaultValue Returned if there is no value for the specified
347      * type
348      * @return Value, or defaultValue if <code>key</code> is not defined
349      */

350     public Insets getClassSpecificInsetsValue(SynthContext context, String JavaDoc key,
351                                               Insets defaultValue) {
352         Object JavaDoc value = getClassSpecificValue(context, key);
353
354         if (value instanceof Insets) {
355             return (Insets)value;
356         }
357         return defaultValue;
358     }
359
360     /**
361      * Convenience method to get a class specific Boolean value.
362      *
363      * @param context SynthContext indentifying requestor
364      * @param key Key identifying class specific value
365      * @param defaultValue Returned if there is no value for the specified
366      * type
367      * @return Value, or defaultValue if <code>key</code> is not defined
368      */

369     public boolean getClassSpecificBoolValue(SynthContext context, String JavaDoc key,
370                                              boolean defaultValue) {
371         Object JavaDoc value = getClassSpecificValue(context, key);
372
373         if (value instanceof Boolean JavaDoc) {
374             return ((Boolean JavaDoc)value).booleanValue();
375         }
376         return defaultValue;
377     }
378
379     public Object JavaDoc getDefaultValue(SynthContext context, Object JavaDoc key) {
380         // See if this is a class specific value.
381
Object JavaDoc classKey = CLASS_SPECIFIC_MAP.get(key);
382         Object JavaDoc value = null;
383
384         if (classKey != null) {
385             value = getClassSpecificValue(context, (String JavaDoc)classKey);
386             if (value != null) {
387                 return value;
388             }
389         }
390             
391         if (key == "ScrollPane.viewportBorderInsets") {
392             return GTKPainter.INSTANCE.getScrollPaneInsets(context,
393                                                      new Insets(0,0,0,0));
394         } else if (key == "Slider.tickColor") {
395             return getColor(context.getComponent(), context.getRegion(),
396                             context.getComponentState(), ColorType.FOREGROUND);
397         }
398         synchronized (DATA) {
399             value = DATA.get(key);
400         }
401         if (value instanceof StyleSpecificValue) {
402             put(key, ((StyleSpecificValue)value).getValue(context));
403         }
404         if (value == null && key != "engine") {
405             // For backward compatability we'll fallback to the UIManager.
406
// We don't go to the UIManager for engine as the engine is GTK
407
// specific.
408
value = UIManager.get(key);
409             if (key == "Table.rowHeight") {
410                 int focusLineWidth = getClassSpecificIntValue(
411                          context, "focus-line-width", 0);
412                 if (value == null && focusLineWidth > 0) {
413                     value = new Integer JavaDoc(16 + 2 * focusLineWidth);
414                 }
415             }
416         }
417         // Don't call super, we don't want to pick up defaults from
418
// SynthStyle.
419
return value;
420     }
421
422     /**
423      * Returns the font for the specified state. This should NOT callback
424      * to the JComponent.
425      *
426      * @param c JComponent the style is associated with
427      * @param id Region identifier
428      * @param state State of the region.
429      * @return Font to render with
430      */

431     protected Font getFontForState(JComponent c, Region id, int state) {
432         state = GTKLookAndFeel.synthStateToGTKState(id, state);
433
434         Font f = super.getFontForState(c, id, state);
435
436         if (f == null) {
437             return DEFAULT_FONT;
438         }
439         return f;
440     }
441
442     Color getGTKColor(int state, ColorType type) {
443         return getGTKColor(null, null, state, type);
444     }
445
446     /**
447      * This method is to be used from within GTK when do NOT want
448      * the component state to be mapped. It will NOT remap the state as
449      * the other various getters do.
450      *
451      * @param c JComponent the style is associated with
452      * @param id Region identifier
453      * @param state State of the region.
454      * @param type Type of color being requested.
455      * @return Color to render with
456      */

457     public Color getGTKColor(JComponent c, Region id,
458                       int state, ColorType type) {
459         // NOTE: c and id are only ever null when this is called from
460
// GTKLookAndFeel.loadSystemColorDefaults.
461
if (c != null && id != null) {
462             if (!id.isSubregion() &&
463                 (state & SynthConstants.ENABLED) == SynthConstants.ENABLED) {
464                 if (type == ColorType.BACKGROUND) {
465                     Color bg = c.getBackground();
466                     if (!(bg instanceof UIResource)) {
467                         return bg;
468                     }
469                 }
470                 else if (type == ColorType.FOREGROUND) {
471                     Color fg = c.getForeground();
472                     if (!(fg instanceof UIResource)) {
473                         return fg;
474                     }
475                 }
476                 else if (type == ColorType.TEXT_FOREGROUND) {
477                     Color fg = c.getForeground();
478                     if (!(fg instanceof UIResource)) {
479                         return fg;
480                     }
481                 }
482                 else if (type == ColorType.TEXT_BACKGROUND) {
483                     Color bg = c.getBackground();
484                     if (!(bg instanceof UIResource)) {
485                         return bg;
486                     }
487                 }
488             }
489         }
490         Color color = super.getColorForState(c, id, state, type);
491         if (color != null) {
492             return color;
493         }
494         return getDefaultColor(c, id, state, type);
495     }
496
497     /**
498      * getColor is overriden to map the state from a Synth state to the
499      * GTK state, this should be not used when you have already mapped the
500      * state. Additionally this will map TEXT_FOREGROUND to the
501      * <code>c.getForeground()</code> if it is non-null and not a UIResource.
502      *
503      * @param c JComponent the style is associated with
504      * @param id Region identifier
505      * @param state State of the region.
506      * @param type Type of color being requested.
507      * @return Color to render with
508      */

509     public Color getColor(JComponent c, Region id, int state,
510                           ColorType type) {
511         if (id == Region.LABEL && type == ColorType.TEXT_FOREGROUND) {
512             type = ColorType.FOREGROUND;
513         }
514         state = GTKLookAndFeel.synthStateToGTKState(id, state);
515         if (!id.isSubregion() &&
516                 (state & SynthConstants.ENABLED) == SynthConstants.ENABLED) {
517             if (type == ColorType.BACKGROUND) {
518                 return c.getBackground();
519             }
520             else if (type == ColorType.FOREGROUND) {
521                 return c.getForeground();
522             }
523             else if (type == ColorType.TEXT_FOREGROUND) {
524                 Color fg = c.getForeground();
525                 if (fg != null && !(fg instanceof UIResource)) {
526                     // Only use the fg for text if specified.
527
return fg;
528                 }
529             }
530         }
531         return getColorForState(c, id, state, type);
532     }
533
534     /**
535      * Returns the color for the specified state. This redirects to the
536      * JComponent <code>c</code> as necessary. If this does not redirect
537      * to the JComponent <code>getColorForState</code> is invoked.
538      *
539      * @param c JComponent the style is associated with
540      * @param id Region identifier
541      * @param state State of the region.
542      * @param type Type of color being requested.
543      * @return Color to render with
544      */

545     protected Color getColorForState(JComponent c, Region id, int state,
546                                      ColorType type) {
547         Color color = super.getColorForState(c, id, state, type);
548
549         if (color != null) {
550             return color;
551         }
552         if (type == ColorType.FOCUS) {
553             return BLACK_COLOR;
554         }
555         else if (type == GTKColorType.BLACK) {
556             return BLACK_COLOR;
557         }
558         else if (type == GTKColorType.WHITE) {
559             return WHITE_COLOR;
560         }
561         if (type == ColorType.TEXT_FOREGROUND && (GTKStyleFactory.
562                     isLabelBearing(id) || id == Region.MENU_ITEM_ACCELERATOR ||
563                     id == Region.TABBED_PANE_TAB)) {
564             type = ColorType.FOREGROUND;
565         }
566         else if (id == Region.TABLE || id == Region.LIST ||
567                  id == Region.TREE || id == Region.TREE_CELL){
568             if (type == ColorType.FOREGROUND) {
569                 type = ColorType.TEXT_FOREGROUND;
570                 if (state == SynthConstants.PRESSED) {
571                     state = SynthConstants.SELECTED;
572                 }
573             }
574             else if (type == ColorType.BACKGROUND) {
575                 type = ColorType.TEXT_BACKGROUND;
576                 if (state == SynthConstants.PRESSED) {
577                     state = SynthConstants.SELECTED;
578                 }
579             }
580         }
581         return getDefaultColor(c, id, state, type);
582     }
583
584     /**
585      * Returns the Color to use if the GTKStyle does not specify a color.
586      *
587      * @param c JComponent the style is associated with
588      * @param id Region identifier
589      * @param state State of the region.
590      * @param type Type of color being requested.
591      * @return Color to render with
592      */

593     Color getDefaultColor(JComponent c, Region id, int state,
594                           ColorType type) {
595         if (type == ColorType.FOCUS) {
596             return BLACK_COLOR;
597         }
598         else if (type == GTKColorType.BLACK) {
599             return BLACK_COLOR;
600         }
601         else if (type == GTKColorType.WHITE) {
602             return WHITE_COLOR;
603         }
604         for (int counter = DEFAULT_COLOR_MAP.length - 1;
605                      counter >= 0; counter--) {
606             if ((DEFAULT_COLOR_MAP[counter] & state) != 0) {
607                 if (type.getID() < DEFAULT_COLORS[counter].length) {
608                     return DEFAULT_COLORS[counter][type.getID()];
609                 }
610             }
611         }
612         if (type.getID() < DEFAULT_COLORS[2].length) {
613             return DEFAULT_COLORS[2][type.getID()];
614         }
615         return null;
616     }
617
618     /**
619      * Returns the value to initialize the opacity property of the Component
620      * to. A Style should NOT assume the opacity will remain this value, the
621      * developer may reset it or override it.
622      *
623      * @param context SynthContext indentifying requestor
624      * @return opaque Whether or not the JComponent is opaque.
625      */

626     public boolean isOpaque(SynthContext context) {
627         Region region = context.getRegion();
628         if (region == Region.COMBO_BOX ||
629               region == Region.DESKTOP_PANE ||
630               region == Region.DESKTOP_ICON ||
631               region == Region.EDITOR_PANE ||
632               region == Region.FORMATTED_TEXT_FIELD ||
633               region == Region.INTERNAL_FRAME ||
634               region == Region.LIST ||
635               region == Region.MENU_BAR ||
636               region == Region.PASSWORD_FIELD ||
637               region == Region.POPUP_MENU ||
638               region == Region.PROGRESS_BAR ||
639               region == Region.ROOT_PANE ||
640               region == Region.SCROLL_PANE ||
641               region == Region.SPINNER ||
642               region == Region.TABLE ||
643               region == Region.TEXT_AREA ||
644               region == Region.TEXT_FIELD ||
645               region == Region.TEXT_PANE ||
646               region == Region.TOOL_BAR_DRAG_WINDOW ||
647               region == Region.TOOL_TIP ||
648               region == Region.TREE ||
649               region == Region.VIEWPORT) {
650             return true;
651         }
652         Component c = context.getComponent();
653         String JavaDoc name = c.getName();
654         if (name == "ComboBox.renderer" || name == "ComboBox.listRenderer") {
655             return true;
656         }
657         return false;
658     }
659
660     /**
661      * Returns the X thickness to use for this GTKStyle.
662      *
663      * @return x thickness.
664      */

665     public int getXThickness() {
666         return xThickness;
667     }
668
669     /**
670      * Returns the Y thickness to use for this GTKStyle.
671      *
672      * @return x thickness.
673      */

674     public int getYThickness() {
675         return yThickness;
676     }
677
678     private Icon getStockIcon(SynthContext context, String JavaDoc key, int type) {
679         Icon icon = null;
680         GTKStockIconInfo iconInfo = null;
681         GTKIconSource bestSource = null;
682         int direction = LTR;
683         
684         if (context != null) {
685             ComponentOrientation co = context.getComponent().
686                                               getComponentOrientation();
687
688             if (co == null || co.isLeftToRight()) {
689                 direction = LTR;
690             }
691             else {
692                 direction = RTL;
693             }
694         }
695         // See if the style defines an icon
696
if (icons != null) {
697             for (int i = 0; i < icons.length; i++) {
698                 // find the first one that matches our key
699
if (icons[i].getKey() == key) {
700                     iconInfo = icons[i];
701                     break;
702                 }
703             }
704             
705             if (iconInfo != null) {
706                 // PENDING(shannonh) - pass in actual state
707
bestSource = iconInfo.getBestIconSource(direction,
708                                                         SynthConstants.ENABLED,
709                                                         type);
710             }
711             
712             if (bestSource != null) {
713                 icon = bestSource.toIcon();
714             }
715         }
716         
717         if (icon == null) {
718             // Use a default icon
719
String JavaDoc propName = ICON_PROPERTY_PREFIX + key + '.' + type + '.' +
720                               (direction == RTL ? "rtl" : "ltr");
721             Image JavaDoc img = (Image JavaDoc)Toolkit.getDefaultToolkit().
722                                        getDesktopProperty(propName);
723             if (img != null) {
724                 icon = new ImageIcon(img);
725                 return icon;
726             } else {
727                 icon = (Icon)((UIDefaults.LazyValue)LookAndFeel.makeIcon(
728                               GTKStyle.class, "resources/" + key + "-" + type +
729                               ".png")).createValue(null);
730             }
731         }
732         
733         if (icon == null) {
734             return null;
735         }
736         BufferedImage JavaDoc image = null;
737
738         // If the stock icon we found had a wildcard size,
739
// we force the size to match that requested
740
if (bestSource == null || bestSource.getSize() == UNDEFINED) {
741             Dimension iconSize = GTKStockIconInfo.getIconSize(type);
742             
743             if (iconSize != null && (icon.getIconWidth() != iconSize.width ||
744                     icon.getIconHeight() != iconSize.height)) {
745                 image = new BufferedImage JavaDoc(iconSize.width, iconSize.height,
746                         BufferedImage.TYPE_INT_ARGB);
747                 
748                 Graphics2D g2d = (Graphics2D)image.getGraphics();
749                 
750                 // for nicer scaling
751
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
752                         RenderingHints.VALUE_INTERPOLATION_BILINEAR);
753                 
754                 Image JavaDoc oldImage = getImageFromIcon(icon, false);
755                 g2d.drawImage(oldImage, 0, 0, iconSize.width, iconSize.height, null);
756                 g2d.dispose();
757             }
758         }
759 /* This is not done for now. We cache icons and use cached copies regardless
760    of the component state, so we don't want to cache desaturated icons
761    
762         if (bestSource == null || bestSource.getState() == UNDEFINED) {
763             // We may need to change saturation for some states
764             int state = context.getComponentState();
765             if (state == SynthConstants.DISABLED ||
766                 state == SynthConstants.MOUSE_OVER) {
767                 
768                 if (image == null) {
769                     image = (BufferedImage)getImageFromIcon(icon, true);
770                 }
771                 float rescaleFactor =
772                         (state == SynthConstants.DISABLED ? 0.8f : 1.2f);
773                 RescaleOp op = new RescaleOp(rescaleFactor, 0, null);
774                 // RescaleOp allows for in-place filtering
775                 op.filter(image, image);
776             }
777         }
778 */

779         if (image != null) {
780             icon = new ImageIcon(image);
781         }
782         return icon;
783     }
784     
785     private Image JavaDoc getImageFromIcon(Icon icon, boolean requireBufferedImage) {
786         Image JavaDoc img = null;
787         
788         if (icon instanceof ImageIcon) {
789             img = ((ImageIcon)icon).getImage();
790             if (requireBufferedImage && !(img instanceof BufferedImage JavaDoc)) {
791                 img = null;
792             }
793         }
794         if (img == null) {
795             img = new BufferedImage JavaDoc(icon.getIconWidth(), icon.getIconHeight(),
796                                     BufferedImage.TYPE_INT_ARGB);
797             Graphics g = img.getGraphics();
798             icon.paintIcon(null, g, 0, 0);
799             g.dispose();
800         }
801         return img;
802     }
803     
804     /**
805      * Adds the specific label based properties from <code>style</code> to
806      * this style.
807      */

808     void addLabelProperties(GTKStyle style) {
809         StateInfo[] states = getStateInfo();
810         StateInfo[] oStates = style.getStateInfo();
811         // Take the font
812
setFont(style.getFontForState(null, null, 0));
813         // And TEXT_FOREGROUND
814
if (states == null) {
815             if (oStates == null) {
816                 return;
817             }
818             states = new StateInfo[oStates.length];
819             for (int counter = 0; counter < oStates.length; counter++) {
820                 Color color = oStates[counter].getColor(
821                                      GTKColorType.FOREGROUND);
822
823                 states[counter] = createStateInfo(oStates[counter].
824                      getComponentState(), GTKColorType.TEXT_FOREGROUND, color);
825             }
826         }
827         else {
828             // Reset the text foreground of all our states, this will ensure
829
// the correct color is picked up if style doesn't specify a
830
// text color.
831
for (int counter = states.length - 1; counter >= 0; counter--) {
832                 ((GTKStateInfo)states[counter]).setColor(
833                                GTKColorType.TEXT_FOREGROUND, null);
834             }
835             if (oStates != null) {
836                 for (int oCounter = oStates.length - 1; oCounter >= 0;
837                          oCounter--) {
838                     boolean matched = false;
839                     StateInfo oState = oStates[oCounter];
840                     int componentState = oState.getComponentState();
841                     Color color = oState.getColor(GTKColorType.FOREGROUND);
842
843                     for (int tCounter = states.length - 1; tCounter >= 0;
844                              tCounter--) {
845                         if (componentState == states[tCounter].
846                                      getComponentState()) {
847                             ((GTKStateInfo)states[tCounter]).setColor(
848                                       GTKColorType.TEXT_FOREGROUND, color);
849                             matched = true;
850                             break;
851                         }
852                     }
853                     if (!matched) {
854                         StateInfo[] newStates = new StateInfo[states.length+1];
855                         System.arraycopy(states, 0, newStates, 0,
856                                          states.length);
857                         newStates[states.length] = createStateInfo(
858                                  componentState, GTKColorType.TEXT_FOREGROUND,
859                                  color);
860                         states = newStates;
861                     }
862                 }
863             }
864         }
865     }
866
867     /**
868      * Creates a StateInfo with the specified component state, ColorType
869      * and color. Subclasses that create a custom GTKStateInfo will need
870      * to subclass and override this.
871      */

872     GTKStateInfo createStateInfo(int state, ColorType type, Color color) {
873         Color[] colors = new Color[GTKColorType.MAX_COUNT];
874
875         colors[type.getID()] = color;
876         return new GTKStateInfo(state, null, colors, null);
877     }
878
879     /**
880      * Adds a value specific to the style.
881      */

882     void put(Object JavaDoc key, Object JavaDoc value) {
883         Map data = getData();
884         if (data== null) {
885             data = new HashMap();
886             setData(data);
887         }
888         data.put(key, value);
889     }
890
891     /**
892      * Returns true if the style should fill in the background of the
893      * specified context for the specified state.
894      */

895     boolean fillBackground(SynthContext context, int state) {
896         GTKStateInfo info = (GTKStateInfo)getStateInfo(state);
897
898         if (info != null) {
899             Object JavaDoc backgroundImage = info.getBackgroundImage();
900
901             if (backgroundImage == "<none>" || backgroundImage == null) {
902                 return true;
903             }
904             return false;
905         }
906         return true;
907     }
908
909     /**
910      * Returns the Icon to fill the background in with for the specified
911      * context and state.
912      */

913     Image JavaDoc getBackgroundImage(SynthContext context, int state) {
914         GTKStateInfo info = (GTKStateInfo)getStateInfo(state);
915
916         if (info != null) {
917             Object JavaDoc backgroundImage = info.getBackgroundImage();
918
919             if (backgroundImage instanceof Image JavaDoc) {
920                 return (Image JavaDoc)backgroundImage;
921             }
922         }
923         return null;
924     }
925
926     /**
927      * Creates a clone of this GTKStyle.
928      *
929      * @return Clone of this GTKStyle.
930      */

931     public Object JavaDoc clone() {
932         GTKStyle style = (GTKStyle)super.clone();
933
934         style.classSpecificValues = cloneClassSpecificValues(
935                                          style.classSpecificValues);
936         return style;
937     }
938
939     /**
940      * Merges the contents of this Style with that of the passed in Style,
941      * returning the resulting merged syle. Properties of this
942      * <code>GTKStyle</code> will take precedence over those of the
943      * passed in <code>DefaultSynthStyle</code>. For example, if this
944      * style specifics a non-null font, the returned style will have its
945      * font so to that regardless of the <code>style</code>'s font.
946      *
947      * @param style Style to add our styles to
948      * @return Merged style.
949      */

950     public DefaultSynthStyle addTo(DefaultSynthStyle style) {
951         if (!(style instanceof GTKStyle)) {
952             style = new GTKStyle(style);
953         }
954         GTKStyle gtkStyle = (GTKStyle)super.addTo(style);
955         if (xThickness != UNDEFINED_THICKNESS) {
956             gtkStyle.xThickness = xThickness;
957         }
958         if (yThickness != UNDEFINED_THICKNESS) {
959             gtkStyle.yThickness = yThickness;
960         }
961         if (gtkStyle.icons == null) {
962             gtkStyle.icons = icons;
963         }
964         else if (icons != null) {
965             GTKStockIconInfo[] mergedIcons =
966                 new GTKStockIconInfo[gtkStyle.icons.length + icons.length];
967                 
968             System.arraycopy(icons, 0, mergedIcons, 0, icons.length);
969             System.arraycopy(gtkStyle.icons, 0, mergedIcons, icons.length, gtkStyle.icons.length);
970             
971             gtkStyle.icons = mergedIcons;
972         }
973         
974         if (gtkStyle.classSpecificValues == null) {
975             gtkStyle.classSpecificValues =
976                 cloneClassSpecificValues(classSpecificValues);
977         } else {
978             addClassSpecificValues(classSpecificValues, gtkStyle.classSpecificValues);
979         }
980             
981         return gtkStyle;
982     }
983
984     /**
985      * Adds the data from one set of class specific values into another.
986      *
987      * @param from the list to grab data from (may be null)
988      * @param to the list to add data to (may not be null)
989      */

990     static void addClassSpecificValues(CircularIdentityList from,
991                                         CircularIdentityList to) {
992         if (to == null) {
993             throw new IllegalArgumentException JavaDoc("to may not be null");
994         }
995         
996         if (from == null) {
997             return;
998         }
999
1000        synchronized(from) {
1001            Object JavaDoc firstKey = from.next();
1002            if (firstKey != null) {
1003                Object JavaDoc key = firstKey;
1004                do {
1005                    CircularIdentityList cList = ((CircularIdentityList)
1006                            from.get());
1007                    CircularIdentityList oSublist = (CircularIdentityList)
1008                                     to.get(key);
1009                    if (oSublist == null) {
1010                        to.set(key, cList.clone());
1011                    }
1012                    else {
1013                        Object JavaDoc cFirstKey = cList.next();
1014
1015                        if (cFirstKey != null) {
1016                            Object JavaDoc cKey = cFirstKey;
1017                            do {
1018                                oSublist.set(cKey, cList.get());
1019                                cKey = cList.next();
1020                            } while (cKey != cFirstKey);
1021                        }
1022                    }
1023                    key = from.next();
1024                } while (key != firstKey);
1025            }
1026        }
1027    }
1028
1029    /**
1030     * Clones the class specific values.
1031     */

1032    static CircularIdentityList cloneClassSpecificValues(
1033                    CircularIdentityList list) {
1034        if (list == null) {
1035            return null;
1036        }
1037        CircularIdentityList clone;
1038        synchronized(list) {
1039            Object JavaDoc firstKey = list.next();
1040            if (firstKey == null) {
1041                // Empty list
1042
return null;
1043            }
1044            clone = new CircularIdentityList();
1045            Object JavaDoc key = firstKey;
1046            do {
1047                clone.set(key, ((CircularIdentityList)list.get()).clone());
1048                key = list.next();
1049            } while (key != firstKey);
1050        }
1051        return clone;
1052    }
1053
1054    /**
1055     * GTKStockIconInfo mirrors the information from a stock declaration
1056     * in the rc file: stock icon id, and a set of icon source
1057     * specifications.
1058     */

1059    static class GTKStockIconInfo {
1060        private String JavaDoc key;
1061        private GTKIconSource[] sources;
1062        private static Map<String JavaDoc,Integer JavaDoc> ICON_TYPE_MAP;
1063        private static final Object JavaDoc ICON_SIZE_KEY = new StringBuffer JavaDoc("IconSize");
1064        
1065        GTKStockIconInfo(String JavaDoc key, GTKIconSource[] sources) {
1066            this.key = key.intern();
1067            this.sources = sources;
1068            Arrays.sort(this.sources);
1069        }
1070        
1071        public String JavaDoc getKey() {
1072            return key;
1073        }
1074        
1075        public GTKIconSource getBestIconSource(int direction, int state, int size) {
1076            for (int i = 0; i < sources.length; i++) {
1077                GTKIconSource src = sources[i];
1078                
1079                if ((src.direction == UNDEFINED || src.direction == direction)
1080                        && (src.state == UNDEFINED || src.state == state)
1081                        && (src.size == UNDEFINED || src.size == size)) {
1082                    return src;
1083                }
1084            }
1085            
1086            return null;
1087        }
1088
1089        public String JavaDoc toString() {
1090            StringBuffer JavaDoc buf = new StringBuffer JavaDoc("STOCK ICON " + key + ":\n");
1091            
1092            for (int i = 0; i < sources.length; i++) {
1093                buf.append(" ").append(sources[i].toString()).append('\n');
1094            }
1095            
1096            // remove last newline
1097
buf.deleteCharAt(buf.length() - 1);
1098            
1099            return buf.toString();
1100        }
1101        
1102        /**
1103         * Return icon type (GtkIconSize value) given a symbolic name which can
1104         * occur in a theme file.
1105         *
1106         * @param size symbolic name, e.g. gtk-button
1107         * @return icon type. Valid types are 1 to 6
1108         */

1109        public static int getIconType(String JavaDoc size) {
1110            if (size == null) {
1111                return UNDEFINED;
1112            }
1113            if (ICON_TYPE_MAP == null) {
1114                initIconTypeMap();
1115            }
1116            Integer JavaDoc n = ICON_TYPE_MAP.get(size);
1117            return n != null ? n.intValue() : UNDEFINED;
1118        }
1119        
1120        private static void initIconTypeMap() {
1121            ICON_TYPE_MAP = new HashMap<String JavaDoc,Integer JavaDoc>();
1122            ICON_TYPE_MAP.put("gtk-menu", new Integer JavaDoc(1));
1123            ICON_TYPE_MAP.put("gtk-small-toolbar", new Integer JavaDoc(2));
1124            ICON_TYPE_MAP.put("gtk-large-toolbar", new Integer JavaDoc(3));
1125            ICON_TYPE_MAP.put("gtk-button", new Integer JavaDoc(4));
1126            ICON_TYPE_MAP.put("gtk-dnd", new Integer JavaDoc(5));
1127            ICON_TYPE_MAP.put("gtk-dialog", new Integer JavaDoc(6));
1128        }
1129
1130        /**
1131         * Return the size of a particular icon type (logical size)
1132         *
1133         * @param type icon type (GtkIconSize value)
1134         * @return a Dimension object, or null if lsize is invalid
1135         */

1136        public static Dimension getIconSize(int type) {
1137            Dimension[] iconSizes = getIconSizesMap();
1138            return type >= 0 && type < iconSizes.length ?
1139                iconSizes[type] : null;
1140        }
1141        
1142        /**
1143         * Change icon size in a type to size mapping. This is called by code
1144         * that parses the gtk-icon-sizes setting
1145         *
1146         * @param type icon type (GtkIconSize value)
1147         * @param w the new icon width
1148         * @param h the new icon height
1149         */

1150        public static void setIconSize(int type, int w, int h) {
1151            Dimension[] iconSizes = getIconSizesMap();
1152            if (type >= 0 && type < iconSizes.length) {
1153                iconSizes[type] = new Dimension(w, h);
1154            }
1155        }
1156        
1157        private static Dimension[] getIconSizesMap() {
1158            AppContext appContext = AppContext.getAppContext();
1159            Dimension[] iconSizes = (Dimension[])appContext.get(ICON_SIZE_KEY);
1160
1161            if (iconSizes == null) {
1162                iconSizes = new Dimension[7];
1163                iconSizes[0] = null; // GTK_ICON_SIZE_INVALID
1164
iconSizes[1] = new Dimension(16, 16); // GTK_ICON_SIZE_MENU
1165
iconSizes[2] = new Dimension(18, 18); // GTK_ICON_SIZE_SMALL_TOOLBAR
1166
iconSizes[3] = new Dimension(24, 24); // GTK_ICON_SIZE_LARGE_TOOLBAR
1167
iconSizes[4] = new Dimension(20, 20); // GTK_ICON_SIZE_BUTTON
1168
iconSizes[5] = new Dimension(32, 32); // GTK_ICON_SIZE_DND
1169
iconSizes[6] = new Dimension(48, 48); // GTK_ICON_SIZE_DIALOG
1170
appContext.put(ICON_SIZE_KEY, iconSizes);
1171            }
1172            return iconSizes;
1173        }
1174    }
1175
1176
1177    /**
1178     * GTKIconSource represents a single icon source specification,
1179     * as declared inside a stock definition in an rc file:
1180     * path to image, size, direction, and state.
1181     */

1182    static class GTKIconSource implements Comparable JavaDoc {
1183        private Object JavaDoc image;
1184        private int direction;
1185        private int state;
1186        private int size;
1187        
1188        GTKIconSource(String JavaDoc image, int direction, int state, String JavaDoc size) {
1189            this.image = image;
1190            this.direction = direction;
1191            this.state = state;
1192            
1193            this.size = GTKStockIconInfo.getIconType(size);
1194        }
1195
1196        public int getDirection() {
1197            return direction;
1198        }
1199        
1200        public int getState() {
1201            return state;
1202        }
1203
1204        public int getSize() {
1205            return size;
1206        }
1207        
1208        public int compareTo(Object JavaDoc o) {
1209            GTKIconSource other = (GTKIconSource)o;
1210
1211            if (direction != UNDEFINED && other.direction == UNDEFINED) {
1212                return -1;
1213            } else if (direction == UNDEFINED && other.direction != UNDEFINED) {
1214                return 1;
1215            } else if (state != UNDEFINED && other.state == UNDEFINED) {
1216                return -1;
1217            } else if (state == UNDEFINED && other.state != UNDEFINED) {
1218                return 1;
1219            } else if (size != UNDEFINED && other.size == UNDEFINED) {
1220                return -1;
1221            } else if (size == UNDEFINED && other.size != UNDEFINED) {
1222                return 1;
1223            } else {
1224                return 0;
1225            }
1226        }
1227
1228        public String JavaDoc toString() {
1229            return "image=" + image + ", dir=" + getDirectionName(direction)
1230                   + ", state=" + getStateName(state, "*")
1231                   + ", size=" + (size == UNDEFINED ? "*" : ""+size);
1232        }
1233        
1234        // used above by toString()
1235
private static String JavaDoc getDirectionName(int dir) {
1236            switch(dir) {
1237                case LTR: return "LTR";
1238                case RTL: return "RTL";
1239                case UNDEFINED: return "*";
1240            }
1241
1242            return "UNKNOWN";
1243        }
1244        
1245        public Icon toIcon() {
1246            if (image == null || image instanceof Icon) {
1247                return (Icon)image;
1248            }
1249            
1250            ImageIcon ii = (ImageIcon)AccessController.doPrivileged(new PrivilegedAction() {
1251                public Object JavaDoc run() {
1252                    return new ImageIcon((String JavaDoc)image);
1253                }
1254            });
1255
1256            if (ii.getIconWidth() > 0 && ii.getIconHeight() > 0) {
1257                image = ii;
1258            } else {
1259                // if we decide to mimic GTK and show a broken image,
1260
// it would be assigned to 'image' here
1261
image = null;
1262            }
1263            
1264            return (Icon)image;
1265        }
1266    }
1267
1268    public String JavaDoc toString() {
1269        StringBuffer JavaDoc buf = new StringBuffer JavaDoc(super.toString());
1270
1271        if (xThickness != UNDEFINED_THICKNESS) {
1272            buf.append("xt=").append(String.valueOf(xThickness)).append('\n');
1273        }
1274
1275        if (yThickness != UNDEFINED_THICKNESS) {
1276            buf.append("yt=").append(String.valueOf(yThickness)).append('\n');
1277        }
1278
1279        if (classSpecificValues != null) {
1280            buf.append("*** Properties ***\n");
1281            buf.append(classSpecValsToString(classSpecificValues)).append('\n');
1282        }
1283
1284        if (icons != null) {
1285            buf.append("*** Stock Icons ***\n");
1286            for (int i = 0; i < icons.length; i++) {
1287                buf.append(icons[i].toString()).append('\n');
1288            }
1289        }
1290
1291        // remove last newline
1292
buf.deleteCharAt(buf.length() - 1);
1293
1294        return buf.toString();
1295    }
1296
1297    // used by toString()
1298
private static String JavaDoc classSpecValsToString(CircularIdentityList parent) {
1299        StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1300
1301        Object JavaDoc parentFirst = parent.next();
1302            
1303        if (parentFirst == null) {
1304            return "";
1305        }
1306
1307        Object JavaDoc parentKey = parentFirst;
1308
1309        do {
1310            buf.append(parentKey).append('\n');
1311
1312            CircularIdentityList child = (CircularIdentityList)parent.get();
1313
1314            Object JavaDoc childFirst = child.next();
1315                
1316            if (childFirst == null) {
1317                break;
1318            }
1319                    
1320            Object JavaDoc childKey = childFirst;
1321                    
1322            do {
1323                buf.append(" ").append(childKey).append('=').append(child.get()).append('\n');
1324                childKey = child.next();
1325            } while (childKey != childFirst);
1326            
1327            parentKey = parent.next();
1328        } while (parentKey != parentFirst);
1329
1330        // remove last newline
1331
buf.deleteCharAt(buf.length() - 1);
1332
1333        return buf.toString();
1334    }
1335
1336    /**
1337     * A subclass of StateInfo adding additional GTK state information.
1338     */

1339    public static class GTKStateInfo extends StateInfo {
1340        // <none>: fill in with background color
1341
// <parent>: do nothing, parent will have handled it
1342
// image: paint it.
1343
private Object JavaDoc backgroundImage;
1344
1345        /**
1346         * Creates a new GTKStateInfo with the specified properties
1347         *
1348         * @param state Component state that this StateInfo should be used
1349         * for
1350         * @param font Font for this state
1351         * @param colors Colors for this state
1352         * @param backgroundImage Background image
1353         */

1354        public GTKStateInfo(int state, Font font, Color[] colors,
1355                            Object JavaDoc backgroundImage) {
1356            super(state, font, colors);
1357            this.backgroundImage = backgroundImage;
1358        }
1359
1360        /**
1361         * Creates a GTKStateInfo that is a copy of the passed in
1362         * <code>StateInfo</code>.
1363         *
1364         * @param info StateInfo to copy.
1365         */

1366        public GTKStateInfo(StateInfo info) {
1367            super(info);
1368            if (info instanceof GTKStateInfo) {
1369                backgroundImage = ((GTKStateInfo)info).backgroundImage;
1370            }
1371        }
1372
1373        void setColor(ColorType type, Color color) {
1374            Color[] colors = getColors();
1375            if (colors == null) {
1376                if (color == null) {
1377                    return;
1378                }
1379                colors = new Color[GTKColorType.MAX_COUNT];
1380                setColors(colors);
1381            }
1382            colors[type.getID()] = color;
1383        }
1384
1385        /**
1386         * Returns the Color to used for the specified ColorType.
1387         *
1388         * @return Color.
1389         */

1390        public Color getColor(ColorType type) {
1391            Color color = super.getColor(type);
1392
1393            if (color == null) {
1394                Color[] colors = getColors();
1395                Color bg;
1396
1397                if (colors != null && (bg = super.getColor(
1398                                        GTKColorType.BACKGROUND)) != null) {
1399                    if (type == GTKColorType.LIGHT) {
1400                        color = colors[GTKColorType.LIGHT.getID()] =
1401                                  calculateLightColor(bg);
1402                    }
1403                    else if (type == GTKColorType.MID) {
1404                        color = colors[GTKColorType.MID.getID()] =
1405                                       calculateMidColor(bg);
1406                    }
1407                    else if (type == GTKColorType.DARK) {
1408                        color = colors[GTKColorType.DARK.getID()] =
1409                                       calculateDarkColor(bg);
1410                    }
1411                }
1412            }
1413            return color;
1414        }
1415
1416        /**
1417         * This returns the background image, and will be one of:
1418         * the String "<none>", the String "<parent>" or an Image.
1419         *
1420         * @return the background.
1421         */

1422        Object JavaDoc getBackgroundImage() {
1423            if (backgroundImage == null ||
1424                     (backgroundImage instanceof Image JavaDoc) ||
1425                     backgroundImage == "<none>" ||
1426                     backgroundImage == "<parent>") {
1427                return backgroundImage;
1428            }
1429
1430            ImageIcon ii = (ImageIcon)AccessController.doPrivileged(new PrivilegedAction() {
1431                public Object JavaDoc run() {
1432                    return new ImageIcon((String JavaDoc)backgroundImage);
1433                }
1434            });
1435
1436            if (ii.getIconWidth() > 0 && ii.getIconHeight() > 0) {
1437                backgroundImage = ii.getImage();
1438            } else {
1439                backgroundImage = null;
1440            }
1441
1442            return backgroundImage;
1443        }
1444
1445        /**
1446         * Creates and returns a copy of this GTKStateInfo.
1447         *
1448         * @return Copy of this StateInfo.
1449         */

1450        public Object JavaDoc clone() {
1451            return new GTKStateInfo(this);
1452        }
1453
1454        /**
1455         * Merges the contents of this GTKStateInfo with that of the passed in
1456         * GTKStateInfo, returning the resulting merged StateInfo. Properties
1457         * of this <code>GTKStateInfo</code> will take precedence over those
1458         * of the
1459         * passed in <code>GTKStateInfo</code>. For example, if this
1460         * GTKStateInfo specifics a non-null font, the returned GTKStateInfo
1461         * will have its font so to that regardless of the
1462         * <code>GTKStateInfo</code>'s font.
1463         *
1464         * @param info StateInfo to add our styles to
1465         * @return Merged StateInfo.
1466         */

1467        public StateInfo addTo(StateInfo info) {
1468            if (!(info instanceof GTKStateInfo)) {
1469                info = new GTKStateInfo(info);
1470            }
1471            else {
1472                super.addTo(info);
1473            }
1474            GTKStateInfo gInfo = (GTKStateInfo)info;
1475
1476            if (backgroundImage != null) {
1477                gInfo.backgroundImage = backgroundImage;
1478            }
1479            return gInfo;
1480        }
1481
1482        public String JavaDoc toString() {
1483            StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1484            
1485            buf.append(getStateName(getComponentState(), "UNDEFINED")).append(":\n");
1486            
1487            if (getColor(GTKColorType.FOREGROUND) != null) {
1488                buf.append(" fg=").append(getColor(GTKColorType.FOREGROUND)).append('\n');
1489            }
1490            
1491            if (getColor(GTKColorType.BACKGROUND) != null) {
1492                buf.append(" bg=").append(getColor(GTKColorType.BACKGROUND)).append('\n');
1493            }
1494            
1495            if (getColor(GTKColorType.TEXT_FOREGROUND) != null) {
1496                buf.append(" text=").append(getColor(GTKColorType.TEXT_FOREGROUND)).append('\n');
1497            }
1498            
1499            if (getColor(GTKColorType.TEXT_BACKGROUND) != null) {
1500                buf.append(" base=").append(getColor(GTKColorType.TEXT_BACKGROUND)).append('\n');
1501            }
1502            
1503            if (backgroundImage != null) {
1504                buf.append(" pmn=").append(backgroundImage).append('\n');
1505            }
1506            
1507            // remove last newline
1508
buf.deleteCharAt(buf.length() - 1);
1509
1510            return buf.toString();
1511        }
1512    }
1513    
1514    // used by toString() in some of our inner classes
1515
static String JavaDoc getStateName(int state, String JavaDoc undef) {
1516        switch(state) {
1517            case SynthConstants.ENABLED: return "NORMAL";
1518            case SynthConstants.PRESSED: return "ACTIVE";
1519            case SynthConstants.SELECTED: return "SELECTED";
1520            case SynthConstants.MOUSE_OVER: return "PRELIGHT";
1521            case SynthConstants.DISABLED: return "INSENSITIVE";
1522            case UNDEFINED: return undef;
1523        }
1524        
1525        return "UNKNOWN";
1526    }
1527    
1528    /**
1529     * A tagging interface indicating that a value coming from
1530     * DATA should be added to the Style's data after invoking getValue.
1531     * This is useful for lazy type properties that need to key off information
1532     * kept in the style.
1533     */

1534    interface StyleSpecificValue {
1535        public Object JavaDoc getValue(SynthContext context);
1536    }
1537
1538
1539    /**
1540     * An Icon that is fetched using getStockIcon.
1541     */

1542    private static class GTKStockIcon extends SynthIcon implements Cloneable JavaDoc,
1543                                              StyleSpecificValue {
1544        private String JavaDoc key;
1545        private int size;
1546        private boolean loadedLTR;
1547        private boolean loadedRTL;
1548        private Icon ltrIcon;
1549        private Icon rtlIcon;
1550        private SynthStyle style;
1551
1552        GTKStockIcon(String JavaDoc key, int size) {
1553            this.key = key;
1554            this.size = size;
1555        }
1556
1557        public void paintIcon(SynthContext context, Graphics g, int x,
1558                              int y, int w, int h) {
1559            Icon icon = getIcon(context);
1560
1561            if (icon != null) {
1562                if (context == null) {
1563                    icon.paintIcon(null, g, x, y);
1564                }
1565                else {
1566                    icon.paintIcon(context.getComponent(), g, x, y);
1567                }
1568            }
1569        }
1570
1571        public int getIconWidth(SynthContext context) {
1572            Icon icon = getIcon(context);
1573
1574            if (icon != null) {
1575                return icon.getIconWidth();
1576            }
1577            return 0;
1578        }
1579
1580        public int getIconHeight(SynthContext context) {
1581            Icon icon = getIcon(context);
1582
1583            if (icon != null) {
1584                return icon.getIconHeight();
1585            }
1586            return 0;
1587        }
1588
1589        private Icon getIcon(SynthContext context) {
1590            if (context != null) {
1591                ComponentOrientation co = context.getComponent().
1592                                                  getComponentOrientation();
1593                SynthStyle style = context.getStyle();
1594
1595                if (style != this.style) {
1596                    this.style = style;
1597                    loadedLTR = loadedRTL = false;
1598                }
1599                if (co == null || co.isLeftToRight()) {
1600                    if (!loadedLTR) {
1601                        loadedLTR = true;
1602                        ltrIcon = ((GTKStyle)context.getStyle()).
1603                                  getStockIcon(context, key, size);
1604                    }
1605                    return ltrIcon;
1606                }
1607                else if (!loadedRTL) {
1608                    loadedRTL = true;
1609                    rtlIcon = ((GTKStyle)context.getStyle()).
1610                              getStockIcon(context, key,size);
1611                }
1612                return rtlIcon;
1613            }
1614            return ltrIcon;
1615        }
1616
1617        public Object JavaDoc getValue(SynthContext context) {
1618            try {
1619                return clone();
1620            } catch (CloneNotSupportedException JavaDoc cnse) {
1621            }
1622            return null;
1623        }
1624    }
1625
1626
1627    /**
1628     * MetalLazyValue is a slimmed down version of <code>ProxyLaxyValue</code>.
1629     * The code is duplicate so that it can get at the package private
1630     * classes in gtk.
1631     */

1632    static class GTKLazyValue implements UIDefaults.LazyValue {
1633        /**
1634         * Name of the class to create.
1635         */

1636        private String JavaDoc className;
1637        private String JavaDoc methodName;
1638
1639        GTKLazyValue(String JavaDoc name) {
1640            this(name, null);
1641        }
1642
1643        GTKLazyValue(String JavaDoc name, String JavaDoc methodName) {
1644            this.className = name;
1645            this.methodName = methodName;
1646        }
1647
1648        public Object JavaDoc createValue(UIDefaults table) {
1649            try {
1650                Class JavaDoc c = Class.forName(className, true,Thread.currentThread().
1651                                        getContextClassLoader());
1652
1653                if (methodName == null) {
1654                    return c.newInstance();
1655                }
1656                Method m = c.getMethod(methodName, null);
1657
1658                return m.invoke(c, null);
1659            } catch (ClassNotFoundException JavaDoc cnfe) {
1660            } catch (IllegalAccessException JavaDoc iae) {
1661            } catch (InvocationTargetException ite) {
1662            } catch (NoSuchMethodException JavaDoc nsme) {
1663            } catch (InstantiationException JavaDoc ie) {
1664            }
1665            return null;
1666        }
1667    }
1668
1669
1670    static {
1671        DEFAULT_COLOR_MAP = new int[] {
1672            SynthConstants.PRESSED, SynthConstants.SELECTED,
1673            SynthConstants.ENABLED, SynthConstants.MOUSE_OVER,
1674            SynthConstants.DISABLED
1675        };
1676
1677        DEFAULT_COLORS = new Color[5][];
1678
1679        // 2.0 colors
1680
//
1681
if (!GTKLookAndFeel.is2_2()) {
1682            DEFAULT_COLORS[0] = getColorsFrom(
1683                    new ColorUIResource(195, 195, 195), BLACK_COLOR);
1684            DEFAULT_COLORS[1] = getColorsFrom(
1685                    new ColorUIResource(0, 0, 156), WHITE_COLOR);
1686            DEFAULT_COLORS[2] = getColorsFrom(
1687                    new ColorUIResource(214, 214, 214), BLACK_COLOR);
1688            DEFAULT_COLORS[3] = getColorsFrom(
1689                    new ColorUIResource(233, 233, 233), BLACK_COLOR);
1690            DEFAULT_COLORS[4] = getColorsFrom(
1691                    new ColorUIResource(214, 214, 214),
1692                    new ColorUIResource(117, 117, 117));
1693            DEFAULT_COLORS[0][GTKColorType.TEXT_BACKGROUND.getID()] = new
1694                    ColorUIResource(188, 210, 238);
1695            DEFAULT_COLORS[1][GTKColorType.TEXT_BACKGROUND.getID()] = new
1696                    ColorUIResource(164, 223, 255);
1697            DEFAULT_COLORS[1][GTKColorType.TEXT_FOREGROUND.getID()] =
1698                    BLACK_COLOR;
1699            DEFAULT_COLORS[2][GTKColorType.TEXT_FOREGROUND.getID()] =
1700                    BLACK_COLOR;
1701            DEFAULT_COLORS[4][GTKColorType.TEXT_FOREGROUND.getID()] =
1702                DEFAULT_COLORS[2][GTKColorType.TEXT_FOREGROUND.getID()];
1703        }
1704        else {
1705            // 2.2 colors
1706
DEFAULT_COLORS[0] = getColorsFrom(
1707                    new ColorUIResource(186, 181, 171), BLACK_COLOR);
1708            DEFAULT_COLORS[1] = getColorsFrom(
1709                    new ColorUIResource(75, 105, 131), WHITE_COLOR);
1710            DEFAULT_COLORS[2] = getColorsFrom(
1711                    new ColorUIResource(220, 218, 213), BLACK_COLOR);
1712            DEFAULT_COLORS[3] = getColorsFrom(
1713                    new ColorUIResource(238, 235, 231), BLACK_COLOR);
1714            DEFAULT_COLORS[4] = getColorsFrom(
1715                    new ColorUIResource(220, 218, 213),
1716                    new ColorUIResource(117, 117, 117));
1717            DEFAULT_COLORS[0][GTKColorType.TEXT_BACKGROUND.getID()] = new
1718                    ColorUIResource(128, 125, 116);
1719            DEFAULT_COLORS[1][GTKColorType.TEXT_BACKGROUND.getID()] = new
1720                    ColorUIResource(75, 105, 131);
1721            DEFAULT_COLORS[2][GTKColorType.TEXT_BACKGROUND.getID()] =
1722                    WHITE_COLOR;
1723            DEFAULT_COLORS[3][GTKColorType.TEXT_BACKGROUND.getID()] =
1724                    WHITE_COLOR;
1725            DEFAULT_COLORS[4][GTKColorType.TEXT_BACKGROUND.getID()] = new
1726                    ColorUIResource(238, 235, 231);
1727            DEFAULT_COLORS[0][GTKColorType.TEXT_FOREGROUND.getID()] =
1728                    WHITE_COLOR;
1729            DEFAULT_COLORS[1][GTKColorType.TEXT_FOREGROUND.getID()] =
1730                    WHITE_COLOR;
1731            DEFAULT_COLORS[2][GTKColorType.TEXT_FOREGROUND.getID()] =
1732                    BLACK_COLOR;
1733            DEFAULT_COLORS[3][GTKColorType.TEXT_FOREGROUND.getID()] =
1734                    BLACK_COLOR;
1735            DEFAULT_COLORS[4][GTKColorType.TEXT_FOREGROUND.getID()] = new
1736                    ColorUIResource(117, 117, 117);
1737        }
1738
1739        CLASS_SPECIFIC_MAP = new HashMap();
1740        CLASS_SPECIFIC_MAP.put("CheckBox.iconTextGap", "indicator-spacing");
1741        CLASS_SPECIFIC_MAP.put("Slider.thumbHeight", "slider-width");
1742        CLASS_SPECIFIC_MAP.put("Slider.trackBorder", "trough-border");
1743        CLASS_SPECIFIC_MAP.put("SplitPane.size", "handle-size");
1744        CLASS_SPECIFIC_MAP.put("Tree.expanderSize", "expander-size");
1745        CLASS_SPECIFIC_MAP.put("ScrollBar.thumbHeight", "slider-width");
1746        CLASS_SPECIFIC_MAP.put("TextArea.caretForeground", "cursor-color");
1747        CLASS_SPECIFIC_MAP.put("TextArea.caretAspectRatio", "cursor-aspect-ratio");
1748        CLASS_SPECIFIC_MAP.put("TextField.caretForeground", "cursor-color");
1749        CLASS_SPECIFIC_MAP.put("TextField.caretAspectRatio", "cursor-aspect-ratio");
1750        CLASS_SPECIFIC_MAP.put("PasswordField.caretForeground", "cursor-color");
1751        CLASS_SPECIFIC_MAP.put("PasswordField.caretAspectRatio", "cursor-aspect-ratio");
1752        CLASS_SPECIFIC_MAP.put("FormattedTextField.caretForeground", "cursor-color");
1753        CLASS_SPECIFIC_MAP.put("FormattedTextField.caretAspectRatio", "cursor-aspect-");
1754        CLASS_SPECIFIC_MAP.put("TextPane.caretForeground", "cursor-color");
1755        CLASS_SPECIFIC_MAP.put("TextPane.caretAspectRatio", "cursor-aspect-ratio");
1756        CLASS_SPECIFIC_MAP.put("EditorPane.caretForeground", "cursor-color");
1757        CLASS_SPECIFIC_MAP.put("EditorPane.caretAspectRatio", "cursor-aspect-ratio");
1758
1759        Object JavaDoc[] defaults = {
1760            "FileChooser.cancelIcon", new GTKStockIcon("gtk-cancel", 4),
1761            "FileChooser.okIcon", new GTKStockIcon("gtk-ok", 4),
1762
1763            "OptionPane.errorIcon", new GTKStockIcon("gtk-dialog-error", 6),
1764            "OptionPane.informationIcon", new GTKStockIcon("gtk-dialog-info", 6),
1765            "OptionPane.warningIcon", new GTKStockIcon("gtk-dialog-warning", 6),
1766            "OptionPane.questionIcon", new GTKStockIcon("gtk-dialog-question", 6),
1767            "OptionPane.yesIcon", new GTKStockIcon("gtk-yes", 4),
1768            "OptionPane.noIcon", new GTKStockIcon("gtk-no", 4),
1769            "OptionPane.cancelIcon", new GTKStockIcon("gtk-cancel", 4),
1770            "OptionPane.okIcon", new GTKStockIcon("gtk-ok", 4),
1771        };
1772
1773        for (int counter = 0, max = defaults.length; counter < max;
1774                 counter++) {
1775            DATA.put(defaults[counter], defaults[++counter]);
1776        }
1777    }
1778}
1779
Popular Tags