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