src/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java

Print this page




 266                 for (Object obj : d.keySet()) {
 267                     if (obj instanceof String) {
 268                         String key = (String)obj;
 269                         if (key.startsWith(prefix)) {
 270                             map.put(key, d.get(key));
 271                         }
 272                     }
 273                 }
 274                 if (inherit) {
 275                     defaults.putAll(map);
 276                 } else {
 277                     defaults = map;
 278                 }
 279             }
 280         }
 281 
 282         //a list of the different types of states used by this style. This
 283         //list may contain only "standard" states (those defined by Synth),
 284         //or it may contain custom states, or it may contain only "standard"
 285         //states but list them in a non-standard order.
 286         List<State> states = new ArrayList<State>();
 287         //a map of state name to code
 288         Map<String,Integer> stateCodes = new HashMap<String,Integer>();
 289         //This is a list of runtime "state" context objects. These contain
 290         //the values associated with each state.
 291         List<RuntimeState> runtimeStates = new ArrayList<RuntimeState>();
 292 
 293         //determine whether there are any custom states, or custom state
 294         //order. If so, then read all those custom states and define the
 295         //"values" stateTypes to be a non-null array.
 296         //Otherwise, let the "values" stateTypes be null to indicate that
 297         //there are no custom states or custom state ordering
 298         String statesString = (String)defaults.get(prefix + ".States");
 299         if (statesString != null) {
 300             String s[] = statesString.split(",");
 301             for (int i=0; i<s.length; i++) {
 302                 s[i] = s[i].trim();
 303                 if (!State.isStandardStateName(s[i])) {
 304                     //this is a non-standard state name, so look for the
 305                     //custom state associated with it
 306                     String stateName = prefix + "." + s[i];
 307                     State customState = (State)defaults.get(stateName);
 308                     if (customState != null) {
 309                         states.add(customState);
 310                     }
 311                 } else {
 312                     states.add(State.getStandardState(s[i]));
 313                 }
 314             }
 315 
 316             //if there were any states defined, then set the stateTypes array
 317             //to be non-null. Otherwise, leave it null (meaning, use the
 318             //standard synth states).
 319             if (states.size() > 0) {
 320                 values.stateTypes = states.toArray(new State[states.size()]);
 321             }
 322 
 323             //assign codes for each of the state types
 324             int code = 1;
 325             for (State state : states) {
 326                 stateCodes.put(state.getName(), code);
 327                 code <<= 1;
 328             }
 329         } else {
 330             //since there were no custom states defined, setup the list of
 331             //standard synth states. Note that the "v.stateTypes" is not
 332             //being set here, indicating that at runtime the state selection
 333             //routines should use standard synth states instead of custom
 334             //states. I do need to popuplate this temp list now though, so that
 335             //the remainder of this method will function as expected.
 336             states.add(State.Enabled);
 337             states.add(State.MouseOver);
 338             states.add(State.Pressed);
 339             states.add(State.Disabled);
 340             states.add(State.Focused);
 341             states.add(State.Selected);
 342             states.add(State.Default);
 343 
 344             //assign codes for the states
 345             stateCodes.put("Enabled", ENABLED);


 446                 if ("backgroundPainter".equals(property)) {
 447                     rs.backgroundPainter = getPainter(defaults, key);
 448                 } else if ("foregroundPainter".equals(property)) {
 449                     rs.foregroundPainter = getPainter(defaults, key);
 450                 } else if ("borderPainter".equals(property)) {
 451                     rs.borderPainter = getPainter(defaults, key);
 452                 } else {
 453                     rs.defaults.put(property, defaults.get(key));
 454                 }
 455             }
 456         }
 457 
 458         //now that I've collected all the runtime states, I'll sort them based
 459         //on their integer "state" (see SynthState for how this works).
 460         Collections.sort(runtimeStates, STATE_COMPARATOR);
 461 
 462         //finally, set the array of runtime states on the values object
 463         values.states = runtimeStates.toArray(new RuntimeState[runtimeStates.size()]);
 464     }
 465 
 466     private Painter getPainter(Map<String, Object> defaults, String key) {
 467         Object p = defaults.get(key);
 468         if (p instanceof UIDefaults.LazyValue) {
 469             p = ((UIDefaults.LazyValue)p).createValue(UIManager.getDefaults());
 470         }
 471         return (p instanceof Painter ? (Painter)p : null);


 472     }
 473 
 474     /**
 475      * {@inheritDoc}
 476      *
 477      * Overridden to cause this style to populate itself with data from
 478      * UIDefaults, if necessary.
 479      */
 480     @Override public Insets getInsets(SynthContext ctx, Insets in) {
 481         if (in == null) {
 482             in = new Insets(0, 0, 0, 0);
 483         }
 484 
 485         Values v = getValues(ctx);
 486 
 487         if (v.contentMargins == null) {
 488             in.bottom = in.top = in.left = in.right = 0;
 489             return in;
 490         } else {
 491             in.bottom = v.contentMargins.bottom;


 672             }
 673             // Search Region Defaults
 674             if (obj == null && v.defaults != null) {
 675                 obj = v.defaults.get(partialKey);
 676             }
 677             // return found object
 678             // Search UIManager Defaults
 679             if (obj == null) obj = UIManager.get(fullKey);
 680             // Search Synth Defaults for InputMaps
 681             if (obj == null && partialKey.equals("focusInputMap")) {
 682                 obj = super.get(ctx, fullKey);
 683             }
 684             // if all we got was a null, store this fact for later use
 685             v.cache.put(new CacheKey(partialKey, xstate),
 686                     obj == null ? NULL : obj);
 687         }
 688         // return found object
 689         return obj == NULL ? null : obj;
 690     }
 691 






 692     /**
 693      * Gets the appropriate background Painter, if there is one, for the state
 694      * specified in the given SynthContext. This method does appropriate
 695      * fallback searching, as described in #get.
 696      *
 697      * @param ctx The SynthContext. Must not be null.
 698      * @return The background painter associated for the given state, or null if
 699      * none could be found.
 700      */
 701     public Painter getBackgroundPainter(SynthContext ctx) {
 702         Values v = getValues(ctx);
 703         int xstate = getExtendedState(ctx, v);
 704         Painter p = null;
 705 
 706         // check the cache
 707         tmpKey.init("backgroundPainter$$instance", xstate);
 708         p = (Painter)v.cache.get(tmpKey);
 709         if (p != null) return p;
 710 
 711         // not in cache, so lookup and store in cache
 712         RuntimeState s = null;
 713         int[] lastIndex = new int[] {-1};
 714         while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
 715             if (s.backgroundPainter != null) {
 716                 p = s.backgroundPainter;
 717                 break;
 718             }
 719         }
 720         if (p == null) p = (Painter)get(ctx, "backgroundPainter");
 721         if (p != null) {
 722             v.cache.put(new CacheKey("backgroundPainter$$instance", xstate), p);
 723         }
 724         return p;
 725     }
 726 
 727     /**
 728      * Gets the appropriate foreground Painter, if there is one, for the state
 729      * specified in the given SynthContext. This method does appropriate
 730      * fallback searching, as described in #get.
 731      *
 732      * @param ctx The SynthContext. Must not be null.
 733      * @return The foreground painter associated for the given state, or null if
 734      * none could be found.
 735      */
 736     public Painter getForegroundPainter(SynthContext ctx) {
 737         Values v = getValues(ctx);
 738         int xstate = getExtendedState(ctx, v);
 739         Painter p = null;
 740 
 741         // check the cache
 742         tmpKey.init("foregroundPainter$$instance", xstate);
 743         p = (Painter)v.cache.get(tmpKey);
 744         if (p != null) return p;
 745 
 746         // not in cache, so lookup and store in cache
 747         RuntimeState s = null;
 748         int[] lastIndex = new int[] {-1};
 749         while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
 750             if (s.foregroundPainter != null) {
 751                 p = s.foregroundPainter;
 752                 break;
 753             }
 754         }
 755         if (p == null) p = (Painter)get(ctx, "foregroundPainter");
 756         if (p != null) {
 757             v.cache.put(new CacheKey("foregroundPainter$$instance", xstate), p);
 758         }
 759         return p;
 760     }
 761 
 762     /**
 763      * Gets the appropriate border Painter, if there is one, for the state
 764      * specified in the given SynthContext. This method does appropriate
 765      * fallback searching, as described in #get.
 766      *
 767      * @param ctx The SynthContext. Must not be null.
 768      * @return The border painter associated for the given state, or null if
 769      * none could be found.
 770      */
 771     public Painter getBorderPainter(SynthContext ctx) {
 772         Values v = getValues(ctx);
 773         int xstate = getExtendedState(ctx, v);
 774         Painter p = null;
 775 
 776         // check the cache
 777         tmpKey.init("borderPainter$$instance", xstate);
 778         p = (Painter)v.cache.get(tmpKey);
 779         if (p != null) return p;
 780 
 781         // not in cache, so lookup and store in cache
 782         RuntimeState s = null;
 783         int[] lastIndex = new int[] {-1};
 784         while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
 785             if (s.borderPainter != null) {
 786                 p = s.borderPainter;
 787                 break;
 788             }
 789         }
 790         if (p == null) p = (Painter)get(ctx, "borderPainter");
 791         if (p != null) {
 792             v.cache.put(new CacheKey("borderPainter$$instance", xstate), p);
 793         }
 794         return p;
 795     }
 796 
 797     /**
 798      * Utility method which returns the proper Values based on the given
 799      * SynthContext. Ensures that parsing of the values has occurred, or
 800      * reoccurs as necessary.
 801      *
 802      * @param ctx The SynthContext
 803      * @return a non-null values reference
 804      */
 805     private Values getValues(SynthContext ctx) {
 806         validate();
 807         return values;
 808     }
 809 
 810     /**


 834      * style information to use for a given state requires a single integer
 835      * bit string where each bit in the integer represents a different state
 836      * that the component is in. This method uses the componentState as
 837      * reported in the SynthContext, in addition to custom states, to determine
 838      * what this extended state is.</p>
 839      *
 840      * <p>In addition, this method checks the component in the given context
 841      * for a client property called "Nimbus.State". If one exists, then it will
 842      * decompose the String associated with that property to determine what
 843      * state to return. In this way, the developer can force a component to be
 844      * in a specific state, regardless of what the "real" state of the component
 845      * is.</p>
 846      *
 847      * <p>The string associated with "Nimbus.State" would be of the form:
 848      * <pre>Enabled+CustomState+MouseOver</pre></p>
 849      *
 850      * @param ctx
 851      * @param v
 852      * @return
 853      */

 854     private int getExtendedState(SynthContext ctx, Values v) {
 855         JComponent c = ctx.getComponent();
 856         int xstate = 0;
 857         int mask = 1;
 858         //check for the Nimbus.State client property
 859         //Performance NOTE: getClientProperty ends up inside a synchronized
 860         //block, so there is some potential for performance issues here, however
 861         //I'm not certain that there is one on a modern VM.
 862         Object property = c.getClientProperty("Nimbus.State");
 863         if (property != null) {
 864             String stateNames = property.toString();
 865             String[] states = stateNames.split("\\+");
 866             if (v.stateTypes == null){
 867                 // standard states only
 868                 for (String stateStr : states) {
 869                     State.StandardState s = State.getStandardState(stateStr);
 870                     if (s != null) xstate |= s.getState();
 871                 }
 872             } else {
 873                 // custom states
 874                 for (State s : v.stateTypes) {
 875                     if (contains(states, s.getName())) {
 876                         xstate |= mask;
 877                     }
 878                     mask <<= 1;
 879                 }
 880             }
 881         } else {
 882             //if there are no custom states defined, then simply return the
 883             //state that Synth reported
 884             if (v.stateTypes == null) return ctx.getComponentState();
 885 
 886             //there are custom states on this values, so I'll have to iterate
 887             //over them all and return a custom extended state
 888             int state = ctx.getComponentState();
 889             for (State s : v.stateTypes) {
 890                 if (s.isInState(c, state)) {
 891                     xstate |= mask;
 892                 }
 893                 mask <<= 1;
 894             }


1001                 return states[bestIndex];
1002             }
1003             if (wildIndex != -1) {
1004                 lastState[0] = wildIndex;
1005                 return states[wildIndex];
1006             }
1007         }
1008         lastState[0] = -1;
1009         return null;
1010     }
1011 
1012     /**
1013      * Contains values such as the UIDefaults and painters associated with
1014      * a state. Whereas <code>State</code> represents a distinct state that a
1015      * component can be in (such as Enabled), this class represents the colors,
1016      * fonts, painters, etc associated with some state for this
1017      * style.
1018      */
1019     private final class RuntimeState implements Cloneable {
1020         int state;
1021         Painter backgroundPainter;
1022         Painter foregroundPainter;
1023         Painter borderPainter;
1024         String stateName;
1025         UIDefaults defaults = new UIDefaults(10, .7f);
1026 
1027         private RuntimeState(int state, String stateName) {
1028             this.state = state;
1029             this.stateName = stateName;
1030         }
1031 
1032         @Override
1033         public String toString() {
1034             return stateName;
1035         }
1036 
1037         @Override
1038         public RuntimeState clone() {
1039             RuntimeState clone = new RuntimeState(state, stateName);
1040             clone.backgroundPainter = backgroundPainter;
1041             clone.foregroundPainter = foregroundPainter;
1042             clone.borderPainter = borderPainter;
1043             clone.defaults.putAll(defaults);
1044             return clone;
1045         }
1046     }
1047 
1048     /**
1049      * Essentially a struct of data for a style. A default instance of this
1050      * class is used by NimbusStyle. Additional instances exist for each
1051      * component that has overrides.
1052      */
1053     private static final class Values {
1054         /**
1055          * The list of State types. A State represents a type of state, such
1056          * as Enabled, Default, WindowFocused, etc. These can be custom states.
1057          */
1058         State[] stateTypes = null;
1059         /**
1060          * The list of actual runtime state representations. These can represent things such
1061          * as Enabled + Focused. Thus, they differ from States in that they contain
1062          * several states together, and have associated properties, data, etc.
1063          */
1064         RuntimeState[] states = null;
1065         /**
1066          * The content margins for this region.
1067          */
1068         Insets contentMargins;
1069         /**
1070          * Defaults on the region/component level.
1071          */
1072         UIDefaults defaults = new UIDefaults(10, .7f);
1073         /**
1074          * Simple cache. After a value has been looked up, it is stored
1075          * in this cache for later retrieval. The key is a concatenation of
1076          * the property being looked up, two dollar signs, and the extended
1077          * state. So for example:
1078          *




 266                 for (Object obj : d.keySet()) {
 267                     if (obj instanceof String) {
 268                         String key = (String)obj;
 269                         if (key.startsWith(prefix)) {
 270                             map.put(key, d.get(key));
 271                         }
 272                     }
 273                 }
 274                 if (inherit) {
 275                     defaults.putAll(map);
 276                 } else {
 277                     defaults = map;
 278                 }
 279             }
 280         }
 281 
 282         //a list of the different types of states used by this style. This
 283         //list may contain only "standard" states (those defined by Synth),
 284         //or it may contain custom states, or it may contain only "standard"
 285         //states but list them in a non-standard order.
 286         List<State<?>> states = new ArrayList<>();
 287         //a map of state name to code
 288         Map<String,Integer> stateCodes = new HashMap<>();
 289         //This is a list of runtime "state" context objects. These contain
 290         //the values associated with each state.
 291         List<RuntimeState> runtimeStates = new ArrayList<>();
 292 
 293         //determine whether there are any custom states, or custom state
 294         //order. If so, then read all those custom states and define the
 295         //"values" stateTypes to be a non-null array.
 296         //Otherwise, let the "values" stateTypes be null to indicate that
 297         //there are no custom states or custom state ordering
 298         String statesString = (String)defaults.get(prefix + ".States");
 299         if (statesString != null) {
 300             String s[] = statesString.split(",");
 301             for (int i=0; i<s.length; i++) {
 302                 s[i] = s[i].trim();
 303                 if (!State.isStandardStateName(s[i])) {
 304                     //this is a non-standard state name, so look for the
 305                     //custom state associated with it
 306                     String stateName = prefix + "." + s[i];
 307                     State<?> customState = (State)defaults.get(stateName);
 308                     if (customState != null) {
 309                         states.add(customState);
 310                     }
 311                 } else {
 312                     states.add(State.getStandardState(s[i]));
 313                 }
 314             }
 315 
 316             //if there were any states defined, then set the stateTypes array
 317             //to be non-null. Otherwise, leave it null (meaning, use the
 318             //standard synth states).
 319             if (states.size() > 0) {
 320                 values.stateTypes = states.toArray(new State<?>[states.size()]);
 321             }
 322 
 323             //assign codes for each of the state types
 324             int code = 1;
 325             for (State<?> state : states) {
 326                 stateCodes.put(state.getName(), code);
 327                 code <<= 1;
 328             }
 329         } else {
 330             //since there were no custom states defined, setup the list of
 331             //standard synth states. Note that the "v.stateTypes" is not
 332             //being set here, indicating that at runtime the state selection
 333             //routines should use standard synth states instead of custom
 334             //states. I do need to popuplate this temp list now though, so that
 335             //the remainder of this method will function as expected.
 336             states.add(State.Enabled);
 337             states.add(State.MouseOver);
 338             states.add(State.Pressed);
 339             states.add(State.Disabled);
 340             states.add(State.Focused);
 341             states.add(State.Selected);
 342             states.add(State.Default);
 343 
 344             //assign codes for the states
 345             stateCodes.put("Enabled", ENABLED);


 446                 if ("backgroundPainter".equals(property)) {
 447                     rs.backgroundPainter = getPainter(defaults, key);
 448                 } else if ("foregroundPainter".equals(property)) {
 449                     rs.foregroundPainter = getPainter(defaults, key);
 450                 } else if ("borderPainter".equals(property)) {
 451                     rs.borderPainter = getPainter(defaults, key);
 452                 } else {
 453                     rs.defaults.put(property, defaults.get(key));
 454                 }
 455             }
 456         }
 457 
 458         //now that I've collected all the runtime states, I'll sort them based
 459         //on their integer "state" (see SynthState for how this works).
 460         Collections.sort(runtimeStates, STATE_COMPARATOR);
 461 
 462         //finally, set the array of runtime states on the values object
 463         values.states = runtimeStates.toArray(new RuntimeState[runtimeStates.size()]);
 464     }
 465 
 466     private Painter<Object> getPainter(Map<String, Object> defaults, String key) {
 467         Object p = defaults.get(key);
 468         if (p instanceof UIDefaults.LazyValue) {
 469             p = ((UIDefaults.LazyValue)p).createValue(UIManager.getDefaults());
 470         }
 471         @SuppressWarnings("unchecked")
 472         Painter<Object> tmp = (p instanceof Painter ? (Painter)p : null);
 473         return tmp;
 474     }
 475 
 476     /**
 477      * {@inheritDoc}
 478      *
 479      * Overridden to cause this style to populate itself with data from
 480      * UIDefaults, if necessary.
 481      */
 482     @Override public Insets getInsets(SynthContext ctx, Insets in) {
 483         if (in == null) {
 484             in = new Insets(0, 0, 0, 0);
 485         }
 486 
 487         Values v = getValues(ctx);
 488 
 489         if (v.contentMargins == null) {
 490             in.bottom = in.top = in.left = in.right = 0;
 491             return in;
 492         } else {
 493             in.bottom = v.contentMargins.bottom;


 674             }
 675             // Search Region Defaults
 676             if (obj == null && v.defaults != null) {
 677                 obj = v.defaults.get(partialKey);
 678             }
 679             // return found object
 680             // Search UIManager Defaults
 681             if (obj == null) obj = UIManager.get(fullKey);
 682             // Search Synth Defaults for InputMaps
 683             if (obj == null && partialKey.equals("focusInputMap")) {
 684                 obj = super.get(ctx, fullKey);
 685             }
 686             // if all we got was a null, store this fact for later use
 687             v.cache.put(new CacheKey(partialKey, xstate),
 688                     obj == null ? NULL : obj);
 689         }
 690         // return found object
 691         return obj == NULL ? null : obj;
 692     }
 693 
 694     @SuppressWarnings("unchecked")
 695     private static Painter<Object> paintFilter(@SuppressWarnings("rawtypes") Painter painter) {
 696         return (Painter<Object>) painter;
 697     }
 698 
 699 
 700     /**
 701      * Gets the appropriate background Painter, if there is one, for the state
 702      * specified in the given SynthContext. This method does appropriate
 703      * fallback searching, as described in #get.
 704      *
 705      * @param ctx The SynthContext. Must not be null.
 706      * @return The background painter associated for the given state, or null if
 707      * none could be found.
 708      */
 709     public Painter<Object> getBackgroundPainter(SynthContext ctx) {
 710         Values v = getValues(ctx);
 711         int xstate = getExtendedState(ctx, v);
 712         Painter<Object> p = null;
 713 
 714         // check the cache
 715         tmpKey.init("backgroundPainter$$instance", xstate);
 716         p = paintFilter((Painter)v.cache.get(tmpKey));
 717         if (p != null) return p;
 718 
 719         // not in cache, so lookup and store in cache
 720         RuntimeState s = null;
 721         int[] lastIndex = new int[] {-1};
 722         while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
 723             if (s.backgroundPainter != null) {
 724                 p = paintFilter(s.backgroundPainter);
 725                 break;
 726             }
 727         }
 728         if (p == null) p = paintFilter((Painter)get(ctx, "backgroundPainter"));
 729         if (p != null) {
 730             v.cache.put(new CacheKey("backgroundPainter$$instance", xstate), p);
 731         }
 732         return p;
 733     }
 734 
 735     /**
 736      * Gets the appropriate foreground Painter, if there is one, for the state
 737      * specified in the given SynthContext. This method does appropriate
 738      * fallback searching, as described in #get.
 739      *
 740      * @param ctx The SynthContext. Must not be null.
 741      * @return The foreground painter associated for the given state, or null if
 742      * none could be found.
 743      */
 744     public Painter<Object> getForegroundPainter(SynthContext ctx) {
 745         Values v = getValues(ctx);
 746         int xstate = getExtendedState(ctx, v);
 747         Painter<Object> p = null;
 748 
 749         // check the cache
 750         tmpKey.init("foregroundPainter$$instance", xstate);
 751         p = paintFilter((Painter)v.cache.get(tmpKey));
 752         if (p != null) return p;
 753 
 754         // not in cache, so lookup and store in cache
 755         RuntimeState s = null;
 756         int[] lastIndex = new int[] {-1};
 757         while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
 758             if (s.foregroundPainter != null) {
 759                 p = paintFilter(s.foregroundPainter);
 760                 break;
 761             }
 762         }
 763         if (p == null) p = paintFilter((Painter)get(ctx, "foregroundPainter"));
 764         if (p != null) {
 765             v.cache.put(new CacheKey("foregroundPainter$$instance", xstate), p);
 766         }
 767         return p;
 768     }
 769 
 770     /**
 771      * Gets the appropriate border Painter, if there is one, for the state
 772      * specified in the given SynthContext. This method does appropriate
 773      * fallback searching, as described in #get.
 774      *
 775      * @param ctx The SynthContext. Must not be null.
 776      * @return The border painter associated for the given state, or null if
 777      * none could be found.
 778      */
 779     public Painter<Object> getBorderPainter(SynthContext ctx) {
 780         Values v = getValues(ctx);
 781         int xstate = getExtendedState(ctx, v);
 782         Painter<Object> p = null;
 783 
 784         // check the cache
 785         tmpKey.init("borderPainter$$instance", xstate);
 786         p = paintFilter((Painter)v.cache.get(tmpKey));
 787         if (p != null) return p;
 788 
 789         // not in cache, so lookup and store in cache
 790         RuntimeState s = null;
 791         int[] lastIndex = new int[] {-1};
 792         while ((s = getNextState(v.states, lastIndex, xstate)) != null) {
 793             if (s.borderPainter != null) {
 794                 p = paintFilter(s.borderPainter);
 795                 break;
 796             }
 797         }
 798         if (p == null) p = paintFilter((Painter)get(ctx, "borderPainter"));
 799         if (p != null) {
 800             v.cache.put(new CacheKey("borderPainter$$instance", xstate), p);
 801         }
 802         return p;
 803     }
 804 
 805     /**
 806      * Utility method which returns the proper Values based on the given
 807      * SynthContext. Ensures that parsing of the values has occurred, or
 808      * reoccurs as necessary.
 809      *
 810      * @param ctx The SynthContext
 811      * @return a non-null values reference
 812      */
 813     private Values getValues(SynthContext ctx) {
 814         validate();
 815         return values;
 816     }
 817 
 818     /**


 842      * style information to use for a given state requires a single integer
 843      * bit string where each bit in the integer represents a different state
 844      * that the component is in. This method uses the componentState as
 845      * reported in the SynthContext, in addition to custom states, to determine
 846      * what this extended state is.</p>
 847      *
 848      * <p>In addition, this method checks the component in the given context
 849      * for a client property called "Nimbus.State". If one exists, then it will
 850      * decompose the String associated with that property to determine what
 851      * state to return. In this way, the developer can force a component to be
 852      * in a specific state, regardless of what the "real" state of the component
 853      * is.</p>
 854      *
 855      * <p>The string associated with "Nimbus.State" would be of the form:
 856      * <pre>Enabled+CustomState+MouseOver</pre></p>
 857      *
 858      * @param ctx
 859      * @param v
 860      * @return
 861      */
 862     @SuppressWarnings({"unchecked", "rawtypes"})
 863     private int getExtendedState(SynthContext ctx, Values v) {
 864         JComponent c = ctx.getComponent();
 865         int xstate = 0;
 866         int mask = 1;
 867         //check for the Nimbus.State client property
 868         //Performance NOTE: getClientProperty ends up inside a synchronized
 869         //block, so there is some potential for performance issues here, however
 870         //I'm not certain that there is one on a modern VM.
 871         Object property = c.getClientProperty("Nimbus.State");
 872         if (property != null) {
 873             String stateNames = property.toString();
 874             String[] states = stateNames.split("\\+");
 875             if (v.stateTypes == null){
 876                 // standard states only
 877                 for (String stateStr : states) {
 878                     State.StandardState s = State.getStandardState(stateStr);
 879                     if (s != null) xstate |= s.getState();
 880                 }
 881             } else {
 882                 // custom states
 883                 for (State<?> s : v.stateTypes) {
 884                     if (contains(states, s.getName())) {
 885                         xstate |= mask;
 886                     }
 887                     mask <<= 1;
 888                 }
 889             }
 890         } else {
 891             //if there are no custom states defined, then simply return the
 892             //state that Synth reported
 893             if (v.stateTypes == null) return ctx.getComponentState();
 894 
 895             //there are custom states on this values, so I'll have to iterate
 896             //over them all and return a custom extended state
 897             int state = ctx.getComponentState();
 898             for (State s : v.stateTypes) {
 899                 if (s.isInState(c, state)) {
 900                     xstate |= mask;
 901                 }
 902                 mask <<= 1;
 903             }


1010                 return states[bestIndex];
1011             }
1012             if (wildIndex != -1) {
1013                 lastState[0] = wildIndex;
1014                 return states[wildIndex];
1015             }
1016         }
1017         lastState[0] = -1;
1018         return null;
1019     }
1020 
1021     /**
1022      * Contains values such as the UIDefaults and painters associated with
1023      * a state. Whereas <code>State</code> represents a distinct state that a
1024      * component can be in (such as Enabled), this class represents the colors,
1025      * fonts, painters, etc associated with some state for this
1026      * style.
1027      */
1028     private final class RuntimeState implements Cloneable {
1029         int state;
1030         Painter<Object> backgroundPainter;
1031         Painter<Object> foregroundPainter;
1032         Painter<Object> borderPainter;
1033         String stateName;
1034         UIDefaults defaults = new UIDefaults(10, .7f);
1035 
1036         private RuntimeState(int state, String stateName) {
1037             this.state = state;
1038             this.stateName = stateName;
1039         }
1040 
1041         @Override
1042         public String toString() {
1043             return stateName;
1044         }
1045 
1046         @Override
1047         public RuntimeState clone() {
1048             RuntimeState clone = new RuntimeState(state, stateName);
1049             clone.backgroundPainter = backgroundPainter;
1050             clone.foregroundPainter = foregroundPainter;
1051             clone.borderPainter = borderPainter;
1052             clone.defaults.putAll(defaults);
1053             return clone;
1054         }
1055     }
1056 
1057     /**
1058      * Essentially a struct of data for a style. A default instance of this
1059      * class is used by NimbusStyle. Additional instances exist for each
1060      * component that has overrides.
1061      */
1062     private static final class Values {
1063         /**
1064          * The list of State types. A State represents a type of state, such
1065          * as Enabled, Default, WindowFocused, etc. These can be custom states.
1066          */
1067         State<?>[] stateTypes = null;
1068         /**
1069          * The list of actual runtime state representations. These can represent things such
1070          * as Enabled + Focused. Thus, they differ from States in that they contain
1071          * several states together, and have associated properties, data, etc.
1072          */
1073         RuntimeState[] states = null;
1074         /**
1075          * The content margins for this region.
1076          */
1077         Insets contentMargins;
1078         /**
1079          * Defaults on the region/component level.
1080          */
1081         UIDefaults defaults = new UIDefaults(10, .7f);
1082         /**
1083          * Simple cache. After a value has been looked up, it is stored
1084          * in this cache for later retrieval. The key is a concatenation of
1085          * the property being looked up, two dollar signs, and the extended
1086          * state. So for example:
1087          *