001: //** Copyright Statement ***************************************************
002: //The Salmon Open Framework for Internet Applications (SOFIA)
003: // Copyright (C) 1999 - 2002, Salmon LLC
004: //
005: // This program is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU General Public License version 2
007: // as published by the Free Software Foundation;
008: //
009: // This program is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: // GNU General Public License for more details.
013: //
014: // You should have received a copy of the GNU General Public License
015: // along with this program; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: //
018: // For more information please visit http://www.salmonllc.com
019: //** End Copyright Statement ***************************************************
020:
021: package com.salmonllc.personalization;
022:
023: import javax.swing.plaf.ColorUIResource;
024: import javax.swing.plaf.FontUIResource;
025: import java.util.*;
026: import java.awt.*;
027: import java.lang.reflect.Method;
028:
029: /**
030: * A skin is a collection of attributes that are applied to the components of a page to create a personalized look
031: */
032:
033: public class Skin {
034: private Class[] _stringTypes = { String.class };
035: private Class[] _booleanTypes = { Boolean.TYPE };
036: private Class[] _intTypes = { Integer.TYPE };
037: private Class[] _colorUITypes = { ColorUIResource.class };
038: private Class[] _colorTypes = { Color.class };
039: private Class[] _fontUITypes = { FontUIResource.class };
040: private Class[] _fontTypes = { Font.class };
041:
042: private static final String SWING_LOOK_AND_FEEL = "SwingLookAndFeel";
043: private static final String SWING_METAL_THEME = "SwingMetalTheme";
044:
045: private Hashtable _classAttrib = new Hashtable();
046: private Hashtable _instanceAttrib = new Hashtable();
047: private Hashtable _wildCards = new Hashtable();
048: private Properties _props = new Properties();
049: private Vector _work = new Vector();
050:
051: /**
052: * Sets a class attribute in the Skin
053: * @param className The name of the class
054: * @param attributeName The name of the attribute in the class to set
055: * @param attributeValue The value to set the attribute to
056: */
057: public void setClassAttribute(String className,
058: String attributeName, String attributeValue) {
059: putItemInList(_classAttrib, null, className, attributeName,
060: attributeValue);
061: }
062:
063: /**
064: * Gets the value of a class attribute in the Skin
065: * @param className The name of the class
066: * @param attributeName The name of the attribute in the class to set
067: */
068:
069: public String getClassAttribute(String className,
070: String attributeName) {
071: return getValue(_classAttrib, className, attributeName);
072: }
073:
074: /**
075: * Gets all the attributes for a particular class in the skin
076: */
077: public Attribute[] getClassAttributes(String className) {
078: _work.setSize(0);
079: getAttributes(_classAttrib, className, _work);
080: Attribute ret[] = new Attribute[_work.size()];
081: _work.copyInto(ret);
082: return ret;
083: }
084:
085: /**
086: * Sets an intance attribute in the Skin
087: * @param instanceName The name of the component. It may contain a % sign in the first or last character to indicate a wild card.
088: * @param attributeName The name of the attribute in the class to set
089: * @param attributeValue The value to set the attribute to
090: */
091: public void setInstanceAttribute(String instanceName,
092: String attributeName, String attributeValue) {
093: putItemInList(_instanceAttrib, _wildCards, instanceName,
094: attributeName, attributeValue);
095: }
096:
097: /**
098: * Gets the value of an instance attribute in the Skin
099: * @param instanceName The name of the class. It may contain a % sign in the first or last character to indicate a wild card.
100: * @param attributeName The name of the attribute in the class to set
101: */
102:
103: public String getInstanceAttribute(String instanceName,
104: String attributeName) {
105: return getValue(_instanceAttrib, instanceName, attributeName);
106: }
107:
108: /**
109: * Gets all the attributes for a particular class in the skin
110: */
111: public Attribute[] getInstanceAttributes(String instanceName) {
112: _work.setSize(0);
113: getAttributes(_instanceAttrib, instanceName, _work);
114: Enumeration e = _wildCards.keys();
115: while (e.hasMoreElements()) {
116: String key = (String) e.nextElement();
117: if (equalsWildCard(key, instanceName))
118: getAttributes(_instanceAttrib, key, _work);
119: }
120: Attribute ret[] = new Attribute[_work.size()];
121: _work.copyInto(ret);
122: return ret;
123: }
124:
125: private void getAttributes(Hashtable tab, String key, Vector v) {
126: Attribute att = (Attribute) tab.get(key);
127: while (att != null) {
128: v.add(att);
129: att = att.getNext();
130: }
131: }
132:
133: private String getValue(Hashtable tab, String key,
134: String attributeName) {
135: Attribute att = (Attribute) tab.get(key);
136: if (att == null)
137: return null;
138: else {
139: while (att != null) {
140: if (att.getAttribute().equals(attributeName))
141: return att.getValue();
142: att = att.getNext();
143: }
144: }
145: return null;
146: }
147:
148: private void putItemInList(Hashtable tab, Hashtable wildCards,
149: String key, String attributeName, String attributeValue) {
150: Attribute att = (Attribute) tab.get(key);
151: if (att == null) {
152: att = new Attribute(attributeName, attributeValue);
153: tab.put(key, att);
154: if (wildCards != null)
155: if (key.startsWith("%") || key.endsWith("%"))
156: wildCards.put(key, att);
157: } else {
158: Attribute lastAtt = att;
159: while (att != null) {
160: lastAtt = att;
161: if (att.getAttribute().equals(attributeName)) {
162: att.setValue(attributeValue);
163: return;
164: }
165: att = att.getNext();
166: }
167: att = new Attribute(attributeName, attributeValue);
168: lastAtt.setNext(att);
169: }
170: }
171:
172: private static boolean equalsWildCard(String st1, String st2) {
173: int end = st1.length() - 1;
174: int st2Pos = 0;
175: boolean endsWith = (st1.charAt(0) == '%');
176: boolean startsWidth = (st1.charAt(end) == '%');
177:
178: if (startsWidth && endsWith) {
179: int len = st2.length();
180: char char1 = st1.charAt(1);
181: for (int i = 0; i < len; i++) {
182: if (st2.charAt(i) == char1) {
183: //found first character, now look for the rest
184: for (int j = 1; j < end && i < len; j++, i++) {
185: if (st2.charAt(i) != st1.charAt(j)) {
186: i--;
187: break;
188: } else if (j == (end - 1))
189: return true;
190: }
191: }
192: }
193: return false;
194: } else {
195: //for ends with
196: if (endsWith) {
197: st2Pos = st2.length() - 1;
198: for (int i = end; i > 0; i--) {
199: if (st1.charAt(i) != st2.charAt(st2Pos))
200: return false;
201: st2Pos--;
202: if (st2Pos < 0)
203: return false;
204: }
205: return true;
206: }
207: //for starts with
208: else if (startsWidth) {
209: end--;
210: st2Pos = 0;
211: for (int i = 0; i < end; i++) {
212: if (st1.charAt(i) != st2.charAt(st2Pos))
213: return false;
214: st2Pos++;
215: }
216: return true;
217: }
218: }
219:
220: return true;
221: }
222:
223: /**
224: * Returns the properties object used by this skin
225: */
226: public Properties getProperties() {
227: return _props;
228: }
229:
230: /**
231: * Adds a property to the properties object for this skin
232: */
233: public void setProperty(String key, String value) {
234: _props.put(key, value);
235: }
236:
237: /**
238: * If the skin has a swing metal theme property set, return it otherwise return null
239: */
240: public String getSwingMetalTheme() {
241: Object o = _props.get(SWING_METAL_THEME);
242: if (o == null)
243: return null;
244: else
245: return (String) o;
246: }
247:
248: /**
249: * If the skin has a swing look and feel property set, return it otherwise return null
250: */
251: public String getSwingLookAndFeel() {
252: Object o = _props.get(SWING_LOOK_AND_FEEL);
253: if (o == null)
254: return null;
255: else
256: return (String) o;
257: }
258:
259: /**
260: * Apply class and instance attributes of the skin to the object
261: */
262: public void applyAttributes(Object o) {
263: Class c = o.getClass();
264: Attribute at[] = getClassAttributes(o.getClass().getName());
265: for (int i = 0; i < at.length; i++) {
266: applyAttribute(at[i], o, c);
267: }
268: String name = null;
269: try {
270: if (o instanceof Component)
271: name = ((Component) o).getName();
272: else if (o instanceof SMetalTheme)
273: name = "SMetalTheme";
274: else if (o instanceof Nameable)
275: name = ((Nameable) o).getName();
276: } catch (Exception e) {
277: }
278:
279: if (name != null) {
280: at = getInstanceAttributes(name);
281: for (int i = 0; i < at.length; i++) {
282: applyAttribute(at[i], o, c);
283: }
284: }
285: }
286:
287: private void applyAttribute(Attribute att, Object o, Class c) {
288: StringBuffer sb = new StringBuffer(
289: att.getAttribute().length() + 3);
290: sb.append("set");
291: sb.append(att.getAttribute());
292: sb.setCharAt(3, Character.toUpperCase(att.getAttribute()
293: .charAt(0)));
294: String name = sb.toString();
295:
296: Object ar[] = new Object[1];
297: //first try integer
298: try {
299: Method m = c.getMethod(name, _intTypes);
300: ar[0] = new Integer(Integer.parseInt(att.getValue()));
301: m.invoke(o, ar);
302: return;
303:
304: } catch (Exception e) {
305: }
306:
307: //next try boolean
308: try {
309: Method m = c.getMethod(name, _booleanTypes);
310: String val = att.getValue();
311: if (val.equalsIgnoreCase("T")
312: || val.equalsIgnoreCase("TRUE")) {
313: ar[0] = Boolean.TRUE;
314: m.invoke(o, ar);
315: return;
316: } else if (val.equalsIgnoreCase("F")
317: || val.equalsIgnoreCase("FALSE")) {
318: ar[0] = Boolean.FALSE;
319: m.invoke(o, ar);
320: return;
321: }
322: } catch (Exception e) {
323: }
324:
325: //next try String
326: try {
327: Method m = c.getMethod(name, _stringTypes);
328: ar[0] = att.getValue();
329: m.invoke(o, ar);
330: return;
331: } catch (Exception e) {
332: }
333:
334: //next try colors
335: Color col = getColor(att.getValue());
336: if (col != null) {
337: try {
338: Method m = c.getMethod(name, _colorUITypes);
339: ar[0] = new ColorUIResource(col);
340: m.invoke(o, ar);
341: return;
342: } catch (Exception e) {
343: }
344:
345: try {
346: Method m = c.getMethod(name, _colorTypes);
347: ar[0] = col;
348: m.invoke(o, ar);
349: return;
350: } catch (Exception e) {
351: }
352: }
353:
354: //Next try fonts
355: Font ft = getFont(att.getValue());
356: if (ft != null) {
357: try {
358: Method m = c.getMethod(name, _fontUITypes);
359: ar[0] = new FontUIResource(ft);
360: m.invoke(o, ar);
361: return;
362: } catch (Exception e) {
363: }
364:
365: try {
366: Method m = c.getMethod(name, _fontTypes);
367: ar[0] = ft;
368: m.invoke(o, ar);
369: return;
370: } catch (Exception e) {
371: }
372: }
373: }
374:
375: private Color getColor(String col) {
376: if (col.indexOf(",") == -1)
377: return null;
378: StringTokenizer tok = new StringTokenizer(col, ",");
379: try {
380: int red = Integer.parseInt(tok.nextToken().trim());
381: int green = Integer.parseInt(tok.nextToken().trim());
382: int blue = Integer.parseInt(tok.nextToken().trim());
383: return new Color(red, green, blue);
384: } catch (Exception e) {
385: return null;
386: }
387: }
388:
389: private Font getFont(String font) {
390: if (font.indexOf(",") == -1)
391: return null;
392: StringTokenizer tok = new StringTokenizer(font, ",");
393: try {
394: String ft = tok.nextToken();
395: int sytle = getFontStyle(tok.nextToken());
396: int size = Integer.parseInt(tok.nextToken().trim());
397: return new Font(ft, sytle, size);
398: } catch (Exception e) {
399: return null;
400: }
401: }
402:
403: private int getFontStyle(String st) {
404: int ret = 0;
405: StringTokenizer tok = new StringTokenizer(st, "|");
406: while (tok.hasMoreTokens()) {
407: String style = tok.nextToken().trim();
408: if (style.equalsIgnoreCase("BOLD"))
409: ret = ret | Font.BOLD;
410: else if (style.equalsIgnoreCase("ITALIC"))
411: ret = ret | Font.ITALIC;
412: else if (style.equalsIgnoreCase("PLAIN"))
413: return Font.PLAIN;
414: }
415: return ret;
416: }
417:
418: /**
419: * Return all attributes in the component. Class attributes are preceeded with "class." and instance attributes are preceeded with "instance."
420: */
421: public Attribute[] getAllAttributes() {
422: Vector v = new Vector();
423: Enumeration e = _classAttrib.keys();
424: while (e.hasMoreElements()) {
425: String key = (String) e.nextElement();
426: Attribute comp = (Attribute) _classAttrib.get(key);
427: while (comp != null) {
428: String newKey = "class." + key + "."
429: + comp.getAttribute();
430: v.add(new Attribute(newKey, comp.getValue()));
431: comp = comp.getNext();
432: }
433: }
434: e = _instanceAttrib.keys();
435: while (e.hasMoreElements()) {
436: String key = (String) e.nextElement();
437: Attribute comp = (Attribute) _instanceAttrib.get(key);
438: while (comp != null) {
439: String newKey = "instance." + key + "."
440: + comp.getAttribute();
441: v.add(new Attribute(newKey, comp.getValue()));
442: comp = comp.getNext();
443: }
444: }
445: e = _props.keys();
446: while (e.hasMoreElements()) {
447: String key = (String) e.nextElement();
448: v.add(new Attribute(key, (String) _props.get(key)));
449: }
450: Attribute ret[] = new Attribute[v.size()];
451: v.copyInto(ret);
452: return ret;
453: }
454: }
|