1. /*
  2. * @(#)DefaultSynthStyleFactory.java 1.6 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.synth;
  8. import javax.swing.*;
  9. import javax.swing.plaf.FontUIResource;
  10. import java.awt.Font;
  11. import java.util.*;
  12. import java.util.regex.*;
  13. import sun.swing.plaf.synth.*;
  14. import sun.swing.BakedArrayList;
  15. /**
  16. * Factory used for obtaining styles. Supports associating a style based on
  17. * the name of the component as returned by <code>Component.getName()</code>,
  18. * and the <code>Region</code> associated with the <code>JComponent</code>.
  19. * Lookup is done using regular expressions.
  20. *
  21. * @version 1.6, 12/19/03
  22. * @author Scott Violet
  23. */
  24. class DefaultSynthStyleFactory extends SynthStyleFactory {
  25. /**
  26. * Used to indicate the lookup should be done based on Component name.
  27. */
  28. public static final int NAME = 0;
  29. /**
  30. * Used to indicate the lookup should be done based on region.
  31. */
  32. public static final int REGION = 1;
  33. /**
  34. * List containing set of StyleAssociations that are to match based on
  35. * Component name.
  36. */
  37. private List _nameStyles;
  38. /**
  39. * List containing set of StyleAssociations that are to match based on
  40. * Region.
  41. */
  42. private List _regionStyles;
  43. /**
  44. * Used during lookup.
  45. */
  46. private BakedArrayList _tmpList;
  47. /**
  48. * Maps from a List (BakedArrayList to be precise) to the merged style.
  49. */
  50. private Map _resolvedStyles;
  51. /**
  52. * Used if there are no styles matching a widget.
  53. */
  54. private SynthStyle _defaultStyle;
  55. DefaultSynthStyleFactory() {
  56. _tmpList = new BakedArrayList(5);
  57. _resolvedStyles = new HashMap();
  58. }
  59. public synchronized void addStyle(DefaultSynthStyle style,
  60. String path, int type) throws PatternSyntaxException {
  61. if (path == null) {
  62. // Make an empty path match all.
  63. path = ".*";
  64. }
  65. if (type == NAME) {
  66. if (_nameStyles == null) {
  67. _nameStyles = new ArrayList();
  68. }
  69. _nameStyles.add(StyleAssociation.createStyleAssociation(
  70. path, style));
  71. }
  72. else if (type == REGION) {
  73. if (_regionStyles == null) {
  74. _regionStyles = new ArrayList();
  75. }
  76. _regionStyles.add(StyleAssociation.createStyleAssociation(
  77. path.toLowerCase(), style));
  78. }
  79. }
  80. /**
  81. * Returns the style for the specified Component.
  82. *
  83. * @param c Component asking for
  84. * @param id ID of the Component
  85. */
  86. public synchronized SynthStyle getStyle(JComponent c, Region id) {
  87. BakedArrayList matches = _tmpList;
  88. matches.clear();
  89. getMatchingStyles(matches, c, id);
  90. if (matches.size() == 0) {
  91. return getDefaultStyle();
  92. }
  93. // Use a cached Style if possible, otherwise create a new one.
  94. matches.cacheHashCode();
  95. SynthStyle style = getCachedStyle(matches);
  96. if (style == null) {
  97. style = mergeStyles(matches);
  98. if (style != null) {
  99. cacheStyle(matches, style);
  100. }
  101. }
  102. return style;
  103. }
  104. /**
  105. * Returns the style to use if there are no matching styles.
  106. */
  107. private SynthStyle getDefaultStyle() {
  108. if (_defaultStyle == null) {
  109. _defaultStyle = new DefaultSynthStyle();
  110. ((DefaultSynthStyle)_defaultStyle).setFont(
  111. new FontUIResource("Dialog", Font.PLAIN,12));
  112. }
  113. return _defaultStyle;
  114. }
  115. /**
  116. * Fetches any styles that match the passed into arguments into
  117. * <code>matches</code>.
  118. */
  119. private void getMatchingStyles(java.util.List matches, JComponent c,
  120. Region id) {
  121. // First match on REGION
  122. if (_regionStyles != null) {
  123. getMatches(id.getLowerCaseName(), _regionStyles, matches);
  124. }
  125. // Then match on name
  126. if (_nameStyles != null) {
  127. String name = c.getName();
  128. if (name == null) {
  129. name = "";
  130. }
  131. getMatches(name, _nameStyles, matches);
  132. }
  133. }
  134. private void getMatches(CharSequence path, java.util.List styles,
  135. java.util.List matches) {
  136. for (int counter = styles.size() - 1; counter >= 0; counter--){
  137. StyleAssociation sa = (StyleAssociation)styles.get(counter);
  138. if (sa.matches(path) && matches.indexOf(sa.getStyle()) == -1) {
  139. matches.add(sa.getStyle());
  140. }
  141. }
  142. }
  143. /**
  144. * Caches the specified style.
  145. */
  146. private void cacheStyle(java.util.List styles, SynthStyle style) {
  147. BakedArrayList cachedStyles = new BakedArrayList(styles);
  148. _resolvedStyles.put(cachedStyles, style);
  149. }
  150. /**
  151. * Returns the cached style from the passed in arguments.
  152. */
  153. private SynthStyle getCachedStyle(java.util.List styles) {
  154. if (styles.size() == 0) {
  155. return null;
  156. }
  157. return (SynthStyle)_resolvedStyles.get(styles);
  158. }
  159. /**
  160. * Creates a single Style from the passed in styles. The passed in List
  161. * is reverse sorted, that is the most recently added style found to
  162. * match will be first.
  163. */
  164. private SynthStyle mergeStyles(java.util.List styles) {
  165. int size = styles.size();
  166. if (size == 0) {
  167. return null;
  168. }
  169. else if (size == 1) {
  170. return (SynthStyle)((DefaultSynthStyle)styles.get(0)).clone();
  171. }
  172. // NOTE: merging is done backwards as DefaultSynthStyleFactory reverses
  173. // order, that is, the most specific style is first.
  174. DefaultSynthStyle style = (DefaultSynthStyle)styles.get(size - 1);
  175. style = (DefaultSynthStyle)style.clone();
  176. for (int counter = size - 2; counter >= 0; counter--) {
  177. style = ((DefaultSynthStyle)styles.get(counter)).addTo(style);
  178. }
  179. return style;
  180. }
  181. }