1 19 20 package org.netbeans.editor; 21 22 import java.util.ArrayList ; 23 import java.util.Collections ; 24 import java.util.List ; 25 import javax.swing.text.Segment ; 26 import javax.swing.text.BadLocationException ; 27 import javax.swing.text.Position ; 28 import javax.swing.text.AbstractDocument ; 29 import javax.swing.undo.AbstractUndoableEdit ; 30 import javax.swing.undo.CannotUndoException ; 31 import javax.swing.undo.CannotRedoException ; 32 import javax.swing.undo.UndoableEdit ; 33 34 40 41 final class DocumentContent implements AbstractDocument.Content , CharSeq, GapStart { 42 43 private static final char[] EMPTY_CHAR_ARRAY = new char[0]; 44 45 51 private static final UndoableEdit INVALID_EDIT = new AbstractUndoableEdit (); 52 53 private static final boolean debugUndo 54 = Boolean.getBoolean("netbeans.debug.editor.document.undo"); 55 56 57 private final MarkVector markVector; 58 59 60 private char[] charArray; 61 62 63 private int gapStart; 64 65 66 private int gapLength; 67 68 DocumentContent() { 69 charArray = EMPTY_CHAR_ARRAY; 70 markVector = new MarkVector(); 71 72 insertText(0, "\n"); } 75 76 public final int getGapStart() { return gapStart; 78 } 79 80 public UndoableEdit insertString(int offset, String text) 81 throws BadLocationException { 82 83 checkBounds(offset, 0, length() - 1); 84 return new Edit (offset, text); 85 } 86 87 public UndoableEdit remove(int offset, int length) 88 throws BadLocationException { 89 90 checkBounds(offset, length, length() - 1); 91 return new Edit (offset, length); 92 } 93 94 public Position createPosition(int offset) throws BadLocationException { 95 return new BasePosition(createMark(offset)); 96 } 97 98 public Position createBiasPosition(int offset, Position.Bias bias) 99 throws BadLocationException { 100 return new BasePosition(createBiasMark(offset, bias)); 101 } 102 103 MultiMark createBiasMark(int offset, Position.Bias bias) throws BadLocationException { 104 checkOffset(offset); 105 return markVector.insert(markVector.createBiasMark(offset, bias)); 106 } 107 108 MultiMark createMark(int offset) throws BadLocationException { 109 checkOffset(offset); 110 return markVector.insert(markVector.createMark(offset)); 111 } 112 113 public int length() { 114 return charArray.length - gapLength; 115 } 116 117 public void getChars(int offset, int length, Segment chars) 118 throws BadLocationException { 119 120 checkBounds(offset, length, length()); 121 122 if ((offset + length) <= gapStart) { chars.array = charArray; 124 chars.offset = offset; 125 126 } else if (offset >= gapStart) { chars.array = charArray; 128 chars.offset = offset + gapLength; 129 130 } else { chars.array = copySpanChars(offset, length); 132 chars.offset = 0; 133 } 134 135 chars.count = length; 136 } 137 138 public String getString(int offset, int length) 139 throws BadLocationException { 140 141 checkBounds(offset, length, length()); 142 return getText(offset, length); 143 } 144 145 String getText(int offset, int length) { 146 if (offset < 0 || length < 0) { 147 throw new IllegalStateException ("offset=" + offset + ", length=" + length); } 149 150 String ret; 151 if ((offset + length) <= gapStart) { ret = new String (charArray, offset, length); 153 154 } else if (offset >= gapStart) { ret = new String (charArray, offset + gapLength, length); 156 157 } else { ret = new String (copySpanChars(offset, length)); 159 } 160 161 return ret; 162 } 163 164 public char charAt(int index) { 165 return charArray[getRawIndex(index)]; 166 } 167 168 void compact() { 169 if (gapLength > 0) { 170 int newLength = charArray.length - gapLength; 171 char[] newCharArray = new char[newLength]; 172 int gapEnd = gapStart + gapLength; 173 System.arraycopy(charArray, 0, newCharArray, 0, gapStart); 174 System.arraycopy(charArray, gapEnd, newCharArray, gapStart, 175 charArray.length - gapEnd); 176 charArray = newCharArray; 177 gapStart = charArray.length; 178 gapLength = 0; 179 } 180 181 markVector.compact(); 182 } 183 184 private int getRawIndex(int index) { 185 return (index < gapStart) ? index : (index + gapLength); 186 } 187 188 private void moveGap(int index) { 189 if (index <= gapStart) { int moveSize = gapStart - index; 191 System.arraycopy(charArray, index, charArray, 192 gapStart + gapLength - moveSize, moveSize); 193 gapStart = index; 194 195 } else { int gapEnd = gapStart + gapLength; 197 int moveSize = index - gapStart; 198 System.arraycopy(charArray, gapEnd, charArray, gapStart, moveSize); 199 gapStart += moveSize; 200 } 201 } 202 203 private void enlargeGap(int extraLength) { 204 int newLength = Math.max(10, charArray.length * 3 / 2 + extraLength); 205 int gapEnd = gapStart + gapLength; 206 int afterGapLength = (charArray.length - gapEnd); 207 int newGapEnd = newLength - afterGapLength; 208 char[] newCharArray = new char[newLength]; 209 System.arraycopy(charArray, 0, newCharArray, 0, gapStart); 210 System.arraycopy(charArray, gapEnd, newCharArray, newGapEnd, afterGapLength); 211 charArray = newCharArray; 212 gapLength = newGapEnd - gapStart; 213 } 214 215 private char[] copyChars(int offset, int length) { 216 char[] ret; 217 if ((offset + length) <= gapStart) { ret = new char[length]; 219 System.arraycopy(charArray, offset, ret, 0, length); 220 221 } else if (offset >= gapStart) { ret = new char[length]; 223 System.arraycopy(charArray, offset + gapLength, ret, 0, length); 224 225 } else { ret = copySpanChars(offset, length); 227 } 228 229 return ret; 230 } 231 232 private char[] copySpanChars(int offset, int length) { 233 char[] ret = new char[length]; 234 int belowGap = gapStart - offset; 235 System.arraycopy(charArray, offset, ret, 0, belowGap); 236 System.arraycopy(charArray, gapStart + gapLength, 237 ret, belowGap, length - belowGap); 238 return ret; 239 } 240 241 void insertText(int offset, String text) { 242 int textLength = text.length(); 244 int extraLength = textLength - gapLength; 245 if (extraLength > 0) { 246 enlargeGap(extraLength); 247 } 248 if (offset != gapStart) { 249 moveGap(offset); 250 } 251 text.getChars(0, textLength, charArray, gapStart); 252 gapStart += textLength; 253 gapLength -= textLength; 254 } 255 256 void removeText(int offset, int length) { 257 if (offset >= gapStart) { if (offset > gapStart) { 260 moveGap(offset); 261 } 262 263 } else { int endOffset = offset + length; 265 if (endOffset <= gapStart) { 266 if (endOffset < gapStart) { 267 moveGap(endOffset); 268 } 269 gapStart -= length; 270 271 } else { gapStart = offset; 273 } 274 } 275 276 gapLength += length; 277 } 278 279 private void checkOffset(int offset) throws BadLocationException { 280 if (offset > length()) { throw new BadLocationException ("Invalid offset=" + offset + ", docLength=" + (length() - 1), offset); } 284 } 285 286 private void checkBounds(int offset, int length, int limitOffset) 287 throws BadLocationException { 288 289 if (offset < 0) { 290 throw new BadLocationException ("Invalid offset=" + offset, offset); } 292 if (length < 0) { 293 throw new BadLocationException ("Invalid length" + length, length); } 295 if (offset + length > limitOffset) { 296 throw new BadLocationException ( 297 "docLength=" + (length() - 1) + ": Invalid offset" + ((length != 0) ? "+length" : "") + "=" + (offset + length), (offset + length) 302 ); 303 } 304 } 305 306 class Edit extends AbstractUndoableEdit { 307 308 312 Edit(int offset, String text) { 313 this.offset = offset; 314 this.length = text.length(); 315 this.text = text; 316 317 undoOrRedo(length, false); 319 } 320 321 325 Edit(int offset, int length) { 326 this.offset = offset; 327 this.length = -length; 328 329 this.text = getText(offset, length); 331 332 undoOrRedo(-length, false); 334 } 335 336 private int offset; 337 338 private int length; 339 340 private String text; 341 342 private MarkVector.Undo markVectorUndo; 343 344 public void undo() throws CannotUndoException { 345 super.undo(); 346 347 if (debugUndo) { 348 System.err.println("UNDO-" + dump()); } 350 undoOrRedo(-length, true); 351 } 352 353 public void redo() throws CannotRedoException { 354 super.redo(); 355 356 if (debugUndo) { 357 System.err.println("REDO-" + dump()); } 359 undoOrRedo(length, false); 360 } 361 362 private String dump() { 363 return ((length >= 0) ? "INSERT" : "REMOVE") + ":offset=" + offset + ", length=" + length + ", text='" + text + '\''; } 367 368 private void undoOrRedo(int len, boolean undo) { 369 if (len < 0) { removeText(offset, -len); 372 } else { insertText(offset, text); 374 } 375 376 markVectorUndo = markVector.update(offset, len, markVectorUndo); 378 } 379 380 383 final String getUndoRedoText() { 384 return text; 385 } 386 387 } 388 } 389 | Popular Tags |