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
)
366 && attr
.containsAttributes(this)
367 && this.containsAttributes(attr
);
370 public String
toString()
372 StringBuffer sb
= new StringBuffer();
373 sb
.append("[StyleContext.SmallattributeSet:");
374 for (int i
= 0; i
< attrs
.length
; ++i
)
377 sb
.append(attrs
[i
].toString());
379 sb
.append(attrs
[i
+1].toString());
383 return sb
.toString();
387 // FIXME: official javadocs suggest that these might be more usefully
388 // implemented using a WeakHashMap, but not sure if that works most
389 // places or whether it really matters anyways.
391 // FIXME: also not sure if these tables ought to be static (singletons),
392 // shared across all StyleContexts. I think so, but it's not clear in
393 // docs. revert to non-shared if you think it matters.
396 * The name of the default style.
398 public static final String DEFAULT_STYLE
= "default";
401 * The default style for this style context.
403 NamedStyle defaultStyle
= new NamedStyle(DEFAULT_STYLE
, null);
405 static Hashtable sharedAttributeSets
= new Hashtable();
406 static Hashtable sharedFonts
= new Hashtable();
408 static StyleContext defaultStyleContext
= new StyleContext();
409 static final int compressionThreshold
= 9;
411 EventListenerList listenerList
;
412 Hashtable styleTable
;
415 * Creates a new instance of the style context. Add the default style
416 * to the style table.
418 public StyleContext()
420 listenerList
= new EventListenerList();
421 styleTable
= new Hashtable();
422 styleTable
.put(DEFAULT_STYLE
, defaultStyle
);
425 protected SmallAttributeSet
createSmallAttributeSet(AttributeSet a
)
427 return new SmallAttributeSet(a
);
430 protected MutableAttributeSet
createLargeAttributeSet(AttributeSet a
)
432 return new SimpleAttributeSet(a
);
435 public void addChangeListener(ChangeListener listener
)
437 listenerList
.add(ChangeListener
.class, listener
);
440 public void removeChangeListener(ChangeListener listener
)
442 listenerList
.remove(ChangeListener
.class, listener
);
445 public ChangeListener
[] getChangeListeners()
447 return (ChangeListener
[]) listenerList
.getListeners(ChangeListener
.class);
450 public Style
addStyle(String name
, Style parent
)
452 Style newStyle
= new NamedStyle(name
, parent
);
454 styleTable
.put(name
, newStyle
);
458 public void removeStyle(String name
)
460 styleTable
.remove(name
);
464 * Get the style from the style table. If the passed name
465 * matches {@link #DEFAULT_STYLE}, returns the default style.
466 * Otherwise returns the previously defined style of
467 * <code>null</code> if the style with the given name is not defined.
469 * @param name the name of the style.
471 * @return the style with the given name or null if no such defined.
473 public Style
getStyle(String name
)
475 return (Style
) styleTable
.get(name
);
479 * Get the names of the style. The returned enumeration always
480 * contains at least one member, the default style.
482 public Enumeration
getStyleNames()
484 return styleTable
.keys();
488 // StyleContexts only understand the "simple" model of fonts present in
489 // pre-java2d systems: fonts are a family name, a size (integral number
490 // of points), and a mask of style parameters (plain, bold, italic, or
491 // bold|italic). We have an inner class here called SimpleFontSpec which
492 // holds such triples.
494 // A SimpleFontSpec can be built for *any* AttributeSet because the size,
495 // family, and style keys in an AttributeSet have default values (defined
496 // over in StyleConstants).
498 // We keep a static cache mapping SimpleFontSpecs to java.awt.Fonts, so
499 // that we reuse Fonts between styles and style contexts.
502 private static class SimpleFontSpec
507 public SimpleFontSpec(String family
,
511 this.family
= family
;
515 public boolean equals(Object obj
)
518 && (obj
instanceof SimpleFontSpec
)
519 && (((SimpleFontSpec
)obj
).family
.equals(this.family
))
520 && (((SimpleFontSpec
)obj
).style
== this.style
)
521 && (((SimpleFontSpec
)obj
).size
== this.size
);
523 public int hashCode()
525 return family
.hashCode() + style
+ size
;
529 public Font
getFont(AttributeSet attr
)
531 String family
= StyleConstants
.getFontFamily(attr
);
532 int style
= Font
.PLAIN
;
533 if (StyleConstants
.isBold(attr
))
535 if (StyleConstants
.isItalic(attr
))
536 style
+= Font
.ITALIC
;
537 int size
= StyleConstants
.getFontSize(attr
);
538 return getFont(family
, style
, size
);
541 public Font
getFont(String family
, int style
, int size
)
543 SimpleFontSpec spec
= new SimpleFontSpec(family
, style
, size
);
544 if (sharedFonts
.containsKey(spec
))
545 return (Font
) sharedFonts
.get(spec
);
548 Font tmp
= new Font(family
, style
, size
);
549 sharedFonts
.put(spec
, tmp
);
554 public FontMetrics
getFontMetrics(Font f
)
556 return Toolkit
.getDefaultToolkit().getFontMetrics(f
);
559 public Color
getForeground(AttributeSet a
)
561 return StyleConstants
.getForeground(a
);
564 public Color
getBackground(AttributeSet a
)
566 return StyleConstants
.getBackground(a
);
569 protected int getCompressionThreshold()
571 return compressionThreshold
;
574 public static StyleContext
getDefaultStyleContext()
576 return defaultStyleContext
;
579 public AttributeSet
addAttribute(AttributeSet old
, Object name
, Object value
)
581 if (old
instanceof MutableAttributeSet
)
583 ((MutableAttributeSet
)old
).addAttribute(name
, value
);
588 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
589 mutable
.addAttribute(name
, value
);
590 if (mutable
.getAttributeCount() >= getCompressionThreshold())
594 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
595 if (sharedAttributeSets
.containsKey(small
))
596 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
598 sharedAttributeSets
.put(small
,small
);
604 public AttributeSet
addAttributes(AttributeSet old
, AttributeSet attributes
)
606 if (old
instanceof MutableAttributeSet
)
608 ((MutableAttributeSet
)old
).addAttributes(attributes
);
613 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
614 mutable
.addAttributes(attributes
);
615 if (mutable
.getAttributeCount() >= getCompressionThreshold())
619 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
620 if (sharedAttributeSets
.containsKey(small
))
621 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
623 sharedAttributeSets
.put(small
,small
);
629 public AttributeSet
getEmptySet()
631 AttributeSet e
= createSmallAttributeSet(null);
632 if (sharedAttributeSets
.containsKey(e
))
633 e
= (AttributeSet
) sharedAttributeSets
.get(e
);
635 sharedAttributeSets
.put(e
, e
);
639 public void reclaim(AttributeSet attributes
)
641 if (sharedAttributeSets
.containsKey(attributes
))
642 sharedAttributeSets
.remove(attributes
);
645 public AttributeSet
removeAttribute(AttributeSet old
, Object name
)
647 if (old
instanceof MutableAttributeSet
)
649 ((MutableAttributeSet
)old
).removeAttribute(name
);
650 if (old
.getAttributeCount() < getCompressionThreshold())
652 SmallAttributeSet small
= createSmallAttributeSet(old
);
653 if (!sharedAttributeSets
.containsKey(small
))
654 sharedAttributeSets
.put(small
,small
);
655 old
= (AttributeSet
) sharedAttributeSets
.get(small
);
661 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
662 mutable
.removeAttribute(name
);
663 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
664 if (sharedAttributeSets
.containsKey(small
))
665 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
667 sharedAttributeSets
.put(small
,small
);
672 public AttributeSet
removeAttributes(AttributeSet old
, AttributeSet attributes
)
674 return removeAttributes(old
, attributes
.getAttributeNames());
677 public AttributeSet
removeAttributes(AttributeSet old
, Enumeration names
)
679 if (old
instanceof MutableAttributeSet
)
681 ((MutableAttributeSet
)old
).removeAttributes(names
);
682 if (old
.getAttributeCount() < getCompressionThreshold())
684 SmallAttributeSet small
= createSmallAttributeSet(old
);
685 if (!sharedAttributeSets
.containsKey(small
))
686 sharedAttributeSets
.put(small
,small
);
687 old
= (AttributeSet
) sharedAttributeSets
.get(small
);
693 MutableAttributeSet mutable
= createLargeAttributeSet(old
);
694 mutable
.removeAttributes(names
);
695 SmallAttributeSet small
= createSmallAttributeSet(mutable
);
696 if (sharedAttributeSets
.containsKey(small
))
697 small
= (SmallAttributeSet
) sharedAttributeSets
.get(small
);
699 sharedAttributeSets
.put(small
,small
);
705 // FIXME: there's some sort of quasi-serialization stuff in here which I
706 // have left incomplete; I'm not sure I understand the intent properly.
708 public static Object
getStaticAttribute(Object key
)
710 throw new InternalError("not implemented");
713 public static Object
getStaticAttributeKey(Object key
)
715 throw new InternalError("not implemented");
718 public static void readAttributeSet(ObjectInputStream in
, MutableAttributeSet a
)
719 throws ClassNotFoundException
, IOException
721 throw new InternalError("not implemented");
724 public static void writeAttributeSet(ObjectOutputStream out
, AttributeSet a
)
727 throw new InternalError("not implemented");
730 public void readAttributes(ObjectInputStream in
, MutableAttributeSet a
)
731 throws ClassNotFoundException
, IOException
733 throw new InternalError("not implemented");
736 public void writeAttributes(ObjectOutputStream out
, AttributeSet a
)
739 throw new InternalError("not implemented");