Frames | No Frames |
1: /* AttributedString.java -- Models text with attributes 2: Copyright (C) 1998, 1999, 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 java.text; 40: 41: import gnu.java.lang.CPStringBuilder; 42: 43: import java.util.ArrayList; 44: import java.util.Arrays; 45: import java.util.HashMap; 46: import java.util.Hashtable; 47: import java.util.Iterator; 48: import java.util.Map; 49: import java.util.Set; 50: 51: /** 52: * This class models a <code>String</code> with attributes over various 53: * subranges of the string. It allows applications to access this 54: * information via the <code>AttributedCharacterIterator</code> interface. 55: * 56: * @since 1.2 57: * 58: * @author Aaron M. Renn (arenn@urbanophile.com) 59: * @since 1.2 60: */ 61: public class AttributedString 62: { 63: 64: /** 65: * The attributes and ranges of text over which those attributes apply. 66: */ 67: final class AttributeRange 68: { 69: 70: /** A Map of the attributes */ 71: Map attribs; 72: 73: /** The beginning index of the attributes */ 74: int beginIndex; 75: 76: /** The ending index of the attributes */ 77: int endIndex; 78: 79: /** 80: * Creates a new attribute range. 81: * 82: * @param attribs the attributes. 83: * @param beginIndex the start index. 84: * @param endIndex the end index. 85: */ 86: AttributeRange(Map attribs, int beginIndex, int endIndex) 87: { 88: this.attribs = attribs; 89: this.beginIndex = beginIndex; 90: this.endIndex = endIndex; 91: } 92: 93: } // Inner class AttributeRange 94: 95: /** The string we are representing. */ 96: private StringCharacterIterator sci; 97: 98: /** The attribute information */ 99: private AttributeRange[] attribs; 100: 101: /** 102: * Creates a new instance of <code>AttributedString</code> 103: * that represents the specified <code>String</code> with no attributes. 104: * 105: * @param str The <code>String</code> to be attributed (<code>null</code> not 106: * permitted). 107: * 108: * @throws NullPointerException if <code>str</code> is <code>null</code>. 109: */ 110: public AttributedString(String str) 111: { 112: sci = new StringCharacterIterator(str); 113: attribs = new AttributeRange[0]; 114: } 115: 116: /** 117: * Creates a new instance of <code>AttributedString</code> 118: * that represents that specified <code>String</code> with the specified 119: * attributes over the entire length of the <code>String</code>. 120: * 121: * @param str The <code>String</code> to be attributed. 122: * @param attributes The attribute list. 123: */ 124: public AttributedString(String str, 125: Map<? extends AttributedCharacterIterator.Attribute, ?> attributes) 126: { 127: this(str); 128: 129: attribs = new AttributeRange[1]; 130: attribs[0] = new AttributeRange(attributes, 0, str.length()); 131: } 132: 133: /** 134: * Initializes a new instance of <code>AttributedString</code> 135: * that will use the text and attribute information from the specified 136: * <code>AttributedCharacterIterator</code>. 137: * 138: * @param aci The <code>AttributedCharacterIterator</code> containing the 139: * text and attribute information (<code>null</code> not 140: * permitted). 141: * 142: * @throws NullPointerException if <code>aci</code> is <code>null</code>. 143: */ 144: public AttributedString(AttributedCharacterIterator aci) 145: { 146: this(aci, aci.getBeginIndex(), aci.getEndIndex(), null); 147: } 148: 149: /** 150: * Initializes a new instance of <code>AttributedString</code> 151: * that will use the text and attribute information from the specified 152: * subrange of the specified <code>AttributedCharacterIterator</code>. 153: * 154: * @param aci The <code>AttributedCharacterIterator</code> containing the 155: * text and attribute information. 156: * @param beginIndex The beginning index of the text subrange. 157: * @param endIndex The ending index of the text subrange. 158: */ 159: public AttributedString(AttributedCharacterIterator aci, int beginIndex, 160: int endIndex) 161: { 162: this(aci, beginIndex, endIndex, null); 163: } 164: 165: /** 166: * Initializes a new instance of <code>AttributedString</code> 167: * that will use the text and attribute information from the specified 168: * subrange of the specified <code>AttributedCharacterIterator</code>. 169: * Only attributes from the source iterator that are present in the 170: * specified array of attributes will be included in the attribute list 171: * for this object. 172: * 173: * @param aci The <code>AttributedCharacterIterator</code> containing the 174: * text and attribute information. 175: * @param begin The beginning index of the text subrange. 176: * @param end The ending index of the text subrange. 177: * @param attributes A list of attributes to include from the iterator, or 178: * <code>null</code> to include all attributes. 179: */ 180: public AttributedString(AttributedCharacterIterator aci, int begin, int end, 181: AttributedCharacterIterator.Attribute[] attributes) 182: { 183: // Validate some arguments 184: if ((begin < 0) || (end < begin) || end > aci.getEndIndex()) 185: throw new IllegalArgumentException("Bad index values"); 186: 187: CPStringBuilder sb = new CPStringBuilder(""); 188: 189: // Get the valid attribute list 190: Set allAttribs = aci.getAllAttributeKeys(); 191: if (attributes != null) 192: allAttribs.retainAll(Arrays.asList(attributes)); 193: 194: // Loop through and extract the attributes 195: char c = aci.setIndex(begin); 196: 197: ArrayList accum = new ArrayList(); 198: do 199: { 200: sb.append(c); 201: 202: Iterator iter = allAttribs.iterator(); 203: while(iter.hasNext()) 204: { 205: Object obj = iter.next(); 206: 207: // What should we do if this is not true? 208: if (!(obj instanceof AttributedCharacterIterator.Attribute)) 209: continue; 210: 211: AttributedCharacterIterator.Attribute attrib = 212: (AttributedCharacterIterator.Attribute)obj; 213: 214: // Make sure the attribute is defined. 215: Object attribObj = aci.getAttribute(attrib); 216: if (attribObj == null) 217: continue; 218: int rl = aci.getRunLimit(attrib); 219: if (rl > end) 220: rl = end; 221: rl -= begin; 222: 223: // Check to see if we already processed this one 224: int rs = aci.getRunStart(attrib); 225: if ((rs < aci.getIndex()) && (aci.getIndex() != begin)) 226: continue; 227: 228: // If the attribute run starts before the beginning index, we 229: // need to junk it if it is an Annotation. 230: rs -= begin; 231: if (rs < 0) 232: { 233: if (attribObj instanceof Annotation) 234: continue; 235: 236: rs = 0; 237: } 238: 239: // Create a map object. Yes this will only contain one attribute 240: Map newMap = new Hashtable(); 241: newMap.put(attrib, attribObj); 242: 243: // Add it to the attribute list. 244: accum.add(new AttributeRange(newMap, rs, rl)); 245: } 246: 247: c = aci.next(); 248: } 249: while( aci.getIndex() < end ); 250: 251: attribs = new AttributeRange[accum.size()]; 252: attribs = (AttributeRange[]) accum.toArray(attribs); 253: 254: sci = new StringCharacterIterator(sb.toString()); 255: } 256: 257: /** 258: * Adds a new attribute that will cover the entire string. 259: * 260: * @param attrib The attribute to add. 261: * @param value The value of the attribute. 262: */ 263: public void addAttribute(AttributedCharacterIterator.Attribute attrib, 264: Object value) 265: { 266: addAttribute(attrib, value, 0, sci.getEndIndex()); 267: } 268: 269: /** 270: * Adds a new attribute that will cover the specified subrange 271: * of the string. 272: * 273: * @param attrib The attribute to add. 274: * @param value The value of the attribute, which may be <code>null</code>. 275: * @param begin The beginning index of the subrange. 276: * @param end The ending index of the subrange. 277: * 278: * @exception IllegalArgumentException If attribute is <code>null</code> or 279: * the subrange is not valid. 280: */ 281: public void addAttribute(AttributedCharacterIterator.Attribute attrib, 282: Object value, int begin, int end) 283: { 284: if (attrib == null) 285: throw new IllegalArgumentException("null attribute"); 286: if (end <= begin) 287: throw new IllegalArgumentException("Requires end > begin"); 288: HashMap hm = new HashMap(); 289: hm.put(attrib, value); 290: 291: addAttributes(hm, begin, end); 292: } 293: 294: /** 295: * Adds all of the attributes in the specified list to the 296: * specified subrange of the string. 297: * 298: * @param attributes The list of attributes. 299: * @param beginIndex The beginning index. 300: * @param endIndex The ending index 301: * 302: * @throws NullPointerException if <code>attributes</code> is 303: * <code>null</code>. 304: * @throws IllegalArgumentException if the subrange is not valid. 305: */ 306: public void addAttributes(Map<? extends AttributedCharacterIterator.Attribute, ?> attributes, 307: int beginIndex, int endIndex) 308: { 309: if (attributes == null) 310: throw new NullPointerException("null attribute"); 311: 312: if ((beginIndex < 0) || (endIndex > sci.getEndIndex()) || 313: (endIndex <= beginIndex)) 314: throw new IllegalArgumentException("bad range"); 315: 316: AttributeRange[] new_list = new AttributeRange[attribs.length + 1]; 317: System.arraycopy(attribs, 0, new_list, 0, attribs.length); 318: attribs = new_list; 319: attribs[attribs.length - 1] = new AttributeRange(attributes, beginIndex, 320: endIndex); 321: } 322: 323: /** 324: * Returns an <code>AttributedCharacterIterator</code> that 325: * will iterate over the entire string. 326: * 327: * @return An <code>AttributedCharacterIterator</code> for the entire string. 328: */ 329: public AttributedCharacterIterator getIterator() 330: { 331: return(new AttributedStringIterator(sci, attribs, 0, sci.getEndIndex(), 332: null)); 333: } 334: 335: /** 336: * Returns an <code>AttributedCharacterIterator</code> that 337: * will iterate over the entire string. This iterator will return information 338: * about the list of attributes in the specified array. Attributes not in 339: * the array may or may not be returned by the iterator. If the specified 340: * array is <code>null</code>, all attributes will be returned. 341: * 342: * @param attributes A list of attributes to include in the returned iterator. 343: * 344: * @return An <code>AttributedCharacterIterator</code> for this string. 345: */ 346: public AttributedCharacterIterator getIterator( 347: AttributedCharacterIterator.Attribute[] attributes) 348: { 349: return(getIterator(attributes, 0, sci.getEndIndex())); 350: } 351: 352: /** 353: * Returns an <code>AttributedCharacterIterator</code> that 354: * will iterate over the specified subrange. This iterator will return 355: * information about the list of attributes in the specified array. 356: * Attributes not in the array may or may not be returned by the iterator. 357: * If the specified array is <code>null</code>, all attributes will be 358: * returned. 359: * 360: * @param attributes A list of attributes to include in the returned iterator. 361: * @param beginIndex The beginning index of the subrange. 362: * @param endIndex The ending index of the subrange. 363: * 364: * @return An <code>AttributedCharacterIterator</code> for this string. 365: */ 366: public AttributedCharacterIterator getIterator( 367: AttributedCharacterIterator.Attribute[] attributes, 368: int beginIndex, int endIndex) 369: { 370: if ((beginIndex < 0) || (endIndex > sci.getEndIndex()) || 371: (endIndex < beginIndex)) 372: throw new IllegalArgumentException("bad range"); 373: 374: return(new AttributedStringIterator(sci, attribs, beginIndex, endIndex, 375: attributes)); 376: } 377: 378: } // class AttributedString