Source for javax.swing.text.SimpleAttributeSet

   1: /* SimpleAttributeSet.java --
   2:    Copyright (C) 2004, 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 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.io.Serializable;
  42: import java.util.Enumeration;
  43: import java.util.Hashtable;
  44: 
  45: /**
  46:  * A set of attributes.
  47:  */
  48: public class SimpleAttributeSet
  49:   implements MutableAttributeSet, Serializable, Cloneable
  50: {
  51:   /** The serialization UID (compatible with JDK1.5). */
  52:   private static final long serialVersionUID = 8267656273837665219L;
  53: 
  54:   /**
  55:    * An empty attribute set.
  56:    */
  57:   public static final AttributeSet EMPTY = new EmptyAttributeSet();
  58: 
  59:   /** Storage for the attributes. */
  60:   Hashtable tab;
  61: 
  62:   /**
  63:    * Creates a new attribute set that is initially empty.
  64:    */
  65:   public SimpleAttributeSet()
  66:   {
  67:     tab = new Hashtable();
  68:   }
  69:   
  70:   /**
  71:    * Creates a new <code>SimpleAttributeSet</code> with the same attributes
  72:    * and resolve parent as the specified set.
  73:    * 
  74:    * @param a  the attributes (<code>null</code> not permitted).
  75:    * 
  76:    * @throws NullPointerException if <code>a</code> is <code>null</code>.
  77:    */
  78:   public SimpleAttributeSet(AttributeSet a)
  79:   {
  80:     tab = new Hashtable();
  81:     addAttributes(a);
  82:   }
  83: 
  84:   /**
  85:    * Adds an attribute with the given <code>name</code> and <code>value</code>
  86:    * to the set.  If the set already contains an attribute with the given
  87:    * <code>name</code>, the attribute value is updated.
  88:    * 
  89:    * @param name  the attribute name (<code>null</code> not permitted).
  90:    * @param value  the value (<code>null</code> not permitted).
  91:    * 
  92:    * @throws NullPointerException if either argument is <code>null</code>.
  93:    */
  94:   public void addAttribute(Object name, Object value)
  95:   {
  96:     tab.put(name, value);
  97:   }
  98: 
  99:   /**
 100:    * Adds all the attributes from <code>attributes</code> to this set.
 101:    * 
 102:    * @param attributes  the set of attributes to add (<code>null</code> not
 103:    *                    permitted).
 104:    *                    
 105:    * @throws NullPointerException if <code>attributes</code> is 
 106:    *         <code>null</code>.
 107:    */
 108:   public void addAttributes(AttributeSet attributes)
 109:   {
 110:     Enumeration e = attributes.getAttributeNames();
 111:     while (e.hasMoreElements())
 112:       {
 113:         Object name = e.nextElement();
 114:         Object val = attributes.getAttribute(name);
 115:         tab.put(name, val);
 116:       }
 117:   }
 118: 
 119:   /**
 120:    * Returns a clone of the attribute set.
 121:    * 
 122:    * @return A clone of the attribute set.
 123:    */
 124:   public Object clone()
 125:   {
 126:     SimpleAttributeSet s = new SimpleAttributeSet();
 127:     s.tab = (Hashtable) tab.clone();
 128:     return s;
 129:   }
 130: 
 131:   /**
 132:    * Returns true if the given name and value represent an attribute
 133:    * found either in this AttributeSet or in its resolve parent hierarchy.
 134:    * @param name the key for the attribute
 135:    * @param value the value for the attribute
 136:    * @return true if the attribute is found here or in this set's resolve
 137:    * parent hierarchy
 138:    */
 139:   public boolean containsAttribute(Object name, Object value)
 140:   {
 141:     if (value == null)
 142:       throw new NullPointerException("Null 'value' argument.");
 143:     if (tab.containsKey(name))
 144:       return tab.get(name).equals(value);
 145:     else
 146:       {
 147:         AttributeSet p = getResolveParent();
 148:         if (p != null)
 149:           return p.containsAttribute(name, value);
 150:         else
 151:           return false;
 152:       }
 153:   }
 154:   
 155:   /**
 156:    * Returns true if the given name and value are found in this AttributeSet.
 157:    * Does not check the resolve parent.
 158:    * @param name the key for the attribute
 159:    * @param value the value for the attribute
 160:    * @return true if the attribute is found in this AttributeSet
 161:    */
 162:   boolean containsAttributeLocally(Object name, Object value)
 163:   {
 164:     return tab.containsKey(name) 
 165:       && tab.get(name).equals(value);
 166:   }
 167: 
 168:   /**
 169:    * Returns <code>true</code> of this <code>AttributeSet</code> contains all
 170:    * of the specified <code>attributes</code>.
 171:    *
 172:    * @param attributes the requested attributes
 173:    *
 174:    * @return <code>true</code> of this <code>AttributeSet</code> contains all
 175:    *         of the specified <code>attributes</code>
 176:    */
 177:   public boolean containsAttributes(AttributeSet attributes)
 178:   {
 179:     Enumeration e = attributes.getAttributeNames();
 180:     while (e.hasMoreElements())
 181:       {
 182:         Object name = e.nextElement();
 183:         Object val = attributes.getAttribute(name);
 184:         if (! containsAttribute(name, val))
 185:           return false;        
 186:       }
 187:     return true;
 188:   }
 189: 
 190:   /**
 191:    * Creates and returns a copy of this <code>AttributeSet</code>.
 192:    *
 193:    * @return a copy of this <code>AttributeSet</code>
 194:    */
 195:   public AttributeSet copyAttributes()
 196:   {
 197:     return (AttributeSet) clone();
 198:   }
 199: 
 200:   /**
 201:    * Checks this set for equality with an arbitrary object.
 202:    * 
 203:    * @param obj  the object (<code>null</code> permitted).
 204:    * 
 205:    * @return <code>true</code> if this set is equal to <code>obj</code>, and
 206:    *         <code>false</code> otherwise. 
 207:    */
 208:   public boolean equals(Object obj)
 209:   {
 210:     return 
 211:       (obj instanceof AttributeSet)
 212:       && this.isEqual((AttributeSet) obj);
 213:   }
 214: 
 215:   /**
 216:    * Returns the value of the specified attribute, or <code>null</code> if 
 217:    * there is no attribute with that name.  If the attribute is not defined
 218:    * directly in this set, the parent hierarchy (if there is one) will be
 219:    * used.
 220:    * 
 221:    * @param name  the attribute (<code>null</code> not permitted).
 222:    * 
 223:    * @throws NullPointerException if <code>name</code> is <code>null</code>.
 224:    */
 225:   public Object getAttribute(Object name)
 226:   {
 227:     Object val = tab.get(name);
 228:     if (val != null) 
 229:       return val;
 230: 
 231:     AttributeSet p = getResolveParent();
 232:     if (p != null)
 233:       return p.getAttribute(name);
 234: 
 235:     return null;
 236:   }
 237: 
 238:   /**
 239:    * Returns the number of attributes stored in this set, plus 1 if a parent
 240:    * has been specified (the reference to the parent is stored as a special 
 241:    * attribute).  The attributes stored in the parent do NOT contribute
 242:    * to the count.
 243:    * 
 244:    * @return The attribute count.
 245:    */
 246:   public int getAttributeCount()
 247:   {
 248:     return tab.size();
 249:   }
 250: 
 251:   /**
 252:    * Returns an enumeration of the attribute names.
 253:    * 
 254:    * @return An enumeration of the attribute names.
 255:    */
 256:   public Enumeration getAttributeNames()
 257:   {
 258:     return tab.keys();
 259:   }
 260: 
 261:   /**
 262:    * Returns the resolving parent.
 263:    * 
 264:    * @return The resolving parent (possibly <code>null</code>).
 265:    * 
 266:    * @see #setResolveParent(AttributeSet)
 267:    */
 268:   public AttributeSet getResolveParent()
 269:   {
 270:     return (AttributeSet) tab.get(ResolveAttribute);
 271:   }
 272: 
 273:   /**
 274:    * Returns a hash code for this instance.
 275:    * 
 276:    * @return A hash code.
 277:    */
 278:   public int hashCode()
 279:   {
 280:     return tab.hashCode();
 281:   }
 282: 
 283:   /**
 284:    * Returns <code>true</code> if the given attribute is defined in this set,
 285:    * and <code>false</code> otherwise.  The parent attribute set is not
 286:    * checked.
 287:    * 
 288:    * @param attrName  the attribute name (<code>null</code> not permitted).
 289:    */
 290:   public boolean isDefined(Object attrName)
 291:   {
 292:     return tab.containsKey(attrName);
 293:   }
 294: 
 295:   /**
 296:    * Returns <code>true</code> if the set contains no attributes, and 
 297:    * <code>false</code> otherwise.  Note that the resolving parent is 
 298:    * stored as an attribute, so this method will return <code>false</code> if 
 299:    * a resolving parent is set.
 300:    * 
 301:    * @return <code>true</code> if the set contains no attributes, and 
 302:    * <code>false</code> otherwise.
 303:    */
 304:   public boolean isEmpty()
 305:   {
 306:     return tab.isEmpty();    
 307:   }
 308: 
 309:   /**
 310:    * Returns true if the given set has the same number of attributes
 311:    * as this set and <code>containsAttributes(attr)</code> returns
 312:    * <code>true</code>.
 313:    * 
 314:    * @param attr  the attribute set (<code>null</code> not permitted).
 315:    * 
 316:    * @return A boolean.
 317:    * 
 318:    * @throws NullPointerException if <code>attr</code> is <code>null</code>.
 319:    */
 320:   public boolean isEqual(AttributeSet attr)
 321:   {
 322:     return getAttributeCount() == attr.getAttributeCount()
 323:       && this.containsAttributes(attr);
 324:   }
 325:     
 326:   /**
 327:    * Removes the attribute with the specified <code>name</code>, if this 
 328:    * attribute is defined.  This method will only remove an attribute from
 329:    * this set, not from the resolving parent.
 330:    * 
 331:    * @param name  the attribute name (<code>null</code> not permitted).
 332:    * 
 333:    * @throws NullPointerException if <code>name</code> is <code>null</code>.
 334:    */
 335:   public void removeAttribute(Object name)
 336:   {
 337:     tab.remove(name);
 338:   }
 339: 
 340:   /**
 341:    * Removes attributes from this set if they are found in the 
 342:    * given set.  Only attributes whose key AND value are removed.
 343:    * Removes attributes only from this set, not from the resolving parent.  
 344:    * Since the resolving parent is stored as an attribute, if 
 345:    * <code>attributes</code> has the same resolving parent as this set, the
 346:    * parent will be removed from this set.
 347:    * 
 348:    * @param attributes  the attributes (<code>null</code> not permitted).
 349:    */
 350:   public void removeAttributes(AttributeSet attributes)
 351:   {
 352:     Enumeration e = attributes.getAttributeNames();
 353:     while (e.hasMoreElements())
 354:       {
 355:         Object name = e.nextElement();
 356:         Object val = attributes.getAttribute(name);
 357:         if (containsAttributeLocally(name, val))
 358:           removeAttribute(name);     
 359:       }
 360:   }
 361: 
 362:   /**
 363:    * Removes the attributes listed in <code>names</code>.
 364:    * 
 365:    * @param names  the attribute names (<code>null</code> not permitted).
 366:    * 
 367:    * @throws NullPointerException if <code>names</code> is <code>null</code> 
 368:    *         or contains any <code>null</code> values.
 369:    */
 370:   public void removeAttributes(Enumeration names)
 371:   {
 372:     while (names.hasMoreElements())
 373:       {
 374:         removeAttribute(names.nextElement());
 375:       }    
 376:   }
 377: 
 378:   /**
 379:    * Sets the reolving parent for this set.  When looking up an attribute, if
 380:    * it is not found in this set, then the resolving parent is also used for
 381:    * the lookup.
 382:    * <p>
 383:    * Note that the parent is stored as an attribute, and will contribute 1 to 
 384:    * the count returned by {@link #getAttributeCount()}. 
 385:    * 
 386:    * @param parent  the parent attribute set (<code>null</code> not permitted).
 387:    * 
 388:    * @throws NullPointerException if <code>parent</code> is <code>null</code>.
 389:    * 
 390:    * @see #setResolveParent(AttributeSet)
 391:    */
 392:   public void setResolveParent(AttributeSet parent)
 393:   {
 394:     addAttribute(ResolveAttribute, parent);
 395:   }
 396:   
 397:   /**
 398:    * Returns a string representation of this instance, typically used for
 399:    * debugging purposes.
 400:    * 
 401:    * @return A string representation of this instance.
 402:    */
 403:   public String toString()
 404:   {
 405:     return tab.toString();
 406:   }    
 407: }