Merge from mainline
[official-gcc.git] / libjava / classpath / javax / swing / text / StyleContext.java
blobdabc0ba9cd01b351f1112afb38d83b370cd34d58
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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;
42 import java.awt.Font;
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;
73 String name;
75 public NamedStyle()
77 this(null, null);
80 public NamedStyle(Style parent)
82 this(null, parent);
85 public NamedStyle(String name, Style parent)
87 this.name = name;
88 this.attributes = getEmptySet();
89 this.changeEvent = new ChangeEvent(this);
90 this.listenerList = new EventListenerList();
91 setResolveParent(parent);
94 public String getName()
96 return name;
99 public void setName(String n)
101 name = n;
102 fireStateChanged();
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);
137 fireStateChanged();
140 public void addAttributes(AttributeSet attr)
142 attributes = StyleContext.this.addAttributes(attributes, attr);
143 fireStateChanged();
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);
189 fireStateChanged();
192 public void removeAttributes(AttributeSet attrs)
194 attributes = StyleContext.this.removeAttributes(attributes, attrs);
195 fireStateChanged();
198 public void removeAttributes(Enumeration names)
200 attributes = StyleContext.this.removeAttributes(attributes, names);
201 fireStateChanged();
205 public AttributeSet getResolveParent()
207 return attributes.getResolveParent();
210 public void setResolveParent(AttributeSet parent)
212 if (parent != null)
214 attributes = StyleContext.this.addAttribute
215 (attributes, ResolveAttribute, parent);
217 fireStateChanged();
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)
232 if (a == null)
233 attrs = new Object[0];
234 else
236 int n = a.getAttributeCount();
237 int i = 0;
238 attrs = new Object[n * 2];
239 Enumeration e = a.getAttributeNames();
240 while (e.hasMoreElements())
242 Object name = e.nextElement();
243 attrs[i++] = name;
244 attrs[i++] = a.getAttribute(name);
249 public SmallAttributeSet(Object [] a)
251 if (a == null)
252 attrs = new Object[0];
253 else
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))
271 return true;
273 return false;
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))
284 return false;
286 return true;
289 public AttributeSet copyAttributes()
291 return (AttributeSet) clone();
294 public boolean equals(Object obj)
296 return
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))
306 return attrs[i+1];
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));
318 return null;
321 public int getAttributeCount()
323 return attrs.length / 2;
326 public Enumeration getAttributeNames()
328 return new Enumeration()
330 int i = 0;
331 public boolean hasMoreElements()
333 return i < attrs.length;
335 public Object nextElement()
337 i += 2;
338 return attrs[i-2];
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))
358 return true;
360 return false;
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)
375 sb.append(" (");
376 sb.append(attrs[i].toString());
377 sb.append("=");
378 sb.append(attrs[i+1].toString());
379 sb.append(")");
381 sb.append("]");
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);
452 if (name != null)
453 styleTable.put(name, newStyle);
454 return 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
503 String family;
504 int style;
505 int size;
506 public SimpleFontSpec(String family,
507 int style,
508 int size)
510 this.family = family;
511 this.style = style;
512 this.size = size;
514 public boolean equals(Object obj)
516 return (obj != null)
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))
533 style += Font.BOLD;
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);
545 else
547 Font tmp = new Font(family, style, size);
548 sharedFonts.put(spec, tmp);
549 return 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);
583 return old;
585 else
587 MutableAttributeSet mutable = createLargeAttributeSet(old);
588 mutable.addAttribute(name, value);
589 if (mutable.getAttributeCount() >= getCompressionThreshold())
590 return mutable;
591 else
593 SmallAttributeSet small = createSmallAttributeSet(mutable);
594 if (sharedAttributeSets.containsKey(small))
595 small = (SmallAttributeSet) sharedAttributeSets.get(small);
596 else
597 sharedAttributeSets.put(small,small);
598 return small;
603 public AttributeSet addAttributes(AttributeSet old, AttributeSet attributes)
605 if (old instanceof MutableAttributeSet)
607 ((MutableAttributeSet)old).addAttributes(attributes);
608 return old;
610 else
612 MutableAttributeSet mutable = createLargeAttributeSet(old);
613 mutable.addAttributes(attributes);
614 if (mutable.getAttributeCount() >= getCompressionThreshold())
615 return mutable;
616 else
618 SmallAttributeSet small = createSmallAttributeSet(mutable);
619 if (sharedAttributeSets.containsKey(small))
620 small = (SmallAttributeSet) sharedAttributeSets.get(small);
621 else
622 sharedAttributeSets.put(small,small);
623 return small;
628 public AttributeSet getEmptySet()
630 AttributeSet e = createSmallAttributeSet(null);
631 if (sharedAttributeSets.containsKey(e))
632 e = (AttributeSet) sharedAttributeSets.get(e);
633 else
634 sharedAttributeSets.put(e, e);
635 return 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);
656 return old;
658 else
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);
665 else
666 sharedAttributeSets.put(small,small);
667 return 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);
688 return old;
690 else
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);
697 else
698 sharedAttributeSets.put(small,small);
699 return 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)
724 throws IOException
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)
736 throws IOException
738 throw new InternalError("not implemented");