1 7 package com.sun.java.swing.plaf.nimbus; 8 9 import com.sun.java.swing.Painter; 10 11 import javax.swing.JComponent ; 12 import javax.swing.UIDefaults ; 13 import javax.swing.UIManager ; 14 import javax.swing.plaf.ColorUIResource ; 15 import javax.swing.plaf.synth.ColorType ; 16 import static javax.swing.plaf.synth.SynthConstants .*; 17 import javax.swing.plaf.synth.SynthContext ; 18 import javax.swing.plaf.synth.SynthPainter ; 19 import javax.swing.plaf.synth.SynthStyle ; 20 import java.awt.Color ; 21 import java.awt.Font ; 22 import java.awt.Insets ; 23 import java.util.ArrayList ; 24 import java.util.Collections ; 25 import java.util.Comparator ; 26 import java.util.HashMap ; 27 import java.util.HashSet ; 28 import java.util.List ; 29 import java.util.Map ; 30 import java.util.TreeMap ; 31 import java.util.WeakHashMap ; 32 import javax.swing.plaf.synth.SynthConstants ; 33 34 105 public final class NimbusStyle extends SynthStyle { 106 107 108 public static final String LARGE_KEY = "large"; 109 public static final String SMALL_KEY = "small"; 110 public static final String MINI_KEY = "mini"; 111 public static final double LARGE_SCALE = 1.15; 112 public static final double SMALL_SCALE = 0.857; 113 public static final double MINI_SCALE = 0.714; 114 115 122 private static final Object NULL = '\0'; 123 135 private static final Color DEFAULT_COLOR = new ColorUIResource (Color.BLACK); 136 142 private String prefix; 143 149 private SynthPainter painter; 150 157 private Values values; 158 167 private WeakHashMap <JComponent , Values> overrides; 168 169 173 private CacheKey tmpKey = new CacheKey("", 0); 174 175 184 NimbusStyle(String prefix) { 185 this.prefix = prefix; 186 overrides = new WeakHashMap <JComponent , Values>(); 187 this.painter = new SynthPainterImpl(this); 188 } 189 190 196 @Override public void installDefaults(SynthContext ctx) { 197 validate(); 198 199 super.installDefaults(ctx); 202 } 203 204 208 private void validate() { 209 if (values != null) return; 212 213 values = new Values(); 215 216 TreeMap <String , Object > myDefaults = new TreeMap <String , Object >(); 218 219 for (Object obj : new HashSet (UIManager.getDefaults().keySet())) { 222 String key = obj == null ? null : obj.toString(); 223 if (key != null && key.startsWith(prefix)) { 224 myDefaults.put(key, UIManager.getDefaults().get(key)); 225 } 226 } 227 228 UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults(); 230 for (Object obj : new HashSet (lafDefaults.keySet())) { 231 String key = obj == null ? null : obj.toString(); 232 if (key != null && key.startsWith(prefix)) { 233 myDefaults.put(key, lafDefaults.get(key)); 234 } 235 } 236 237 init(values, myDefaults); 241 } 242 243 251 private void init(Values v, TreeMap <String , Object > myDefaults) { 252 List <State> states = new ArrayList <State>(); 257 Map <String ,Integer > stateCodes = new HashMap <String ,Integer >(); 259 List <RuntimeState> runtimeStates = new ArrayList <RuntimeState>(); 262 263 String statesString = (String )myDefaults.get(prefix + ".States"); 269 if (statesString != null) { 270 String s[] = statesString.split(","); 271 for (int i=0; i<s.length; i++) { 272 s[i] = s[i].trim(); 273 if (!State.isStandardStateName(s[i])) { 274 String stateName = prefix + "." + s[i]; 277 State customState = (State)myDefaults.get(stateName); 278 if (customState != null) { 279 states.add(customState); 280 } 281 } else { 282 states.add(State.getStandardState(s[i])); 283 } 284 } 285 286 if (states.size() > 0) { 290 v.stateTypes = states.toArray(new State[states.size()]); 291 } 292 293 int code = 1; 295 for (State state : states) { 296 stateCodes.put(state.getName(), code); 297 code <<= 1; 298 } 299 } else { 300 states.add(State.Enabled); 307 states.add(State.MouseOver); 308 states.add(State.Pressed); 309 states.add(State.Disabled); 310 states.add(State.Focused); 311 states.add(State.Selected); 312 states.add(State.Default); 313 314 stateCodes.put("Enabled", ENABLED); 316 stateCodes.put("MouseOver", MOUSE_OVER); 317 stateCodes.put("Pressed", PRESSED); 318 stateCodes.put("Disabled", DISABLED); 319 stateCodes.put("Focused", FOCUSED); 320 stateCodes.put("Selected", SELECTED); 321 stateCodes.put("Default", DEFAULT); 322 } 323 324 325 for (String key : myDefaults.keySet()) { 327 String temp = key.substring(prefix.length()); 331 if (temp.indexOf('"') != -1 || temp.indexOf(':') != -1) continue; 334 temp = temp.substring(1); 336 342 String stateString = null; 344 String property = null; 345 int bracketIndex = temp.indexOf(']'); 346 if (bracketIndex < 0) { 347 property = temp; 349 } else { 350 stateString = temp.substring(0, bracketIndex); 351 property = temp.substring(bracketIndex + 2); 352 } 353 354 if (stateString == null) { 357 if ("contentMargins".equals(property)) { 364 v.contentMargins = (Insets )myDefaults.get(key); 365 } else if ("States".equals(property)) { 366 } else { 368 v.defaults.put(property, myDefaults.get(key)); 369 } 370 } else { 371 boolean skip = false; 376 int componentState = 0; 379 String [] stateParts = stateString.split("\\+"); 382 for (String s : stateParts) { 385 if (stateCodes.containsKey(s)) { 386 componentState |= stateCodes.get(s); 387 } else { 388 skip = true; 391 break; 392 } 393 } 394 395 if (skip) continue; 396 397 RuntimeState rs = null; 399 for (RuntimeState s : runtimeStates) { 400 if (s.state == componentState) { 401 rs = s; 402 break; 403 } 404 } 405 406 if (rs == null) { 408 rs = new RuntimeState(componentState, stateString); 409 runtimeStates.add(rs); 410 } 411 412 if ("backgroundPainter".equals(property)) { 418 rs.backgroundPainter = (Painter)myDefaults.get(key); 419 } else if ("foregroundPainter".equals(property)) { 420 rs.foregroundPainter = (Painter) myDefaults.get(key); 421 } else if ("borderPainter".equals(property)) { 422 rs.borderPainter = (Painter) myDefaults.get(key); 423 } else { 424 rs.defaults.put(property, myDefaults.get(key)); 425 } 426 } 427 } 428 429 Collections.sort(runtimeStates,new Comparator <RuntimeState>() { 432 @Override 433 public int compare(RuntimeState a, RuntimeState b) { 434 return a.state - b.state; 435 } 436 }); 437 438 v.states = runtimeStates.toArray(new RuntimeState[0]); 440 } 441 442 448 @Override public Insets getInsets(SynthContext ctx, Insets in) { 449 if (in == null) { 450 in = new Insets (0, 0, 0, 0); 451 } 452 453 Values v = getValues(ctx); 454 455 if (v.contentMargins == null) { 456 in.bottom = in.top = in.left = in.right = 0; 457 return in; 458 } else { 459 in.bottom = v.contentMargins.bottom; 460 in.top = v.contentMargins.top; 461 in.left = v.contentMargins.left; 462 in.right = v.contentMargins.right; 463 String scaleKey = (String )ctx.getComponent().getClientProperty( 466 "JComponent.sizeVariant"); 467 if (scaleKey != null){ 468 if (LARGE_KEY.equals(scaleKey)){ 469 in.bottom *= LARGE_SCALE; 470 in.top *= LARGE_SCALE; 471 in.left *= LARGE_SCALE; 472 in.right *= LARGE_SCALE; 473 } else if (SMALL_KEY.equals(scaleKey)){ 474 in.bottom *= SMALL_SCALE; 475 in.top *= SMALL_SCALE; 476 in.left *= SMALL_SCALE; 477 in.right *= SMALL_SCALE; 478 } else if (MINI_KEY.equals(scaleKey)){ 479 in.bottom *= MINI_SCALE; 480 in.top *= MINI_SCALE; 481 in.left *= MINI_SCALE; 482 in.right *= MINI_SCALE; 483 } 484 } 485 return in; 486 } 487 } 488 489 508 @Override protected Color getColorForState(SynthContext ctx, ColorType type) { 509 String key = null; 510 if (type == ColorType.BACKGROUND) { 511 key = "background"; 512 } else if (type == ColorType.FOREGROUND) { 513 key = "textForeground"; 515 } else if (type == ColorType.TEXT_BACKGROUND) { 516 key = "textBackground"; 517 } else if (type == ColorType.TEXT_FOREGROUND) { 518 key = "textForeground"; 519 } else if (type == ColorType.FOCUS) { 520 key = "focus"; 521 } else if (type != null) { 522 key = type.toString(); 523 } else { 524 return DEFAULT_COLOR; 525 } 526 Color c = (Color ) get(ctx, key); 527 if (c == null) c = DEFAULT_COLOR; 529 return c; 530 } 531 532 540 @Override protected Font getFontForState(SynthContext ctx) { 541 Font f = (Font )get(ctx, "font"); 542 if (f == null) f = UIManager.getFont("defaultFont"); 543 544 String scaleKey = (String )ctx.getComponent().getClientProperty( 547 "JComponent.sizeVariant"); 548 if (scaleKey != null){ 549 if (LARGE_KEY.equals(scaleKey)){ 550 f = f.deriveFont(Math.round(f.getSize2D()*LARGE_SCALE)); 551 } else if (SMALL_KEY.equals(scaleKey)){ 552 f = f.deriveFont(Math.round(f.getSize2D()*SMALL_SCALE)); 553 } else if (MINI_KEY.equals(scaleKey)){ 554 f = f.deriveFont(Math.round(f.getSize2D()*MINI_SCALE)); 555 } 556 } 557 return f; 558 559 } 560 561 567 @Override public SynthPainter getPainter(SynthContext ctx) { 568 return painter; 569 } 570 571 578 @Override public boolean isOpaque(SynthContext ctx) { 579 if ("Table.cellRenderer".equals(ctx.getComponent().getName())) { 581 return true; 582 } 583 Boolean opaque = (Boolean )get(ctx, "opaque"); 584 return opaque == null ? false : opaque; 585 } 586 587 620 @Override public Object get(SynthContext ctx, Object key) { 621 Values v = getValues(ctx); 622 623 String fullKey = key.toString(); 625 String partialKey = fullKey.substring(fullKey.indexOf(".") + 1); 626 627 Object obj = null; 628 int xstate = getExtendedState(ctx, v); 629 630 tmpKey.init(partialKey, xstate); 632 obj = v.cache.get(tmpKey); 633 boolean wasInCache = obj != null; 634 if (!wasInCache){ 635 RuntimeState s = null; 637 int[] lastIndex = new int[] {-1}; 638 while (obj == null && 639 (s = getNextState(v.states, lastIndex, xstate)) != null) { 640 obj = s.defaults.get(partialKey); 641 } 642 if (obj == null && v.defaults != null) { 644 obj = v.defaults.get(partialKey); 645 } 646 if (obj == null) obj = UIManager.get(fullKey); 649 if (obj == null && partialKey.equals("focusInputMap")) { 651 obj = super.get(ctx, fullKey); 652 } 653 v.cache.put(new CacheKey(partialKey, xstate), 655 obj == null ? NULL : obj); 656 } 657 return obj == NULL ? null : obj; 659 } 660 661 670 public Painter getBackgroundPainter(SynthContext ctx) { 671 Values v = getValues(ctx); 672 int xstate = getExtendedState(ctx, v); 673 Painter p = null; 674 675 tmpKey.init("backgroundPainter$$instance", xstate); 677 p = (Painter)v.cache.get(tmpKey); 678 if (p != null) return p; 679 680 RuntimeState s = null; 682 int[] lastIndex = new int[] {-1}; 683 while ((s = getNextState(v.states, lastIndex, xstate)) != null) { 684 if (s.backgroundPainter != null) { 685 p = s.backgroundPainter; 686 break; 687 } 688 } 689 if (p == null) p = (Painter)get(ctx, "backgroundPainter"); 690 if (p != null) { 691 v.cache.put(new CacheKey("backgroundPainter$$instance", xstate), p); 692 } 693 return p; 694 } 695 696 705 public Painter getForegroundPainter(SynthContext ctx) { 706 Values v = getValues(ctx); 707 int xstate = getExtendedState(ctx, v); 708 Painter p = null; 709 710 tmpKey.init("foregroundPainter$$instance", xstate); 712 p = (Painter)v.cache.get(tmpKey); 713 if (p != null) return p; 714 715 RuntimeState s = null; 717 int[] lastIndex = new int[] {-1}; 718 while ((s = getNextState(v.states, lastIndex, xstate)) != null) { 719 if (s.foregroundPainter != null) { 720 p = s.foregroundPainter; 721 break; 722 } 723 } 724 if (p == null) p = (Painter)get(ctx, "foregroundPainter"); 725 if (p != null) { 726 v.cache.put(new CacheKey("foregroundPainter$$instance", xstate), p); 727 } 728 return p; 729 } 730 731 740 public Painter getBorderPainter(SynthContext ctx) { 741 Values v = getValues(ctx); 742 int xstate = getExtendedState(ctx, v); 743 Painter p = null; 744 745 tmpKey.init("borderPainter$$instance", xstate); 747 p = (Painter)v.cache.get(tmpKey); 748 if (p != null) return p; 749 750 RuntimeState s = null; 752 int[] lastIndex = new int[] {-1}; 753 while ((s = getNextState(v.states, lastIndex, xstate)) != null) { 754 if (s.borderPainter != null) { 755 p = s.borderPainter; 756 break; 757 } 758 } 759 if (p == null) p = (Painter)get(ctx, "borderPainter"); 760 if (p != null) { 761 v.cache.put(new CacheKey("borderPainter$$instance", xstate), p); 762 } 763 return p; 764 } 765 766 776 private Values getValues(SynthContext ctx) { 777 validate(); 778 779 JComponent c = ctx.getComponent(); 782 Values v = overrides.get(c); 783 if (v != null) return v; 784 785 Object o = c.getClientProperty("Nimbus.Overrides"); 789 790 if (o == null) return values; 793 794 if (o instanceof UIDefaults ) { 798 Object i = c.getClientProperty("Nimbus.Overrides.InheritDefaults"); 799 boolean inheritDefaults = i instanceof Boolean ? (Boolean )i : true; 800 UIDefaults d = (UIDefaults )o; 801 TreeMap <String , Object > map = new TreeMap <String , Object >(); 802 for (Object obj : d.keySet()) { 803 if (obj instanceof String ) { 804 String key = (String )obj; 805 if (key.startsWith(prefix + ".")) { 806 map.put(key, d.get(key)); 807 } 808 } 809 } 810 v = new Values(); 811 if (inheritDefaults) { 812 if (values.stateTypes != null) { 814 v.stateTypes = new State[values.stateTypes.length]; 815 System.arraycopy(values.stateTypes, 0,v.stateTypes, 0, 816 values.stateTypes.length); 817 } 818 v.contentMargins = values.contentMargins; 819 if (values.states != null) { 820 v.states = new RuntimeState[values.states.length]; 821 for (int j=0; j<v.states.length; j++) { 822 v.states[j] = values.states[j].clone(); 823 } 824 } 825 v.defaults.putAll(values.defaults); 826 } 827 init(v, map); 828 overrides.put(c, v); 829 } 830 831 return v == null ? values : v; 832 } 833 834 845 private boolean contains(String [] names, String name) { 846 assert name != null; 847 for (int i=0; i<names.length; i++) { 848 if (name.equals(names[i])) { 849 return true; 850 } 851 } 852 return false; 853 } 854 855 878 private int getExtendedState(SynthContext ctx, Values v) { 879 JComponent c = ctx.getComponent(); 880 int xstate = 0; 881 int mask = 1; 882 Object property = c.getClientProperty("Nimbus.State"); 887 if (property != null) { 888 String stateNames = property.toString(); 889 String [] states = stateNames.split("\\+"); 890 if (v.stateTypes == null){ 891 for (String stateStr : states) { 893 State.StandardState s = State.getStandardState(stateStr); 894 if (s != null) xstate |= s.getState(); 895 } 896 } else { 897 for (State s : v.stateTypes) { 899 if (contains(states, s.getName())) { 900 xstate |= mask; 901 } 902 mask <<= 1; 903 } 904 } 905 } else { 906 if (v.stateTypes == null) return ctx.getComponentState(); 909 910 int state = ctx.getComponentState(); 913 for (State s : v.stateTypes) { 914 if (s.isInState(c, state)) { 915 xstate |= mask; 916 } 917 mask <<= 1; 918 } 919 } 920 return xstate; 921 } 922 923 950 private RuntimeState getNextState(RuntimeState[] states, 951 int[] lastState, 952 int xstate) { 953 957 968 if (states != null && states.length > 0) { 969 int bestCount = 0; 970 int bestIndex = -1; 971 int wildIndex = -1; 972 973 if (xstate == 0) { 976 for (int counter = states.length - 1; counter >= 0; counter--) { 977 if (states[counter].state == 0) { 978 lastState[0] = counter; 979 return states[counter]; 980 } 981 } 982 lastState[0] = -1; 984 return null; 985 } 986 987 989 int lastStateIndex = lastState == null || lastState[0] == -1 ? 993 states.length : lastState[0]; 994 995 for (int counter = lastStateIndex - 1; counter >= 0; counter--) { 996 int oState = states[counter].state; 997 998 if (oState == 0) { 999 if (wildIndex == -1) { 1000 wildIndex = counter; 1001 } 1002 } else if ((xstate & oState) == oState) { 1003 1008 int bitCount = oState; 1010 bitCount -= (0xaaaaaaaa & bitCount) >>> 1; 1011 bitCount = (bitCount & 0x33333333) + ((bitCount >>> 2) & 1012 0x33333333); 1013 bitCount = bitCount + (bitCount >>> 4) & 0x0f0f0f0f; 1014 bitCount += bitCount >>> 8; 1015 bitCount += bitCount >>> 16; 1016 bitCount = bitCount & 0xff; 1017 if (bitCount > bestCount) { 1018 bestIndex = counter; 1019 bestCount = bitCount; 1020 } 1021 } 1022 } 1023 if (bestIndex != -1) { 1024 lastState[0] = bestIndex; 1025 return states[bestIndex]; 1026 } 1027 if (wildIndex != -1) { 1028 lastState[0] = wildIndex; 1029 return states[wildIndex]; 1030 } 1031 } 1032 lastState[0] = -1; 1033 return null; 1034 } 1035 1036 1043 private final class RuntimeState implements Cloneable { 1044 int state; 1045 Painter backgroundPainter; 1046 Painter foregroundPainter; 1047 Painter borderPainter; 1048 String stateName; 1049 UIDefaults defaults = new UIDefaults (10, .7f); 1050 1051 private RuntimeState(int state, String stateName) { 1052 this.state = state; 1053 this.stateName = stateName; 1054 } 1055 1056 @Override 1057 public String toString() { 1058 return stateName; 1059 } 1060 1061 @Override 1062 public RuntimeState clone() { 1063 RuntimeState clone = new RuntimeState(state, stateName); 1064 clone.backgroundPainter = backgroundPainter; 1065 clone.foregroundPainter = foregroundPainter; 1066 clone.borderPainter = borderPainter; 1067 clone.defaults.putAll(defaults); 1068 return clone; 1069 } 1070 } 1071 1072 1077 private static final class Values { 1078 1082 State[] stateTypes = null; 1083 1088 RuntimeState[] states = null; 1089 1092 Insets contentMargins; 1093 1096 UIDefaults defaults = new UIDefaults (10, .7f); 1097 1105 Map <CacheKey,Object > cache = new HashMap <CacheKey,Object >(); 1106 } 1107 1108 1112 private static final class CacheKey { 1113 private String key; 1114 private int xstate; 1115 1116 CacheKey(Object key, int xstate) { 1117 init(key, xstate); 1118 } 1119 1120 void init(Object key, int xstate) { 1121 this.key = key.toString(); 1122 this.xstate = xstate; 1123 } 1124 1125 @Override 1126 public boolean equals(Object obj) { 1127 final CacheKey other = (CacheKey) obj; 1128 if (obj == null) return false; 1129 if (this.xstate != other.xstate) return false; 1130 if (!this.key.equals(other.key)) return false; 1131 return true; 1132 } 1133 1134 @Override 1135 public int hashCode() { 1136 int hash = 3; 1137 hash = 29 * hash + this.key.hashCode(); 1138 hash = 29 * hash + this.xstate; 1139 return hash; 1140 } 1141 } 1142} 1143 | Popular Tags |