/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* <p>A SynthStyle implementation used by Nimbus. Each Region that has been
* registered with the NimbusLookAndFeel will have an associated NimbusStyle.
* Third party components that are registered with the NimbusLookAndFeel will
* therefore be handed a NimbusStyle from the look and feel from the
* #getStyle(JComponent, Region) method.</p>
*
* <p>This class properly reads and retrieves values placed in the UIDefaults
* according to the standard Nimbus naming conventions. It will create and
* retrieve painters, fonts, colors, and other data stored there.</p>
*
* <p>NimbusStyle also supports the ability to override settings on a per
* component basis. NimbusStyle checks the component's client property map for
* "Nimbus.Overrides". If the value associated with this key is an instance of
* UIDefaults, then the values in that defaults table will override the standard
* Nimbus defaults in UIManager, but for that component instance only.</p>
*
* <p>Optionally, you may specify the client property
* "Nimbus.Overrides.InheritDefaults". If true, this client property indicates
* that the defaults located in UIManager should first be read, and then
* replaced with defaults located in the component client properties. If false,
* then only the defaults located in the component client property map will
* be used. If not specified, it is assumed to be true.</p>
*
* <p>You must specify "Nimbus.Overrides" for "Nimbus.Overrides.InheritDefaults"
* to have any effect. "Nimbus.Overrides" indicates whether there are any
* overrides, while "Nimbus.Overrides.InheritDefaults" indicates whether those
* overrides should first be initialized with the defaults from UIManager.</p>
*
* <p>The NimbusStyle is reloaded whenever a property change event is fired
* for a component for "Nimbus.Overrides" or "Nimbus.Overrides.InheritDefaults".
* So for example, setting a new UIDefaults on a component would cause the
* style to be reloaded.</p>
*
* <p>The values are only read out of UIManager once, and then cached. If
* you need to read the values again (for example, if the UI is being reloaded),
* then discard this NimbusStyle and read a new one from NimbusLookAndFeel
* using NimbusLookAndFeel.getStyle.</p>
*
* <p>The primary API of interest in this class for 3rd party component authors
* are the three methods which retrieve painters: #getBackgroundPainter,
* #getForegroundPainter, and #getBorderPainter.</p>
*
* <p>NimbusStyle allows you to specify custom states, or modify the order of
* states. Synth (and thus Nimbus) has the concept of a "state". For example,
* a JButton might be in the "MOUSE_OVER" state, or the "ENABLED" state, or the
* "DISABLED" state. These are all "standard" states which are defined in synth,
* and which apply to all synth Regions.</p>
*
* <p>Sometimes, however, you need to have a custom state. For example, you
* want JButton to render differently if it's parent is a JToolbar. In Nimbus,
* you specify these custom states by including a special key in UIDefaults.
* The following UIDefaults entries define three states for this button:</p>
*
* <pre><code>
* JButton.States = Enabled, Disabled, Toolbar
* JButton[Enabled].backgroundPainter = somePainter
* JButton[Disabled].background = BLUE
* JButton[Toolbar].backgroundPainter = someOtherPaint
* </code></pre>
*
* <p>As you can see, the <code>JButton.States</code> entry lists the states
* that the JButton style will support. You then specify the settings for
* each state. If you do not specify the <code>JButton.States</code> entry,
* then the standard Synth states will be assumed. If you specify the entry
* but the list of states is empty or null, then the standard synth states
* will be assumed.</p>
*
* @author Richard Bair
* @author Jasper Potts
*/
/**
* Special constant used for performance reasons during the get() method.
* If get() runs through all of the search locations and determines that
* there is no value, then NULL will be placed into the values map. This way
* on subsequent lookups it will simply extract NULL, see it, and return
* null rather than continuing the lookup procedure.
*/
/**
* <p>The Color to return from getColorForState if it would otherwise have
* returned null.</p>
*
* <p>Returning null from getColorForState is a very bad thing, as it causes
* the AWT peer for the component to install a SystemColor, which is not a
* UIResource. As a result, if <code>null</code> is returned from
* getColorForState, then thereafter the color is not updated for other
* states or on LAF changes or updates. This DEFAULT_COLOR is used to
* ensure that a ColorUIResource is always returned from
* getColorForState.</p>
*/
/**
* Simple Comparator for ordering the RuntimeStates according to their
* rank.
*/
new Comparator<RuntimeState>() {
}
};
/**
* The prefix for the component or region that this NimbusStyle
* represents. This prefix is used to lookup state in the UIManager.
* It should be something like Button or Slider.Thumb or "MyButton" or
* ComboBox."ComboBox.arrowButton" or "MyComboBox"."ComboBox.arrowButton"
*/
/**
* The SynthPainter that will be returned from this NimbusStyle. The
* SynthPainter returned will be a SynthPainterImpl, which will in turn
* delegate back to this NimbusStyle for the proper Painter (not
* SynthPainter) to use for painting the foreground, background, or border.
*/
/**
* Data structure containing all of the defaults, insets, states, and other
* values associated with this style. This instance refers to default
* values, and are used when no overrides are discovered in the client
* properties of a component. These values are lazily created on first
* access.
*/
/**
* A temporary CacheKey used to perform lookups. This pattern avoids
* creating useless garbage keys, or concatenating strings, etc.
*/
/**
* Some NimbusStyles are created for a specific component only. In Nimbus,
* this happens whenever the component has as a client property a
* UIDefaults which overrides (or supplements) those defaults found in
* UIManager.
*/
/**
* Create a new NimbusStyle. Only the prefix must be supplied. At the
* appropriate time, installDefaults will be called. At that point, all of
* the state information will be pulled from UIManager and stored locally
* within this style.
*
* @param prefix Something like Button or Slider.Thumb or
* org.jdesktop.swingx.JXStatusBar or ComboBox."ComboBox.arrowButton"
* @param c an optional reference to a component that this NimbusStyle
* should be associated with. This is only used when the component
* has Nimbus overrides registered in its client properties and
* should be null otherwise.
*/
if (c != null) {
}
this.painter = new SynthPainterImpl(this);
}
/**
* @inheritDoc
*
* Overridden to cause this style to populate itself with data from
* UIDefaults, if necessary.
*/
validate();
//delegate to the superclass to install defaults such as background,
//foreground, font, and opaque onto the swing component.
super.installDefaults(ctx);
}
/**
* Pulls data out of UIDefaults, if it has not done so already, and sets
* up the internal state.
*/
private void validate() {
// a non-null values object is the flag we use to determine whether
// to reparse from UIManager.
// reconstruct this NimbusStyle based on the entries in the UIManager
// and possibly based on any overrides within the component's
// client properties (assuming such a component exists and contains
// any Nimbus.Overrides)
// inspect the client properties for the key "Nimbus.Overrides". If the
// value is an instance of UIDefaults, then these defaults are used
// in place of, or in addition to, the defaults in UIManager.
// We know component.get() is non-null here, as if the component
// were GC'ed, we wouldn't be processing its style.
if (o instanceof UIDefaults) {
"Nimbus.Overrides.InheritDefaults");
UIDefaults d = (UIDefaults)o;
}
}
}
if (inherit) {
} else {
}
}
}
//a list of the different types of states used by this style. This
//list may contain only "standard" states (those defined by Synth),
//or it may contain custom states, or it may contain only "standard"
//states but list them in a non-standard order.
//a map of state name to code
//This is a list of runtime "state" context objects. These contain
//the values associated with each state.
//determine whether there are any custom states, or custom state
//order. If so, then read all those custom states and define the
//"values" stateTypes to be a non-null array.
//Otherwise, let the "values" stateTypes be null to indicate that
//there are no custom states or custom state ordering
if (statesString != null) {
for (int i=0; i<s.length; i++) {
s[i] = s[i].trim();
if (!State.isStandardStateName(s[i])) {
//this is a non-standard state name, so look for the
//custom state associated with it
if (customState != null) {
}
} else {
}
}
//if there were any states defined, then set the stateTypes array
//to be non-null. Otherwise, leave it null (meaning, use the
//standard synth states).
}
//assign codes for each of the state types
int code = 1;
code <<= 1;
}
} else {
//since there were no custom states defined, setup the list of
//standard synth states. Note that the "v.stateTypes" is not
//being set here, indicating that at runtime the state selection
//routines should use standard synth states instead of custom
//states. I do need to popuplate this temp list now though, so that
//the remainder of this method will function as expected.
//assign codes for the states
}
//Now iterate over all the keys in the defaults table
//The key is something like JButton.Enabled.backgroundPainter,
//or JButton.States, or JButton.background.
//Remove the "JButton." portion of the key
//if there is a " or : then we skip it because it is a subregion
//of some kind
//remove the separator
//At this point, temp may be any of the following:
//background
//[Enabled].background
//[Enabled+MouseOver].background
//property.foo
//parse out the states and the property
if (bracketIndex < 0) {
//there is not a state string, so property = temp
} else {
}
//now that I have the state (if any) and the property, get the
//value for this property and install it where it belongs
if (stateString == null) {
//there was no state, just a property. Check for the custom
//"contentMargins" property (which is handled specially by
//in which case it is not a real property and should be ignored.
//otherwise, assume it is a property and install it on the
//values object
//ignore
} else {
}
} else {
//it is possible that the developer has a malformed UIDefaults
//entry, such that something was specified in the place of
//the State portion of the key but it wasn't a state. In this
//case, skip will be set to true
boolean skip = false;
//this variable keeps track of the int value associated with
//the state. See SynthState for details.
int componentState = 0;
//Multiple states may be specified in the string, such as
//Enabled+MouseOver
//For each state, we need to find the State object associated
//with it, or skip it if it cannot be found.
for (String s : stateParts) {
if (stateCodes.containsKey(s)) {
} else {
//Was not a state. Maybe it was a subregion or something
//skip it.
skip = true;
break;
}
}
if (skip) continue;
//find the RuntimeState for this State
for (RuntimeState s : runtimeStates) {
if (s.state == componentState) {
rs = s;
break;
}
}
//couldn't find the runtime state, so create a new one
}
//check for a couple special properties, such as for the
//painters. If these are found, then set the specially on
//the runtime state. Else, it is just a normal property,
//so put it in the UIDefaults associated with that runtime
//state
} else {
}
}
}
//now that I've collected all the runtime states, I'll sort them based
//on their integer "state" (see SynthState for how this works).
//finally, set the array of runtime states on the values object
}
if (p instanceof UIDefaults.LazyValue) {
}
}
/**
* @inheritDoc
*
* Overridden to cause this style to populate itself with data from
* UIDefaults, if necessary.
*/
}
if (v.contentMargins == null) {
return in;
} else {
// Account for scale
// The key "JComponent.sizeVariant" is used to match Apple's LAF
"JComponent.sizeVariant");
}
}
return in;
}
}
/**
* @inheritDoc
*
* <p>Overridden to cause this style to populate itself with data from
* UIDefaults, if necessary.</p>
*
* <p>In addition, NimbusStyle handles ColorTypes slightly differently from
* Synth.</p>
* <ul>
* <li>ColorType.BACKGROUND will equate to the color stored in UIDefaults
* named "background".</li>
* <li>ColorType.TEXT_BACKGROUND will equate to the color stored in
* UIDefaults named "textBackground".</li>
* <li>ColorType.FOREGROUND will equate to the color stored in UIDefaults
* named "textForeground".</li>
* <li>ColorType.TEXT_FOREGROUND will equate to the color stored in
* UIDefaults named "textForeground".</li>
* </ul>
*/
key = "background";
//map FOREGROUND as TEXT_FOREGROUND
key = "textForeground";
key = "textBackground";
key = "textForeground";
key = "focus";
} else {
return DEFAULT_COLOR;
}
//if all else fails, return a default color (which is a ColorUIResource)
if (c == null) c = DEFAULT_COLOR;
return c;
}
/**
* @inheritDoc
*
* Overridden to cause this style to populate itself with data from
* UIDefaults, if necessary. If a value named "font" is not found in
* UIDefaults, then the "defaultFont" font in UIDefaults will be returned
* instead.
*/
// Account for scale
// The key "JComponent.sizeVariant" is used to match Apple's LAF
"JComponent.sizeVariant");
}
}
return f;
}
/**
* @inheritDoc
*
* Returns the SynthPainter for this style, which ends up delegating to
* the Painters installed in this style.
*/
return painter;
}
/**
* @inheritDoc
*
* Overridden to cause this style to populate itself with data from
* UIDefaults, if necessary. If opacity is not specified in UI defaults,
* then it defaults to being non-opaque.
*/
// Force Table CellRenderers to be opaque
return true;
}
}
/**
* @inheritDoc
*
* <p>Overridden to cause this style to populate itself with data from
* UIDefaults, if necessary.</p>
*
* <p>Properties in UIDefaults may be specified in a chained manner. For
* example:
* <pre>
* background
* Button.opacity
* Button.Enabled.foreground
* Button.Enabled+Selected.background
* </pre></p>
*
* <p>In this example, suppose you were in the Enabled+Selected state and
* searched for "foreground". In this case, we first check for
* Button.Enabled+Selected.foreground, but no such color exists. We then
* fall back to the next valid state, in this case,
* Button.Enabled.foreground, and have a match. So we return it.</p>
*
* <p>Again, if we were in the state Enabled and looked for "background", we
* wouldn't find it in Button.Enabled, or in Button, but would at the top
* level in UIManager. So we return that value.</p>
*
* <p>One special note: the "key" passed to this method could be of the form
* "background" or "Button.background" where "Button" equals the prefix
* passed to the NimbusStyle constructor. In either case, it looks for
* "background".</p>
*
* @param ctx
* @param key must not be null
*/
// strip off the prefix, if there is one.
// check the cache
if (!wasInCache){
// Search exact matching states and then lesser matching states
RuntimeState s = null;
int[] lastIndex = new int[] {-1};
}
// Search Region Defaults
}
// return found object
// Search UIManager Defaults
// Search Synth Defaults for InputMaps
}
// if all we got was a null, store this fact for later use
}
// return found object
}
/**
* Gets the appropriate background Painter, if there is one, for the state
* specified in the given SynthContext. This method does appropriate
* fallback searching, as described in #get.
*
* @param ctx The SynthContext. Must not be null.
* @return The background painter associated for the given state, or null if
* none could be found.
*/
// check the cache
if (p != null) return p;
// not in cache, so lookup and store in cache
RuntimeState s = null;
int[] lastIndex = new int[] {-1};
if (s.backgroundPainter != null) {
p = s.backgroundPainter;
break;
}
}
if (p != null) {
}
return p;
}
/**
* Gets the appropriate foreground Painter, if there is one, for the state
* specified in the given SynthContext. This method does appropriate
* fallback searching, as described in #get.
*
* @param ctx The SynthContext. Must not be null.
* @return The foreground painter associated for the given state, or null if
* none could be found.
*/
// check the cache
if (p != null) return p;
// not in cache, so lookup and store in cache
RuntimeState s = null;
int[] lastIndex = new int[] {-1};
if (s.foregroundPainter != null) {
p = s.foregroundPainter;
break;
}
}
if (p != null) {
}
return p;
}
/**
* Gets the appropriate border Painter, if there is one, for the state
* specified in the given SynthContext. This method does appropriate
* fallback searching, as described in #get.
*
* @param ctx The SynthContext. Must not be null.
* @return The border painter associated for the given state, or null if
* none could be found.
*/
// check the cache
if (p != null) return p;
// not in cache, so lookup and store in cache
RuntimeState s = null;
int[] lastIndex = new int[] {-1};
if (s.borderPainter != null) {
p = s.borderPainter;
break;
}
}
if (p != null) {
}
return p;
}
/**
* Utility method which returns the proper Values based on the given
* SynthContext. Ensures that parsing of the values has occurred, or
* reoccurs as necessary.
*
* @param ctx The SynthContext
* @return a non-null values reference
*/
validate();
return values;
}
/**
* Simple utility method that searchs the given array of Strings for the
* given string. This method is only called from getExtendedState if
* the developer has specified a specific state for the component to be
* in (ie, has "wedged" the component in that state) by specifying
* they client property "Nimbus.State".
*
* @param names a non-null array of strings
* @param name the name to look for in the array
* @return true or false based on whether the given name is in the array
*/
return true;
}
}
return false;
}
/**
* <p>Gets the extended state for a given synth context. Nimbus supports the
* ability to define custom states. The algorithm used for choosing what
* style information to use for a given state requires a single integer
* bit string where each bit in the integer represents a different state
* that the component is in. This method uses the componentState as
* reported in the SynthContext, in addition to custom states, to determine
* what this extended state is.</p>
*
* <p>In addition, this method checks the component in the given context
* for a client property called "Nimbus.State". If one exists, then it will
* decompose the String associated with that property to determine what
* state to return. In this way, the developer can force a component to be
* in a specific state, regardless of what the "real" state of the component
* is.</p>
*
* <p>The string associated with "Nimbus.State" would be of the form:
* <pre>Enabled+CustomState+MouseOver</pre></p>
*
* @param ctx
* @param v
* @return
*/
int xstate = 0;
int mask = 1;
//check for the Nimbus.State client property
//Performance NOTE: getClientProperty ends up inside a synchronized
//block, so there is some potential for performance issues here, however
//I'm not certain that there is one on a modern VM.
if (v.stateTypes == null){
// standard states only
}
} else {
// custom states
for (State s : v.stateTypes) {
}
mask <<= 1;
}
}
} else {
//if there are no custom states defined, then simply return the
//state that Synth reported
//there are custom states on this values, so I'll have to iterate
//over them all and return a custom extended state
for (State s : v.stateTypes) {
}
mask <<= 1;
}
}
return xstate;
}
/**
* <p>Gets the RuntimeState that most closely matches the state in the given
* context, but is less specific than the given "lastState". Essentially,
* this allows you to search for the next best state.</p>
*
* <p>For example, if you had the following three states:
* <pre>
* Enabled
* Enabled+Pressed
* Disabled
* </pre>
* And you wanted to find the state that best represented
* ENABLED+PRESSED+FOCUSED and <code>lastState</code> was null (or an
* empty array, or an array with a single int with index == -1), then
* Enabled+Pressed would be returned. If you then call this method again but
* pass the index of Enabled+Pressed as the "lastState", then
* Enabled would be returned. If you call this method a third time and pass
* the index of Enabled in as the <code>lastState</code>, then null would be
* returned.</p>
*
* <p>The actual code path for determining the proper state is the same as
* in Synth.</p>
*
* @param ctx
* @param lastState a 1 element array, allowing me to do pass-by-reference.
* @return
*/
int[] lastState,
int xstate) {
// Use the StateInfo with the most bits that matches that of state.
// If there are none, then fallback to
// the StateInfo with a state of 0, indicating it'll match anything.
// Consider if we have 3 StateInfos a, b and c with states:
// SELECTED, SELECTED | ENABLED, 0
//
// Input Return Value
// ----- ------------
// SELECTED a
// SELECTED | ENABLED b
// MOUSE_OVER c
// SELECTED | ENABLED | FOCUSED b
// ENABLED c
int bestCount = 0;
int bestIndex = -1;
int wildIndex = -1;
//if xstate is 0, then search for the runtime state with component
//state of 0. That is, find the exact match and return it.
if (xstate == 0) {
}
}
//an exact match couldn't be found, so there was no match.
return null;
}
//xstate is some value != 0
//determine from which index to start looking. If lastState[0] is -1
//then we know to start from the end of the state array. Otherwise,
//we start at the lastIndex - 1.
if (oState == 0) {
if (wildIndex == -1) {
}
// This is key, we need to make sure all bits of the
// StateInfo match, otherwise a StateInfo with
// SELECTED | ENABLED would match ENABLED, which we
// don't want.
// This comes from BigInteger.bitCnt
0x33333333);
}
}
}
if (bestIndex != -1) {
}
if (wildIndex != -1) {
}
}
return null;
}
/**
* Contains values such as the UIDefaults and painters asssociated with
* a state. Whereas <code>State</code> represents a distinct state that a
* component can be in (such as Enabled), this class represents the colors,
* fonts, painters, etc associated with some state for this
* style.
*/
int state;
}
return stateName;
}
return clone;
}
}
/**
* Essentially a struct of data for a style. A default instance of this
* class is used by NimbusStyle. Additional instances exist for each
* component that has overrides.
*/
private static final class Values {
/**
* The list of State types. A State represents a type of state, such
* as Enabled, Default, WindowFocused, etc. These can be custom states.
*/
/**
* The list of actual runtime state representations. These can represent things such
* as Enabled + Focused. Thus, they differ from States in that they contain
* several states together, and have associated properties, data, etc.
*/
/**
* The content margins for this region.
*/
/**
*/
/**
* Simple cache. After a value has been looked up, it is stored
* in this cache for later retrieval. The key is a concatenation of
* the property being looked up, two dollar signs, and the extended
* state. So for example:
*
* foo.bar$$2353
*/
}
/**
* This implementation presupposes that key is never null and that
* the two keys being checked for equality are never null
*/
private static final class CacheKey {
private int xstate;
}
}
return true;
}
public int hashCode() {
int hash = 3;
return hash;
}
}
}