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