1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58:
59: import ;
60: import ;
61: import ;
62:
63: public class StyleContext
64: implements Serializable, AbstractDocument.AttributeContext
65: {
66:
67: private static final long serialVersionUID = 8042858831190784241L;
68:
69: public class NamedStyle
70: implements Serializable, Style
71: {
72:
73: private static final long serialVersionUID = -6690628971806226374L;
74:
75: protected transient ChangeEvent changeEvent;
76: protected EventListenerList listenerList;
77:
78: private transient AttributeSet attributes;
79:
80: public NamedStyle()
81: {
82: this(null, null);
83: }
84:
85: public NamedStyle(Style parent)
86: {
87: this(null, parent);
88: }
89:
90: public NamedStyle(String name, Style parent)
91: {
92: attributes = getEmptySet();
93: listenerList = new EventListenerList();
94: if (name != null)
95: setName(name);
96: if (parent != null)
97: setResolveParent(parent);
98: }
99:
100: public String getName()
101: {
102: String name = null;
103: if (isDefined(StyleConstants.NameAttribute))
104: name = getAttribute(StyleConstants.NameAttribute).toString();
105: return name;
106: }
107:
108: public void setName(String n)
109: {
110: if (n != null)
111: addAttribute(StyleConstants.NameAttribute, n);
112: }
113:
114: public void addChangeListener(ChangeListener l)
115: {
116: listenerList.add(ChangeListener.class, l);
117: }
118:
119: public void removeChangeListener(ChangeListener l)
120: {
121: listenerList.remove(ChangeListener.class, l);
122: }
123:
124: public <T extends EventListener> T[] getListeners(Class<T> listenerType)
125: {
126: return listenerList.getListeners(listenerType);
127: }
128:
129: public ChangeListener[] getChangeListeners()
130: {
131: return (ChangeListener[]) getListeners(ChangeListener.class);
132: }
133:
134: protected void fireStateChanged()
135: {
136: ChangeListener[] listeners = getChangeListeners();
137: for (int i = 0; i < listeners.length; ++i)
138: {
139:
140: if (changeEvent == null)
141: changeEvent = new ChangeEvent(this);
142: listeners[i].stateChanged(changeEvent);
143: }
144: }
145:
146: public void addAttribute(Object name, Object value)
147: {
148: attributes = StyleContext.this.addAttribute(attributes, name, value);
149: fireStateChanged();
150: }
151:
152: public void addAttributes(AttributeSet attr)
153: {
154: attributes = StyleContext.this.addAttributes(attributes, attr);
155: fireStateChanged();
156: }
157:
158: public boolean containsAttribute(Object name, Object value)
159: {
160: return attributes.containsAttribute(name, value);
161: }
162:
163: public boolean containsAttributes(AttributeSet attrs)
164: {
165: return attributes.containsAttributes(attrs);
166: }
167:
168: public AttributeSet copyAttributes()
169: {
170:
171: NamedStyle copy = new NamedStyle();
172: copy.attributes = attributes.copyAttributes();
173: return copy;
174: }
175:
176: public Object getAttribute(Object attrName)
177: {
178: return attributes.getAttribute(attrName);
179: }
180:
181: public int getAttributeCount()
182: {
183: return attributes.getAttributeCount();
184: }
185:
186: public Enumeration<?> getAttributeNames()
187: {
188: return attributes.getAttributeNames();
189: }
190:
191: public boolean isDefined(Object attrName)
192: {
193: return attributes.isDefined(attrName);
194: }
195:
196: public boolean isEqual(AttributeSet attr)
197: {
198: return attributes.isEqual(attr);
199: }
200:
201: public void removeAttribute(Object name)
202: {
203: attributes = StyleContext.this.removeAttribute(attributes, name);
204: fireStateChanged();
205: }
206:
207: public void removeAttributes(AttributeSet attrs)
208: {
209: attributes = StyleContext.this.removeAttributes(attributes, attrs);
210: fireStateChanged();
211: }
212:
213: public void removeAttributes(Enumeration<?> names)
214: {
215: attributes = StyleContext.this.removeAttributes(attributes, names);
216: fireStateChanged();
217: }
218:
219:
220: public AttributeSet getResolveParent()
221: {
222: return attributes.getResolveParent();
223: }
224:
225: public void setResolveParent(AttributeSet parent)
226: {
227: if (parent != null)
228: addAttribute(StyleConstants.ResolveAttribute, parent);
229: else
230: removeAttribute(StyleConstants.ResolveAttribute);
231: }
232:
233: public String toString()
234: {
235: return "NamedStyle:" + getName() + " " + attributes;
236: }
237:
238: private void writeObject(ObjectOutputStream s)
239: throws IOException
240: {
241: s.defaultWriteObject();
242: writeAttributeSet(s, attributes);
243: }
244:
245: private void readObject(ObjectInputStream s)
246: throws ClassNotFoundException, IOException
247: {
248: s.defaultReadObject();
249: attributes = SimpleAttributeSet.EMPTY;
250: readAttributeSet(s, this);
251: }
252: }
253:
254: public class SmallAttributeSet
255: implements AttributeSet
256: {
257: final Object [] attrs;
258: private AttributeSet resolveParent;
259: public SmallAttributeSet(AttributeSet a)
260: {
261: int n = a.getAttributeCount();
262: int i = 0;
263: attrs = new Object[n * 2];
264: Enumeration e = a.getAttributeNames();
265: while (e.hasMoreElements())
266: {
267: Object name = e.nextElement();
268: Object value = a.getAttribute(name);
269: if (name == ResolveAttribute)
270: resolveParent = (AttributeSet) value;
271: attrs[i++] = name;
272: attrs[i++] = value;
273: }
274: }
275:
276: public SmallAttributeSet(Object [] a)
277: {
278: attrs = a;
279: for (int i = 0; i < attrs.length; i += 2)
280: {
281: if (attrs[i] == ResolveAttribute)
282: resolveParent = (AttributeSet) attrs[i + 1];
283: }
284: }
285:
286: public Object clone()
287: {
288: return this;
289: }
290:
291: public boolean containsAttribute(Object name, Object value)
292: {
293: return value.equals(getAttribute(name));
294: }
295:
296: public boolean containsAttributes(AttributeSet a)
297: {
298: boolean res = true;
299: Enumeration e = a.getAttributeNames();
300: while (e.hasMoreElements() && res)
301: {
302: Object name = e.nextElement();
303: res = a.getAttribute(name).equals(getAttribute(name));
304: }
305: return res;
306: }
307:
308: public AttributeSet copyAttributes()
309: {
310: return this;
311: }
312:
313: public boolean equals(Object obj)
314: {
315: boolean eq = false;
316: if (obj instanceof AttributeSet)
317: {
318: AttributeSet atts = (AttributeSet) obj;
319: eq = getAttributeCount() == atts.getAttributeCount()
320: && containsAttributes(atts);
321: }
322: return eq;
323: }
324:
325: public Object getAttribute(Object key)
326: {
327: Object att = null;
328: if (key == StyleConstants.ResolveAttribute)
329: att = resolveParent;
330:
331: for (int i = 0; i < attrs.length && att == null; i += 2)
332: {
333: if (attrs[i].equals(key))
334: att = attrs[i + 1];
335: }
336:
337:
338:
339: if (att == null)
340: {
341: AttributeSet parent = getResolveParent();
342: if (parent != null)
343: att = parent.getAttribute(key);
344: }
345:
346: return att;
347: }
348:
349: public int getAttributeCount()
350: {
351: return attrs.length / 2;
352: }
353:
354: public Enumeration<?> getAttributeNames()
355: {
356: return new Enumeration()
357: {
358: int i = 0;
359: public boolean hasMoreElements()
360: {
361: return i < attrs.length;
362: }
363: public Object nextElement()
364: {
365: i += 2;
366: return attrs[i-2];
367: }
368: };
369: }
370:
371: public AttributeSet getResolveParent()
372: {
373: return resolveParent;
374: }
375:
376: public int hashCode()
377: {
378: return java.util.Arrays.asList(attrs).hashCode();
379: }
380:
381: public boolean isDefined(Object key)
382: {
383: for (int i = 0; i < attrs.length; i += 2)
384: {
385: if (attrs[i].equals(key))
386: return true;
387: }
388: return false;
389: }
390:
391: public boolean isEqual(AttributeSet attr)
392: {
393: boolean eq;
394:
395:
396: if (attr instanceof SmallAttributeSet)
397: eq = attr == this;
398: else
399: eq = getAttributeCount() == attr.getAttributeCount()
400: && this.containsAttributes(attr);
401: return eq;
402: }
403:
404: public String toString()
405: {
406: StringBuilder sb = new StringBuilder();
407: sb.append('{');
408: for (int i = 0; i < attrs.length; i += 2)
409: {
410: if (attrs[i + 1] instanceof AttributeSet)
411: {
412: sb.append(attrs[i]);
413: sb.append("=AttributeSet,");
414: }
415: else
416: {
417: sb.append(attrs[i]);
418: sb.append('=');
419: sb.append(attrs[i + 1]);
420: sb.append(',');
421: }
422: }
423: sb.append("}");
424: return sb.toString();
425: }
426: }
427:
428:
431: static
432: {
433:
434: try
435: {
436: for (Iterator i = StyleConstants.keys.iterator(); i.hasNext();)
437: registerStaticAttributeKey(i.next());
438: }
439: catch (Throwable t)
440: {
441: t.printStackTrace();
442: }
443: }
444:
445:
448: public static final String DEFAULT_STYLE = "default";
449:
450: static Hashtable sharedAttributeSets = new Hashtable();
451: static Hashtable sharedFonts = new Hashtable();
452:
453: static StyleContext defaultStyleContext;
454: static final int compressionThreshold = 9;
455:
456:
459: private static Hashtable writeAttributeKeys;
460: private static Hashtable readAttributeKeys;
461:
462: private NamedStyle styles;
463:
464:
467: private transient MutableAttributeSet search = new SimpleAttributeSet();
468:
469:
472: private transient Map attributeSetPool =
473: Collections.synchronizedMap(new WeakHashMap());
474:
475:
479: public StyleContext()
480: {
481: styles = new NamedStyle(null);
482: addStyle(DEFAULT_STYLE, null);
483: }
484:
485: protected SmallAttributeSet createSmallAttributeSet(AttributeSet a)
486: {
487: return new SmallAttributeSet(a);
488: }
489:
490: protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
491: {
492: return new SimpleAttributeSet(a);
493: }
494:
495: public void addChangeListener(ChangeListener listener)
496: {
497: styles.addChangeListener(listener);
498: }
499:
500: public void removeChangeListener(ChangeListener listener)
501: {
502: styles.removeChangeListener(listener);
503: }
504:
505: public ChangeListener[] getChangeListeners()
506: {
507: return styles.getChangeListeners();
508: }
509:
510: public Style addStyle(String name, Style parent)
511: {
512: Style newStyle = new NamedStyle(name, parent);
513: if (name != null)
514: styles.addAttribute(name, newStyle);
515: return newStyle;
516: }
517:
518: public void removeStyle(String name)
519: {
520: styles.removeAttribute(name);
521: }
522:
523:
533: public Style getStyle(String name)
534: {
535: return (Style) styles.getAttribute(name);
536: }
537:
538:
542: public Enumeration<?> getStyleNames()
543: {
544: return styles.getAttributeNames();
545: }
546:
547: private void readObject(ObjectInputStream in)
548: throws ClassNotFoundException, IOException
549: {
550: search = new SimpleAttributeSet();
551: attributeSetPool = Collections.synchronizedMap(new WeakHashMap());
552: in.defaultReadObject();
553: }
554:
555: private void writeObject(ObjectOutputStream out)
556: throws IOException
557: {
558: cleanupPool();
559: out.defaultWriteObject();
560: }
561:
562:
563:
564:
565:
566:
567:
568:
569:
570:
571:
572:
573:
574:
575:
576:
577: private static class SimpleFontSpec
578: {
579: String family;
580: int style;
581: int size;
582: public SimpleFontSpec(String family,
583: int style,
584: int size)
585: {
586: this.family = family;
587: this.style = style;
588: this.size = size;
589: }
590: public boolean equals(Object obj)
591: {
592: return (obj != null)
593: && (obj instanceof SimpleFontSpec)
594: && (((SimpleFontSpec)obj).family.equals(this.family))
595: && (((SimpleFontSpec)obj).style == this.style)
596: && (((SimpleFontSpec)obj).size == this.size);
597: }
598: public int hashCode()
599: {
600: return family.hashCode() + style + size;
601: }
602: }
603:
604: public Font getFont(AttributeSet attr)
605: {
606: String family = StyleConstants.getFontFamily(attr);
607: int style = Font.PLAIN;
608: if (StyleConstants.isBold(attr))
609: style += Font.BOLD;
610: if (StyleConstants.isItalic(attr))
611: style += Font.ITALIC;
612: int size = StyleConstants.getFontSize(attr);
613: return getFont(family, style, size);
614: }
615:
616: public Font getFont(String family, int style, int size)
617: {
618: SimpleFontSpec spec = new SimpleFontSpec(family, style, size);
619: if (sharedFonts.containsKey(spec))
620: return (Font) sharedFonts.get(spec);
621: else
622: {
623: Font tmp = new Font(family, style, size);
624: sharedFonts.put(spec, tmp);
625: return tmp;
626: }
627: }
628:
629: public FontMetrics getFontMetrics(Font f)
630: {
631: return Toolkit.getDefaultToolkit().getFontMetrics(f);
632: }
633:
634: public Color getForeground(AttributeSet a)
635: {
636: return StyleConstants.getForeground(a);
637: }
638:
639: public Color getBackground(AttributeSet a)
640: {
641: return StyleConstants.getBackground(a);
642: }
643:
644: protected int getCompressionThreshold()
645: {
646: return compressionThreshold;
647: }
648:
649: public static StyleContext getDefaultStyleContext()
650: {
651: if (defaultStyleContext == null)
652: defaultStyleContext = new StyleContext();
653: return defaultStyleContext;
654: }
655:
656: public synchronized AttributeSet addAttribute(AttributeSet old, Object name,
657: Object value)
658: {
659: AttributeSet ret;
660: if (old.getAttributeCount() + 1 < getCompressionThreshold())
661: {
662: search.removeAttributes(search);
663: search.addAttributes(old);
664: search.addAttribute(name, value);
665: reclaim(old);
666: ret = searchImmutableSet();
667: }
668: else
669: {
670: MutableAttributeSet mas = getMutableAttributeSet(old);
671: mas.addAttribute(name, value);
672: ret = mas;
673: }
674: return ret;
675: }
676:
677: public synchronized AttributeSet addAttributes(AttributeSet old,
678: AttributeSet attributes)
679: {
680: AttributeSet ret;
681: if (old.getAttributeCount() + attributes.getAttributeCount()
682: < getCompressionThreshold())
683: {
684: search.removeAttributes(search);
685: search.addAttributes(old);
686: search.addAttributes(attributes);
687: reclaim(old);
688: ret = searchImmutableSet();
689: }
690: else
691: {
692: MutableAttributeSet mas = getMutableAttributeSet(old);
693: mas.addAttributes(attributes);
694: ret = mas;
695: }
696: return ret;
697: }
698:
699: public AttributeSet getEmptySet()
700: {
701: return SimpleAttributeSet.EMPTY;
702: }
703:
704: public void reclaim(AttributeSet attributes)
705: {
706: cleanupPool();
707: }
708:
709: public synchronized AttributeSet removeAttribute(AttributeSet old,
710: Object name)
711: {
712: AttributeSet ret;
713: if (old.getAttributeCount() - 1 <= getCompressionThreshold())
714: {
715: search.removeAttributes(search);
716: search.addAttributes(old);
717: search.removeAttribute(name);
718: reclaim(old);
719: ret = searchImmutableSet();
720: }
721: else
722: {
723: MutableAttributeSet mas = getMutableAttributeSet(old);
724: mas.removeAttribute(name);
725: ret = mas;
726: }
727: return ret;
728: }
729:
730: public synchronized AttributeSet removeAttributes(AttributeSet old,
731: AttributeSet attributes)
732: {
733: AttributeSet ret;
734: if (old.getAttributeCount() <= getCompressionThreshold())
735: {
736: search.removeAttributes(search);
737: search.addAttributes(old);
738: search.removeAttributes(attributes);
739: reclaim(old);
740: ret = searchImmutableSet();
741: }
742: else
743: {
744: MutableAttributeSet mas = getMutableAttributeSet(old);
745: mas.removeAttributes(attributes);
746: ret = mas;
747: }
748: return ret;
749: }
750:
751: public synchronized AttributeSet removeAttributes(AttributeSet old,
752: Enumeration<?> names)
753: {
754: AttributeSet ret;
755: if (old.getAttributeCount() <= getCompressionThreshold())
756: {
757: search.removeAttributes(search);
758: search.addAttributes(old);
759: search.removeAttributes(names);
760: reclaim(old);
761: ret = searchImmutableSet();
762: }
763: else
764: {
765: MutableAttributeSet mas = getMutableAttributeSet(old);
766: mas.removeAttributes(names);
767: ret = mas;
768: }
769: return ret;
770: }
771:
772:
778: public static Object getStaticAttribute(Object key)
779: {
780: if (key == null)
781: return null;
782: return readAttributeKeys.get(key);
783: }
784:
785:
792: public static Object getStaticAttributeKey(Object key)
793: {
794: return key.getClass().getName() + "." + key.toString();
795: }
796:
797:
809: public static void readAttributeSet(ObjectInputStream in,
810: MutableAttributeSet a)
811: throws ClassNotFoundException, IOException
812: {
813: int count = in.readInt();
814: for (int i = 0; i < count; i++)
815: {
816: Object key = in.readObject();
817: Object val = in.readObject();
818: if (readAttributeKeys != null)
819: {
820: Object staticKey = readAttributeKeys.get(key);
821: if (staticKey != null)
822: key = staticKey;
823: Object staticVal = readAttributeKeys.get(val);
824: if (staticVal != null)
825: val = staticVal;
826: }
827: a.addAttribute(key, val);
828: }
829: }
830:
831:
840: public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a)
841: throws IOException
842: {
843: int count = a.getAttributeCount();
844: out.writeInt(count);
845: Enumeration e = a.getAttributeNames();
846: while (e.hasMoreElements())
847: {
848: Object key = e.nextElement();
849:
850: if (key instanceof Serializable)
851: out.writeObject(key);
852: else
853: {
854: Object io = writeAttributeKeys.get(key);
855: if (io == null)
856: throw new NotSerializableException(key.getClass().getName()
857: + ", key: " + key);
858: out.writeObject(io);
859: }
860:
861: Object val = a.getAttribute(key);
862: Object io = writeAttributeKeys.get(val);
863: if (val instanceof Serializable)
864: out.writeObject(io != null ? io : val);
865: else
866: {
867: if (io == null)
868: throw new NotSerializableException(val.getClass().getName());
869: out.writeObject(io);
870: }
871: }
872: }
873:
874:
883: public void readAttributes(ObjectInputStream in, MutableAttributeSet a)
884: throws ClassNotFoundException, IOException
885: {
886: readAttributeSet(in, a);
887: }
888:
889:
897: public void writeAttributes(ObjectOutputStream out, AttributeSet a)
898: throws IOException
899: {
900: writeAttributeSet(out, a);
901: }
902:
903:
913: public static void registerStaticAttributeKey(Object key)
914: {
915: String io = key.getClass().getName() + "." + key.toString();
916: if (writeAttributeKeys == null)
917: writeAttributeKeys = new Hashtable();
918: if (readAttributeKeys == null)
919: readAttributeKeys = new Hashtable();
920: writeAttributeKeys.put(key, io);
921: readAttributeKeys.put(io, key);
922: }
923:
924:
929: public String toString()
930: {
931: cleanupPool();
932: StringBuilder b = new StringBuilder();
933: Iterator i = attributeSetPool.keySet().iterator();
934: while (i.hasNext())
935: {
936: Object att = i.next();
937: b.append(att);
938: b.append('\n');
939: }
940: return b.toString();
941: }
942:
943:
949: private AttributeSet searchImmutableSet()
950: {
951: SmallAttributeSet k = createSmallAttributeSet(search);
952: WeakReference ref = (WeakReference) attributeSetPool.get(k);
953: SmallAttributeSet a;
954: if (ref == null || (a = (SmallAttributeSet) ref.get()) == null)
955: {
956: a = k;
957: attributeSetPool.put(a, new WeakReference(a));
958: }
959: return a;
960: }
961:
962:
966: private void cleanupPool()
967: {
968:
969: attributeSetPool.size();
970: }
971:
972:
981: private MutableAttributeSet getMutableAttributeSet(AttributeSet a)
982: {
983: MutableAttributeSet mas;
984: if (a instanceof MutableAttributeSet)
985: mas = (MutableAttributeSet) a;
986: else
987: mas = createLargeAttributeSet(a);
988: return mas;
989: }
990: }