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