summaryrefslogtreecommitdiff
path: root/javax/swing/text/StyleContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'javax/swing/text/StyleContext.java')
-rw-r--r--javax/swing/text/StyleContext.java572
1 files changed, 357 insertions, 215 deletions
diff --git a/javax/swing/text/StyleContext.java b/javax/swing/text/StyleContext.java
index 1e869485c..b01d1060f 100644
--- a/javax/swing/text/StyleContext.java
+++ b/javax/swing/text/StyleContext.java
@@ -43,19 +43,23 @@ import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Toolkit;
import java.io.IOException;
+import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.lang.ref.WeakReference;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.WeakHashMap;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
public class StyleContext
- implements Serializable, AbstractDocument.AttributeContext
+ implements Serializable, AbstractDocument.AttributeContext
{
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = 8042858831190784241L;
@@ -66,11 +70,10 @@ public class StyleContext
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = -6690628971806226374L;
- protected ChangeEvent changeEvent;
+ protected transient ChangeEvent changeEvent;
protected EventListenerList listenerList;
- AttributeSet attributes;
- String name;
+ private transient AttributeSet attributes;
public NamedStyle()
{
@@ -84,22 +87,26 @@ public class StyleContext
public NamedStyle(String name, Style parent)
{
- this.name = name;
- this.attributes = getEmptySet();
- this.changeEvent = new ChangeEvent(this);
- this.listenerList = new EventListenerList();
- setResolveParent(parent);
+ attributes = getEmptySet();
+ listenerList = new EventListenerList();
+ if (name != null)
+ setName(name);
+ if (parent != null)
+ setResolveParent(parent);
}
public String getName()
{
+ String name = null;
+ if (isDefined(StyleConstants.NameAttribute))
+ name = getAttribute(StyleConstants.NameAttribute).toString();
return name;
}
public void setName(String n)
{
- name = n;
- fireStateChanged();
+ if (n != null)
+ addAttribute(StyleConstants.NameAttribute, n);
}
public void addChangeListener(ChangeListener l)
@@ -127,6 +134,9 @@ public class StyleContext
ChangeListener[] listeners = getChangeListeners();
for (int i = 0; i < listeners.length; ++i)
{
+ // Lazily create event.
+ if (changeEvent == null)
+ changeEvent = new ChangeEvent(this);
listeners[i].stateChanged(changeEvent);
}
}
@@ -155,7 +165,10 @@ public class StyleContext
public AttributeSet copyAttributes()
{
- return attributes.copyAttributes();
+ // The RI returns a NamedStyle as copy, so do we.
+ NamedStyle copy = new NamedStyle();
+ copy.attributes = attributes.copyAttributes();
+ return copy;
}
public Object getAttribute(Object attrName)
@@ -210,112 +223,125 @@ public class StyleContext
public void setResolveParent(AttributeSet parent)
{
if (parent != null)
- {
- attributes = StyleContext.this.addAttribute
- (attributes, ResolveAttribute, parent);
- }
- fireStateChanged();
+ addAttribute(StyleConstants.ResolveAttribute, parent);
+ else
+ removeAttribute(StyleConstants.ResolveAttribute);
}
public String toString()
{
- return ("[NamedStyle: name=" + name + ", attrs=" + attributes.toString() + "]");
- }
+ return "NamedStyle:" + getName() + " " + attributes;
+ }
+
+ private void writeObject(ObjectOutputStream s)
+ throws IOException
+ {
+ s.defaultWriteObject();
+ writeAttributeSet(s, attributes);
+ }
+
+ private void readObject(ObjectInputStream s)
+ throws ClassNotFoundException, IOException
+ {
+ s.defaultReadObject();
+ attributes = SimpleAttributeSet.EMPTY;
+ readAttributeSet(s, this);
+ }
}
public class SmallAttributeSet
implements AttributeSet
{
final Object [] attrs;
+ private AttributeSet resolveParent;
public SmallAttributeSet(AttributeSet a)
{
- if (a == null)
- attrs = new Object[0];
- else
+ int n = a.getAttributeCount();
+ int i = 0;
+ attrs = new Object[n * 2];
+ Enumeration e = a.getAttributeNames();
+ while (e.hasMoreElements())
{
- int n = a.getAttributeCount();
- int i = 0;
- attrs = new Object[n * 2];
- Enumeration e = a.getAttributeNames();
- while (e.hasMoreElements())
- {
- Object name = e.nextElement();
- attrs[i++] = name;
- attrs[i++] = a.getAttribute(name);
- }
+ Object name = e.nextElement();
+ Object value = a.getAttribute(name);
+ if (name == ResolveAttribute)
+ resolveParent = (AttributeSet) value;
+ attrs[i++] = name;
+ attrs[i++] = value;
}
}
public SmallAttributeSet(Object [] a)
{
- if (a == null)
- attrs = new Object[0];
- else
+ attrs = a;
+ for (int i = 0; i < attrs.length; i += 2)
{
- attrs = new Object[a.length];
- System.arraycopy(a, 0, attrs, 0, a.length);
+ if (attrs[i] == ResolveAttribute)
+ resolveParent = (AttributeSet) attrs[i + 1];
}
}
public Object clone()
{
- return new SmallAttributeSet(this.attrs);
+ return this;
}
public boolean containsAttribute(Object name, Object value)
{
- for (int i = 0; i < attrs.length; i += 2)
- {
- if (attrs[i].equals(name) &&
- attrs[i+1].equals(value))
- return true;
- }
- return false;
+ return value.equals(getAttribute(name));
}
public boolean containsAttributes(AttributeSet a)
{
+ boolean res = true;
Enumeration e = a.getAttributeNames();
- while (e.hasMoreElements())
+ while (e.hasMoreElements() && res)
{
Object name = e.nextElement();
- Object val = a.getAttribute(name);
- if (!containsAttribute(name, val))
- return false;
+ res = a.getAttribute(name).equals(getAttribute(name));
}
- return true;
+ return res;
}
public AttributeSet copyAttributes()
{
- return (AttributeSet) clone();
+ return this;
}
public boolean equals(Object obj)
{
- return
- (obj instanceof AttributeSet)
- && this.isEqual((AttributeSet)obj);
+ boolean eq = false;
+ if (obj instanceof AttributeSet)
+ {
+ AttributeSet atts = (AttributeSet) obj;
+ eq = getAttributeCount() == atts.getAttributeCount()
+ && containsAttributes(atts);
+ }
+ return eq;
}
public Object getAttribute(Object key)
{
- for (int i = 0; i < attrs.length; i += 2)
+ Object att = null;
+ if (key == StyleConstants.ResolveAttribute)
+ att = resolveParent;
+
+ for (int i = 0; i < attrs.length && att == null; i += 2)
{
if (attrs[i].equals(key))
- return attrs[i+1];
+ att = attrs[i + 1];
}
-
+
// Check the resolve parent, unless we're looking for the
- // ResolveAttribute, which would cause an infinite loop
- if (!(key.equals(ResolveAttribute)))
+ // ResolveAttribute, which must not be looked up
+ if (att == null)
{
- Object p = getResolveParent();
- if (p != null && p instanceof AttributeSet)
- return (((AttributeSet)p).getAttribute(key));
+ AttributeSet parent = getResolveParent();
+ if (parent != null)
+ att = parent.getAttribute(key);
}
- return null;
+ return att;
}
public int getAttributeCount()
@@ -342,7 +368,7 @@ public class StyleContext
public AttributeSet getResolveParent()
{
- return (AttributeSet) getAttribute(ResolveAttribute);
+ return resolveParent;
}
public int hashCode()
@@ -362,68 +388,95 @@ public class StyleContext
public boolean isEqual(AttributeSet attr)
{
- return getAttributeCount() == attr.getAttributeCount()
+ boolean eq;
+ // If the other one is also a SmallAttributeSet, it is only considered
+ // equal if it's the same instance.
+ if (attr instanceof SmallAttributeSet)
+ eq = attr == this;
+ else
+ eq = getAttributeCount() == attr.getAttributeCount()
&& this.containsAttributes(attr);
+ return eq;
}
public String toString()
{
- StringBuffer sb = new StringBuffer();
- sb.append("[StyleContext.SmallattributeSet:");
- for (int i = 0; i < attrs.length - 1; ++i)
+ StringBuilder sb = new StringBuilder();
+ sb.append('{');
+ for (int i = 0; i < attrs.length; i += 2)
{
- sb.append(" (");
- sb.append(attrs[i].toString());
- sb.append("=");
- sb.append(attrs[i+1].toString());
- sb.append(")");
+ if (attrs[i + 1] instanceof AttributeSet)
+ {
+ sb.append(attrs[i]);
+ sb.append("=AttributeSet,");
+ }
+ else
+ {
+ sb.append(attrs[i]);
+ sb.append('=');
+ sb.append(attrs[i + 1]);
+ sb.append(',');
+ }
}
- sb.append("]");
+ sb.append("}");
return sb.toString();
}
}
- // FIXME: official javadocs suggest that these might be more usefully
- // implemented using a WeakHashMap, but not sure if that works most
- // places or whether it really matters anyways.
- //
- // FIXME: also not sure if these tables ought to be static (singletons),
- // shared across all StyleContexts. I think so, but it's not clear in
- // docs. revert to non-shared if you think it matters.
-
/**
- * The name of the default style.
+ * Register StyleConstant keys as static attribute keys for serialization.
*/
- public static final String DEFAULT_STYLE = "default";
-
+ static
+ {
+ // Don't let problems while doing this prevent class loading.
+ try
+ {
+ for (Iterator i = StyleConstants.keys.iterator(); i.hasNext();)
+ registerStaticAttributeKey(i.next());
+ }
+ catch (Throwable t)
+ {
+ t.printStackTrace();
+ }
+ }
+
/**
- * The default style for this style context.
+ * The name of the default style.
*/
- NamedStyle defaultStyle = new NamedStyle(DEFAULT_STYLE, null);
+ public static final String DEFAULT_STYLE = "default";
static Hashtable sharedAttributeSets = new Hashtable();
static Hashtable sharedFonts = new Hashtable();
- static StyleContext defaultStyleContext = new StyleContext();
+ static StyleContext defaultStyleContext;
static final int compressionThreshold = 9;
/**
* These attribute keys are handled specially in serialization.
*/
- private static Hashtable staticAttributeKeys = new Hashtable();
+ private static Hashtable writeAttributeKeys;
+ private static Hashtable readAttributeKeys;
+
+ private NamedStyle styles;
+
+ /**
+ * Used for searching attributes in the pool.
+ */
+ private transient MutableAttributeSet search = new SimpleAttributeSet();
+
+ /**
+ * A pool of immutable AttributeSets.
+ */
+ private transient WeakHashMap attributeSetPool = new WeakHashMap();
- EventListenerList listenerList;
- Hashtable styleTable;
-
/**
* Creates a new instance of the style context. Add the default style
* to the style table.
*/
public StyleContext()
{
- listenerList = new EventListenerList();
- styleTable = new Hashtable();
- styleTable.put(DEFAULT_STYLE, defaultStyle);
+ styles = new NamedStyle(null);
+ addStyle(DEFAULT_STYLE, null);
}
protected SmallAttributeSet createSmallAttributeSet(AttributeSet a)
@@ -438,30 +491,30 @@ public class StyleContext
public void addChangeListener(ChangeListener listener)
{
- listenerList.add(ChangeListener.class, listener);
+ styles.addChangeListener(listener);
}
public void removeChangeListener(ChangeListener listener)
{
- listenerList.remove(ChangeListener.class, listener);
+ styles.removeChangeListener(listener);
}
public ChangeListener[] getChangeListeners()
{
- return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
+ return styles.getChangeListeners();
}
public Style addStyle(String name, Style parent)
{
Style newStyle = new NamedStyle(name, parent);
if (name != null)
- styleTable.put(name, newStyle);
+ styles.addAttribute(name, newStyle);
return newStyle;
}
public void removeStyle(String name)
{
- styleTable.remove(name);
+ styles.removeAttribute(name);
}
/**
@@ -476,7 +529,7 @@ public class StyleContext
*/
public Style getStyle(String name)
{
- return (Style) styleTable.get(name);
+ return (Style) styles.getAttribute(name);
}
/**
@@ -485,7 +538,22 @@ public class StyleContext
*/
public Enumeration<?> getStyleNames()
{
- return styleTable.keys();
+ return styles.getAttributeNames();
+ }
+
+ private void readObject(ObjectInputStream in)
+ throws ClassNotFoundException, IOException
+ {
+ search = new SimpleAttributeSet();
+ attributeSetPool = new WeakHashMap();
+ in.defaultReadObject();
+ }
+
+ private void writeObject(ObjectOutputStream out)
+ throws IOException
+ {
+ cleanupPool();
+ out.defaultWriteObject();
}
//
@@ -577,132 +645,120 @@ public class StyleContext
public static StyleContext getDefaultStyleContext()
{
+ if (defaultStyleContext == null)
+ defaultStyleContext = new StyleContext();
return defaultStyleContext;
}
public AttributeSet addAttribute(AttributeSet old, Object name, Object value)
{
- if (old instanceof MutableAttributeSet)
+ AttributeSet ret;
+ if (old.getAttributeCount() + 1 < getCompressionThreshold())
{
- ((MutableAttributeSet)old).addAttribute(name, value);
- return old;
+ search.removeAttributes(search);
+ search.addAttributes(old);
+ search.addAttribute(name, value);
+ reclaim(old);
+ ret = searchImmutableSet();
}
- else
+ else
{
- MutableAttributeSet mutable = createLargeAttributeSet(old);
- mutable.addAttribute(name, value);
- if (mutable.getAttributeCount() >= getCompressionThreshold())
- return mutable;
- else
- {
- SmallAttributeSet small = createSmallAttributeSet(mutable);
- if (sharedAttributeSets.containsKey(small))
- small = (SmallAttributeSet) sharedAttributeSets.get(small);
- else
- sharedAttributeSets.put(small,small);
- return small;
- }
+ MutableAttributeSet mas = getMutableAttributeSet(old);
+ mas.addAttribute(name, value);
+ ret = mas;
}
+ return ret;
}
public AttributeSet addAttributes(AttributeSet old, AttributeSet attributes)
{
- if (old instanceof MutableAttributeSet)
+ AttributeSet ret;
+ if (old.getAttributeCount() + attributes.getAttributeCount()
+ < getCompressionThreshold())
{
- ((MutableAttributeSet)old).addAttributes(attributes);
- return old;
+ search.removeAttributes(search);
+ search.addAttributes(old);
+ search.addAttributes(attributes);
+ reclaim(old);
+ ret = searchImmutableSet();
}
- else
+ else
{
- MutableAttributeSet mutable = createLargeAttributeSet(old);
- mutable.addAttributes(attributes);
- if (mutable.getAttributeCount() >= getCompressionThreshold())
- return mutable;
- else
- {
- SmallAttributeSet small = createSmallAttributeSet(mutable);
- if (sharedAttributeSets.containsKey(small))
- small = (SmallAttributeSet) sharedAttributeSets.get(small);
- else
- sharedAttributeSets.put(small,small);
- return small;
- }
+ MutableAttributeSet mas = getMutableAttributeSet(old);
+ mas.addAttributes(attributes);
+ ret = mas;
}
+ return ret;
}
public AttributeSet getEmptySet()
{
- AttributeSet e = createSmallAttributeSet(null);
- if (sharedAttributeSets.containsKey(e))
- e = (AttributeSet) sharedAttributeSets.get(e);
- else
- sharedAttributeSets.put(e, e);
- return e;
+ return SimpleAttributeSet.EMPTY;
}
public void reclaim(AttributeSet attributes)
{
- if (sharedAttributeSets.containsKey(attributes))
- sharedAttributeSets.remove(attributes);
+ cleanupPool();
}
public AttributeSet removeAttribute(AttributeSet old, Object name)
{
- if (old instanceof MutableAttributeSet)
+ AttributeSet ret;
+ if (old.getAttributeCount() - 1 <= getCompressionThreshold())
{
- ((MutableAttributeSet)old).removeAttribute(name);
- if (old.getAttributeCount() < getCompressionThreshold())
- {
- SmallAttributeSet small = createSmallAttributeSet(old);
- if (!sharedAttributeSets.containsKey(small))
- sharedAttributeSets.put(small,small);
- old = (AttributeSet) sharedAttributeSets.get(small);
- }
- return old;
+ search.removeAttributes(search);
+ search.addAttributes(old);
+ search.removeAttribute(name);
+ reclaim(old);
+ ret = searchImmutableSet();
}
- else
- {
- MutableAttributeSet mutable = createLargeAttributeSet(old);
- mutable.removeAttribute(name);
- SmallAttributeSet small = createSmallAttributeSet(mutable);
- if (sharedAttributeSets.containsKey(small))
- small = (SmallAttributeSet) sharedAttributeSets.get(small);
- else
- sharedAttributeSets.put(small,small);
- return small;
+ else
+ {
+ MutableAttributeSet mas = getMutableAttributeSet(old);
+ mas.removeAttribute(name);
+ ret = mas;
}
+ return ret;
}
public AttributeSet removeAttributes(AttributeSet old, AttributeSet attributes)
{
- return removeAttributes(old, attributes.getAttributeNames());
+ AttributeSet ret;
+ if (old.getAttributeCount() <= getCompressionThreshold())
+ {
+ search.removeAttributes(search);
+ search.addAttributes(old);
+ search.removeAttributes(attributes);
+ reclaim(old);
+ ret = searchImmutableSet();
+ }
+ else
+ {
+ MutableAttributeSet mas = getMutableAttributeSet(old);
+ mas.removeAttributes(attributes);
+ ret = mas;
+ }
+ return ret;
}
public AttributeSet removeAttributes(AttributeSet old, Enumeration<?> names)
{
- if (old instanceof MutableAttributeSet)
+ AttributeSet ret;
+ if (old.getAttributeCount() <= getCompressionThreshold())
{
- ((MutableAttributeSet)old).removeAttributes(names);
- if (old.getAttributeCount() < getCompressionThreshold())
- {
- SmallAttributeSet small = createSmallAttributeSet(old);
- if (!sharedAttributeSets.containsKey(small))
- sharedAttributeSets.put(small,small);
- old = (AttributeSet) sharedAttributeSets.get(small);
- }
- return old;
+ search.removeAttributes(search);
+ search.addAttributes(old);
+ search.removeAttributes(names);
+ reclaim(old);
+ ret = searchImmutableSet();
}
- else
- {
- MutableAttributeSet mutable = createLargeAttributeSet(old);
- mutable.removeAttributes(names);
- SmallAttributeSet small = createSmallAttributeSet(mutable);
- if (sharedAttributeSets.containsKey(small))
- small = (SmallAttributeSet) sharedAttributeSets.get(small);
- else
- sharedAttributeSets.put(small,small);
- return small;
- }
+ else
+ {
+ MutableAttributeSet mas = getMutableAttributeSet(old);
+ mas.removeAttributes(names);
+ ret = mas;
+ }
+ return ret;
}
/**
@@ -715,7 +771,7 @@ public class StyleContext
{
if (key == null)
return null;
- return staticAttributeKeys.get(key);
+ return readAttributeKeys.get(key);
}
/**
@@ -742,27 +798,25 @@ public class StyleContext
* stream
* @throws IOException - any I/O error
*/
- public static void readAttributeSet(ObjectInputStream in, MutableAttributeSet a)
+ public static void readAttributeSet(ObjectInputStream in,
+ MutableAttributeSet a)
throws ClassNotFoundException, IOException
{
- if (in == null || a == null)
- return;
-
- Object key = in.readObject();
- Object val = in.readObject();
- while (key != null && val != null)
+ int count = in.readInt();
+ for (int i = 0; i < count; i++)
{
- Object staticKey = staticAttributeKeys.get(key);
- Object staticVal = staticAttributeKeys.get(val);
-
- if (staticKey != null)
- key = staticKey;
- if (staticVal != null)
- val = staticVal;
-
+ Object key = in.readObject();
+ Object val = in.readObject();
+ if (readAttributeKeys != null)
+ {
+ Object staticKey = readAttributeKeys.get(key);
+ if (staticKey != null)
+ key = staticKey;
+ Object staticVal = readAttributeKeys.get(val);
+ if (staticVal != null)
+ val = staticVal;
+ }
a.addAttribute(key, val);
- key = in.readObject();
- val = in.readObject();
}
}
@@ -778,18 +832,35 @@ public class StyleContext
public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a)
throws IOException
{
+ int count = a.getAttributeCount();
+ out.writeInt(count);
Enumeration e = a.getAttributeNames();
while (e.hasMoreElements())
{
- Object oldKey = e.nextElement();
- Object newKey = getStaticAttribute(oldKey);
- Object key = (newKey == null) ? oldKey : newKey;
-
- out.writeObject(key);
- out.writeObject(a.getAttribute(oldKey));
+ Object key = e.nextElement();
+ // Write key.
+ if (key instanceof Serializable)
+ out.writeObject(key);
+ else
+ {
+ Object io = writeAttributeKeys.get(key);
+ if (io == null)
+ throw new NotSerializableException(key.getClass().getName()
+ + ", key: " + key);
+ out.writeObject(io);
+ }
+ // Write value.
+ Object val = a.getAttribute(key);
+ Object io = writeAttributeKeys.get(val);
+ if (val instanceof Serializable)
+ out.writeObject(io != null ? io : val);
+ else
+ {
+ if (io == null)
+ throw new NotSerializableException(val.getClass().getName());
+ out.writeObject(io);
+ }
}
- out.writeObject(null);
- out.writeObject(null);
}
/**
@@ -833,8 +904,79 @@ public class StyleContext
*/
public static void registerStaticAttributeKey(Object key)
{
- if (key != null)
- staticAttributeKeys.put(key.getClass().getName() + "." + key.toString(),
- key);
+ String io = key.getClass().getName() + "." + key.toString();
+ if (writeAttributeKeys == null)
+ writeAttributeKeys = new Hashtable();
+ if (readAttributeKeys == null)
+ readAttributeKeys = new Hashtable();
+ writeAttributeKeys.put(key, io);
+ readAttributeKeys.put(io, key);
+ }
+
+ /**
+ * Returns a string representation of this StyleContext.
+ *
+ * @return a string representation of this StyleContext
+ */
+ public String toString()
+ {
+ cleanupPool();
+ StringBuilder b = new StringBuilder();
+ Iterator i = attributeSetPool.keySet().iterator();
+ while (i.hasNext())
+ {
+ Object att = i.next();
+ b.append(att);
+ b.append('\n');
+ }
+ return b.toString();
+ }
+
+ /**
+ * Searches the AttributeSet pool and returns a pooled instance if available,
+ * or pool a new one.
+ *
+ * @return an immutable attribute set that equals the current search key
+ */
+ private AttributeSet searchImmutableSet()
+ {
+ SmallAttributeSet k = createSmallAttributeSet(search);
+ WeakReference ref = (WeakReference) attributeSetPool.get(k);
+ SmallAttributeSet a;
+ if (ref == null || (a = (SmallAttributeSet) ref.get()) == null)
+ {
+ a = k;
+ attributeSetPool.put(a, new WeakReference(a));
+ }
+ return a;
+ }
+
+ /**
+ * Cleans up the attribute set pool from entries that are no longer
+ * referenced.
+ */
+ private void cleanupPool()
+ {
+ // TODO: How else can we force cleaning up the WeakHashMap?
+ attributeSetPool.size();
+ }
+
+ /**
+ * Returns a MutableAttributeSet that holds a. If a itself is mutable,
+ * this returns a itself, otherwise it creates a new SimpleAtttributeSet
+ * via {@link #createLargeAttributeSet(AttributeSet)}.
+ *
+ * @param a the AttributeSet to create a mutable set for
+ *
+ * @return a mutable attribute set that corresponds to a
+ */
+ private MutableAttributeSet getMutableAttributeSet(AttributeSet a)
+ {
+ MutableAttributeSet mas;
+ if (a instanceof MutableAttributeSet)
+ mas = (MutableAttributeSet) a;
+ else
+ mas = createLargeAttributeSet(a);
+ return mas;
}
}