author | darcy |
Fri, 03 Apr 2015 10:41:34 -0700 | |
changeset 29894 | 3e16b51732f5 |
parent 25859 | 3317bb8137f4 |
child 37569 | bf2bc4d9491d |
permissions | -rw-r--r-- |
2658 | 1 |
/* |
29894
3e16b51732f5
8076520: Fix missing doclint warnings in javax.swing.{table, tree, undo, plaf.{metal, nimbus, synth}}
darcy
parents:
25859
diff
changeset
|
2 |
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. |
2658 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2658 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2658 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2658 | 24 |
*/ |
25 |
package javax.swing.plaf.nimbus; |
|
26 |
||
27 |
import javax.swing.Painter; |
|
28 |
||
29 |
import javax.swing.JComponent; |
|
30 |
import javax.swing.UIDefaults; |
|
31 |
import javax.swing.UIManager; |
|
32 |
import javax.swing.plaf.ColorUIResource; |
|
33 |
import javax.swing.plaf.synth.ColorType; |
|
34 |
import static javax.swing.plaf.synth.SynthConstants.*; |
|
35 |
import javax.swing.plaf.synth.SynthContext; |
|
36 |
import javax.swing.plaf.synth.SynthPainter; |
|
37 |
import javax.swing.plaf.synth.SynthStyle; |
|
38 |
import java.awt.Color; |
|
39 |
import java.awt.Font; |
|
40 |
import java.awt.Insets; |
|
5453
3d39f942ca6e
6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory
peterz
parents:
3741
diff
changeset
|
41 |
import java.lang.ref.WeakReference; |
2658 | 42 |
import java.util.ArrayList; |
43 |
import java.util.Collections; |
|
44 |
import java.util.Comparator; |
|
45 |
import java.util.HashMap; |
|
46 |
import java.util.List; |
|
47 |
import java.util.Map; |
|
48 |
import java.util.TreeMap; |
|
49 |
||
50 |
/** |
|
51 |
* <p>A SynthStyle implementation used by Nimbus. Each Region that has been |
|
52 |
* registered with the NimbusLookAndFeel will have an associated NimbusStyle. |
|
53 |
* Third party components that are registered with the NimbusLookAndFeel will |
|
54 |
* therefore be handed a NimbusStyle from the look and feel from the |
|
55 |
* #getStyle(JComponent, Region) method.</p> |
|
56 |
* |
|
57 |
* <p>This class properly reads and retrieves values placed in the UIDefaults |
|
58 |
* according to the standard Nimbus naming conventions. It will create and |
|
59 |
* retrieve painters, fonts, colors, and other data stored there.</p> |
|
60 |
* |
|
61 |
* <p>NimbusStyle also supports the ability to override settings on a per |
|
62 |
* component basis. NimbusStyle checks the component's client property map for |
|
63 |
* "Nimbus.Overrides". If the value associated with this key is an instance of |
|
64 |
* UIDefaults, then the values in that defaults table will override the standard |
|
65 |
* Nimbus defaults in UIManager, but for that component instance only.</p> |
|
66 |
* |
|
67 |
* <p>Optionally, you may specify the client property |
|
68 |
* "Nimbus.Overrides.InheritDefaults". If true, this client property indicates |
|
69 |
* that the defaults located in UIManager should first be read, and then |
|
70 |
* replaced with defaults located in the component client properties. If false, |
|
71 |
* then only the defaults located in the component client property map will |
|
72 |
* be used. If not specified, it is assumed to be true.</p> |
|
73 |
* |
|
74 |
* <p>You must specify "Nimbus.Overrides" for "Nimbus.Overrides.InheritDefaults" |
|
75 |
* to have any effect. "Nimbus.Overrides" indicates whether there are any |
|
76 |
* overrides, while "Nimbus.Overrides.InheritDefaults" indicates whether those |
|
77 |
* overrides should first be initialized with the defaults from UIManager.</p> |
|
78 |
* |
|
79 |
* <p>The NimbusStyle is reloaded whenever a property change event is fired |
|
80 |
* for a component for "Nimbus.Overrides" or "Nimbus.Overrides.InheritDefaults". |
|
81 |
* So for example, setting a new UIDefaults on a component would cause the |
|
82 |
* style to be reloaded.</p> |
|
83 |
* |
|
84 |
* <p>The values are only read out of UIManager once, and then cached. If |
|
85 |
* you need to read the values again (for example, if the UI is being reloaded), |
|
86 |
* then discard this NimbusStyle and read a new one from NimbusLookAndFeel |
|
87 |
* using NimbusLookAndFeel.getStyle.</p> |
|
88 |
* |
|
89 |
* <p>The primary API of interest in this class for 3rd party component authors |
|
90 |
* are the three methods which retrieve painters: #getBackgroundPainter, |
|
91 |
* #getForegroundPainter, and #getBorderPainter.</p> |
|
92 |
* |
|
93 |
* <p>NimbusStyle allows you to specify custom states, or modify the order of |
|
94 |
* states. Synth (and thus Nimbus) has the concept of a "state". For example, |
|
95 |
* a JButton might be in the "MOUSE_OVER" state, or the "ENABLED" state, or the |
|
96 |
* "DISABLED" state. These are all "standard" states which are defined in synth, |
|
97 |
* and which apply to all synth Regions.</p> |
|
98 |
* |
|
99 |
* <p>Sometimes, however, you need to have a custom state. For example, you |
|
100 |
* want JButton to render differently if it's parent is a JToolbar. In Nimbus, |
|
101 |
* you specify these custom states by including a special key in UIDefaults. |
|
102 |
* The following UIDefaults entries define three states for this button:</p> |
|
103 |
* |
|
104 |
* <pre><code> |
|
105 |
* JButton.States = Enabled, Disabled, Toolbar |
|
106 |
* JButton[Enabled].backgroundPainter = somePainter |
|
107 |
* JButton[Disabled].background = BLUE |
|
108 |
* JButton[Toolbar].backgroundPainter = someOtherPaint |
|
109 |
* </code></pre> |
|
110 |
* |
|
111 |
* <p>As you can see, the <code>JButton.States</code> entry lists the states |
|
112 |
* that the JButton style will support. You then specify the settings for |
|
113 |
* each state. If you do not specify the <code>JButton.States</code> entry, |
|
114 |
* then the standard Synth states will be assumed. If you specify the entry |
|
115 |
* but the list of states is empty or null, then the standard synth states |
|
116 |
* will be assumed.</p> |
|
117 |
* |
|
118 |
* @author Richard Bair |
|
119 |
* @author Jasper Potts |
|
120 |
*/ |
|
121 |
public final class NimbusStyle extends SynthStyle { |
|
122 |
/* Keys and scales for large/small/mini components, based on Apples sizes */ |
|
29894
3e16b51732f5
8076520: Fix missing doclint warnings in javax.swing.{table, tree, undo, plaf.{metal, nimbus, synth}}
darcy
parents:
25859
diff
changeset
|
123 |
/** Large key */ |
2658 | 124 |
public static final String LARGE_KEY = "large"; |
29894
3e16b51732f5
8076520: Fix missing doclint warnings in javax.swing.{table, tree, undo, plaf.{metal, nimbus, synth}}
darcy
parents:
25859
diff
changeset
|
125 |
/** Small key */ |
2658 | 126 |
public static final String SMALL_KEY = "small"; |
29894
3e16b51732f5
8076520: Fix missing doclint warnings in javax.swing.{table, tree, undo, plaf.{metal, nimbus, synth}}
darcy
parents:
25859
diff
changeset
|
127 |
/** Mini key */ |
2658 | 128 |
public static final String MINI_KEY = "mini"; |
29894
3e16b51732f5
8076520: Fix missing doclint warnings in javax.swing.{table, tree, undo, plaf.{metal, nimbus, synth}}
darcy
parents:
25859
diff
changeset
|
129 |
/** Large scale */ |
2658 | 130 |
public static final double LARGE_SCALE = 1.15; |
29894
3e16b51732f5
8076520: Fix missing doclint warnings in javax.swing.{table, tree, undo, plaf.{metal, nimbus, synth}}
darcy
parents:
25859
diff
changeset
|
131 |
/** Small scale */ |
2658 | 132 |
public static final double SMALL_SCALE = 0.857; |
29894
3e16b51732f5
8076520: Fix missing doclint warnings in javax.swing.{table, tree, undo, plaf.{metal, nimbus, synth}}
darcy
parents:
25859
diff
changeset
|
133 |
/** Mini scale */ |
2658 | 134 |
public static final double MINI_SCALE = 0.714; |
135 |
||
136 |
/** |
|
137 |
* Special constant used for performance reasons during the get() method. |
|
138 |
* If get() runs through all of the search locations and determines that |
|
139 |
* there is no value, then NULL will be placed into the values map. This way |
|
140 |
* on subsequent lookups it will simply extract NULL, see it, and return |
|
141 |
* null rather than continuing the lookup procedure. |
|
142 |
*/ |
|
143 |
private static final Object NULL = '\0'; |
|
144 |
/** |
|
145 |
* <p>The Color to return from getColorForState if it would otherwise have |
|
146 |
* returned null.</p> |
|
147 |
* |
|
148 |
* <p>Returning null from getColorForState is a very bad thing, as it causes |
|
149 |
* the AWT peer for the component to install a SystemColor, which is not a |
|
150 |
* UIResource. As a result, if <code>null</code> is returned from |
|
151 |
* getColorForState, then thereafter the color is not updated for other |
|
152 |
* states or on LAF changes or updates. This DEFAULT_COLOR is used to |
|
153 |
* ensure that a ColorUIResource is always returned from |
|
154 |
* getColorForState.</p> |
|
155 |
*/ |
|
156 |
private static final Color DEFAULT_COLOR = new ColorUIResource(Color.BLACK); |
|
157 |
/** |
|
158 |
* Simple Comparator for ordering the RuntimeStates according to their |
|
159 |
* rank. |
|
160 |
*/ |
|
161 |
private static final Comparator<RuntimeState> STATE_COMPARATOR = |
|
162 |
new Comparator<RuntimeState>() { |
|
163 |
@Override |
|
164 |
public int compare(RuntimeState a, RuntimeState b) { |
|
165 |
return a.state - b.state; |
|
166 |
} |
|
167 |
}; |
|
168 |
/** |
|
169 |
* The prefix for the component or region that this NimbusStyle |
|
170 |
* represents. This prefix is used to lookup state in the UIManager. |
|
171 |
* It should be something like Button or Slider.Thumb or "MyButton" or |
|
172 |
* ComboBox."ComboBox.arrowButton" or "MyComboBox"."ComboBox.arrowButton" |
|
173 |
*/ |
|
174 |
private String prefix; |
|
175 |
/** |
|
176 |
* The SynthPainter that will be returned from this NimbusStyle. The |
|
177 |
* SynthPainter returned will be a SynthPainterImpl, which will in turn |
|
178 |
* delegate back to this NimbusStyle for the proper Painter (not |
|
179 |
* SynthPainter) to use for painting the foreground, background, or border. |
|
180 |
*/ |
|
181 |
private SynthPainter painter; |
|
182 |
/** |
|
183 |
* Data structure containing all of the defaults, insets, states, and other |
|
184 |
* values associated with this style. This instance refers to default |
|
185 |
* values, and are used when no overrides are discovered in the client |
|
186 |
* properties of a component. These values are lazily created on first |
|
187 |
* access. |
|
188 |
*/ |
|
189 |
private Values values; |
|
190 |
||
191 |
/** |
|
192 |
* A temporary CacheKey used to perform lookups. This pattern avoids |
|
193 |
* creating useless garbage keys, or concatenating strings, etc. |
|
194 |
*/ |
|
195 |
private CacheKey tmpKey = new CacheKey("", 0); |
|
196 |
||
197 |
/** |
|
198 |
* Some NimbusStyles are created for a specific component only. In Nimbus, |
|
199 |
* this happens whenever the component has as a client property a |
|
200 |
* UIDefaults which overrides (or supplements) those defaults found in |
|
201 |
* UIManager. |
|
202 |
*/ |
|
5453
3d39f942ca6e
6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory
peterz
parents:
3741
diff
changeset
|
203 |
private WeakReference<JComponent> component; |
2658 | 204 |
|
205 |
/** |
|
206 |
* Create a new NimbusStyle. Only the prefix must be supplied. At the |
|
207 |
* appropriate time, installDefaults will be called. At that point, all of |
|
208 |
* the state information will be pulled from UIManager and stored locally |
|
209 |
* within this style. |
|
210 |
* |
|
211 |
* @param prefix Something like Button or Slider.Thumb or |
|
212 |
* org.jdesktop.swingx.JXStatusBar or ComboBox."ComboBox.arrowButton" |
|
213 |
* @param c an optional reference to a component that this NimbusStyle |
|
214 |
* should be associated with. This is only used when the component |
|
215 |
* has Nimbus overrides registered in its client properties and |
|
216 |
* should be null otherwise. |
|
217 |
*/ |
|
218 |
NimbusStyle(String prefix, JComponent c) { |
|
5453
3d39f942ca6e
6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory
peterz
parents:
3741
diff
changeset
|
219 |
if (c != null) { |
3d39f942ca6e
6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory
peterz
parents:
3741
diff
changeset
|
220 |
this.component = new WeakReference<JComponent>(c); |
3d39f942ca6e
6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory
peterz
parents:
3741
diff
changeset
|
221 |
} |
2658 | 222 |
this.prefix = prefix; |
223 |
this.painter = new SynthPainterImpl(this); |
|
224 |
} |
|
225 |
||
226 |
/** |
|
20169 | 227 |
* {@inheritDoc} |
2658 | 228 |
* |
229 |
* Overridden to cause this style to populate itself with data from |
|
230 |
* UIDefaults, if necessary. |
|
231 |
*/ |
|
232 |
@Override public void installDefaults(SynthContext ctx) { |
|
233 |
validate(); |
|
234 |
||
235 |
//delegate to the superclass to install defaults such as background, |
|
236 |
//foreground, font, and opaque onto the swing component. |
|
237 |
super.installDefaults(ctx); |
|
238 |
} |
|
239 |
||
240 |
/** |
|
241 |
* Pulls data out of UIDefaults, if it has not done so already, and sets |
|
242 |
* up the internal state. |
|
243 |
*/ |
|
244 |
private void validate() { |
|
245 |
// a non-null values object is the flag we use to determine whether |
|
246 |
// to reparse from UIManager. |
|
247 |
if (values != null) return; |
|
248 |
||
249 |
// reconstruct this NimbusStyle based on the entries in the UIManager |
|
250 |
// and possibly based on any overrides within the component's |
|
251 |
// client properties (assuming such a component exists and contains |
|
252 |
// any Nimbus.Overrides) |
|
253 |
values = new Values(); |
|
254 |
||
3741 | 255 |
Map<String, Object> defaults = |
256 |
((NimbusLookAndFeel) UIManager.getLookAndFeel()). |
|
257 |
getDefaultsForPrefix(prefix); |
|
2658 | 258 |
|
259 |
// inspect the client properties for the key "Nimbus.Overrides". If the |
|
260 |
// value is an instance of UIDefaults, then these defaults are used |
|
261 |
// in place of, or in addition to, the defaults in UIManager. |
|
262 |
if (component != null) { |
|
5453
3d39f942ca6e
6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory
peterz
parents:
3741
diff
changeset
|
263 |
// We know component.get() is non-null here, as if the component |
3d39f942ca6e
6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory
peterz
parents:
3741
diff
changeset
|
264 |
// were GC'ed, we wouldn't be processing its style. |
3d39f942ca6e
6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory
peterz
parents:
3741
diff
changeset
|
265 |
Object o = component.get().getClientProperty("Nimbus.Overrides"); |
2658 | 266 |
if (o instanceof UIDefaults) { |
5453
3d39f942ca6e
6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory
peterz
parents:
3741
diff
changeset
|
267 |
Object i = component.get().getClientProperty( |
2658 | 268 |
"Nimbus.Overrides.InheritDefaults"); |
269 |
boolean inherit = i instanceof Boolean ? (Boolean)i : true; |
|
270 |
UIDefaults d = (UIDefaults)o; |
|
271 |
TreeMap<String, Object> map = new TreeMap<String, Object>(); |
|
272 |
for (Object obj : d.keySet()) { |
|
273 |
if (obj instanceof String) { |
|
274 |
String key = (String)obj; |
|
275 |
if (key.startsWith(prefix)) { |
|
276 |
map.put(key, d.get(key)); |
|
277 |
} |
|
278 |
} |
|
279 |
} |
|
280 |
if (inherit) { |
|
281 |
defaults.putAll(map); |
|
282 |
} else { |
|
283 |
defaults = map; |
|
284 |
} |
|
285 |
} |
|
286 |
} |
|
287 |
||
288 |
//a list of the different types of states used by this style. This |
|
289 |
//list may contain only "standard" states (those defined by Synth), |
|
290 |
//or it may contain custom states, or it may contain only "standard" |
|
291 |
//states but list them in a non-standard order. |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
292 |
List<State<?>> states = new ArrayList<>(); |
2658 | 293 |
//a map of state name to code |
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
294 |
Map<String,Integer> stateCodes = new HashMap<>(); |
2658 | 295 |
//This is a list of runtime "state" context objects. These contain |
296 |
//the values associated with each state. |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
297 |
List<RuntimeState> runtimeStates = new ArrayList<>(); |
2658 | 298 |
|
299 |
//determine whether there are any custom states, or custom state |
|
300 |
//order. If so, then read all those custom states and define the |
|
301 |
//"values" stateTypes to be a non-null array. |
|
302 |
//Otherwise, let the "values" stateTypes be null to indicate that |
|
303 |
//there are no custom states or custom state ordering |
|
3741 | 304 |
String statesString = (String)defaults.get(prefix + ".States"); |
2658 | 305 |
if (statesString != null) { |
306 |
String s[] = statesString.split(","); |
|
307 |
for (int i=0; i<s.length; i++) { |
|
308 |
s[i] = s[i].trim(); |
|
309 |
if (!State.isStandardStateName(s[i])) { |
|
310 |
//this is a non-standard state name, so look for the |
|
311 |
//custom state associated with it |
|
312 |
String stateName = prefix + "." + s[i]; |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
313 |
State<?> customState = (State)defaults.get(stateName); |
2658 | 314 |
if (customState != null) { |
315 |
states.add(customState); |
|
316 |
} |
|
317 |
} else { |
|
318 |
states.add(State.getStandardState(s[i])); |
|
319 |
} |
|
320 |
} |
|
321 |
||
322 |
//if there were any states defined, then set the stateTypes array |
|
323 |
//to be non-null. Otherwise, leave it null (meaning, use the |
|
324 |
//standard synth states). |
|
325 |
if (states.size() > 0) { |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
326 |
values.stateTypes = states.toArray(new State<?>[states.size()]); |
2658 | 327 |
} |
328 |
||
329 |
//assign codes for each of the state types |
|
330 |
int code = 1; |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
331 |
for (State<?> state : states) { |
2658 | 332 |
stateCodes.put(state.getName(), code); |
333 |
code <<= 1; |
|
334 |
} |
|
335 |
} else { |
|
336 |
//since there were no custom states defined, setup the list of |
|
337 |
//standard synth states. Note that the "v.stateTypes" is not |
|
338 |
//being set here, indicating that at runtime the state selection |
|
339 |
//routines should use standard synth states instead of custom |
|
340 |
//states. I do need to popuplate this temp list now though, so that |
|
341 |
//the remainder of this method will function as expected. |
|
342 |
states.add(State.Enabled); |
|
343 |
states.add(State.MouseOver); |
|
344 |
states.add(State.Pressed); |
|
345 |
states.add(State.Disabled); |
|
346 |
states.add(State.Focused); |
|
347 |
states.add(State.Selected); |
|
348 |
states.add(State.Default); |
|
349 |
||
350 |
//assign codes for the states |
|
351 |
stateCodes.put("Enabled", ENABLED); |
|
352 |
stateCodes.put("MouseOver", MOUSE_OVER); |
|
353 |
stateCodes.put("Pressed", PRESSED); |
|
354 |
stateCodes.put("Disabled", DISABLED); |
|
355 |
stateCodes.put("Focused", FOCUSED); |
|
356 |
stateCodes.put("Selected", SELECTED); |
|
357 |
stateCodes.put("Default", DEFAULT); |
|
358 |
} |
|
359 |
||
360 |
//Now iterate over all the keys in the defaults table |
|
3741 | 361 |
for (String key : defaults.keySet()) { |
2658 | 362 |
//The key is something like JButton.Enabled.backgroundPainter, |
363 |
//or JButton.States, or JButton.background. |
|
364 |
//Remove the "JButton." portion of the key |
|
365 |
String temp = key.substring(prefix.length()); |
|
366 |
//if there is a " or : then we skip it because it is a subregion |
|
367 |
//of some kind |
|
368 |
if (temp.indexOf('"') != -1 || temp.indexOf(':') != -1) continue; |
|
369 |
//remove the separator |
|
370 |
temp = temp.substring(1); |
|
371 |
//At this point, temp may be any of the following: |
|
372 |
//background |
|
373 |
//[Enabled].background |
|
374 |
//[Enabled+MouseOver].background |
|
375 |
//property.foo |
|
376 |
||
377 |
//parse out the states and the property |
|
378 |
String stateString = null; |
|
379 |
String property = null; |
|
380 |
int bracketIndex = temp.indexOf(']'); |
|
381 |
if (bracketIndex < 0) { |
|
382 |
//there is not a state string, so property = temp |
|
383 |
property = temp; |
|
384 |
} else { |
|
385 |
stateString = temp.substring(0, bracketIndex); |
|
386 |
property = temp.substring(bracketIndex + 2); |
|
387 |
} |
|
388 |
||
389 |
//now that I have the state (if any) and the property, get the |
|
390 |
//value for this property and install it where it belongs |
|
391 |
if (stateString == null) { |
|
392 |
//there was no state, just a property. Check for the custom |
|
393 |
//"contentMargins" property (which is handled specially by |
|
394 |
//Synth/Nimbus). Also check for the property being "States", |
|
395 |
//in which case it is not a real property and should be ignored. |
|
396 |
//otherwise, assume it is a property and install it on the |
|
397 |
//values object |
|
398 |
if ("contentMargins".equals(property)) { |
|
3741 | 399 |
values.contentMargins = (Insets)defaults.get(key); |
2658 | 400 |
} else if ("States".equals(property)) { |
401 |
//ignore |
|
402 |
} else { |
|
3741 | 403 |
values.defaults.put(property, defaults.get(key)); |
2658 | 404 |
} |
405 |
} else { |
|
406 |
//it is possible that the developer has a malformed UIDefaults |
|
407 |
//entry, such that something was specified in the place of |
|
408 |
//the State portion of the key but it wasn't a state. In this |
|
409 |
//case, skip will be set to true |
|
410 |
boolean skip = false; |
|
411 |
//this variable keeps track of the int value associated with |
|
412 |
//the state. See SynthState for details. |
|
413 |
int componentState = 0; |
|
414 |
//Multiple states may be specified in the string, such as |
|
415 |
//Enabled+MouseOver |
|
416 |
String[] stateParts = stateString.split("\\+"); |
|
417 |
//For each state, we need to find the State object associated |
|
418 |
//with it, or skip it if it cannot be found. |
|
419 |
for (String s : stateParts) { |
|
420 |
if (stateCodes.containsKey(s)) { |
|
421 |
componentState |= stateCodes.get(s); |
|
422 |
} else { |
|
423 |
//Was not a state. Maybe it was a subregion or something |
|
424 |
//skip it. |
|
425 |
skip = true; |
|
426 |
break; |
|
427 |
} |
|
428 |
} |
|
429 |
||
430 |
if (skip) continue; |
|
431 |
||
432 |
//find the RuntimeState for this State |
|
433 |
RuntimeState rs = null; |
|
434 |
for (RuntimeState s : runtimeStates) { |
|
435 |
if (s.state == componentState) { |
|
436 |
rs = s; |
|
437 |
break; |
|
438 |
} |
|
439 |
} |
|
440 |
||
441 |
//couldn't find the runtime state, so create a new one |
|
442 |
if (rs == null) { |
|
443 |
rs = new RuntimeState(componentState, stateString); |
|
444 |
runtimeStates.add(rs); |
|
445 |
} |
|
446 |
||
447 |
//check for a couple special properties, such as for the |
|
448 |
//painters. If these are found, then set the specially on |
|
449 |
//the runtime state. Else, it is just a normal property, |
|
450 |
//so put it in the UIDefaults associated with that runtime |
|
451 |
//state |
|
452 |
if ("backgroundPainter".equals(property)) { |
|
3741 | 453 |
rs.backgroundPainter = getPainter(defaults, key); |
2658 | 454 |
} else if ("foregroundPainter".equals(property)) { |
3741 | 455 |
rs.foregroundPainter = getPainter(defaults, key); |
2658 | 456 |
} else if ("borderPainter".equals(property)) { |
3741 | 457 |
rs.borderPainter = getPainter(defaults, key); |
2658 | 458 |
} else { |
3741 | 459 |
rs.defaults.put(property, defaults.get(key)); |
2658 | 460 |
} |
461 |
} |
|
462 |
} |
|
463 |
||
464 |
//now that I've collected all the runtime states, I'll sort them based |
|
465 |
//on their integer "state" (see SynthState for how this works). |
|
466 |
Collections.sort(runtimeStates, STATE_COMPARATOR); |
|
467 |
||
468 |
//finally, set the array of runtime states on the values object |
|
3741 | 469 |
values.states = runtimeStates.toArray(new RuntimeState[runtimeStates.size()]); |
470 |
} |
|
471 |
||
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
472 |
private Painter<Object> getPainter(Map<String, Object> defaults, String key) { |
3741 | 473 |
Object p = defaults.get(key); |
474 |
if (p instanceof UIDefaults.LazyValue) { |
|
475 |
p = ((UIDefaults.LazyValue)p).createValue(UIManager.getDefaults()); |
|
476 |
} |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
477 |
@SuppressWarnings("unchecked") |
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
478 |
Painter<Object> tmp = (p instanceof Painter ? (Painter)p : null); |
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
479 |
return tmp; |
2658 | 480 |
} |
481 |
||
482 |
/** |
|
20169 | 483 |
* {@inheritDoc} |
2658 | 484 |
* |
485 |
* Overridden to cause this style to populate itself with data from |
|
486 |
* UIDefaults, if necessary. |
|
487 |
*/ |
|
488 |
@Override public Insets getInsets(SynthContext ctx, Insets in) { |
|
489 |
if (in == null) { |
|
490 |
in = new Insets(0, 0, 0, 0); |
|
491 |
} |
|
492 |
||
493 |
Values v = getValues(ctx); |
|
494 |
||
495 |
if (v.contentMargins == null) { |
|
496 |
in.bottom = in.top = in.left = in.right = 0; |
|
497 |
return in; |
|
498 |
} else { |
|
499 |
in.bottom = v.contentMargins.bottom; |
|
500 |
in.top = v.contentMargins.top; |
|
501 |
in.left = v.contentMargins.left; |
|
502 |
in.right = v.contentMargins.right; |
|
503 |
// Account for scale |
|
504 |
// The key "JComponent.sizeVariant" is used to match Apple's LAF |
|
505 |
String scaleKey = (String)ctx.getComponent().getClientProperty( |
|
506 |
"JComponent.sizeVariant"); |
|
507 |
if (scaleKey != null){ |
|
508 |
if (LARGE_KEY.equals(scaleKey)){ |
|
509 |
in.bottom *= LARGE_SCALE; |
|
510 |
in.top *= LARGE_SCALE; |
|
511 |
in.left *= LARGE_SCALE; |
|
512 |
in.right *= LARGE_SCALE; |
|
513 |
} else if (SMALL_KEY.equals(scaleKey)){ |
|
514 |
in.bottom *= SMALL_SCALE; |
|
515 |
in.top *= SMALL_SCALE; |
|
516 |
in.left *= SMALL_SCALE; |
|
517 |
in.right *= SMALL_SCALE; |
|
518 |
} else if (MINI_KEY.equals(scaleKey)){ |
|
519 |
in.bottom *= MINI_SCALE; |
|
520 |
in.top *= MINI_SCALE; |
|
521 |
in.left *= MINI_SCALE; |
|
522 |
in.right *= MINI_SCALE; |
|
523 |
} |
|
524 |
} |
|
525 |
return in; |
|
526 |
} |
|
527 |
} |
|
528 |
||
529 |
/** |
|
20169 | 530 |
* {@inheritDoc} |
2658 | 531 |
* |
532 |
* <p>Overridden to cause this style to populate itself with data from |
|
533 |
* UIDefaults, if necessary.</p> |
|
534 |
* |
|
535 |
* <p>In addition, NimbusStyle handles ColorTypes slightly differently from |
|
536 |
* Synth.</p> |
|
537 |
* <ul> |
|
538 |
* <li>ColorType.BACKGROUND will equate to the color stored in UIDefaults |
|
539 |
* named "background".</li> |
|
540 |
* <li>ColorType.TEXT_BACKGROUND will equate to the color stored in |
|
541 |
* UIDefaults named "textBackground".</li> |
|
542 |
* <li>ColorType.FOREGROUND will equate to the color stored in UIDefaults |
|
543 |
* named "textForeground".</li> |
|
544 |
* <li>ColorType.TEXT_FOREGROUND will equate to the color stored in |
|
545 |
* UIDefaults named "textForeground".</li> |
|
546 |
* </ul> |
|
547 |
*/ |
|
548 |
@Override protected Color getColorForState(SynthContext ctx, ColorType type) { |
|
549 |
String key = null; |
|
550 |
if (type == ColorType.BACKGROUND) { |
|
551 |
key = "background"; |
|
552 |
} else if (type == ColorType.FOREGROUND) { |
|
553 |
//map FOREGROUND as TEXT_FOREGROUND |
|
554 |
key = "textForeground"; |
|
555 |
} else if (type == ColorType.TEXT_BACKGROUND) { |
|
556 |
key = "textBackground"; |
|
557 |
} else if (type == ColorType.TEXT_FOREGROUND) { |
|
558 |
key = "textForeground"; |
|
559 |
} else if (type == ColorType.FOCUS) { |
|
560 |
key = "focus"; |
|
561 |
} else if (type != null) { |
|
562 |
key = type.toString(); |
|
563 |
} else { |
|
564 |
return DEFAULT_COLOR; |
|
565 |
} |
|
566 |
Color c = (Color) get(ctx, key); |
|
567 |
//if all else fails, return a default color (which is a ColorUIResource) |
|
568 |
if (c == null) c = DEFAULT_COLOR; |
|
569 |
return c; |
|
570 |
} |
|
571 |
||
572 |
/** |
|
20169 | 573 |
* {@inheritDoc} |
2658 | 574 |
* |
575 |
* Overridden to cause this style to populate itself with data from |
|
576 |
* UIDefaults, if necessary. If a value named "font" is not found in |
|
577 |
* UIDefaults, then the "defaultFont" font in UIDefaults will be returned |
|
578 |
* instead. |
|
579 |
*/ |
|
580 |
@Override protected Font getFontForState(SynthContext ctx) { |
|
581 |
Font f = (Font)get(ctx, "font"); |
|
582 |
if (f == null) f = UIManager.getFont("defaultFont"); |
|
583 |
||
584 |
// Account for scale |
|
585 |
// The key "JComponent.sizeVariant" is used to match Apple's LAF |
|
586 |
String scaleKey = (String)ctx.getComponent().getClientProperty( |
|
587 |
"JComponent.sizeVariant"); |
|
588 |
if (scaleKey != null){ |
|
589 |
if (LARGE_KEY.equals(scaleKey)){ |
|
590 |
f = f.deriveFont(Math.round(f.getSize2D()*LARGE_SCALE)); |
|
591 |
} else if (SMALL_KEY.equals(scaleKey)){ |
|
592 |
f = f.deriveFont(Math.round(f.getSize2D()*SMALL_SCALE)); |
|
593 |
} else if (MINI_KEY.equals(scaleKey)){ |
|
594 |
f = f.deriveFont(Math.round(f.getSize2D()*MINI_SCALE)); |
|
595 |
} |
|
596 |
} |
|
597 |
return f; |
|
598 |
} |
|
599 |
||
600 |
/** |
|
20169 | 601 |
* {@inheritDoc} |
2658 | 602 |
* |
603 |
* Returns the SynthPainter for this style, which ends up delegating to |
|
604 |
* the Painters installed in this style. |
|
605 |
*/ |
|
606 |
@Override public SynthPainter getPainter(SynthContext ctx) { |
|
607 |
return painter; |
|
608 |
} |
|
609 |
||
610 |
/** |
|
20169 | 611 |
* {@inheritDoc} |
2658 | 612 |
* |
613 |
* Overridden to cause this style to populate itself with data from |
|
614 |
* UIDefaults, if necessary. If opacity is not specified in UI defaults, |
|
615 |
* then it defaults to being non-opaque. |
|
616 |
*/ |
|
617 |
@Override public boolean isOpaque(SynthContext ctx) { |
|
618 |
// Force Table CellRenderers to be opaque |
|
619 |
if ("Table.cellRenderer".equals(ctx.getComponent().getName())) { |
|
620 |
return true; |
|
621 |
} |
|
622 |
Boolean opaque = (Boolean)get(ctx, "opaque"); |
|
623 |
return opaque == null ? false : opaque; |
|
624 |
} |
|
625 |
||
626 |
/** |
|
20169 | 627 |
* {@inheritDoc} |
2658 | 628 |
* |
629 |
* <p>Overridden to cause this style to populate itself with data from |
|
630 |
* UIDefaults, if necessary.</p> |
|
631 |
* |
|
632 |
* <p>Properties in UIDefaults may be specified in a chained manner. For |
|
633 |
* example: |
|
634 |
* <pre> |
|
635 |
* background |
|
636 |
* Button.opacity |
|
637 |
* Button.Enabled.foreground |
|
638 |
* Button.Enabled+Selected.background |
|
20169 | 639 |
* </pre> |
2658 | 640 |
* |
641 |
* <p>In this example, suppose you were in the Enabled+Selected state and |
|
642 |
* searched for "foreground". In this case, we first check for |
|
643 |
* Button.Enabled+Selected.foreground, but no such color exists. We then |
|
644 |
* fall back to the next valid state, in this case, |
|
645 |
* Button.Enabled.foreground, and have a match. So we return it.</p> |
|
646 |
* |
|
647 |
* <p>Again, if we were in the state Enabled and looked for "background", we |
|
648 |
* wouldn't find it in Button.Enabled, or in Button, but would at the top |
|
649 |
* level in UIManager. So we return that value.</p> |
|
650 |
* |
|
651 |
* <p>One special note: the "key" passed to this method could be of the form |
|
652 |
* "background" or "Button.background" where "Button" equals the prefix |
|
653 |
* passed to the NimbusStyle constructor. In either case, it looks for |
|
654 |
* "background".</p> |
|
655 |
* |
|
22260
c9185e010e03
8031082: Fix non-missing doclint problems in client libraries
darcy
parents:
21278
diff
changeset
|
656 |
* @param ctx SynthContext identifying requester |
2658 | 657 |
* @param key must not be null |
658 |
*/ |
|
659 |
@Override public Object get(SynthContext ctx, Object key) { |
|
660 |
Values v = getValues(ctx); |
|
661 |
||
662 |
// strip off the prefix, if there is one. |
|
663 |
String fullKey = key.toString(); |
|
25122
1ecc464c69d2
8044460: Cleanup new Boolean and single character strings
rriggs
parents:
22260
diff
changeset
|
664 |
String partialKey = fullKey.substring(fullKey.indexOf('.') + 1); |
2658 | 665 |
|
666 |
Object obj = null; |
|
667 |
int xstate = getExtendedState(ctx, v); |
|
668 |
||
669 |
// check the cache |
|
670 |
tmpKey.init(partialKey, xstate); |
|
671 |
obj = v.cache.get(tmpKey); |
|
672 |
boolean wasInCache = obj != null; |
|
673 |
if (!wasInCache){ |
|
674 |
// Search exact matching states and then lesser matching states |
|
675 |
RuntimeState s = null; |
|
676 |
int[] lastIndex = new int[] {-1}; |
|
677 |
while (obj == null && |
|
678 |
(s = getNextState(v.states, lastIndex, xstate)) != null) { |
|
679 |
obj = s.defaults.get(partialKey); |
|
680 |
} |
|
681 |
// Search Region Defaults |
|
682 |
if (obj == null && v.defaults != null) { |
|
683 |
obj = v.defaults.get(partialKey); |
|
684 |
} |
|
685 |
// return found object |
|
686 |
// Search UIManager Defaults |
|
687 |
if (obj == null) obj = UIManager.get(fullKey); |
|
688 |
// Search Synth Defaults for InputMaps |
|
689 |
if (obj == null && partialKey.equals("focusInputMap")) { |
|
690 |
obj = super.get(ctx, fullKey); |
|
691 |
} |
|
692 |
// if all we got was a null, store this fact for later use |
|
693 |
v.cache.put(new CacheKey(partialKey, xstate), |
|
694 |
obj == null ? NULL : obj); |
|
695 |
} |
|
696 |
// return found object |
|
697 |
return obj == NULL ? null : obj; |
|
698 |
} |
|
699 |
||
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
700 |
@SuppressWarnings("unchecked") |
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
701 |
private static Painter<Object> paintFilter(@SuppressWarnings("rawtypes") Painter painter) { |
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
702 |
return (Painter<Object>) painter; |
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
703 |
} |
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
704 |
|
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
705 |
|
2658 | 706 |
/** |
707 |
* Gets the appropriate background Painter, if there is one, for the state |
|
708 |
* specified in the given SynthContext. This method does appropriate |
|
709 |
* fallback searching, as described in #get. |
|
710 |
* |
|
711 |
* @param ctx The SynthContext. Must not be null. |
|
712 |
* @return The background painter associated for the given state, or null if |
|
713 |
* none could be found. |
|
714 |
*/ |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
715 |
public Painter<Object> getBackgroundPainter(SynthContext ctx) { |
2658 | 716 |
Values v = getValues(ctx); |
717 |
int xstate = getExtendedState(ctx, v); |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
718 |
Painter<Object> p = null; |
2658 | 719 |
|
720 |
// check the cache |
|
721 |
tmpKey.init("backgroundPainter$$instance", xstate); |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
722 |
p = paintFilter((Painter)v.cache.get(tmpKey)); |
2658 | 723 |
if (p != null) return p; |
724 |
||
725 |
// not in cache, so lookup and store in cache |
|
726 |
RuntimeState s = null; |
|
727 |
int[] lastIndex = new int[] {-1}; |
|
728 |
while ((s = getNextState(v.states, lastIndex, xstate)) != null) { |
|
729 |
if (s.backgroundPainter != null) { |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
730 |
p = paintFilter(s.backgroundPainter); |
2658 | 731 |
break; |
732 |
} |
|
733 |
} |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
734 |
if (p == null) p = paintFilter((Painter)get(ctx, "backgroundPainter")); |
2658 | 735 |
if (p != null) { |
736 |
v.cache.put(new CacheKey("backgroundPainter$$instance", xstate), p); |
|
737 |
} |
|
738 |
return p; |
|
739 |
} |
|
740 |
||
741 |
/** |
|
742 |
* Gets the appropriate foreground Painter, if there is one, for the state |
|
743 |
* specified in the given SynthContext. This method does appropriate |
|
744 |
* fallback searching, as described in #get. |
|
745 |
* |
|
746 |
* @param ctx The SynthContext. Must not be null. |
|
747 |
* @return The foreground painter associated for the given state, or null if |
|
748 |
* none could be found. |
|
749 |
*/ |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
750 |
public Painter<Object> getForegroundPainter(SynthContext ctx) { |
2658 | 751 |
Values v = getValues(ctx); |
752 |
int xstate = getExtendedState(ctx, v); |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
753 |
Painter<Object> p = null; |
2658 | 754 |
|
755 |
// check the cache |
|
756 |
tmpKey.init("foregroundPainter$$instance", xstate); |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
757 |
p = paintFilter((Painter)v.cache.get(tmpKey)); |
2658 | 758 |
if (p != null) return p; |
759 |
||
760 |
// not in cache, so lookup and store in cache |
|
761 |
RuntimeState s = null; |
|
762 |
int[] lastIndex = new int[] {-1}; |
|
763 |
while ((s = getNextState(v.states, lastIndex, xstate)) != null) { |
|
764 |
if (s.foregroundPainter != null) { |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
765 |
p = paintFilter(s.foregroundPainter); |
2658 | 766 |
break; |
767 |
} |
|
768 |
} |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
769 |
if (p == null) p = paintFilter((Painter)get(ctx, "foregroundPainter")); |
2658 | 770 |
if (p != null) { |
771 |
v.cache.put(new CacheKey("foregroundPainter$$instance", xstate), p); |
|
772 |
} |
|
773 |
return p; |
|
774 |
} |
|
775 |
||
776 |
/** |
|
777 |
* Gets the appropriate border Painter, if there is one, for the state |
|
778 |
* specified in the given SynthContext. This method does appropriate |
|
779 |
* fallback searching, as described in #get. |
|
780 |
* |
|
781 |
* @param ctx The SynthContext. Must not be null. |
|
782 |
* @return The border painter associated for the given state, or null if |
|
783 |
* none could be found. |
|
784 |
*/ |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
785 |
public Painter<Object> getBorderPainter(SynthContext ctx) { |
2658 | 786 |
Values v = getValues(ctx); |
787 |
int xstate = getExtendedState(ctx, v); |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
788 |
Painter<Object> p = null; |
2658 | 789 |
|
790 |
// check the cache |
|
791 |
tmpKey.init("borderPainter$$instance", xstate); |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
792 |
p = paintFilter((Painter)v.cache.get(tmpKey)); |
2658 | 793 |
if (p != null) return p; |
794 |
||
795 |
// not in cache, so lookup and store in cache |
|
796 |
RuntimeState s = null; |
|
797 |
int[] lastIndex = new int[] {-1}; |
|
798 |
while ((s = getNextState(v.states, lastIndex, xstate)) != null) { |
|
799 |
if (s.borderPainter != null) { |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
800 |
p = paintFilter(s.borderPainter); |
2658 | 801 |
break; |
802 |
} |
|
803 |
} |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
804 |
if (p == null) p = paintFilter((Painter)get(ctx, "borderPainter")); |
2658 | 805 |
if (p != null) { |
806 |
v.cache.put(new CacheKey("borderPainter$$instance", xstate), p); |
|
807 |
} |
|
808 |
return p; |
|
809 |
} |
|
810 |
||
811 |
/** |
|
812 |
* Utility method which returns the proper Values based on the given |
|
813 |
* SynthContext. Ensures that parsing of the values has occurred, or |
|
814 |
* reoccurs as necessary. |
|
815 |
* |
|
816 |
* @param ctx The SynthContext |
|
817 |
* @return a non-null values reference |
|
818 |
*/ |
|
819 |
private Values getValues(SynthContext ctx) { |
|
820 |
validate(); |
|
821 |
return values; |
|
822 |
} |
|
823 |
||
824 |
/** |
|
21278 | 825 |
* Simple utility method that searches the given array of Strings for the |
2658 | 826 |
* given string. This method is only called from getExtendedState if |
827 |
* the developer has specified a specific state for the component to be |
|
828 |
* in (ie, has "wedged" the component in that state) by specifying |
|
829 |
* they client property "Nimbus.State". |
|
830 |
* |
|
831 |
* @param names a non-null array of strings |
|
832 |
* @param name the name to look for in the array |
|
833 |
* @return true or false based on whether the given name is in the array |
|
834 |
*/ |
|
835 |
private boolean contains(String[] names, String name) { |
|
836 |
assert name != null; |
|
837 |
for (int i=0; i<names.length; i++) { |
|
838 |
if (name.equals(names[i])) { |
|
839 |
return true; |
|
840 |
} |
|
841 |
} |
|
842 |
return false; |
|
843 |
} |
|
844 |
||
845 |
/** |
|
846 |
* <p>Gets the extended state for a given synth context. Nimbus supports the |
|
847 |
* ability to define custom states. The algorithm used for choosing what |
|
848 |
* style information to use for a given state requires a single integer |
|
849 |
* bit string where each bit in the integer represents a different state |
|
850 |
* that the component is in. This method uses the componentState as |
|
851 |
* reported in the SynthContext, in addition to custom states, to determine |
|
852 |
* what this extended state is.</p> |
|
853 |
* |
|
854 |
* <p>In addition, this method checks the component in the given context |
|
855 |
* for a client property called "Nimbus.State". If one exists, then it will |
|
856 |
* decompose the String associated with that property to determine what |
|
857 |
* state to return. In this way, the developer can force a component to be |
|
858 |
* in a specific state, regardless of what the "real" state of the component |
|
859 |
* is.</p> |
|
860 |
* |
|
861 |
* <p>The string associated with "Nimbus.State" would be of the form: |
|
862 |
* <pre>Enabled+CustomState+MouseOver</pre></p> |
|
863 |
* |
|
864 |
* @param ctx |
|
865 |
* @param v |
|
866 |
* @return |
|
867 |
*/ |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
868 |
@SuppressWarnings({"unchecked", "rawtypes"}) |
2658 | 869 |
private int getExtendedState(SynthContext ctx, Values v) { |
870 |
JComponent c = ctx.getComponent(); |
|
871 |
int xstate = 0; |
|
872 |
int mask = 1; |
|
873 |
//check for the Nimbus.State client property |
|
874 |
//Performance NOTE: getClientProperty ends up inside a synchronized |
|
875 |
//block, so there is some potential for performance issues here, however |
|
876 |
//I'm not certain that there is one on a modern VM. |
|
877 |
Object property = c.getClientProperty("Nimbus.State"); |
|
878 |
if (property != null) { |
|
879 |
String stateNames = property.toString(); |
|
880 |
String[] states = stateNames.split("\\+"); |
|
881 |
if (v.stateTypes == null){ |
|
882 |
// standard states only |
|
883 |
for (String stateStr : states) { |
|
884 |
State.StandardState s = State.getStandardState(stateStr); |
|
885 |
if (s != null) xstate |= s.getState(); |
|
886 |
} |
|
887 |
} else { |
|
888 |
// custom states |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
889 |
for (State<?> s : v.stateTypes) { |
2658 | 890 |
if (contains(states, s.getName())) { |
891 |
xstate |= mask; |
|
892 |
} |
|
893 |
mask <<= 1; |
|
894 |
} |
|
895 |
} |
|
896 |
} else { |
|
897 |
//if there are no custom states defined, then simply return the |
|
898 |
//state that Synth reported |
|
899 |
if (v.stateTypes == null) return ctx.getComponentState(); |
|
900 |
||
901 |
//there are custom states on this values, so I'll have to iterate |
|
902 |
//over them all and return a custom extended state |
|
903 |
int state = ctx.getComponentState(); |
|
904 |
for (State s : v.stateTypes) { |
|
905 |
if (s.isInState(c, state)) { |
|
906 |
xstate |= mask; |
|
907 |
} |
|
908 |
mask <<= 1; |
|
909 |
} |
|
910 |
} |
|
911 |
return xstate; |
|
912 |
} |
|
913 |
||
914 |
/** |
|
915 |
* <p>Gets the RuntimeState that most closely matches the state in the given |
|
916 |
* context, but is less specific than the given "lastState". Essentially, |
|
917 |
* this allows you to search for the next best state.</p> |
|
918 |
* |
|
919 |
* <p>For example, if you had the following three states: |
|
920 |
* <pre> |
|
921 |
* Enabled |
|
922 |
* Enabled+Pressed |
|
923 |
* Disabled |
|
924 |
* </pre> |
|
925 |
* And you wanted to find the state that best represented |
|
926 |
* ENABLED+PRESSED+FOCUSED and <code>lastState</code> was null (or an |
|
927 |
* empty array, or an array with a single int with index == -1), then |
|
928 |
* Enabled+Pressed would be returned. If you then call this method again but |
|
929 |
* pass the index of Enabled+Pressed as the "lastState", then |
|
930 |
* Enabled would be returned. If you call this method a third time and pass |
|
931 |
* the index of Enabled in as the <code>lastState</code>, then null would be |
|
932 |
* returned.</p> |
|
933 |
* |
|
934 |
* <p>The actual code path for determining the proper state is the same as |
|
935 |
* in Synth.</p> |
|
936 |
* |
|
937 |
* @param ctx |
|
938 |
* @param lastState a 1 element array, allowing me to do pass-by-reference. |
|
939 |
* @return |
|
940 |
*/ |
|
941 |
private RuntimeState getNextState(RuntimeState[] states, |
|
942 |
int[] lastState, |
|
943 |
int xstate) { |
|
944 |
// Use the StateInfo with the most bits that matches that of state. |
|
945 |
// If there are none, then fallback to |
|
946 |
// the StateInfo with a state of 0, indicating it'll match anything. |
|
947 |
||
948 |
// Consider if we have 3 StateInfos a, b and c with states: |
|
949 |
// SELECTED, SELECTED | ENABLED, 0 |
|
950 |
// |
|
951 |
// Input Return Value |
|
952 |
// ----- ------------ |
|
953 |
// SELECTED a |
|
954 |
// SELECTED | ENABLED b |
|
955 |
// MOUSE_OVER c |
|
956 |
// SELECTED | ENABLED | FOCUSED b |
|
957 |
// ENABLED c |
|
958 |
||
959 |
if (states != null && states.length > 0) { |
|
960 |
int bestCount = 0; |
|
961 |
int bestIndex = -1; |
|
962 |
int wildIndex = -1; |
|
963 |
||
964 |
//if xstate is 0, then search for the runtime state with component |
|
965 |
//state of 0. That is, find the exact match and return it. |
|
966 |
if (xstate == 0) { |
|
967 |
for (int counter = states.length - 1; counter >= 0; counter--) { |
|
968 |
if (states[counter].state == 0) { |
|
969 |
lastState[0] = counter; |
|
970 |
return states[counter]; |
|
971 |
} |
|
972 |
} |
|
973 |
//an exact match couldn't be found, so there was no match. |
|
974 |
lastState[0] = -1; |
|
975 |
return null; |
|
976 |
} |
|
977 |
||
978 |
//xstate is some value != 0 |
|
979 |
||
980 |
//determine from which index to start looking. If lastState[0] is -1 |
|
981 |
//then we know to start from the end of the state array. Otherwise, |
|
982 |
//we start at the lastIndex - 1. |
|
983 |
int lastStateIndex = lastState == null || lastState[0] == -1 ? |
|
984 |
states.length : lastState[0]; |
|
985 |
||
986 |
for (int counter = lastStateIndex - 1; counter >= 0; counter--) { |
|
987 |
int oState = states[counter].state; |
|
988 |
||
989 |
if (oState == 0) { |
|
990 |
if (wildIndex == -1) { |
|
991 |
wildIndex = counter; |
|
992 |
} |
|
993 |
} else if ((xstate & oState) == oState) { |
|
994 |
// This is key, we need to make sure all bits of the |
|
995 |
// StateInfo match, otherwise a StateInfo with |
|
996 |
// SELECTED | ENABLED would match ENABLED, which we |
|
997 |
// don't want. |
|
998 |
||
999 |
// This comes from BigInteger.bitCnt |
|
1000 |
int bitCount = oState; |
|
1001 |
bitCount -= (0xaaaaaaaa & bitCount) >>> 1; |
|
1002 |
bitCount = (bitCount & 0x33333333) + ((bitCount >>> 2) & |
|
1003 |
0x33333333); |
|
1004 |
bitCount = bitCount + (bitCount >>> 4) & 0x0f0f0f0f; |
|
1005 |
bitCount += bitCount >>> 8; |
|
1006 |
bitCount += bitCount >>> 16; |
|
1007 |
bitCount = bitCount & 0xff; |
|
1008 |
if (bitCount > bestCount) { |
|
1009 |
bestIndex = counter; |
|
1010 |
bestCount = bitCount; |
|
1011 |
} |
|
1012 |
} |
|
1013 |
} |
|
1014 |
if (bestIndex != -1) { |
|
1015 |
lastState[0] = bestIndex; |
|
1016 |
return states[bestIndex]; |
|
1017 |
} |
|
1018 |
if (wildIndex != -1) { |
|
1019 |
lastState[0] = wildIndex; |
|
1020 |
return states[wildIndex]; |
|
1021 |
} |
|
1022 |
} |
|
1023 |
lastState[0] = -1; |
|
1024 |
return null; |
|
1025 |
} |
|
1026 |
||
1027 |
/** |
|
21278 | 1028 |
* Contains values such as the UIDefaults and painters associated with |
2658 | 1029 |
* a state. Whereas <code>State</code> represents a distinct state that a |
1030 |
* component can be in (such as Enabled), this class represents the colors, |
|
1031 |
* fonts, painters, etc associated with some state for this |
|
1032 |
* style. |
|
1033 |
*/ |
|
1034 |
private final class RuntimeState implements Cloneable { |
|
1035 |
int state; |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
1036 |
Painter<Object> backgroundPainter; |
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
1037 |
Painter<Object> foregroundPainter; |
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
1038 |
Painter<Object> borderPainter; |
2658 | 1039 |
String stateName; |
1040 |
UIDefaults defaults = new UIDefaults(10, .7f); |
|
1041 |
||
1042 |
private RuntimeState(int state, String stateName) { |
|
1043 |
this.state = state; |
|
1044 |
this.stateName = stateName; |
|
1045 |
} |
|
1046 |
||
1047 |
@Override |
|
1048 |
public String toString() { |
|
1049 |
return stateName; |
|
1050 |
} |
|
1051 |
||
1052 |
@Override |
|
1053 |
public RuntimeState clone() { |
|
1054 |
RuntimeState clone = new RuntimeState(state, stateName); |
|
1055 |
clone.backgroundPainter = backgroundPainter; |
|
1056 |
clone.foregroundPainter = foregroundPainter; |
|
1057 |
clone.borderPainter = borderPainter; |
|
1058 |
clone.defaults.putAll(defaults); |
|
1059 |
return clone; |
|
1060 |
} |
|
1061 |
} |
|
1062 |
||
1063 |
/** |
|
1064 |
* Essentially a struct of data for a style. A default instance of this |
|
1065 |
* class is used by NimbusStyle. Additional instances exist for each |
|
1066 |
* component that has overrides. |
|
1067 |
*/ |
|
1068 |
private static final class Values { |
|
1069 |
/** |
|
1070 |
* The list of State types. A State represents a type of state, such |
|
1071 |
* as Enabled, Default, WindowFocused, etc. These can be custom states. |
|
1072 |
*/ |
|
25565
ce603b34c98d
8043548: Fix raw and unchecked lint warnings in javax.swing.plaf.*
darcy
parents:
25122
diff
changeset
|
1073 |
State<?>[] stateTypes = null; |
2658 | 1074 |
/** |
1075 |
* The list of actual runtime state representations. These can represent things such |
|
1076 |
* as Enabled + Focused. Thus, they differ from States in that they contain |
|
1077 |
* several states together, and have associated properties, data, etc. |
|
1078 |
*/ |
|
1079 |
RuntimeState[] states = null; |
|
1080 |
/** |
|
1081 |
* The content margins for this region. |
|
1082 |
*/ |
|
1083 |
Insets contentMargins; |
|
1084 |
/** |
|
1085 |
* Defaults on the region/component level. |
|
1086 |
*/ |
|
1087 |
UIDefaults defaults = new UIDefaults(10, .7f); |
|
1088 |
/** |
|
1089 |
* Simple cache. After a value has been looked up, it is stored |
|
1090 |
* in this cache for later retrieval. The key is a concatenation of |
|
1091 |
* the property being looked up, two dollar signs, and the extended |
|
1092 |
* state. So for example: |
|
1093 |
* |
|
1094 |
* foo.bar$$2353 |
|
1095 |
*/ |
|
1096 |
Map<CacheKey,Object> cache = new HashMap<CacheKey,Object>(); |
|
1097 |
} |
|
1098 |
||
1099 |
/** |
|
1100 |
* This implementation presupposes that key is never null and that |
|
1101 |
* the two keys being checked for equality are never null |
|
1102 |
*/ |
|
1103 |
private static final class CacheKey { |
|
1104 |
private String key; |
|
1105 |
private int xstate; |
|
1106 |
||
1107 |
CacheKey(Object key, int xstate) { |
|
1108 |
init(key, xstate); |
|
1109 |
} |
|
1110 |
||
1111 |
void init(Object key, int xstate) { |
|
1112 |
this.key = key.toString(); |
|
1113 |
this.xstate = xstate; |
|
1114 |
} |
|
1115 |
||
1116 |
@Override |
|
1117 |
public boolean equals(Object obj) { |
|
1118 |
final CacheKey other = (CacheKey) obj; |
|
1119 |
if (obj == null) return false; |
|
1120 |
if (this.xstate != other.xstate) return false; |
|
1121 |
if (!this.key.equals(other.key)) return false; |
|
1122 |
return true; |
|
1123 |
} |
|
1124 |
||
1125 |
@Override |
|
1126 |
public int hashCode() { |
|
1127 |
int hash = 3; |
|
1128 |
hash = 29 * hash + this.key.hashCode(); |
|
1129 |
hash = 29 * hash + this.xstate; |
|
1130 |
return hash; |
|
1131 |
} |
|
1132 |
} |
|
1133 |
} |