Source for java.text.AttributedString

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