KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > swing > plaf > gtk > ThemeValue


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.swing.plaf.gtk;
21
22 import javax.swing.*;
23 import java.awt.*;
24 import java.beans.PropertyChangeEvent JavaDoc;
25 import java.beans.PropertyChangeListener JavaDoc;
26 import java.lang.reflect.Constructor JavaDoc;
27 import java.lang.reflect.Field JavaDoc;
28 import java.lang.reflect.Method JavaDoc;
29 import java.util.HashSet JavaDoc;
30 import java.util.Iterator JavaDoc;
31
32 /**
33  * Value which will look something up via reflection from the GTK theme.
34  *
35  * @author Tim Boudreau
36  */

37 final class ThemeValue implements UIDefaults.ActiveValue {
38     private final Object JavaDoc fallback;
39     private final Object JavaDoc aRegion;
40     private Object JavaDoc aColorType = null;
41     private boolean darken = false;
42     
43     private Object JavaDoc value = null;
44     
45     private static Boolean JavaDoc functioning = null;
46     
47     /** Creates a new instance of GTKColor */
48     public ThemeValue(Object JavaDoc region, Object JavaDoc colorType, Object JavaDoc fallback) {
49         this.fallback = fallback;
50         this.aRegion = region;
51         this.aColorType = colorType;
52         register(this);
53     }
54
55     /** Creates a new instance of GTKColor */
56     public ThemeValue(Object JavaDoc region, Object JavaDoc colorType, Object JavaDoc fallback, boolean darken) {
57         this.fallback = fallback;
58         this.aRegion = region;
59         this.aColorType = colorType;
60         this.darken = darken;
61         register(this);
62     }
63     
64     public ThemeValue (Object JavaDoc region, Font fallback) {
65         this.fallback = fallback;
66         this.aRegion = region;
67         register(this);
68     }
69     
70     public Object JavaDoc createValue(UIDefaults table) {
71         if (value == null) {
72             if (!functioning()) {
73                 value = fallback;
74             } else {
75                 if (fallback instanceof Font) {
76                     Object JavaDoc val = getFont();
77                     if (ct++ < 4) {
78                         //Wrong values returned if GTK not yet initialized
79
return val;
80                     }
81                     value = val;
82                 } else {
83                     value = getColor();
84                 }
85             }
86         }
87         return value != null ? value : fallback;
88     }
89     
90     private int ct = 0;
91     
92     void clear() {
93         value = null;
94     }
95     
96     public Font getFont() {
97         Object JavaDoc style = getSynthStyle (aRegion);
98         if (Boolean.TRUE.equals(functioning)) {
99             try {
100                 Font result = (Font) synthStyle_getFontForState.invoke (style,
101                     new Object JavaDoc [] {
102                         getSynthContext ()
103                     });
104                 if (result == null) {
105                     result = (Font) fallback;
106                 }
107                 return result;
108             } catch (Exception JavaDoc e) {
109                 functioning = Boolean.FALSE;
110                 if (log) {
111                     e.printStackTrace();
112                 }
113             }
114         }
115         //This will only happen once, after which functioning will be false
116
return null;
117     }
118     
119     private static boolean log = Boolean.getBoolean ("themeValue.log");
120
121     public Color getColor () {
122         Object JavaDoc style = getSynthStyle (aRegion);
123         if (Boolean.TRUE.equals(functioning)) {
124             try {
125                 Color result = (Color) synthStyle_getColorForState.invoke (style,
126                     new Object JavaDoc [] {
127                         getSynthContext (),
128                         aColorType
129                     });
130                 if (result == null) {
131                     result = (Color) fallback;
132                 }
133                 if (darken) {
134                     result = result.darker();
135                 }
136                 return result;
137             } catch (Exception JavaDoc e) {
138                 functioning = Boolean.FALSE;
139                 if (log) {
140                     e.printStackTrace();
141                 }
142             }
143         }
144         //This will only happen once, after which functioning will be false
145
return null;
146     }
147     
148     public static boolean functioning() {
149         if (functioning == null) {
150             checkFunctioning();
151         }
152         return functioning.booleanValue();
153     }
154
155     private static void checkFunctioning() {
156         functioning = Boolean.FALSE;
157         try {
158             gtkLookAndFeel = Class.forName ("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); //NOI18N
159
synthLookAndFeel = Class.forName ("javax.swing.plaf.synth.SynthLookAndFeel"); //NOI18N
160
region = Class.forName ("javax.swing.plaf.synth.Region"); //NOI18N
161
synthStyle = Class.forName ("javax.swing.plaf.synth.SynthStyle"); //NOI18N
162
synthContext = Class.forName ("javax.swing.plaf.synth.SynthContext"); //NOI18N
163
colorType = Class.forName ("javax.swing.plaf.synth.ColorType"); //NOI18N
164
gtkColorType = Class.forName ("com.sun.java.swing.plaf.gtk.GTKColorType"); //NOI18N
165
synthUI = Class.forName ("sun.swing.plaf.synth.SynthUI"); //NOI18N
166

167
168             synthContextConstructor = synthContext.getDeclaredConstructor(
169                 JComponent.class,
170                 region, synthStyle,
171                 Integer.TYPE
172             );
173             synthContextConstructor.setAccessible(true);
174
175             synthStyle_getColorForState = synthStyle.getDeclaredMethod ("getColorForState", //NOI18N
176
synthContext, colorType );
177                  
178             synthStyle_getColorForState.setAccessible(true);
179             
180             synthStyle_getFontForState = synthStyle.getDeclaredMethod ("getFontForState", //NOI18N
181
synthContext );
182                 
183             synthStyle_getFontForState.setAccessible(true);
184             
185
186             LIGHT = valueOfField (gtkColorType, "LIGHT"); //NOI18N
187
DARK = valueOfField (gtkColorType, "DARK"); //NOI18N
188
MID = valueOfField (gtkColorType, "MID"); //NOI18N
189
BLACK = valueOfField (gtkColorType, "BLACK"); //NOI18N
190
WHITE = valueOfField (gtkColorType, "WHITE"); //NOI18N
191
TEXT_FOREGROUND = valueOfField (colorType, "TEXT_FOREGROUND"); //NOI18N
192
TEXT_BACKGROUND = valueOfField (colorType, "TEXT_BACKGROUND"); //NOI18N
193
FOCUS = valueOfField (colorType, "FOCUS"); //NOI18N
194

195             synthContext_getContext = synthContext.getDeclaredMethod ("getContext",
196                     new Class JavaDoc[] {
197                         Class JavaDoc.class, JComponent.class, region, synthStyle, Integer.TYPE
198                     });
199             synthContext_getContext.setAccessible(true);
200
201             synthLookAndFeel_getStyle = synthLookAndFeel.getDeclaredMethod ("getStyle",
202                         JComponent.class, region
203                     );
204             synthLookAndFeel_getStyle.setAccessible (true);
205
206             REGION_BUTTON = valueOfField (region, "BUTTON"); //NOI18N
207
REGION_PANEL = valueOfField (region, "PANEL"); //NOI18N
208
REGION_SCROLLBAR_THUMB = valueOfField (region, "SCROLL_BAR_THUMB"); //NOI18N
209
REGION_TAB = valueOfField (region, "TABBED_PANE_TAB"); //NOI18N
210
REGION_INTFRAME = valueOfField (region, "INTERNAL_FRAME_TITLE_PANE"); //NOI18N
211

212             synthUI_getContext = synthUI.getDeclaredMethod ("getContext", JComponent.class ); //NOI18N
213

214             functioning = Boolean.TRUE;
215         } catch (Exception JavaDoc e) {
216             System.err.println ("Cannot initialize GTK colors - using hardcoded defaults " + e.getMessage()); //NOI18N
217
if (log) {
218                 e.printStackTrace();
219             }
220             return;
221         }
222     }
223
224     private static JButton getDummyButton() {
225         if (dummyButton == null) {
226             dummyButton = new JButton();
227             CellRendererPane crp = new CellRendererPane();
228             crp.add (dummyButton);
229         }
230         ButtonModel mdl = dummyButton.getModel();
231         return dummyButton;
232     }
233     
234     private static JButton dummyButton = null;
235     
236     private static Object JavaDoc getSynthContext () {
237         try {
238             JButton dummyButton = getDummyButton();
239             
240             if (synthUI.isAssignableFrom(dummyButton.getUI().getClass())) {
241                 return synthUI_getContext.invoke (dummyButton.getUI(), new Object JavaDoc[] {dummyButton});
242             } else {
243                throw new IllegalStateException JavaDoc ("I don't have a SynthButtonUI to play with"); //NOI18N
244
}
245         } catch (Exception JavaDoc e) {
246             functioning = Boolean.FALSE;
247             if (log) {
248                 e.printStackTrace();
249             }
250             return null;
251         }
252     }
253
254     private static Object JavaDoc getSynthStyle (Object JavaDoc region) {
255         try {
256             return synthLookAndFeel_getStyle.invoke (null, new Object JavaDoc[] { getDummyButton(), region} );
257         } catch (Exception JavaDoc e) {
258             functioning = Boolean.FALSE;
259             if (log) {
260                 e.printStackTrace();
261             }
262             return null;
263         }
264     }
265
266     private static Object JavaDoc valueOfField (Class JavaDoc clazz, String JavaDoc field) throws NoSuchFieldException JavaDoc, IllegalAccessException JavaDoc {
267         Field JavaDoc f = clazz.getDeclaredField(field);
268         f.setAccessible(true);
269         return f.get(null);
270     }
271
272     private static Class JavaDoc<?> synthLookAndFeel = null;
273     private static Class JavaDoc<?> gtkLookAndFeel = null;
274     private static Class JavaDoc<?> colorType = null;
275     private static Class JavaDoc<?> region = null;
276     private static Class JavaDoc<?> synthStyle = null;
277     private static Class JavaDoc<?> synthContext = null;
278     private static Class JavaDoc<?> gtkColorType = null;
279     private static Class JavaDoc<?> synthUI = null;
280
281     private static Constructor JavaDoc synthContextConstructor;
282     private static Method JavaDoc synthStyle_getColorForState = null;
283     private static Method JavaDoc synthStyle_getFontForState = null;
284     private static Method JavaDoc synthLookAndFeel_getStyle = null;
285
286     private static Method JavaDoc synthContext_getContext = null;
287     private static Method JavaDoc synthUI_getContext = null;
288
289     //XXX should be some to delete here once done experimenting
290
static Object JavaDoc /* <Region> */ REGION_BUTTON = null;
291     static Object JavaDoc /* <Region> */ REGION_PANEL = null;
292     static Object JavaDoc /* <Region> */ REGION_SCROLLBAR_THUMB = null;
293     static Object JavaDoc /* <Region> */ REGION_TAB = null;
294     static Object JavaDoc /* <Region> */ REGION_INTFRAME = null;
295
296     static Object JavaDoc /* <GTKColorType> */ LIGHT = null;
297     static Object JavaDoc /* <GTKColorType> */ DARK = null;
298     static Object JavaDoc /* <GTKColorType> */ BLACK = null;
299     static Object JavaDoc /* <GTKColorType> */ WHITE = null;
300     static Object JavaDoc /* <GTKColorType> */ MID = null;
301     static Object JavaDoc /* <ColorType> */ TEXT_FOREGROUND = null;
302     static Object JavaDoc /* <ColorType> */ TEXT_BACKGROUND = null;
303     static Object JavaDoc /* <ColorType> */ FOCUS = null;
304     
305     
306     private static HashSet JavaDoc<ThemeValue> instances = null;
307     /**
308      * Unbeautiful caching - the reflection lookup has serious performance
309      * issues - we will cache values instead. */

310     private static synchronized void register (ThemeValue value) {
311         if (instances == null) {
312             instances = new HashSet JavaDoc<ThemeValue>();
313             registerPcl();
314         }
315         instances.add (value);
316     }
317     
318     private static void registerPcl() {
319         PropertyChangeListener JavaDoc l = new Listener JavaDoc();
320         UIManager.addPropertyChangeListener(l);
321         
322         //Thanks to Scott Violet for how to do this. See also
323
//com.sun.java.swing.plaf.gtk.GtkLookAndFeel.WeakPCL
324

325         Toolkit.getDefaultToolkit().addPropertyChangeListener(
326             "gnome.Gtk/FontName", l); //NOI18N
327
Toolkit.getDefaultToolkit().addPropertyChangeListener(
328             "gnome.Xft/DPI", l); //NOI18N
329
Toolkit.getDefaultToolkit().addPropertyChangeListener(
330             "gnome.Net/ThemeName", l); //NOI18N
331

332     }
333     
334     private static class Listener implements PropertyChangeListener JavaDoc {
335         public void propertyChange (PropertyChangeEvent JavaDoc pce) {
336             if (pce.getSource() instanceof UIManager && "lookAndFeel".equals( //NOI18N
337
pce.getPropertyName())) {
338                     
339                 String JavaDoc s = UIManager.getLookAndFeel().getClass().getName();
340                 if (s.indexOf("gtk") < 0) { //NOI18N
341
//We have changed look and feels somehow. Unregister.
342
UIManager.removePropertyChangeListener(this);
343                     Toolkit.getDefaultToolkit().removePropertyChangeListener(
344                         "gnome.Gtk/FontName", this); //NOI18N
345
Toolkit.getDefaultToolkit().removePropertyChangeListener(
346                         "gnome.Xft/DPI", this); //NOI18N
347
Toolkit.getDefaultToolkit().removePropertyChangeListener(
348                         "gnome.Net/ThemeName", this); //NOI18N
349
}
350             } else {
351                 for (ThemeValue tv: instances) {
352                     tv.clear();
353                 }
354             }
355         }
356     }
357     
358     static {
359         //This must be called to initialize the fields before anyone tries
360
//to construct a ThemeValue passing, say, ThemeValue.LIGHT. These are
361
//populated with values from GTKLookAndFeel by reflection
362
functioning();
363     }
364 }
365
Popular Tags