Source for javax.swing.text.StringContent

   1: /* StringContent.java --
   2:    Copyright (C) 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 javax.swing.text;
  40: 
  41: import java.io.Serializable;
  42: import java.util.Iterator;
  43: import java.util.Vector;
  44: 
  45: import javax.swing.undo.AbstractUndoableEdit;
  46: import javax.swing.undo.CannotRedoException;
  47: import javax.swing.undo.CannotUndoException;
  48: import javax.swing.undo.UndoableEdit;
  49: 
  50: /**
  51:  * An implementation of the <code>AbstractDocument.Content</code>
  52:  * interface useful for small documents or debugging. The character
  53:  * content is a simple character array. It's not really efficient.
  54:  * 
  55:  * <p>Do not use this class for large size.</p>
  56:  */
  57: public final class StringContent implements AbstractDocument.Content, Serializable
  58: {
  59:   // This is package-private to avoid an accessor method.
  60:   char[] content;
  61: 
  62:   private int count;
  63: 
  64:   private Vector positions = new Vector();
  65: 
  66:   private class InsertUndo extends AbstractUndoableEdit
  67:   {
  68:     private int start;
  69:     
  70:     private int length;
  71: 
  72:     private String redoContent;
  73: 
  74:     public InsertUndo(int start, int length)
  75:     {
  76:       super();
  77:       this.start = start;
  78:       this.length = length;
  79:     }
  80: 
  81:     public void undo()
  82:     {
  83:       super.undo();
  84:       try
  85:         {
  86:           StringContent.this.checkLocation(this.start, this.length);
  87:           this.redoContent = new String(StringContent.this.content, this.start, this.length);
  88:           StringContent.this.remove(this.start, this.length);
  89:         }
  90:       catch (BadLocationException b)
  91:         {
  92:           throw new CannotUndoException();
  93:         }
  94:     }
  95:     
  96:     public void redo()
  97:     {
  98:       super.redo();
  99:       try
 100:         {
 101:           StringContent.this.insertString(this.start, this.redoContent);
 102:         }
 103:       catch (BadLocationException b)
 104:         {
 105:           throw new CannotRedoException();
 106:         }
 107:     }
 108:   }
 109: 
 110:   private class RemoveUndo extends AbstractUndoableEdit
 111:   {
 112:     private int start;
 113: 
 114:     private String undoString;
 115: 
 116:     public RemoveUndo(int start, String str)
 117:     {
 118:       super();
 119:       this.start = start;
 120:       this.undoString = str;
 121:     }
 122: 
 123:     public void undo()
 124:     {
 125:       super.undo();
 126:       try
 127:         {
 128:           StringContent.this.insertString(this.start, this.undoString);
 129:         }
 130:       catch (BadLocationException bad)
 131:         {
 132:           throw new CannotUndoException();
 133:         }
 134:     }
 135: 
 136:     public void redo()
 137:     {
 138:       super.redo();
 139:       try
 140:         {
 141:           int end = this.undoString.length();
 142:           StringContent.this.remove(this.start, end);
 143:         }
 144:       catch (BadLocationException bad)
 145:         {
 146:           throw new CannotRedoException();
 147:         }
 148:     }
 149:   }
 150: 
 151:   private class StickyPosition implements Position
 152:   {
 153:     private int offset = -1;
 154: 
 155:     public StickyPosition(int offset)
 156:     {
 157:       this.offset = offset;
 158:     }
 159: 
 160:     // This is package-private to avoid an accessor method.
 161:     void setOffset(int offset)
 162:     {
 163:       this.offset = this.offset >= 0 ? offset : -1;
 164:     }
 165: 
 166:     /**
 167:      * Should be >=0.
 168:      */
 169:     public int getOffset()
 170:     {
 171:       return offset < 0 ? 0 : offset;
 172:     }
 173:   }
 174: 
 175:   public StringContent()
 176:   {
 177:     this(1);
 178:   }
 179: 
 180:   public StringContent(int initialLength)
 181:   {
 182:     super();
 183:     if (initialLength < 1)
 184:       initialLength = 1;
 185:     this.content = new char[initialLength];
 186:     this.content[0] = '\n';
 187:     this.count = 1;
 188:   }
 189: 
 190:   protected Vector getPositionsInRange(Vector v,
 191:                                        int offset,
 192:                                        int length)
 193:   {
 194:     Vector refPos = new Vector();
 195:     Iterator iter = this.positions.iterator();
 196:     while(iter.hasNext())
 197:       {
 198:         Position p = (Position)iter.next();
 199:         if ((offset <= p.getOffset())
 200:             && (p.getOffset() <= (offset + length)))
 201:           refPos.add(p);
 202:       }
 203:     return refPos;
 204:   }
 205: 
 206:   public Position createPosition(int offset) throws BadLocationException
 207:   {
 208:     if (offset < this.count || offset > this.count)
 209:       checkLocation(offset, 0);
 210:     StickyPosition sp = new StickyPosition(offset);
 211:     this.positions.add(sp);
 212:     return sp;
 213:   }
 214:   
 215:   public int length()
 216:   {
 217:     return this.count;
 218:   }
 219:   
 220:   public UndoableEdit insertString(int where, String str)
 221:     throws BadLocationException
 222:   {
 223:     checkLocation(where, 0);
 224:     if (where == this.count)
 225:       throw new BadLocationException("Invalid location", 1);
 226:     if (str == null)
 227:       throw new NullPointerException();
 228:     char[] insert = str.toCharArray();
 229:     char[] temp = new char[this.content.length + insert.length];
 230:     this.count += insert.length;
 231:     // Copy array and insert the string.
 232:     if (where > 0)
 233:       System.arraycopy(this.content, 0, temp, 0, where);
 234:     System.arraycopy(insert, 0, temp, where, insert.length);
 235:     System.arraycopy(this.content, where, temp, (where + insert.length), (temp.length - where - insert.length));
 236:     if (this.content.length < temp.length)
 237:       this.content = new char[temp.length];
 238:     // Copy the result in the original char array.
 239:     System.arraycopy(temp, 0, this.content, 0, temp.length);
 240:     // Move all the positions.
 241:     Vector refPos = getPositionsInRange(this.positions, where, temp.length - where);
 242:     Iterator iter = refPos.iterator();
 243:     while (iter.hasNext())
 244:       {
 245:         StickyPosition p = (StickyPosition)iter.next();
 246:         p.setOffset(p.getOffset() + str.length());
 247:       }
 248:     InsertUndo iundo = new InsertUndo(where, insert.length);
 249:     return iundo;
 250:   }
 251:   
 252:   public UndoableEdit remove(int where, int nitems) throws BadLocationException
 253:   {
 254:     checkLocation(where, nitems);
 255:     char[] temp = new char[(this.content.length - nitems)];
 256:     this.count = this.count - nitems;
 257:     RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where, nitems));
 258:     // Copy array.
 259:     System.arraycopy(this.content, 0, temp, 0, where);
 260:     System.arraycopy(this.content, where + nitems, temp, where, this.content.length - where - nitems);
 261:     this.content = new char[temp.length];
 262:     // Then copy the result in the original char array.
 263:     System.arraycopy(temp, 0, this.content, 0, this.content.length);
 264:     // Move all the positions.
 265:     Vector refPos = getPositionsInRange(this.positions, where, this.content.length + nitems - where);
 266:     Iterator iter = refPos.iterator();
 267:     while (iter.hasNext())
 268:       {
 269:         StickyPosition p = (StickyPosition)iter.next();
 270:         int result = p.getOffset() - nitems;
 271:         p.setOffset(result);
 272:         if (result < 0)
 273:           this.positions.remove(p);
 274:       }
 275:     return rundo;
 276:   }
 277:   
 278:   public String getString(int where, int len) throws BadLocationException
 279:   {
 280:     checkLocation(where, len);
 281:     return new String (this.content, where, len);
 282:   }
 283:   
 284:   public void getChars(int where, int len, Segment txt) throws BadLocationException
 285:   {
 286:     checkLocation(where, len);
 287:     if (txt != null)
 288:       {
 289:         txt.array = this.content;
 290:         txt.offset = where;
 291:         txt.count = len;
 292:       }
 293:   }
 294: 
 295:   // This is package-private to avoid an accessor method.
 296:   void checkLocation(int where, int len) throws BadLocationException
 297:   {
 298:     if (where < 0)
 299:       throw new BadLocationException("Invalid location", 1);
 300:     else if (where > this.count)
 301:       throw new BadLocationException("Invalid location", this.count);
 302:     else if ((where + len)>this.count)
 303:       throw new BadLocationException("Invalid range", this.count);
 304:   }
 305:   
 306: }