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 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 /** The serialization UID (compatible with JDK1.5). */
61 private static final long serialVersionUID
= 8042858831190784241L;
63 public class NamedStyle
64 implements Serializable
, Style
66 /** The serialization UID (compatible with JDK1.5). */
67 private static final long serialVersionUID
= -6690628971806226374L;
69 protected ChangeEvent changeEvent
;
70 protected EventListenerList listenerList
;
72 AttributeSet attributes
;
80 public NamedStyle(Style parent
)
85 public NamedStyle(String name
, Style parent
)
88 this.attributes
= getEmptySet();
89 this.changeEvent
= new ChangeEvent(this);
90 this.listenerList
= new EventListenerList();
91 setResolveParent(parent
);
94 public String
getName()
99 public void setName(String n
)
105 public void addChangeListener(ChangeListener l
)
107 listenerList
.add(ChangeListener
.class, l
);
110 public void removeChangeListener(ChangeListener l
)
112 listenerList
.remove(ChangeListener
.class, l
);
115 public EventListener
[] getListeners(Class listenerType
)
117 return listenerList
.getListeners(listenerType
);
120 public ChangeListener
[] getChangeListeners()
122 return (ChangeListener
[]) getListeners(ChangeListener
.class);
125 protected void fireStateChanged()
127 ChangeListener
[] listeners
= getChangeListeners();
128 for (int i
= 0; i
< listeners
.length
; ++i
)
130 listeners
[i
].stateChanged(changeEvent
);
134 public void addAttribute(Object name
, Object value
)
136 attributes
= StyleContext
.this.addAttribute(attributes
, name
, value
);
140 public void addAttributes(AttributeSet attr
)
142 attributes
= StyleContext
.this.addAttributes(attributes
, attr
);
146 public boolean containsAttribute(Object name
, Object value
)
148 return attributes
.containsAttribute(name
, value
);
151 public boolean containsAttributes(AttributeSet attrs
)
153 return attributes
.containsAttributes(attrs
);
156 public AttributeSet
copyAttributes()
158 return attributes
.copyAttributes();
161 public Object
getAttribute(Object attrName
)
163 return attributes
.getAttribute(attrName
);
166 public int getAttributeCount()
168 return attributes
.getAttributeCount();
171 public Enumeration
getAttributeNames()
173 return attributes
.getAttributeNames();
176 public boolean isDefined(Object attrName
)
178 return attributes
.isDefined(attrName
);
181 public boolean isEqual(AttributeSet attr
)
183 return attributes
.isEqual(attr
);
186 public void removeAttribute(Object name
)
188 attributes
= StyleContext
.this.removeAttribute(attributes
, name
);
192 public void removeAttributes(AttributeSet attrs
)
194 attributes
= StyleContext
.this.removeAttributes(attributes
, attrs
);
198 public void removeAttributes(Enumeration names
)
200 attributes
= StyleContext
.this.removeAttributes(attributes
, names
);
205 public AttributeSet
getResolveParent()
207 return attributes
.getResolveParent();
210 public void setResolveParent(AttributeSet parent
)
214 attributes
= StyleContext
.this.addAttribute
215 (attributes
, ResolveAttribute
, parent
);
220 public String
toString()
222 return ("[NamedStyle: name=" + name
+ ", attrs=" + attributes
.toString() + "]");
226 public class SmallAttributeSet
227 implements AttributeSet
229 final Object
[] attrs
;
230 public SmallAttributeSet(AttributeSet a
)
233 attrs
= new Object
[0];
236 int n
= a
.getAttributeCount();
238 attrs
= new Object
[n
* 2];
239 Enumeration e
= a
.getAttributeNames();
240 while (e
.hasMoreElements())
242 Object name
= e
.nextElement();
244 attrs
[i
++] = a
.getAttribute(name
);
249 public SmallAttributeSet(Object
[] a
)
252 attrs
= new Object
[0];
255 attrs
= new Object
[a
.length
];
256 System
.arraycopy(a
, 0, attrs
, 0, a
.length
);
260 public Object
clone()
262 return new SmallAttributeSet(this.attrs
);
265 public boolean containsAttribute(Object name
, Object value
)
267 for (int i
= 0; i
< attrs
.length
; i
+= 2)
269 if (attrs
[i
].equals(name
) &&
270 attrs
[i
+1].equals(value
))
276 public boolean containsAttributes(AttributeSet a
)
278 Enumeration e
= a
.getAttributeNames();
279 while (e
.hasMoreElements())
281 Object name
= e
.nextElement();
282 Object val
= a
.getAttribute(name
);
283 if (!containsAttribute(name
, val
))
289 public AttributeSet
copyAttributes()
291 return (AttributeSet
) clone();
294 public boolean equals(Object obj
)
297 (obj
instanceof AttributeSet
)
298 && this.isEqual((AttributeSet
)obj
);
301 public Object
getAttribute(Object key
)
303 for (int i
= 0; i
< attrs
.length
; i
+= 2)
305 if (attrs
[i
].equals(key
))
309 // Check the resolve parent, unless we're looking for the
310 // ResolveAttribute, which would cause an infinite loop
311 if (!(key
.equals(ResolveAttribute
)))
313 Object p
= getResolveParent();
314 if (p
!= null && p
instanceof AttributeSet
)
315 return (((AttributeSet
)p
).getAttribute(key
));
321 public int getAttributeCount()
323 return attrs
.length
/ 2;
326 public Enumeration
getAttributeNames()
328 return new Enumeration()
331 public boolean hasMoreElements()
333 return i
< attrs
.length
;
335 public Object
nextElement()
343 public AttributeSet
getResolveParent()
345 return (AttributeSet
) getAttribute(ResolveAttribute
);
348 public int hashCode()
350 return java
.util
.Arrays
.asList(attrs
).hashCode();
353 public boolean isDefined(Object key
)
355 for (int i
= 0; i
< attrs
.length
; i
+= 2)
357 if (attrs
[i
].equals(key
))
363 public boolean isEqual(AttributeSet attr
)
365 return getAttributeCount() == attr
.getAttributeCount()
366 && this.containsAttributes(attr
);
369 public String
toString()
371 StringBuffer sb
= new StringBuffer();
372 sb
.append("[StyleContext.SmallattributeSet:");
373 for (int i
= 0; i
< attrs
.length
; ++i
)
376 sb
.append(attrs
[i
].toString());
378 sb
.append(attrs
[i
+1].toString());
382 return sb
.toString();
386 // FIXME: official javadocs suggest that these might be more usefully
387 // implemented using a WeakHashMap, but not sure if that works most
388 // places or whether it really matters anyways.
390 // FIXME: also not sure if these tables ought to be static (singletons),
391 // shared across all StyleContexts. I think so, but it's not clear in
392 // docs. revert to non-shared if you think it matters.
395 * The name of the default style.
397 public static final String DEFAULT_STYLE
= "default";
400 * The default style for this style context.
402 NamedStyle defaultStyle
= new NamedStyle(DEFAULT_STYLE
, null);
404 static Hashtable sharedAttributeSets
= new Hashtable();
405 static Hashtable sharedFonts
= new Hashtable();
407 static StyleContext defaultStyleContext
= new StyleContext();
408 static final int compressionThreshold
= 9;
410 EventListenerList listenerList
;
411 Hashtable styleTable
;
414 * Creates a new instance of the style context. Add the default style
415 * to the style table.
417 public StyleContext()
419 listenerList
= new EventListenerList();
420 styleTable
= new Hashtable();
421 styleTable
.put(DEFAULT_STYLE
, defaultStyle
);
424 protected SmallAttributeSet
createSmallAttributeSet(AttributeSet a
)
426 return new SmallAttributeSet(a
);
429 protected MutableAttributeSet
createLargeAttributeSet(AttributeSet a
)
431 return new SimpleAttributeSet(a
);
434 public void addChangeListener(ChangeListener listener
)
436 listenerList
.add(ChangeListener
.class, listener
);
439 public void removeChangeListener(ChangeListener listener
)
441 listenerList
.remove(ChangeListener
.class, listener
);
444 public ChangeListener
[] getChangeListeners()
446 return (ChangeListener
[]) listenerList
.getListeners(ChangeListener
.class);
449 public Style
addStyle(String name
, Style parent
)
451 Style newStyle
= new NamedStyle(name
, parent
);
453 styleTable
.put(name
, newStyle
);
457 public void removeStyle(String name
)
459 styleTable
.remove(name
);
463 * Get the style from the style table. If the passed name
464 * matches {@link #DEFAULT_STYLE}, returns the default style.
465 * Otherwise returns the previously defined style of
466 * <code>null</code> if the style with the given name is not defined.
468 * @param name the name of the style.
470 * @return the style with the given name or null if no such defined.
472 public Style
getStyle(String name
)
474 return (Style
) styleTable
.get(name
);
478 * Get the names of the style. The returned enumeration always
479 * contains at least one member, the default style.
481 public Enumeration
getStyleNames()
483 return styleTable
.keys();
487 // StyleContexts only understand the "simple" model of fonts present in
488 // pre-java2d systems: fonts are a family name, a size (integral number
489 // of points), and a mask of style parameters (plain, bold, italic, or
490 // bold|italic). We have an inner class here called SimpleFontSpec which
491 // holds such triples.
493 // A SimpleFontSpec can be built for *any* AttributeSet because the size,
494 // family, and style keys in an AttributeSet have default values (defined
495 // over in StyleConstants).
497 // We keep a static cache mapping SimpleFontSpecs to java.awt.Fonts, so
498 // that we reuse Fonts between styles and style contexts.
501 private static class SimpleFontSpec
506 public SimpleFontSpec(String family
,
510 this.family
= family
;
514 public boolean equals(Object obj
)
517 && (obj
instanceof SimpleFontSpec
)
518 && (((SimpleFontSpec
)obj
).family
.equals(this.family
))
519 && (((SimpleFontSpec
)obj
).style
== this.style
)
520 && (((SimpleFontSpec
)obj
).size
== this.size
);
522 public int hashCode()
524 return family
.hashCode() + style
+ size
;
528 public Font
getFont(AttributeSet attr
)
530 String family
= StyleConstants
.getFontFamily(attr
);
531 int style
= Font
.PLAIN
;
532 if (StyleConstants
.isBold(attr
))
534 if (StyleConstants
.isItalic(attr
))
535 style
+= Font
.ITALIC
;
536 int size
= StyleConstants
.getFontSize(attr
);
537 return getFont(family
, style
, size
);
540 public Font
getFont(String family
, int style
, int size
)
542 SimpleFontSpec spec
= new SimpleFontSpec(family
, style
, size
);
543 if (sharedFonts
.containsKey(spec
))
544 return (Font
) sharedFonts
.get(spec
);
547 Font tmp
= new Font(family
, style
, size
);
548 sharedFonts
.put(spec
, tmp
);
553 public FontMetrics
getFontMetrics(Font f
)
555 return Toolkit
.getDefaultToolkit().getFontMetrics(f
);
558 public Color
getForeground(AttributeSet a
)
560 return StyleConstants
.getForeground(a
);
563 public Color
getBackground(AttributeSet a
)
565 return StyleConstants
.getBackground(a
);
568 protected int getCompressionThreshold()
570 return compressionThreshold
;
573 public static StyleContext
getDefaultStyleContext()
575 return defaultStyleContext
;
578 public AttributeSet
addAttribute(AttributeSet old
, Object name
, Object value
)
580 if (old
instanceof MutableAttributeSet
)
582 ((MutableAttributeSet
)old
).addAttribute(name
, value
);
587 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
588 mutable
.addAttribute(name
, value
);
589 if (mutable
.getAttributeCount() >= getCompressionThreshold())
593 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
594 if (sharedAttributeSets
.containsKey(small
))
595 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
597 sharedAttributeSets
.put(small
,small
);
603 public AttributeSet
addAttributes(AttributeSet old
, AttributeSet attributes
)
605 if (old
instanceof MutableAttributeSet
)
607 ((MutableAttributeSet
)old
).addAttributes(attributes
);
612 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
613 mutable
.addAttributes(attributes
);
614 if (mutable
.getAttributeCount() >= getCompressionThreshold())
618 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
619 if (sharedAttributeSets
.containsKey(small
))
620 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
622 sharedAttributeSets
.put(small
,small
);
628 public AttributeSet
getEmptySet()
630 AttributeSet e
= createSmallAttributeSet(null);
631 if (sharedAttributeSets
.containsKey(e
))
632 e
= (AttributeSet
) sharedAttributeSets
.get(e
);
634 sharedAttributeSets
.put(e
, e
);
638 public void reclaim(AttributeSet attributes
)
640 if (sharedAttributeSets
.containsKey(attributes
))
641 sharedAttributeSets
.remove(attributes
);
644 public AttributeSet
removeAttribute(AttributeSet old
, Object name
)
646 if (old
instanceof MutableAttributeSet
)
648 ((MutableAttributeSet
)old
).removeAttribute(name
);
649 if (old
.getAttributeCount() < getCompressionThreshold())
651 SmallAttributeSet small
= createSmallAttributeSet(old
);
652 if (!sharedAttributeSets
.containsKey(small
))
653 sharedAttributeSets
.put(small
,small
);
654 old
= (AttributeSet
) sharedAttributeSets
.get(small
);
660 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
661 mutable
.removeAttribute(name
);
662 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
663 if (sharedAttributeSets
.containsKey(small
))
664 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
666 sharedAttributeSets
.put(small
,small
);
671 public AttributeSet
removeAttributes(AttributeSet old
, AttributeSet attributes
)
673 return removeAttributes(old
, attributes
.getAttributeNames());
676 public AttributeSet
removeAttributes(AttributeSet old
, Enumeration names
)
678 if (old
instanceof MutableAttributeSet
)
680 ((MutableAttributeSet
)old
).removeAttributes(names
);
681 if (old
.getAttributeCount() < getCompressionThreshold())
683 SmallAttributeSet small
= createSmallAttributeSet(old
);
684 if (!sharedAttributeSets
.containsKey(small
))
685 sharedAttributeSets
.put(small
,small
);
686 old
= (AttributeSet
) sharedAttributeSets
.get(small
);
692 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
693 mutable
.removeAttributes(names
);
694 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
695 if (sharedAttributeSets
.containsKey(small
))
696 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
698 sharedAttributeSets
.put(small
,small
);
704 // FIXME: there's some sort of quasi-serialization stuff in here which I
705 // have left incomplete; I'm not sure I understand the intent properly.
707 public static Object
getStaticAttribute(Object key
)
709 throw new InternalError("not implemented");
712 public static Object
getStaticAttributeKey(Object key
)
714 throw new InternalError("not implemented");
717 public static void readAttributeSet(ObjectInputStream in
, MutableAttributeSet a
)
718 throws ClassNotFoundException
, IOException
720 throw new InternalError("not implemented");
723 public static void writeAttributeSet(ObjectOutputStream out
, AttributeSet a
)
726 throw new InternalError("not implemented");
729 public void readAttributes(ObjectInputStream in
, MutableAttributeSet a
)
730 throws ClassNotFoundException
, IOException
732 throw new InternalError("not implemented");
735 public void writeAttributes(ObjectOutputStream out
, AttributeSet a
)
738 throw new InternalError("not implemented");