001 /* SimpleAttributeSet.java -- 002 Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package javax.swing.text; 040 041 import java.io.Serializable; 042 import java.util.Enumeration; 043 import java.util.Hashtable; 044 045 /** 046 * A set of attributes. 047 */ 048 public class SimpleAttributeSet 049 implements MutableAttributeSet, Serializable, Cloneable 050 { 051 /** The serialization UID (compatible with JDK1.5). */ 052 private static final long serialVersionUID = 8267656273837665219L; 053 054 /** 055 * An empty attribute set. 056 */ 057 public static final AttributeSet EMPTY = new EmptyAttributeSet(); 058 059 /** Storage for the attributes. */ 060 Hashtable tab; 061 062 /** 063 * Creates a new attribute set that is initially empty. 064 */ 065 public SimpleAttributeSet() 066 { 067 tab = new Hashtable(); 068 } 069 070 /** 071 * Creates a new <code>SimpleAttributeSet</code> with the same attributes 072 * and resolve parent as the specified set. 073 * 074 * @param a the attributes (<code>null</code> not permitted). 075 * 076 * @throws NullPointerException if <code>a</code> is <code>null</code>. 077 */ 078 public SimpleAttributeSet(AttributeSet a) 079 { 080 tab = new Hashtable(); 081 addAttributes(a); 082 } 083 084 /** 085 * Adds an attribute with the given <code>name</code> and <code>value</code> 086 * to the set. If the set already contains an attribute with the given 087 * <code>name</code>, the attribute value is updated. 088 * 089 * @param name the attribute name (<code>null</code> not permitted). 090 * @param value the value (<code>null</code> not permitted). 091 * 092 * @throws NullPointerException if either argument is <code>null</code>. 093 */ 094 public void addAttribute(Object name, Object value) 095 { 096 tab.put(name, value); 097 } 098 099 /** 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 attr = null; 127 try 128 { 129 attr = (SimpleAttributeSet) super.clone(); 130 attr.tab = (Hashtable) tab.clone(); 131 } 132 catch (CloneNotSupportedException ex) 133 { 134 assert false; 135 } 136 return attr; 137 } 138 139 /** 140 * Returns true if the given name and value represent an attribute 141 * found either in this AttributeSet or in its resolve parent hierarchy. 142 * @param name the key for the attribute 143 * @param value the value for the attribute 144 * @return true if the attribute is found here or in this set's resolve 145 * parent hierarchy 146 */ 147 public boolean containsAttribute(Object name, Object value) 148 { 149 if (value == null) 150 throw new NullPointerException("Null 'value' argument."); 151 if (tab.containsKey(name)) 152 return tab.get(name).equals(value); 153 else 154 { 155 AttributeSet p = getResolveParent(); 156 if (p != null) 157 return p.containsAttribute(name, value); 158 else 159 return false; 160 } 161 } 162 163 /** 164 * Returns true if the given name and value are found in this AttributeSet. 165 * Does not check the resolve parent. 166 * @param name the key for the attribute 167 * @param value the value for the attribute 168 * @return true if the attribute is found in this AttributeSet 169 */ 170 boolean containsAttributeLocally(Object name, Object value) 171 { 172 return tab.containsKey(name) 173 && tab.get(name).equals(value); 174 } 175 176 /** 177 * Returns <code>true</code> of this <code>AttributeSet</code> contains all 178 * of the specified <code>attributes</code>. 179 * 180 * @param attributes the requested attributes 181 * 182 * @return <code>true</code> of this <code>AttributeSet</code> contains all 183 * of the specified <code>attributes</code> 184 */ 185 public boolean containsAttributes(AttributeSet attributes) 186 { 187 Enumeration e = attributes.getAttributeNames(); 188 while (e.hasMoreElements()) 189 { 190 Object name = e.nextElement(); 191 Object val = attributes.getAttribute(name); 192 if (! containsAttribute(name, val)) 193 return false; 194 } 195 return true; 196 } 197 198 /** 199 * Creates and returns a copy of this <code>AttributeSet</code>. 200 * 201 * @return a copy of this <code>AttributeSet</code> 202 */ 203 public AttributeSet copyAttributes() 204 { 205 return (AttributeSet) clone(); 206 } 207 208 /** 209 * Checks this set for equality with an arbitrary object. 210 * 211 * @param obj the object (<code>null</code> permitted). 212 * 213 * @return <code>true</code> if this set is equal to <code>obj</code>, and 214 * <code>false</code> otherwise. 215 */ 216 public boolean equals(Object obj) 217 { 218 return 219 (obj instanceof AttributeSet) 220 && this.isEqual((AttributeSet) obj); 221 } 222 223 /** 224 * Returns the value of the specified attribute, or <code>null</code> if 225 * there is no attribute with that name. If the attribute is not defined 226 * directly in this set, the parent hierarchy (if there is one) will be 227 * used. 228 * 229 * @param name the attribute (<code>null</code> not permitted). 230 * 231 * @throws NullPointerException if <code>name</code> is <code>null</code>. 232 */ 233 public Object getAttribute(Object name) 234 { 235 Object val = tab.get(name); 236 if (val != null) 237 return val; 238 239 AttributeSet p = getResolveParent(); 240 if (p != null) 241 return p.getAttribute(name); 242 243 return null; 244 } 245 246 /** 247 * Returns the number of attributes stored in this set, plus 1 if a parent 248 * has been specified (the reference to the parent is stored as a special 249 * attribute). The attributes stored in the parent do NOT contribute 250 * to the count. 251 * 252 * @return The attribute count. 253 */ 254 public int getAttributeCount() 255 { 256 return tab.size(); 257 } 258 259 /** 260 * Returns an enumeration of the attribute names. 261 * 262 * @return An enumeration of the attribute names. 263 */ 264 public Enumeration<?> getAttributeNames() 265 { 266 return tab.keys(); 267 } 268 269 /** 270 * Returns the resolving parent. 271 * 272 * @return The resolving parent (possibly <code>null</code>). 273 * 274 * @see #setResolveParent(AttributeSet) 275 */ 276 public AttributeSet getResolveParent() 277 { 278 return (AttributeSet) tab.get(ResolveAttribute); 279 } 280 281 /** 282 * Returns a hash code for this instance. 283 * 284 * @return A hash code. 285 */ 286 public int hashCode() 287 { 288 return tab.hashCode(); 289 } 290 291 /** 292 * Returns <code>true</code> if the given attribute is defined in this set, 293 * and <code>false</code> otherwise. The parent attribute set is not 294 * checked. 295 * 296 * @param attrName the attribute name (<code>null</code> not permitted). 297 */ 298 public boolean isDefined(Object attrName) 299 { 300 return tab.containsKey(attrName); 301 } 302 303 /** 304 * Returns <code>true</code> if the set contains no attributes, and 305 * <code>false</code> otherwise. Note that the resolving parent is 306 * stored as an attribute, so this method will return <code>false</code> if 307 * a resolving parent is set. 308 * 309 * @return <code>true</code> if the set contains no attributes, and 310 * <code>false</code> otherwise. 311 */ 312 public boolean isEmpty() 313 { 314 return tab.isEmpty(); 315 } 316 317 /** 318 * Returns true if the given set has the same number of attributes 319 * as this set and <code>containsAttributes(attr)</code> returns 320 * <code>true</code>. 321 * 322 * @param attr the attribute set (<code>null</code> not permitted). 323 * 324 * @return A boolean. 325 * 326 * @throws NullPointerException if <code>attr</code> is <code>null</code>. 327 */ 328 public boolean isEqual(AttributeSet attr) 329 { 330 return getAttributeCount() == attr.getAttributeCount() 331 && this.containsAttributes(attr); 332 } 333 334 /** 335 * Removes the attribute with the specified <code>name</code>, if this 336 * attribute is defined. This method will only remove an attribute from 337 * this set, not from the resolving parent. 338 * 339 * @param name the attribute name (<code>null</code> not permitted). 340 * 341 * @throws NullPointerException if <code>name</code> is <code>null</code>. 342 */ 343 public void removeAttribute(Object name) 344 { 345 tab.remove(name); 346 } 347 348 /** 349 * Removes attributes from this set if they are found in the 350 * given set. Only attributes whose key AND value are removed. 351 * Removes attributes only from this set, not from the resolving parent. 352 * Since the resolving parent is stored as an attribute, if 353 * <code>attributes</code> has the same resolving parent as this set, the 354 * parent will be removed from this set. 355 * 356 * @param attributes the attributes (<code>null</code> not permitted). 357 */ 358 public void removeAttributes(AttributeSet attributes) 359 { 360 Enumeration e = attributes.getAttributeNames(); 361 while (e.hasMoreElements()) 362 { 363 Object name = e.nextElement(); 364 Object val = attributes.getAttribute(name); 365 if (containsAttributeLocally(name, val)) 366 removeAttribute(name); 367 } 368 } 369 370 /** 371 * Removes the attributes listed in <code>names</code>. 372 * 373 * @param names the attribute names (<code>null</code> not permitted). 374 * 375 * @throws NullPointerException if <code>names</code> is <code>null</code> 376 * or contains any <code>null</code> values. 377 */ 378 public void removeAttributes(Enumeration<?> names) 379 { 380 while (names.hasMoreElements()) 381 { 382 removeAttribute(names.nextElement()); 383 } 384 } 385 386 /** 387 * Sets the reolving parent for this set. When looking up an attribute, if 388 * it is not found in this set, then the resolving parent is also used for 389 * the lookup. 390 * <p> 391 * Note that the parent is stored as an attribute, and will contribute 1 to 392 * the count returned by {@link #getAttributeCount()}. 393 * 394 * @param parent the parent attribute set (<code>null</code> not permitted). 395 * 396 * @throws NullPointerException if <code>parent</code> is <code>null</code>. 397 * 398 * @see #setResolveParent(AttributeSet) 399 */ 400 public void setResolveParent(AttributeSet parent) 401 { 402 addAttribute(ResolveAttribute, parent); 403 } 404 405 /** 406 * Returns a string representation of this instance, typically used for 407 * debugging purposes. 408 * 409 * @return A string representation of this instance. 410 */ 411 public String toString() 412 { 413 return tab.toString(); 414 } 415 }