001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexey A. Ivanov
019: * @version $Revision$
020: */package javax.swing.text;
021:
022: import java.awt.Color;
023: import java.awt.Font;
024: import java.awt.FontMetrics;
025: import java.awt.Toolkit;
026: import java.io.IOException;
027: import java.io.ObjectInputStream;
028: import java.io.ObjectOutputStream;
029: import java.io.Serializable;
030: import java.lang.ref.Reference;
031: import java.lang.ref.ReferenceQueue;
032: import java.lang.ref.WeakReference;
033: import java.util.Enumeration;
034: import java.util.EventListener;
035: import java.util.HashMap;
036: import java.util.Hashtable;
037: import java.util.Iterator;
038: import java.util.Map;
039: import java.util.NoSuchElementException;
040: import java.util.WeakHashMap;
041:
042: import javax.swing.event.ChangeEvent;
043: import javax.swing.event.ChangeListener;
044: import javax.swing.event.EventListenerList;
045:
046: import org.apache.harmony.x.swing.internal.nls.Messages;
047:
048: public class StyleContext implements Serializable,
049: AbstractDocument.AttributeContext {
050:
051: public class NamedStyle implements Style, Serializable {
052:
053: protected transient ChangeEvent changeEvent;
054: protected EventListenerList listenerList = new EventListenerList();
055:
056: /**
057: * This is an instance of AttributeSet. It contains all attributes
058: * including style name and resolve parent. StyleContext is used
059: * for serialization of it. Named style must use StyleContext's methods
060: * for any mutation of it.
061: */
062: private transient AttributeSet attrs = StyleContext.this
063: .getEmptySet();
064:
065: public NamedStyle() {
066: this (null, null);
067: }
068:
069: public NamedStyle(final String name, final Style parent) {
070: setName(name);
071: setResolveParent(parent);
072: }
073:
074: public NamedStyle(final Style parent) {
075: this (null, parent);
076: }
077:
078: public void addAttribute(final Object attrName,
079: final Object value) {
080: attrs = StyleContext.this .addAttribute(attrs, attrName,
081: value);
082: fireStateChanged();
083: }
084:
085: public void addAttributes(final AttributeSet as) {
086: attrs = StyleContext.this .addAttributes(attrs, as);
087: fireStateChanged();
088: }
089:
090: public void addChangeListener(final ChangeListener l) {
091: listenerList.add(ChangeListener.class, l);
092: }
093:
094: public boolean containsAttribute(final Object attrName,
095: final Object value) {
096: return attrs.containsAttribute(attrName, value);
097: }
098:
099: public boolean containsAttributes(final AttributeSet as) {
100: return attrs.containsAttributes(as);
101: }
102:
103: public AttributeSet copyAttributes() {
104: NamedStyle copy = new NamedStyle();
105: copy.attrs = attrs.copyAttributes();
106: return copy;
107: }
108:
109: public Object getAttribute(final Object attrName) {
110: return attrs.getAttribute(attrName);
111: }
112:
113: public int getAttributeCount() {
114: return attrs.getAttributeCount();
115: }
116:
117: public Enumeration<?> getAttributeNames() {
118: return attrs.getAttributeNames();
119: }
120:
121: public ChangeListener[] getChangeListeners() {
122: return (ChangeListener[]) listenerList
123: .getListeners(ChangeListener.class);
124: }
125:
126: public <T extends EventListener> T[] getListeners(
127: final Class<T> listenerType) {
128: return listenerList.getListeners(listenerType);
129: }
130:
131: public String getName() {
132: if (attrs.isDefined(AttributeSet.NameAttribute)) {
133: Object styleName = attrs
134: .getAttribute(AttributeSet.NameAttribute);
135: return styleName != null ? styleName.toString() : null;
136: }
137:
138: return null;
139: }
140:
141: public AttributeSet getResolveParent() {
142: return attrs.getResolveParent();
143: }
144:
145: public boolean isDefined(final Object attrName) {
146: return attrs.isDefined(attrName);
147: }
148:
149: public boolean isEqual(final AttributeSet attr) {
150: return attrs.isEqual(attr);
151: }
152:
153: public void removeAttribute(final Object attrName) {
154: attrs = StyleContext.this .removeAttribute(attrs, attrName);
155: fireStateChanged();
156: }
157:
158: public void removeAttributes(final AttributeSet as) {
159: attrs = StyleContext.this .removeAttributes(this .attrs, as);
160: fireStateChanged();
161: }
162:
163: public void removeAttributes(final Enumeration<?> names) {
164: attrs = StyleContext.this .removeAttributes(attrs, names);
165: fireStateChanged();
166: }
167:
168: public void removeChangeListener(final ChangeListener l) {
169: listenerList.remove(ChangeListener.class, l);
170: }
171:
172: public void setName(final String name) {
173: if (name != null) {
174: addAttribute(AttributeSet.NameAttribute, name);
175: }
176: }
177:
178: public void setResolveParent(final AttributeSet parent) {
179: if (parent == null) {
180: removeAttribute(AttributeSet.ResolveAttribute);
181: } else {
182: addAttribute(AttributeSet.ResolveAttribute, parent);
183: }
184: }
185:
186: public String toString() {
187: String str = new String();
188: str += "NamedStyle:" + getName() + " ";
189: str += attrs.toString();
190: return str;
191: }
192:
193: protected void fireStateChanged() {
194: ChangeListener[] changeListeners = getChangeListeners();
195:
196: if (changeEvent == null && changeListeners.length > 0) {
197: changeEvent = new ChangeEvent(this );
198: }
199: for (int i = 0; i < changeListeners.length; i++) {
200: changeListeners[i].stateChanged(changeEvent);
201: }
202: }
203:
204: private void readObject(final ObjectInputStream in)
205: throws IOException, ClassNotFoundException {
206:
207: in.defaultReadObject();
208: attrs = StyleContext.this .getEmptySet();
209: StyleContext.readAttributeSet(in, this );
210: }
211:
212: private void writeObject(final ObjectOutputStream out)
213: throws IOException {
214:
215: out.defaultWriteObject();
216: StyleContext.writeAttributeSet(out, this );
217: }
218:
219: }
220:
221: public class SmallAttributeSet implements AttributeSet {
222:
223: private final Object[] attributes;
224:
225: public SmallAttributeSet(final AttributeSet attrs) {
226: attributes = new Object[attrs.getAttributeCount() * 2];
227: int i = 0;
228: for (Enumeration e = attrs.getAttributeNames(); e
229: .hasMoreElements();) {
230:
231: Object key = e.nextElement();
232: attributes[i++] = key;
233: attributes[i++] = attrs.getAttribute(key);
234: }
235: }
236:
237: public SmallAttributeSet(final Object[] attributes) {
238: this .attributes = new Object[attributes.length];
239: System.arraycopy(attributes, 0, this .attributes, 0,
240: attributes.length);
241: }
242:
243: public Object clone() {
244: return this ;
245: }
246:
247: public boolean containsAttribute(final Object key,
248: final Object value) {
249: Object attrValue = getAttribute(key);
250: return attrValue != null && value.equals(attrValue);
251: }
252:
253: public boolean containsAttributes(final AttributeSet attrs) {
254: for (Enumeration e = attrs.getAttributeNames(); e
255: .hasMoreElements();) {
256:
257: Object key = e.nextElement();
258: if (!containsAttribute(key, attrs.getAttribute(key))) {
259: return false;
260: }
261: }
262: return true;
263: }
264:
265: public AttributeSet copyAttributes() {
266: return this ;
267: }
268:
269: public boolean equals(final Object obj) {
270: if (obj instanceof AttributeSet) {
271: return isEqual((AttributeSet) obj);
272: }
273: return false;
274: }
275:
276: public Object getAttribute(final Object key) {
277: Object value = null;
278: for (int i = 0; i < attributes.length && value == null; i += 2) {
279: if (attributes[i].equals(key)) {
280: value = attributes[i + 1];
281: }
282: }
283:
284: if (value == null
285: && !key.equals(AttributeSet.ResolveAttribute)) {
286: AttributeSet parent = getResolveParent();
287: if (parent != null) {
288: value = parent.getAttribute(key);
289: }
290: }
291:
292: return value;
293: }
294:
295: public int getAttributeCount() {
296: return attributes.length / 2;
297: }
298:
299: public Enumeration<?> getAttributeNames() {
300: return new Enumeration() {
301:
302: private int count = 0;
303:
304: public boolean hasMoreElements() {
305: return count < attributes.length;
306: }
307:
308: public Object nextElement() {
309: if (count >= attributes.length) {
310: new NoSuchElementException(Messages
311: .getString("swing.9A")); //$NON-NLS-1$
312: }
313:
314: Object next = attributes[count++];
315: count++;
316: return next;
317: }
318: };
319: }
320:
321: public AttributeSet getResolveParent() {
322: return (AttributeSet) getAttribute(AttributeSet.ResolveAttribute);
323: }
324:
325: public int hashCode() {
326: // Xors name with value and sums all result together.
327: // Hash codes of equal attribute sets must be equal.
328: // So we must return hash codes that will be equal to
329: // SimpleAttributeSet's hash codes. It means that we must calculate
330: // hash code as it's calculated for hashtable.
331: int hc = 0;
332: for (int i = 0; i < attributes.length; i += 2) {
333: hc += attributes[i].hashCode()
334: ^ attributes[i + 1].hashCode();
335: }
336: return hc;
337: }
338:
339: public boolean isDefined(final Object key) {
340: for (int i = 0; i < attributes.length; i += 2) {
341: if (attributes[i].equals(key)) {
342: return true;
343: }
344: }
345: return false;
346: }
347:
348: public boolean isEqual(final AttributeSet attr) {
349: if (attr.getAttributeCount() != getAttributeCount()) {
350: return false;
351: }
352: return containsAttributes(attr);
353: }
354:
355: public String toString() {
356: String str = new String("{");
357: for (int i = 0; i < attributes.length; i += 2) {
358: str += attributes[i].toString() + "=";
359: Object value = attributes[i + 1];
360: if (value instanceof AttributeSet) {
361: str += "AttributeSet";
362: } else {
363: str += value.toString();
364: }
365: str += ",";
366: }
367: return str += "}";
368: }
369:
370: }
371:
372: /**
373: * Class that stores not only a weak reference to the object,
374: * but the key for the cache (in the HashMap), so that
375: * the referent could be removed from the cache.
376: */
377: private class CacheReference extends WeakReference {
378: /**
379: * The key for cache.
380: */
381: private final Object key;
382:
383: /**
384: * Creates a new weak reference with the key and value pair specified,
385: * registering this reference in the queue specified.
386: *
387: * @param key the key in cache
388: * @param value value in cache that corresponds to the key
389: * @param queue the queue where the reference should be registered
390: */
391: public CacheReference(final Object key, final Object value,
392: final ReferenceQueue queue) {
393: super (value, queue);
394: this .key = key;
395: }
396:
397: /**
398: * Returns the key that corresponds to the referent (value)
399: *
400: * @return the key in cache
401: */
402: public Object getKey() {
403: return key;
404: }
405: }
406:
407: public static final String DEFAULT_STYLE = "default";
408:
409: /**
410: * Maximum number of attributes that stored as an array
411: * (in SmallAttributeSet).
412: */
413: private static final int COMPRESSION_THRESHOLD = 9;
414: /**
415: * Default style context which is returned with getDefaultStyleContext.
416: */
417: private static final StyleContext defaultContext = new StyleContext();
418: /**
419: * Static keys registered with registerStaticKey.
420: */
421: private static Hashtable staticKeys;
422:
423: // Static initializer
424: static {
425: // Create static key store
426: staticKeys = new Hashtable();
427:
428: // Key to be registered as static
429: Object[] keys = { StyleConstants.Alignment,
430: StyleConstants.Background, StyleConstants.BidiLevel,
431: StyleConstants.Bold, StyleConstants.ComponentAttribute,
432: StyleConstants.ComposedTextAttribute,
433: StyleConstants.FirstLineIndent,
434: StyleConstants.FontFamily, StyleConstants.FontSize,
435: StyleConstants.Foreground,
436: StyleConstants.IconAttribute, StyleConstants.Italic,
437: StyleConstants.LeftIndent, StyleConstants.LineSpacing,
438: StyleConstants.ModelAttribute,
439: StyleConstants.NameAttribute,
440: StyleConstants.Orientation,
441: StyleConstants.ResolveAttribute,
442: StyleConstants.RightIndent, StyleConstants.SpaceAbove,
443: StyleConstants.SpaceBelow,
444: StyleConstants.StrikeThrough, StyleConstants.Subscript,
445: StyleConstants.Superscript, StyleConstants.Underline,
446: StyleConstants.TabSet };
447:
448: for (int i = 0; i < keys.length; i++) {
449: StyleContext.registerStaticAttributeKey(keys[i]);
450: }
451: }
452: /**
453: * Used temporary to construct new attribute sets in all methods
454: * that modify sets.
455: */
456: private transient SimpleAttributeSet attrSet = new SimpleAttributeSet();
457:
458: private transient Map cache;
459: private transient Map fontCache;
460: private transient ReferenceQueue queue;
461:
462: private transient NamedStyle styles;
463:
464: public StyleContext() {
465: initTransientFields();
466: addStyle(DEFAULT_STYLE, null);
467: }
468:
469: public synchronized AttributeSet addAttribute(
470: final AttributeSet old, final Object name,
471: final Object value) {
472: attrSet.addAttributes(old);
473: attrSet.addAttribute(name, value);
474:
475: AttributeSet result;
476: if (attrSet.getAttributeCount() <= getCompressionThreshold()) {
477: result = cacheAttributeSet(attrSet);
478: } else {
479: result = createLargeAttributeSet(attrSet);
480: }
481:
482: attrSet.removeAll();
483:
484: return result;
485: }
486:
487: public synchronized AttributeSet addAttributes(
488: final AttributeSet old, final AttributeSet add) {
489: attrSet.addAttributes(old);
490: attrSet.addAttributes(add);
491:
492: AttributeSet result;
493: if (attrSet.getAttributeCount() <= getCompressionThreshold()) {
494: result = cacheAttributeSet(attrSet);
495: } else {
496: result = createLargeAttributeSet(attrSet);
497: }
498:
499: attrSet.removeAll();
500:
501: return result;
502: }
503:
504: public void addChangeListener(final ChangeListener l) {
505: styles.addChangeListener(l);
506: }
507:
508: public Style addStyle(final String name, final Style parent) {
509: NamedStyle style = new NamedStyle(name, parent);
510: if (name != null) {
511: styles.addAttribute(name, style);
512: }
513: return style;
514: }
515:
516: public Color getBackground(final AttributeSet as) {
517: return StyleConstants.getBackground(as);
518: }
519:
520: public ChangeListener[] getChangeListeners() {
521: return styles.getChangeListeners();
522: }
523:
524: public AttributeSet getEmptySet() {
525: return EmptyAttributeSet.EMPTY;
526: }
527:
528: public Font getFont(final AttributeSet as) {
529: final boolean bold = StyleConstants.isBold(as);
530: final boolean italic = StyleConstants.isItalic(as);
531: int style = Font.PLAIN;
532: if (bold && italic) {
533: style = Font.BOLD | Font.ITALIC;
534: } else if (bold) {
535: style = Font.BOLD;
536: } else if (italic) {
537: style = Font.ITALIC;
538: }
539:
540: return getFont(StyleConstants.getFontFamily(as), style,
541: StyleConstants.getFontSize(as));
542: }
543:
544: /**
545: * Checks if the specified font is cached, and returns the cached instance,
546: * or creates a new font and caches it.
547: * <p>
548: * We use a string with font parameters as key in the font cache.
549: */
550: public Font getFont(final String family, final int style,
551: final int size) {
552: collectGarbageInCache();
553:
554: String key = family + "-" + style + "-" + size;
555:
556: Reference cr = (Reference) fontCache.get(key);
557: Font font = null;
558: if (cr != null) {
559: font = (Font) cr.get();
560: }
561:
562: if (font == null) {
563: font = new Font(family, style, size);
564: fontCache.put(key, new CacheReference(key, font, queue));
565: }
566:
567: return font;
568: }
569:
570: public FontMetrics getFontMetrics(final Font font) {
571: return Toolkit.getDefaultToolkit().getFontMetrics(font);
572: }
573:
574: public Color getForeground(final AttributeSet as) {
575: return StyleConstants.getForeground(as);
576: }
577:
578: public Style getStyle(final String name) {
579: return (Style) styles.getAttribute(name);
580: }
581:
582: public Enumeration<?> getStyleNames() {
583: return styles.getAttributeNames();
584: }
585:
586: public void readAttributes(final ObjectInputStream ois,
587: final MutableAttributeSet mas)
588: throws ClassNotFoundException, IOException {
589:
590: StyleContext.readAttributeSet(ois, mas);
591: }
592:
593: /**
594: * This methods just does nothing because we use
595: * <code>WeakReference</code>s to remove unused attribute sets from cache.
596: */
597: public void reclaim(final AttributeSet a) {
598: }
599:
600: public synchronized AttributeSet removeAttribute(
601: final AttributeSet old, final Object name) {
602: attrSet.addAttributes(old);
603: attrSet.removeAttribute(name);
604:
605: AttributeSet result;
606: final int count = attrSet.getAttributeCount();
607: if (count == 0) {
608: result = EmptyAttributeSet.EMPTY;
609: } else if (count <= getCompressionThreshold()) {
610: result = cacheAttributeSet(attrSet);
611: } else {
612: result = createLargeAttributeSet(attrSet);
613: }
614:
615: attrSet.removeAll();
616:
617: return result;
618: }
619:
620: public synchronized AttributeSet removeAttributes(
621: final AttributeSet old, final AttributeSet rem) {
622: attrSet.addAttributes(old);
623: attrSet.removeAttributes(rem);
624:
625: AttributeSet result;
626: final int count = attrSet.getAttributeCount();
627: if (count == 0) {
628: result = EmptyAttributeSet.EMPTY;
629: } else if (count <= getCompressionThreshold()) {
630: result = cacheAttributeSet(attrSet);
631: } else {
632: result = createLargeAttributeSet(attrSet);
633: }
634:
635: attrSet.removeAll();
636:
637: return result;
638: }
639:
640: public synchronized AttributeSet removeAttributes(
641: final AttributeSet old, final Enumeration<?> names) {
642: attrSet.addAttributes(old);
643: attrSet.removeAttributes(names);
644:
645: AttributeSet result;
646: final int count = attrSet.getAttributeCount();
647: if (count == 0) {
648: result = EmptyAttributeSet.EMPTY;
649: } else if (count <= getCompressionThreshold()) {
650: result = cacheAttributeSet(attrSet);
651: } else {
652: result = createLargeAttributeSet(attrSet);
653: }
654:
655: attrSet.removeAll();
656:
657: return result;
658: }
659:
660: public void removeChangeListener(final ChangeListener l) {
661: styles.removeChangeListener(l);
662: }
663:
664: public void removeStyle(final String name) {
665: styles.removeAttribute(name);
666: }
667:
668: /**
669: * Returns a string representing all cached attribute sets.
670: */
671: public String toString() {
672: String str = new String();
673: Iterator keys;
674: Object key;
675:
676: keys = cache.keySet().iterator();
677: while (keys.hasNext()) {
678: key = keys.next();
679:
680: // Key is instance of AttributeSet (ALWAYS TRUE), print it
681: str += key.toString() + "\n";
682: }
683:
684: return str;
685: }
686:
687: public void writeAttributes(final ObjectOutputStream oos,
688: final AttributeSet as) throws IOException {
689:
690: StyleContext.writeAttributeSet(oos, as);
691: }
692:
693: public static final StyleContext getDefaultStyleContext() {
694: return StyleContext.defaultContext;
695: }
696:
697: /**
698: * Returns the object that registered this key by its corresponding
699: * string representation.
700: */
701: public static Object getStaticAttribute(final Object key) {
702: return staticKeys.get(key);
703: }
704:
705: /**
706: * Returns the string representing this key.
707: * <p>
708: * It is composed of class name, dot and string presentation of the
709: * <code>key</code> (returned by <code>toString</code>).
710: */
711: public static Object getStaticAttributeKey(final Object key) {
712: return key.getClass().getName() + "." + key.toString();
713: }
714:
715: public static void readAttributeSet(final ObjectInputStream ois,
716: final MutableAttributeSet mas)
717: throws ClassNotFoundException, IOException {
718:
719: Object key;
720: Object value;
721: Object staticKey;
722: int count;
723:
724: key = ois.readObject();
725: if (key instanceof Integer) {
726: count = ((Integer) key).intValue();
727: } else {
728: throw new IOException(Messages.getString("swing.9B")); //$NON-NLS-1$
729: }
730:
731: while (count-- > 0) {
732: key = ois.readObject();
733:
734: staticKey = key instanceof String ? StyleContext
735: .getStaticAttribute(key) : null;
736:
737: if (staticKey != null) {
738: key = staticKey;
739: }
740:
741: value = ois.readObject();
742:
743: mas.addAttribute(key, value);
744: }
745: }
746:
747: /**
748: * Stores the <code>key</code> in the <code>staticKeys</code> hash table
749: * with table key returned by <code>getStaticAttributeKey</code>
750: *
751: * @see StyleContext#getStaticAttributeKey(Object)
752: */
753: public static void registerStaticAttributeKey(final Object key) {
754: staticKeys.put(StyleContext.getStaticAttributeKey(key), key);
755: }
756:
757: public static void writeAttributeSet(final ObjectOutputStream oos,
758: final AttributeSet as) throws IOException {
759:
760: Enumeration keys = as.getAttributeNames();
761: Object key;
762: Object value;
763: Object staticKey;
764:
765: oos.writeObject(new Integer(as.getAttributeCount()));
766:
767: while (keys.hasMoreElements()) {
768: key = keys.nextElement();
769:
770: staticKey = StyleContext.getStaticAttributeKey(key);
771: if (staticKeys.containsKey(staticKey)) {
772: oos.writeObject(staticKey);
773: } else {
774: oos.writeObject(key);
775: }
776:
777: value = as.getAttribute(key);
778: oos.writeObject(value);
779: }
780: }
781:
782: protected MutableAttributeSet createLargeAttributeSet(
783: final AttributeSet a) {
784:
785: return (MutableAttributeSet) a.copyAttributes();
786: }
787:
788: protected SmallAttributeSet createSmallAttributeSet(
789: final AttributeSet aSet) {
790:
791: return new SmallAttributeSet(aSet);
792: }
793:
794: protected int getCompressionThreshold() {
795: return COMPRESSION_THRESHOLD;
796: }
797:
798: /**
799: * Checks if the requested attribute set has already been cached, and
800: * returns the cached instance. If not, creates a new SmallAttributeSet
801: * instance using <code>createSmallAttributeSet</code> method and adds
802: * it into the cache.
803: * <p>
804: * We use the attribute set itself as a key in the cache. WeakHashMap
805: * automatically removes unused (unreferenced) objects from the cache.
806: * <p>
807: * Also removes garbage from the font cache.
808: *
809: * @param aSet an attribute set to cache
810: * @return cached attribute set, or newly created one and put in the cache
811: */
812: private SmallAttributeSet cacheAttributeSet(final AttributeSet aSet) {
813:
814: collectGarbageInCache();
815:
816: Reference r = (Reference) cache.get(aSet);
817: SmallAttributeSet as = null;
818: if (r != null) {
819: as = (SmallAttributeSet) r.get();
820: }
821:
822: if (as == null) {
823: as = createSmallAttributeSet(aSet);
824: cache.put(as, new WeakReference(as));
825: }
826:
827: return as;
828: }
829:
830: /**
831: * Removes objects stored in the font cache which were garbage collected.
832: * <code>AttributeSet</code> objects are removed automatically by
833: * <code>WeakHashMap</code>.
834: */
835: private void collectGarbageInCache() {
836: CacheReference r;
837: while ((r = (CacheReference) queue.poll()) != null) {
838: fontCache.remove(r.getKey());
839: }
840: }
841:
842: private void initTransientFields() {
843: cache = new WeakHashMap();
844: fontCache = new HashMap();
845: queue = new ReferenceQueue();
846: attrSet = new SimpleAttributeSet();
847: styles = new NamedStyle();
848: }
849:
850: /**
851: * Deserializes the object. The state of the StyleContext is fully restored,
852: * even the cache of attributes.
853: *
854: * @param ois
855: * @throws IOException
856: * @throws ClassNotFoundException
857: */
858: private void readObject(final ObjectInputStream ois)
859: throws IOException, ClassNotFoundException {
860:
861: ois.defaultReadObject();
862: initTransientFields();
863: StyleContext.readAttributeSet(ois, styles);
864: }
865:
866: /**
867: * Serializes the state of StyleContext. All the styles stored in the
868: * context is also serialized (with their attributes).
869: *
870: * @param oos
871: * @throws IOException
872: */
873: private void writeObject(final ObjectOutputStream oos)
874: throws IOException {
875: oos.defaultWriteObject();
876: StyleContext.writeAttributeSet(oos, styles);
877: }
878:
879: }
|