OSDN Git Service

2004-11-30 Thomas Fitzsimmons <fitzsim@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / javax / swing / text / StyleContext.java
1 /* StyleContext.java --
2    Copyright (C) 2004 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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
19 02111-1307 USA.
20
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.
25
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. */
37
38
39 package javax.swing.text;
40
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;
52
53 import javax.swing.event.ChangeEvent;
54 import javax.swing.event.ChangeListener;
55 import javax.swing.event.EventListenerList;
56
57 public class StyleContext 
58     implements Serializable, AbstractDocument.AttributeContext
59 {
60   public class NamedStyle
61     implements Serializable, Style
62   {
63     protected ChangeEvent changeEvent;
64     protected EventListenerList listenerList;
65       
66     AttributeSet attributes;
67     String name;
68
69     public NamedStyle()
70     {
71       this(null, null);
72     }
73
74     public NamedStyle(Style parent)
75     {
76       this(null, parent);
77     }
78
79     public NamedStyle(String name, Style parent)
80     {
81       this.name = name;
82       this.attributes = getEmptySet();
83       this.changeEvent = new ChangeEvent(this);
84       this.listenerList = new EventListenerList();
85       setResolveParent(parent);
86     }
87
88     public String getName()
89     {
90       return name;
91     }
92
93     public void setName(String n)
94     {
95       name = n;
96       fireStateChanged();
97     }
98
99     public void addChangeListener(ChangeListener l)
100     {
101       listenerList.add(ChangeListener.class, l);
102     }
103       
104     public void removeChangeListener(ChangeListener l)
105     {
106       listenerList.remove(ChangeListener.class, l);
107     }
108       
109     public EventListener[] getListeners(Class listenerType)
110     {
111       return listenerList.getListeners(listenerType);
112     }
113
114     public ChangeListener[] getChangeListeners()
115     {
116       return (ChangeListener[]) getListeners(ChangeListener.class);
117     }
118
119     protected  void fireStateChanged()
120     {
121       ChangeListener[] listeners = getChangeListeners();
122       for (int i = 0; i < listeners.length; ++i)
123         {
124           listeners[i].stateChanged(changeEvent);
125         }
126     }
127
128     public void addAttribute(Object name, Object value)
129     {
130       attributes = StyleContext.this.addAttribute(attributes, name, value);
131       fireStateChanged();
132     }
133
134     public void addAttributes(AttributeSet attr)
135     {
136       attributes = StyleContext.this.addAttributes(attributes, attr);
137       fireStateChanged();
138     }
139
140     public boolean containsAttribute(Object name, Object value)
141     {
142       return attributes.containsAttribute(name, value);
143     }
144       
145     public boolean containsAttributes(AttributeSet attrs)
146     {
147       return attributes.containsAttributes(attrs);
148     }
149
150     public AttributeSet copyAttributes()
151     {
152       return attributes.copyAttributes();
153     }
154             
155     public Object getAttribute(Object attrName)
156     {
157       return attributes.getAttribute(attrName);
158     }
159
160     public int getAttributeCount()
161     {
162       return attributes.getAttributeCount();
163     }
164
165     public Enumeration getAttributeNames()
166     {
167       return attributes.getAttributeNames();
168     }
169       
170     public boolean isDefined(Object attrName)
171     {
172       return attributes.isDefined(attrName);        
173     }
174
175     public boolean isEqual(AttributeSet attr)
176     {
177       return attributes.isEqual(attr);
178     }
179
180     public void removeAttribute(Object name)
181     {
182       attributes = StyleContext.this.removeAttribute(attributes, name);
183       fireStateChanged();
184     }
185
186     public void removeAttributes(AttributeSet attrs)
187     {
188       attributes = StyleContext.this.removeAttributes(attributes, attrs);
189       fireStateChanged();
190     }
191
192     public void removeAttributes(Enumeration names)
193     {
194       attributes = StyleContext.this.removeAttributes(attributes, names);
195       fireStateChanged();
196     }
197
198
199     public AttributeSet getResolveParent()
200     {
201       return attributes.getResolveParent();        
202     }
203
204     public void setResolveParent(AttributeSet parent)
205     {
206       attributes = StyleContext.this.addAttribute(attributes, ResolveAttribute, parent);
207       fireStateChanged();
208     }
209       
210     public String toString()
211     {
212       return ("[NamedStyle: name=" + name + ", attrs=" + attributes.toString() + "]");
213     }      
214   }
215   
216   public class SmallAttributeSet
217     implements AttributeSet
218   {
219     final Object [] attrs;
220     public SmallAttributeSet(AttributeSet a)
221     {
222       if (a == null)
223         attrs = new Object[0];
224       else
225         {
226           int n = a.getAttributeCount();
227           int i = 0;
228           attrs = new Object[n * 2];
229           Enumeration e = a.getAttributeNames();
230           while (e.hasMoreElements())
231             {
232               Object name = e.nextElement();
233               attrs[i++] = name;
234               attrs[i++] = a.getAttribute(name);
235             }
236         }
237     }
238
239     public SmallAttributeSet(Object [] a)
240     {
241       if (a == null)
242         attrs = new Object[0];
243       else
244         {
245           attrs = new Object[a.length];
246           System.arraycopy(a, 0, attrs, 0, a.length);
247         }
248     }
249
250     public Object clone()
251     {
252       return new SmallAttributeSet(this.attrs);
253     }
254
255     public boolean containsAttribute(Object name, Object value)
256     {
257       for (int i = 0; i < attrs.length; i += 2)
258         {
259           if (attrs[i].equals(name) &&
260               attrs[i+1].equals(value))
261             return true;
262         }
263       return false;
264     }
265
266     public boolean containsAttributes(AttributeSet a)
267     {
268       Enumeration e = a.getAttributeNames();
269       while (e.hasMoreElements())
270         {
271           Object name = e.nextElement();
272           Object val = a.getAttribute(name);
273           if (!containsAttribute(name, val))
274             return false;
275         }
276       return true;                      
277     }
278
279     public AttributeSet copyAttributes()
280     {
281       return (AttributeSet) clone();
282     }
283
284     public boolean equals(Object obj)
285     {
286       return 
287         (obj instanceof SmallAttributeSet)
288         && this.isEqual((AttributeSet)obj);
289     }
290  
291     public Object getAttribute(Object key)
292     {
293       for (int i = 0; i < attrs.length; i += 2)
294         {
295           if (attrs[i].equals(key))
296             return attrs[i+1];
297         }
298             
299       Object p = getResolveParent();
300       if (p != null && p instanceof AttributeSet)
301         return (((AttributeSet)p).getAttribute(key));
302       
303       return null;
304     }
305
306     public int getAttributeCount()
307     {
308       return attrs.length / 2;
309     }
310
311     public Enumeration getAttributeNames()
312     {      
313       return new Enumeration() 
314         {
315           int i = 0;
316           public boolean hasMoreElements() 
317           { 
318             return i < attrs.length; 
319           }
320           public Object nextElement() 
321           { 
322             i += 2; 
323             return attrs[i-2]; 
324           }
325         };
326     }
327
328     public AttributeSet getResolveParent()
329     {
330       return (AttributeSet) getAttribute(ResolveAttribute);
331     }
332
333     public int hashCode()
334     {
335       return java.util.Arrays.asList(attrs).hashCode();
336     }
337
338     public boolean isDefined(Object key)
339     {
340       for (int i = 0; i < attrs.length; i += 2)
341         {
342           if (attrs[i].equals(key))
343             return true;
344         }
345       return false;
346     }
347         
348     public boolean isEqual(AttributeSet attr)
349     {
350       return attr != null 
351         && attr.containsAttributes(this)
352         && this.containsAttributes(attr);
353     }
354         
355     public String toString()
356     {
357       StringBuffer sb = new StringBuffer();
358       sb.append("[StyleContext.SmallattributeSet:");
359       for (int i = 0; i < attrs.length; ++i)
360         {
361           sb.append(" (");
362           sb.append(attrs[i].toString());
363           sb.append("=");
364           sb.append(attrs[i+1].toString());
365           sb.append(")");
366         }
367       sb.append("]");
368       return sb.toString();
369     }
370   }
371
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.
375   //
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.
379
380   public static final String DEFAULT_STYLE = "default";
381   
382   static Hashtable sharedAttributeSets = new Hashtable();
383   static Hashtable sharedFonts = new Hashtable();
384
385   static StyleContext defaultStyleContext = new StyleContext();
386   static final int compressionThreshold = 9;
387   
388   EventListenerList listenerList;
389   Hashtable styleTable;
390   
391   public StyleContext()
392   {
393     listenerList = new EventListenerList();
394     styleTable = new Hashtable();
395   }
396
397   protected SmallAttributeSet createSmallAttributeSet(AttributeSet a)
398   {
399     return new SmallAttributeSet(a);
400   }
401   
402   protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
403   {
404     return new SimpleAttributeSet(a);
405   }
406
407   public void addChangeListener(ChangeListener listener)
408   {
409     listenerList.add(ChangeListener.class, listener);
410   }
411
412   public void removeChangeListener(ChangeListener listener)
413   {
414     listenerList.remove(ChangeListener.class, listener);
415   }
416
417   public ChangeListener[] getChangeListeners()
418   {
419     return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
420   }
421     
422   public Style addStyle(String name, Style parent)
423   {
424     Style newStyle = new NamedStyle(name, parent);
425     if (name != null)
426       styleTable.put(name, newStyle);
427     return newStyle;
428   }
429
430   public void removeStyle(String name)
431   {
432     styleTable.remove(name);
433   }
434
435   public Style getStyle(String name)
436   {
437     return (Style) styleTable.get(name);
438   }
439
440   public Enumeration getStyleNames()
441   {
442     return styleTable.keys();
443   }
444
445   //
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.
451   //
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).
455   //
456   // We keep a static cache mapping SimpleFontSpecs to java.awt.Fonts, so
457   // that we reuse Fonts between styles and style contexts.
458   // 
459
460   private static class SimpleFontSpec
461   {
462     String family;
463     int style;
464     int size;
465     public SimpleFontSpec(String family,
466                           int style,
467                           int size)
468     {
469       this.family = family;
470       this.style = style;
471       this.size = size;
472     }
473     public boolean equals(Object obj)
474     {
475       return (obj != null)
476         && (obj instanceof SimpleFontSpec)
477         && (((SimpleFontSpec)obj).family.equals(this.family))
478         && (((SimpleFontSpec)obj).style == this.style)
479         && (((SimpleFontSpec)obj).size == this.size);
480     }
481     public int hashCode()
482     {
483       return family.hashCode() + style + size;
484     }
485   }
486   
487   public Font getFont(AttributeSet attr)
488   {
489     String family = StyleConstants.getFontFamily(attr);
490     int style = Font.PLAIN;
491     if (StyleConstants.isBold(attr))
492       style += Font.BOLD;
493     if (StyleConstants.isItalic(attr))
494       style += Font.ITALIC;      
495     int size = StyleConstants.getFontSize(attr);
496     return getFont(family, style, size);
497   }
498
499   public Font getFont(String family, int style, int size)
500   {
501     SimpleFontSpec spec = new SimpleFontSpec(family, style, size);
502     if (sharedFonts.containsKey(spec))
503       return (Font) sharedFonts.get(spec);
504     else
505       {
506         Font tmp = new Font(family, style, size);
507         sharedFonts.put(spec, tmp);
508         return tmp;
509       }
510   }
511   
512   public FontMetrics getFontMetrics(Font f)
513   {
514     return Toolkit.getDefaultToolkit().getFontMetrics(f);
515   }
516
517   public Color getForeground(AttributeSet a)
518   {
519     return StyleConstants.getForeground(a);
520   }
521
522   public Color getBackground(AttributeSet a)
523   {
524     return StyleConstants.getBackground(a);
525   }
526
527   protected int getCompressionThreshold() 
528   {
529     return compressionThreshold;
530   }
531
532   public static StyleContext getDefaultStyleContext()
533   {
534     return defaultStyleContext;
535   }
536
537   public AttributeSet addAttribute(AttributeSet old, Object name, Object value)
538   {
539     if (old instanceof MutableAttributeSet)
540       {
541         ((MutableAttributeSet)old).addAttribute(name, value);
542         return old;
543       }
544     else 
545       {
546         MutableAttributeSet mutable = createLargeAttributeSet(old);
547         mutable.addAttribute(name, value);
548         if (mutable.getAttributeCount() >= getCompressionThreshold())
549           return mutable;
550         else
551           {
552             SmallAttributeSet small = createSmallAttributeSet(mutable);
553             if (sharedAttributeSets.containsKey(small))
554               small = (SmallAttributeSet) sharedAttributeSets.get(small);
555             else
556               sharedAttributeSets.put(small,small);
557             return small;
558           }
559       }
560   }
561
562   public AttributeSet addAttributes(AttributeSet old, AttributeSet attributes)
563   {
564     if (old instanceof MutableAttributeSet)
565       {
566         ((MutableAttributeSet)old).addAttributes(attributes);
567         return old;
568       }
569     else 
570       {
571         MutableAttributeSet mutable = createLargeAttributeSet(old);
572         mutable.addAttributes(attributes);
573         if (mutable.getAttributeCount() >= getCompressionThreshold())
574           return mutable;
575         else
576           {
577             SmallAttributeSet small = createSmallAttributeSet(mutable);
578             if (sharedAttributeSets.containsKey(small))
579               small = (SmallAttributeSet) sharedAttributeSets.get(small);
580             else
581               sharedAttributeSets.put(small,small);
582             return small;
583           }
584       }
585   }
586
587   public AttributeSet getEmptySet()
588   {
589     AttributeSet e = createSmallAttributeSet(null);
590     if (sharedAttributeSets.containsKey(e))
591       e = (AttributeSet) sharedAttributeSets.get(e);
592     else
593       sharedAttributeSets.put(e, e);
594     return e;
595   }
596
597   public void reclaim(AttributeSet attributes)
598   {
599     if (sharedAttributeSets.containsKey(attributes))
600       sharedAttributeSets.remove(attributes);
601   }
602
603   public AttributeSet removeAttribute(AttributeSet old, Object name)
604   {
605     if (old instanceof MutableAttributeSet)
606       {
607         ((MutableAttributeSet)old).removeAttribute(name);
608         if (old.getAttributeCount() < getCompressionThreshold())
609           {
610             SmallAttributeSet small = createSmallAttributeSet(old);
611             if (!sharedAttributeSets.containsKey(small))
612               sharedAttributeSets.put(small,small);
613             old = (AttributeSet) sharedAttributeSets.get(small);
614           }
615         return old;
616       }
617     else 
618       {          
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);
624         else
625           sharedAttributeSets.put(small,small);
626         return small;
627       }
628   }
629
630   public AttributeSet removeAttributes(AttributeSet old, AttributeSet attributes)
631   {
632     return removeAttributes(old, attributes.getAttributeNames());
633   }
634
635   public AttributeSet removeAttributes(AttributeSet old, Enumeration names)
636   {
637     if (old instanceof MutableAttributeSet)
638       {
639         ((MutableAttributeSet)old).removeAttributes(names);
640         if (old.getAttributeCount() < getCompressionThreshold())
641           {
642             SmallAttributeSet small = createSmallAttributeSet(old);
643             if (!sharedAttributeSets.containsKey(small))
644               sharedAttributeSets.put(small,small);
645             old = (AttributeSet) sharedAttributeSets.get(small);
646           }
647         return old;
648       }
649     else 
650       {          
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);
656         else
657           sharedAttributeSets.put(small,small);
658         return small;
659       } 
660   }
661
662
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.
665
666   public static Object getStaticAttribute(Object key)
667   {
668     throw new InternalError("not implemented");
669   }
670   
671   public static Object getStaticAttributeKey(Object key)
672   {
673     throw new InternalError("not implemented");
674   }
675
676   public static void readAttributeSet(ObjectInputStream in, MutableAttributeSet a)
677     throws ClassNotFoundException, IOException
678   {
679     throw new InternalError("not implemented");
680   }
681   
682   public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a)
683     throws IOException
684   {
685     throw new InternalError("not implemented");
686   }
687
688   public void readAttributes(ObjectInputStream in, MutableAttributeSet a)
689     throws ClassNotFoundException, IOException 
690   {
691     throw new InternalError("not implemented");
692   }
693
694   public void writeAttributes(ObjectOutputStream out, AttributeSet a)
695     throws IOException
696   {
697     throw new InternalError("not implemented");
698   }
699 }