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., 51 Franklin Street, Fifth Floor, 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 gnu
.classpath
.NotImplementedException
;
43 import java
.awt
.Color
;
45 import java
.awt
.FontMetrics
;
46 import java
.awt
.Toolkit
;
47 import java
.io
.IOException
;
48 import java
.io
.ObjectInputStream
;
49 import java
.io
.ObjectOutputStream
;
50 import java
.io
.Serializable
;
51 import java
.util
.Enumeration
;
52 import java
.util
.EventListener
;
53 import java
.util
.HashSet
;
54 import java
.util
.Hashtable
;
56 import javax
.swing
.event
.ChangeEvent
;
57 import javax
.swing
.event
.ChangeListener
;
58 import javax
.swing
.event
.EventListenerList
;
60 public class StyleContext
61 implements Serializable
, AbstractDocument
.AttributeContext
63 /** The serialization UID (compatible with JDK1.5). */
64 private static final long serialVersionUID
= 8042858831190784241L;
66 public class NamedStyle
67 implements Serializable
, Style
69 /** The serialization UID (compatible with JDK1.5). */
70 private static final long serialVersionUID
= -6690628971806226374L;
72 protected ChangeEvent changeEvent
;
73 protected EventListenerList listenerList
;
75 AttributeSet attributes
;
83 public NamedStyle(Style parent
)
88 public NamedStyle(String name
, Style parent
)
91 this.attributes
= getEmptySet();
92 this.changeEvent
= new ChangeEvent(this);
93 this.listenerList
= new EventListenerList();
94 setResolveParent(parent
);
97 public String
getName()
102 public void setName(String n
)
108 public void addChangeListener(ChangeListener l
)
110 listenerList
.add(ChangeListener
.class, l
);
113 public void removeChangeListener(ChangeListener l
)
115 listenerList
.remove(ChangeListener
.class, l
);
118 public EventListener
[] getListeners(Class listenerType
)
120 return listenerList
.getListeners(listenerType
);
123 public ChangeListener
[] getChangeListeners()
125 return (ChangeListener
[]) getListeners(ChangeListener
.class);
128 protected void fireStateChanged()
130 ChangeListener
[] listeners
= getChangeListeners();
131 for (int i
= 0; i
< listeners
.length
; ++i
)
133 listeners
[i
].stateChanged(changeEvent
);
137 public void addAttribute(Object name
, Object value
)
139 attributes
= StyleContext
.this.addAttribute(attributes
, name
, value
);
143 public void addAttributes(AttributeSet attr
)
145 attributes
= StyleContext
.this.addAttributes(attributes
, attr
);
149 public boolean containsAttribute(Object name
, Object value
)
151 return attributes
.containsAttribute(name
, value
);
154 public boolean containsAttributes(AttributeSet attrs
)
156 return attributes
.containsAttributes(attrs
);
159 public AttributeSet
copyAttributes()
161 return attributes
.copyAttributes();
164 public Object
getAttribute(Object attrName
)
166 return attributes
.getAttribute(attrName
);
169 public int getAttributeCount()
171 return attributes
.getAttributeCount();
174 public Enumeration
getAttributeNames()
176 return attributes
.getAttributeNames();
179 public boolean isDefined(Object attrName
)
181 return attributes
.isDefined(attrName
);
184 public boolean isEqual(AttributeSet attr
)
186 return attributes
.isEqual(attr
);
189 public void removeAttribute(Object name
)
191 attributes
= StyleContext
.this.removeAttribute(attributes
, name
);
195 public void removeAttributes(AttributeSet attrs
)
197 attributes
= StyleContext
.this.removeAttributes(attributes
, attrs
);
201 public void removeAttributes(Enumeration names
)
203 attributes
= StyleContext
.this.removeAttributes(attributes
, names
);
208 public AttributeSet
getResolveParent()
210 return attributes
.getResolveParent();
213 public void setResolveParent(AttributeSet parent
)
217 attributes
= StyleContext
.this.addAttribute
218 (attributes
, ResolveAttribute
, parent
);
223 public String
toString()
225 return ("[NamedStyle: name=" + name
+ ", attrs=" + attributes
.toString() + "]");
229 public class SmallAttributeSet
230 implements AttributeSet
232 final Object
[] attrs
;
233 public SmallAttributeSet(AttributeSet a
)
236 attrs
= new Object
[0];
239 int n
= a
.getAttributeCount();
241 attrs
= new Object
[n
* 2];
242 Enumeration e
= a
.getAttributeNames();
243 while (e
.hasMoreElements())
245 Object name
= e
.nextElement();
247 attrs
[i
++] = a
.getAttribute(name
);
252 public SmallAttributeSet(Object
[] a
)
255 attrs
= new Object
[0];
258 attrs
= new Object
[a
.length
];
259 System
.arraycopy(a
, 0, attrs
, 0, a
.length
);
263 public Object
clone()
265 return new SmallAttributeSet(this.attrs
);
268 public boolean containsAttribute(Object name
, Object value
)
270 for (int i
= 0; i
< attrs
.length
; i
+= 2)
272 if (attrs
[i
].equals(name
) &&
273 attrs
[i
+1].equals(value
))
279 public boolean containsAttributes(AttributeSet a
)
281 Enumeration e
= a
.getAttributeNames();
282 while (e
.hasMoreElements())
284 Object name
= e
.nextElement();
285 Object val
= a
.getAttribute(name
);
286 if (!containsAttribute(name
, val
))
292 public AttributeSet
copyAttributes()
294 return (AttributeSet
) clone();
297 public boolean equals(Object obj
)
300 (obj
instanceof AttributeSet
)
301 && this.isEqual((AttributeSet
)obj
);
304 public Object
getAttribute(Object key
)
306 for (int i
= 0; i
< attrs
.length
; i
+= 2)
308 if (attrs
[i
].equals(key
))
312 // Check the resolve parent, unless we're looking for the
313 // ResolveAttribute, which would cause an infinite loop
314 if (!(key
.equals(ResolveAttribute
)))
316 Object p
= getResolveParent();
317 if (p
!= null && p
instanceof AttributeSet
)
318 return (((AttributeSet
)p
).getAttribute(key
));
324 public int getAttributeCount()
326 return attrs
.length
/ 2;
329 public Enumeration
getAttributeNames()
331 return new Enumeration()
334 public boolean hasMoreElements()
336 return i
< attrs
.length
;
338 public Object
nextElement()
346 public AttributeSet
getResolveParent()
348 return (AttributeSet
) getAttribute(ResolveAttribute
);
351 public int hashCode()
353 return java
.util
.Arrays
.asList(attrs
).hashCode();
356 public boolean isDefined(Object key
)
358 for (int i
= 0; i
< attrs
.length
; i
+= 2)
360 if (attrs
[i
].equals(key
))
366 public boolean isEqual(AttributeSet attr
)
368 return getAttributeCount() == attr
.getAttributeCount()
369 && this.containsAttributes(attr
);
372 public String
toString()
374 StringBuffer sb
= new StringBuffer();
375 sb
.append("[StyleContext.SmallattributeSet:");
376 for (int i
= 0; i
< attrs
.length
- 1; ++i
)
379 sb
.append(attrs
[i
].toString());
381 sb
.append(attrs
[i
+1].toString());
385 return sb
.toString();
389 // FIXME: official javadocs suggest that these might be more usefully
390 // implemented using a WeakHashMap, but not sure if that works most
391 // places or whether it really matters anyways.
393 // FIXME: also not sure if these tables ought to be static (singletons),
394 // shared across all StyleContexts. I think so, but it's not clear in
395 // docs. revert to non-shared if you think it matters.
398 * The name of the default style.
400 public static final String DEFAULT_STYLE
= "default";
403 * The default style for this style context.
405 NamedStyle defaultStyle
= new NamedStyle(DEFAULT_STYLE
, null);
407 static Hashtable sharedAttributeSets
= new Hashtable();
408 static Hashtable sharedFonts
= new Hashtable();
410 static StyleContext defaultStyleContext
= new StyleContext();
411 static final int compressionThreshold
= 9;
414 * These attribute keys are handled specially in serialization.
416 private static HashSet staticAttributeKeys
= new HashSet();
418 EventListenerList listenerList
;
419 Hashtable styleTable
;
422 * Creates a new instance of the style context. Add the default style
423 * to the style table.
425 public StyleContext()
427 listenerList
= new EventListenerList();
428 styleTable
= new Hashtable();
429 styleTable
.put(DEFAULT_STYLE
, defaultStyle
);
432 protected SmallAttributeSet
createSmallAttributeSet(AttributeSet a
)
434 return new SmallAttributeSet(a
);
437 protected MutableAttributeSet
createLargeAttributeSet(AttributeSet a
)
439 return new SimpleAttributeSet(a
);
442 public void addChangeListener(ChangeListener listener
)
444 listenerList
.add(ChangeListener
.class, listener
);
447 public void removeChangeListener(ChangeListener listener
)
449 listenerList
.remove(ChangeListener
.class, listener
);
452 public ChangeListener
[] getChangeListeners()
454 return (ChangeListener
[]) listenerList
.getListeners(ChangeListener
.class);
457 public Style
addStyle(String name
, Style parent
)
459 Style newStyle
= new NamedStyle(name
, parent
);
461 styleTable
.put(name
, newStyle
);
465 public void removeStyle(String name
)
467 styleTable
.remove(name
);
471 * Get the style from the style table. If the passed name
472 * matches {@link #DEFAULT_STYLE}, returns the default style.
473 * Otherwise returns the previously defined style of
474 * <code>null</code> if the style with the given name is not defined.
476 * @param name the name of the style.
478 * @return the style with the given name or null if no such defined.
480 public Style
getStyle(String name
)
482 return (Style
) styleTable
.get(name
);
486 * Get the names of the style. The returned enumeration always
487 * contains at least one member, the default style.
489 public Enumeration
getStyleNames()
491 return styleTable
.keys();
495 // StyleContexts only understand the "simple" model of fonts present in
496 // pre-java2d systems: fonts are a family name, a size (integral number
497 // of points), and a mask of style parameters (plain, bold, italic, or
498 // bold|italic). We have an inner class here called SimpleFontSpec which
499 // holds such triples.
501 // A SimpleFontSpec can be built for *any* AttributeSet because the size,
502 // family, and style keys in an AttributeSet have default values (defined
503 // over in StyleConstants).
505 // We keep a static cache mapping SimpleFontSpecs to java.awt.Fonts, so
506 // that we reuse Fonts between styles and style contexts.
509 private static class SimpleFontSpec
514 public SimpleFontSpec(String family
,
518 this.family
= family
;
522 public boolean equals(Object obj
)
525 && (obj
instanceof SimpleFontSpec
)
526 && (((SimpleFontSpec
)obj
).family
.equals(this.family
))
527 && (((SimpleFontSpec
)obj
).style
== this.style
)
528 && (((SimpleFontSpec
)obj
).size
== this.size
);
530 public int hashCode()
532 return family
.hashCode() + style
+ size
;
536 public Font
getFont(AttributeSet attr
)
538 String family
= StyleConstants
.getFontFamily(attr
);
539 int style
= Font
.PLAIN
;
540 if (StyleConstants
.isBold(attr
))
542 if (StyleConstants
.isItalic(attr
))
543 style
+= Font
.ITALIC
;
544 int size
= StyleConstants
.getFontSize(attr
);
545 return getFont(family
, style
, size
);
548 public Font
getFont(String family
, int style
, int size
)
550 SimpleFontSpec spec
= new SimpleFontSpec(family
, style
, size
);
551 if (sharedFonts
.containsKey(spec
))
552 return (Font
) sharedFonts
.get(spec
);
555 Font tmp
= new Font(family
, style
, size
);
556 sharedFonts
.put(spec
, tmp
);
561 public FontMetrics
getFontMetrics(Font f
)
563 return Toolkit
.getDefaultToolkit().getFontMetrics(f
);
566 public Color
getForeground(AttributeSet a
)
568 return StyleConstants
.getForeground(a
);
571 public Color
getBackground(AttributeSet a
)
573 return StyleConstants
.getBackground(a
);
576 protected int getCompressionThreshold()
578 return compressionThreshold
;
581 public static StyleContext
getDefaultStyleContext()
583 return defaultStyleContext
;
586 public AttributeSet
addAttribute(AttributeSet old
, Object name
, Object value
)
588 if (old
instanceof MutableAttributeSet
)
590 ((MutableAttributeSet
)old
).addAttribute(name
, value
);
595 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
596 mutable
.addAttribute(name
, value
);
597 if (mutable
.getAttributeCount() >= getCompressionThreshold())
601 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
602 if (sharedAttributeSets
.containsKey(small
))
603 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
605 sharedAttributeSets
.put(small
,small
);
611 public AttributeSet
addAttributes(AttributeSet old
, AttributeSet attributes
)
613 if (old
instanceof MutableAttributeSet
)
615 ((MutableAttributeSet
)old
).addAttributes(attributes
);
620 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
621 mutable
.addAttributes(attributes
);
622 if (mutable
.getAttributeCount() >= getCompressionThreshold())
626 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
627 if (sharedAttributeSets
.containsKey(small
))
628 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
630 sharedAttributeSets
.put(small
,small
);
636 public AttributeSet
getEmptySet()
638 AttributeSet e
= createSmallAttributeSet(null);
639 if (sharedAttributeSets
.containsKey(e
))
640 e
= (AttributeSet
) sharedAttributeSets
.get(e
);
642 sharedAttributeSets
.put(e
, e
);
646 public void reclaim(AttributeSet attributes
)
648 if (sharedAttributeSets
.containsKey(attributes
))
649 sharedAttributeSets
.remove(attributes
);
652 public AttributeSet
removeAttribute(AttributeSet old
, Object name
)
654 if (old
instanceof MutableAttributeSet
)
656 ((MutableAttributeSet
)old
).removeAttribute(name
);
657 if (old
.getAttributeCount() < getCompressionThreshold())
659 SmallAttributeSet small
= createSmallAttributeSet(old
);
660 if (!sharedAttributeSets
.containsKey(small
))
661 sharedAttributeSets
.put(small
,small
);
662 old
= (AttributeSet
) sharedAttributeSets
.get(small
);
668 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
669 mutable
.removeAttribute(name
);
670 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
671 if (sharedAttributeSets
.containsKey(small
))
672 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
674 sharedAttributeSets
.put(small
,small
);
679 public AttributeSet
removeAttributes(AttributeSet old
, AttributeSet attributes
)
681 return removeAttributes(old
, attributes
.getAttributeNames());
684 public AttributeSet
removeAttributes(AttributeSet old
, Enumeration names
)
686 if (old
instanceof MutableAttributeSet
)
688 ((MutableAttributeSet
)old
).removeAttributes(names
);
689 if (old
.getAttributeCount() < getCompressionThreshold())
691 SmallAttributeSet small
= createSmallAttributeSet(old
);
692 if (!sharedAttributeSets
.containsKey(small
))
693 sharedAttributeSets
.put(small
,small
);
694 old
= (AttributeSet
) sharedAttributeSets
.get(small
);
700 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
701 mutable
.removeAttributes(names
);
702 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
703 if (sharedAttributeSets
.containsKey(small
))
704 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
706 sharedAttributeSets
.put(small
,small
);
712 // FIXME: there's some sort of quasi-serialization stuff in here which I
713 // have left incomplete; I'm not sure I understand the intent properly.
715 public static Object
getStaticAttribute(Object key
)
716 throws NotImplementedException
718 throw new InternalError("not implemented");
721 public static Object
getStaticAttributeKey(Object key
)
722 throws NotImplementedException
724 throw new InternalError("not implemented");
727 public static void readAttributeSet(ObjectInputStream in
, MutableAttributeSet a
)
728 throws ClassNotFoundException
, IOException
, NotImplementedException
730 throw new InternalError("not implemented");
733 public static void writeAttributeSet(ObjectOutputStream out
, AttributeSet a
)
734 throws IOException
, NotImplementedException
736 throw new InternalError("not implemented");
739 public void readAttributes(ObjectInputStream in
, MutableAttributeSet a
)
740 throws ClassNotFoundException
, IOException
, NotImplementedException
742 throw new InternalError("not implemented");
745 public void writeAttributes(ObjectOutputStream out
, AttributeSet a
)
746 throws IOException
, NotImplementedException
748 throw new InternalError("not implemented");
752 * Registers an attribute key as a well-known keys. When an attribute with
753 * such a key is written to a stream,, a special syntax is used so that it
754 * can be recognized when it is read back in. All attribute keys defined
755 * in <code>StyleContext</code> are registered as static keys. If you define
756 * additional attribute keys that you want to exist as nonreplicated objects,
757 * then you should register them using this method.
759 * @param key the key to register as static attribute key
761 public static void registerStaticAttributeKey(Object key
)
763 staticAttributeKeys
.add(key
);