1 /* StyleContext.java --
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text;
41 import java.awt.Color;
43 import java.awt.FontMetrics;
44 import java.awt.Toolkit;
45 import java.io.IOException;
46 import java.io.ObjectInputStream;
47 import java.io.ObjectOutputStream;
48 import java.io.Serializable;
49 import java.util.Enumeration;
50 import java.util.EventListener;
51 import java.util.Hashtable;
53 import javax.swing.event.ChangeEvent;
54 import javax.swing.event.ChangeListener;
55 import javax.swing.event.EventListenerList;
57 public class StyleContext
58 implements Serializable, AbstractDocument.AttributeContext
60 public class NamedStyle
61 implements Serializable, Style
63 protected ChangeEvent changeEvent;
64 protected EventListenerList listenerList;
66 AttributeSet attributes;
74 public NamedStyle(Style parent)
79 public NamedStyle(String name, Style parent)
82 this.attributes = getEmptySet();
83 this.changeEvent = new ChangeEvent(this);
84 this.listenerList = new EventListenerList();
85 setResolveParent(parent);
88 public String getName()
93 public void setName(String n)
99 public void addChangeListener(ChangeListener l)
101 listenerList.add(ChangeListener.class, l);
104 public void removeChangeListener(ChangeListener l)
106 listenerList.remove(ChangeListener.class, l);
109 public EventListener[] getListeners(Class listenerType)
111 return listenerList.getListeners(listenerType);
114 public ChangeListener[] getChangeListeners()
116 return (ChangeListener[]) getListeners(ChangeListener.class);
119 protected void fireStateChanged()
121 ChangeListener[] listeners = getChangeListeners();
122 for (int i = 0; i < listeners.length; ++i)
124 listeners[i].stateChanged(changeEvent);
128 public void addAttribute(Object name, Object value)
130 attributes = StyleContext.this.addAttribute(attributes, name, value);
134 public void addAttributes(AttributeSet attr)
136 attributes = StyleContext.this.addAttributes(attributes, attr);
140 public boolean containsAttribute(Object name, Object value)
142 return attributes.containsAttribute(name, value);
145 public boolean containsAttributes(AttributeSet attrs)
147 return attributes.containsAttributes(attrs);
150 public AttributeSet copyAttributes()
152 return attributes.copyAttributes();
155 public Object getAttribute(Object attrName)
157 return attributes.getAttribute(attrName);
160 public int getAttributeCount()
162 return attributes.getAttributeCount();
165 public Enumeration getAttributeNames()
167 return attributes.getAttributeNames();
170 public boolean isDefined(Object attrName)
172 return attributes.isDefined(attrName);
175 public boolean isEqual(AttributeSet attr)
177 return attributes.isEqual(attr);
180 public void removeAttribute(Object name)
182 attributes = StyleContext.this.removeAttribute(attributes, name);
186 public void removeAttributes(AttributeSet attrs)
188 attributes = StyleContext.this.removeAttributes(attributes, attrs);
192 public void removeAttributes(Enumeration names)
194 attributes = StyleContext.this.removeAttributes(attributes, names);
199 public AttributeSet getResolveParent()
201 return attributes.getResolveParent();
204 public void setResolveParent(AttributeSet parent)
206 attributes = StyleContext.this.addAttribute(attributes, ResolveAttribute, parent);
210 public String toString()
212 return ("[NamedStyle: name=" + name + ", attrs=" + attributes.toString() + "]");
216 public class SmallAttributeSet
217 implements AttributeSet
219 final Object [] attrs;
220 public SmallAttributeSet(AttributeSet a)
223 attrs = new Object[0];
226 int n = a.getAttributeCount();
228 attrs = new Object[n * 2];
229 Enumeration e = a.getAttributeNames();
230 while (e.hasMoreElements())
232 Object name = e.nextElement();
234 attrs[i++] = a.getAttribute(name);
239 public SmallAttributeSet(Object [] a)
242 attrs = new Object[0];
245 attrs = new Object[a.length];
246 System.arraycopy(a, 0, attrs, 0, a.length);
250 public Object clone()
252 return new SmallAttributeSet(this.attrs);
255 public boolean containsAttribute(Object name, Object value)
257 for (int i = 0; i < attrs.length; i += 2)
259 if (attrs[i].equals(name) &&
260 attrs[i+1].equals(value))
266 public boolean containsAttributes(AttributeSet a)
268 Enumeration e = a.getAttributeNames();
269 while (e.hasMoreElements())
271 Object name = e.nextElement();
272 Object val = a.getAttribute(name);
273 if (!containsAttribute(name, val))
279 public AttributeSet copyAttributes()
281 return (AttributeSet) clone();
284 public boolean equals(Object obj)
287 (obj instanceof SmallAttributeSet)
288 && this.isEqual((AttributeSet)obj);
291 public Object getAttribute(Object key)
293 for (int i = 0; i < attrs.length; i += 2)
295 if (attrs[i].equals(key))
299 Object p = getResolveParent();
300 if (p != null && p instanceof AttributeSet)
301 return (((AttributeSet)p).getAttribute(key));
306 public int getAttributeCount()
308 return attrs.length / 2;
311 public Enumeration getAttributeNames()
313 return new Enumeration()
316 public boolean hasMoreElements()
318 return i < attrs.length;
320 public Object nextElement()
328 public AttributeSet getResolveParent()
330 return (AttributeSet) getAttribute(ResolveAttribute);
333 public int hashCode()
335 return java.util.Arrays.asList(attrs).hashCode();
338 public boolean isDefined(Object key)
340 for (int i = 0; i < attrs.length; i += 2)
342 if (attrs[i].equals(key))
348 public boolean isEqual(AttributeSet attr)
351 && attr.containsAttributes(this)
352 && this.containsAttributes(attr);
355 public String toString()
357 StringBuffer sb = new StringBuffer();
358 sb.append("[StyleContext.SmallattributeSet:");
359 for (int i = 0; i < attrs.length; ++i)
362 sb.append(attrs[i].toString());
364 sb.append(attrs[i+1].toString());
368 return sb.toString();
372 // FIXME: official javadocs suggest that these might be more usefully
373 // implemented using a WeakHashMap, but not sure if that works most
374 // places or whether it really matters anyways.
376 // FIXME: also not sure if these tables ought to be static (singletons),
377 // shared across all StyleContexts. I think so, but it's not clear in
378 // docs. revert to non-shared if you think it matters.
380 public static final String DEFAULT_STYLE = "default";
382 static Hashtable sharedAttributeSets = new Hashtable();
383 static Hashtable sharedFonts = new Hashtable();
385 static StyleContext defaultStyleContext = new StyleContext();
386 static final int compressionThreshold = 9;
388 EventListenerList listenerList;
389 Hashtable styleTable;
391 public StyleContext()
393 listenerList = new EventListenerList();
394 styleTable = new Hashtable();
397 protected SmallAttributeSet createSmallAttributeSet(AttributeSet a)
399 return new SmallAttributeSet(a);
402 protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
404 return new SimpleAttributeSet(a);
407 public void addChangeListener(ChangeListener listener)
409 listenerList.add(ChangeListener.class, listener);
412 public void removeChangeListener(ChangeListener listener)
414 listenerList.remove(ChangeListener.class, listener);
417 public ChangeListener[] getChangeListeners()
419 return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
422 public Style addStyle(String name, Style parent)
424 Style newStyle = new NamedStyle(name, parent);
426 styleTable.put(name, newStyle);
430 public void removeStyle(String name)
432 styleTable.remove(name);
435 public Style getStyle(String name)
437 return (Style) styleTable.get(name);
440 public Enumeration getStyleNames()
442 return styleTable.keys();
446 // StyleContexts only understand the "simple" model of fonts present in
447 // pre-java2d systems: fonts are a family name, a size (integral number
448 // of points), and a mask of style parameters (plain, bold, italic, or
449 // bold|italic). We have an inner class here called SimpleFontSpec which
450 // holds such triples.
452 // A SimpleFontSpec can be built for *any* AttributeSet because the size,
453 // family, and style keys in an AttributeSet have default values (defined
454 // over in StyleConstants).
456 // We keep a static cache mapping SimpleFontSpecs to java.awt.Fonts, so
457 // that we reuse Fonts between styles and style contexts.
460 private static class SimpleFontSpec
465 public SimpleFontSpec(String family,
469 this.family = family;
473 public boolean equals(Object obj)
476 && (obj instanceof SimpleFontSpec)
477 && (((SimpleFontSpec)obj).family.equals(this.family))
478 && (((SimpleFontSpec)obj).style == this.style)
479 && (((SimpleFontSpec)obj).size == this.size);
481 public int hashCode()
483 return family.hashCode() + style + size;
487 public Font getFont(AttributeSet attr)
489 String family = StyleConstants.getFontFamily(attr);
490 int style = Font.PLAIN;
491 if (StyleConstants.isBold(attr))
493 if (StyleConstants.isItalic(attr))
494 style += Font.ITALIC;
495 int size = StyleConstants.getFontSize(attr);
496 return getFont(family, style, size);
499 public Font getFont(String family, int style, int size)
501 SimpleFontSpec spec = new SimpleFontSpec(family, style, size);
502 if (sharedFonts.containsKey(spec))
503 return (Font) sharedFonts.get(spec);
506 Font tmp = new Font(family, style, size);
507 sharedFonts.put(spec, tmp);
512 public FontMetrics getFontMetrics(Font f)
514 return Toolkit.getDefaultToolkit().getFontMetrics(f);
517 public Color getForeground(AttributeSet a)
519 return StyleConstants.getForeground(a);
522 public Color getBackground(AttributeSet a)
524 return StyleConstants.getBackground(a);
527 protected int getCompressionThreshold()
529 return compressionThreshold;
532 public static StyleContext getDefaultStyleContext()
534 return defaultStyleContext;
537 public AttributeSet addAttribute(AttributeSet old, Object name, Object value)
539 if (old instanceof MutableAttributeSet)
541 ((MutableAttributeSet)old).addAttribute(name, value);
546 MutableAttributeSet mutable = createLargeAttributeSet(old);
547 mutable.addAttribute(name, value);
548 if (mutable.getAttributeCount() >= getCompressionThreshold())
552 SmallAttributeSet small = createSmallAttributeSet(mutable);
553 if (sharedAttributeSets.containsKey(small))
554 small = (SmallAttributeSet) sharedAttributeSets.get(small);
556 sharedAttributeSets.put(small,small);
562 public AttributeSet addAttributes(AttributeSet old, AttributeSet attributes)
564 if (old instanceof MutableAttributeSet)
566 ((MutableAttributeSet)old).addAttributes(attributes);
571 MutableAttributeSet mutable = createLargeAttributeSet(old);
572 mutable.addAttributes(attributes);
573 if (mutable.getAttributeCount() >= getCompressionThreshold())
577 SmallAttributeSet small = createSmallAttributeSet(mutable);
578 if (sharedAttributeSets.containsKey(small))
579 small = (SmallAttributeSet) sharedAttributeSets.get(small);
581 sharedAttributeSets.put(small,small);
587 public AttributeSet getEmptySet()
589 AttributeSet e = createSmallAttributeSet(null);
590 if (sharedAttributeSets.containsKey(e))
591 e = (AttributeSet) sharedAttributeSets.get(e);
593 sharedAttributeSets.put(e, e);
597 public void reclaim(AttributeSet attributes)
599 if (sharedAttributeSets.containsKey(attributes))
600 sharedAttributeSets.remove(attributes);
603 public AttributeSet removeAttribute(AttributeSet old, Object name)
605 if (old instanceof MutableAttributeSet)
607 ((MutableAttributeSet)old).removeAttribute(name);
608 if (old.getAttributeCount() < getCompressionThreshold())
610 SmallAttributeSet small = createSmallAttributeSet(old);
611 if (!sharedAttributeSets.containsKey(small))
612 sharedAttributeSets.put(small,small);
613 old = (AttributeSet) sharedAttributeSets.get(small);
619 MutableAttributeSet mutable = createLargeAttributeSet(old);
620 mutable.removeAttribute(name);
621 SmallAttributeSet small = createSmallAttributeSet(mutable);
622 if (sharedAttributeSets.containsKey(small))
623 small = (SmallAttributeSet) sharedAttributeSets.get(small);
625 sharedAttributeSets.put(small,small);
630 public AttributeSet removeAttributes(AttributeSet old, AttributeSet attributes)
632 return removeAttributes(old, attributes.getAttributeNames());
635 public AttributeSet removeAttributes(AttributeSet old, Enumeration names)
637 if (old instanceof MutableAttributeSet)
639 ((MutableAttributeSet)old).removeAttributes(names);
640 if (old.getAttributeCount() < getCompressionThreshold())
642 SmallAttributeSet small = createSmallAttributeSet(old);
643 if (!sharedAttributeSets.containsKey(small))
644 sharedAttributeSets.put(small,small);
645 old = (AttributeSet) sharedAttributeSets.get(small);
651 MutableAttributeSet mutable = createLargeAttributeSet(old);
652 mutable.removeAttributes(names);
653 SmallAttributeSet small = createSmallAttributeSet(mutable);
654 if (sharedAttributeSets.containsKey(small))
655 small = (SmallAttributeSet) sharedAttributeSets.get(small);
657 sharedAttributeSets.put(small,small);
663 // FIXME: there's some sort of quasi-serialization stuff in here which I
664 // have left incomplete; I'm not sure I understand the intent properly.
666 public static Object getStaticAttribute(Object key)
668 throw new InternalError("not implemented");
671 public static Object getStaticAttributeKey(Object key)
673 throw new InternalError("not implemented");
676 public static void readAttributeSet(ObjectInputStream in, MutableAttributeSet a)
677 throws ClassNotFoundException, IOException
679 throw new InternalError("not implemented");
682 public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a)
685 throw new InternalError("not implemented");
688 public void readAttributes(ObjectInputStream in, MutableAttributeSet a)
689 throws ClassNotFoundException, IOException
691 throw new InternalError("not implemented");
694 public void writeAttributes(ObjectOutputStream out, AttributeSet a)
697 throw new InternalError("not implemented");