1 /* 2 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. 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 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 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 * 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. 24 */ 25 package javax.swing.plaf.synth; 26 27 import javax.swing.*; 28 import javax.swing.plaf.FontUIResource; 29 import java.awt.Font; 30 import java.util.*; 31 import java.util.regex.*; 32 import sun.swing.plaf.synth.*; 33 import sun.swing.BakedArrayList; 34 35 /** 36 * Factory used for obtaining styles. Supports associating a style based on 37 * the name of the component as returned by <code>Component.getName()</code>, 38 * and the <code>Region</code> associated with the <code>JComponent</code>. 39 * Lookup is done using regular expressions. 40 * 41 * @author Scott Violet 42 */ 43 class DefaultSynthStyleFactory extends SynthStyleFactory { 44 /** 45 * Used to indicate the lookup should be done based on Component name. 46 */ 47 public static final int NAME = 0; 48 /** 49 * Used to indicate the lookup should be done based on region. 50 */ 51 public static final int REGION = 1; 52 53 /** 54 * List containing set of StyleAssociations used in determining matching 55 * styles. 56 */ 57 private List<StyleAssociation> _styles; 58 /** 59 * Used during lookup. 60 */ 61 private BakedArrayList _tmpList; 62 63 /** 64 * Maps from a List (BakedArrayList to be precise) to the merged style. 65 */ 66 private Map<BakedArrayList, SynthStyle> _resolvedStyles; 67 68 /** 69 * Used if there are no styles matching a widget. 70 */ 71 private SynthStyle _defaultStyle; 72 73 74 DefaultSynthStyleFactory() { 75 _tmpList = new BakedArrayList(5); 76 _styles = new ArrayList<StyleAssociation>(); 77 _resolvedStyles = new HashMap<BakedArrayList, SynthStyle>(); 78 } 79 80 public synchronized void addStyle(DefaultSynthStyle style, 81 String path, int type) throws PatternSyntaxException { 82 if (path == null) { 83 // Make an empty path match all. 84 path = ".*"; 85 } 86 if (type == NAME) { 87 _styles.add(StyleAssociation.createStyleAssociation( 88 path, style, type)); 89 } 90 else if (type == REGION) { 91 _styles.add(StyleAssociation.createStyleAssociation( 92 path.toLowerCase(), style, type)); 93 } 94 } 95 96 /** 97 * Returns the style for the specified Component. 98 * 99 * @param c Component asking for 100 * @param id ID of the Component 101 */ 102 public synchronized SynthStyle getStyle(JComponent c, Region id) { 103 BakedArrayList matches = _tmpList; 104 105 matches.clear(); 106 getMatchingStyles(matches, c, id); 107 108 if (matches.size() == 0) { 109 return getDefaultStyle(); 110 } 111 // Use a cached Style if possible, otherwise create a new one. 112 matches.cacheHashCode(); 113 SynthStyle style = getCachedStyle(matches); 114 115 if (style == null) { 116 style = mergeStyles(matches); 117 118 if (style != null) { 119 cacheStyle(matches, style); 120 } 121 } 122 return style; 123 } 124 125 /** 126 * Returns the style to use if there are no matching styles. 127 */ 128 private SynthStyle getDefaultStyle() { 129 if (_defaultStyle == null) { 130 _defaultStyle = new DefaultSynthStyle(); 131 ((DefaultSynthStyle)_defaultStyle).setFont( 132 new FontUIResource(Font.DIALOG, Font.PLAIN,12)); 133 } 134 return _defaultStyle; 135 } 136 137 /** 138 * Fetches any styles that match the passed into arguments into 139 * <code>matches</code>. 140 */ 141 private void getMatchingStyles(List matches, JComponent c, 142 Region id) { 143 String idName = id.getLowerCaseName(); 144 String cName = c.getName(); 145 146 if (cName == null) { 147 cName = ""; 148 } 149 for (int counter = _styles.size() - 1; counter >= 0; counter--){ 150 StyleAssociation sa = _styles.get(counter); 151 String path; 152 153 if (sa.getID() == NAME) { 154 path = cName; 155 } 156 else { 157 path = idName; 158 } 159 160 if (sa.matches(path) && matches.indexOf(sa.getStyle()) == -1) { 161 matches.add(sa.getStyle()); 162 } 163 } 164 } 165 166 /** 167 * Caches the specified style. 168 */ 169 private void cacheStyle(List styles, SynthStyle style) { 170 BakedArrayList cachedStyles = new BakedArrayList(styles); 171 172 _resolvedStyles.put(cachedStyles, style); 173 } 174 175 /** 176 * Returns the cached style from the passed in arguments. 177 */ 178 private SynthStyle getCachedStyle(List styles) { 179 if (styles.size() == 0) { 180 return null; 181 } 182 return _resolvedStyles.get(styles); 183 } 184 185 /** 186 * Creates a single Style from the passed in styles. The passed in List 187 * is reverse sorted, that is the most recently added style found to 188 * match will be first. 189 */ 190 private SynthStyle mergeStyles(List styles) { 191 int size = styles.size(); 192 193 if (size == 0) { 194 return null; 195 } 196 else if (size == 1) { 197 return (SynthStyle)((DefaultSynthStyle)styles.get(0)).clone(); 198 } 199 // NOTE: merging is done backwards as DefaultSynthStyleFactory reverses 200 // order, that is, the most specific style is first. 201 DefaultSynthStyle style = (DefaultSynthStyle)styles.get(size - 1); 202 203 style = (DefaultSynthStyle)style.clone(); 204 for (int counter = size - 2; counter >= 0; counter--) { 205 style = ((DefaultSynthStyle)styles.get(counter)).addTo(style); 206 } 207 return style; 208 } 209 }