1 19 20 package org.netbeans.editor; 21 22 import javax.swing.text.AbstractDocument ; 23 import javax.swing.text.Element ; 24 import javax.swing.text.Document ; 25 import javax.swing.text.AttributeSet ; 26 import javax.swing.text.Position ; 27 import javax.swing.undo.UndoableEdit ; 28 import java.util.ArrayList ; 29 import javax.swing.text.BadLocationException ; 30 import javax.swing.text.Segment ; 31 import javax.swing.text.StyleContext ; 32 import org.netbeans.lib.editor.util.swing.DocumentUtilities; 33 import org.netbeans.lib.editor.util.swing.GapBranchElement; 34 import org.openide.ErrorManager; 35 36 42 43 final class LineRootElement extends GapBranchElement { 44 45 private static final LineElement[] EMPTY_LINE_ELEMENT_ARRAY = new LineElement[0]; 46 47 private static final String NAME 48 = AbstractDocument.SectionElementName; 49 50 private BaseDocument doc; 51 52 private LineElement[] addedLines = EMPTY_LINE_ELEMENT_ARRAY; 53 54 LineRootElement(BaseDocument doc) { 55 this.doc = doc; 56 57 assert (doc.getLength() == 0) : "Cannot start with non-empty document"; 59 Position startPos = doc.getStartPosition(); 60 assert (startPos.getOffset() == 0) : "Document.getStartPosition() != 0"; 62 Position endPos = doc.getEndPosition(); 63 assert (endPos.getOffset() == 1) : "Document.getEndPosition() != 1"; 65 Element line = new LineElement(this, startPos, endPos); 66 replace(0, 0, new Element []{ line }); 67 68 assert (getElement(0) != null); 69 } 70 71 75 private int doubleAddedLinesCapacity() { 76 int addedLinesLength = addedLines.length; 77 int newCapacity = Math.max(4, addedLinesLength * 2); 78 LineElement[] newAddedLines = new LineElement[newCapacity]; 79 System.arraycopy(addedLines, 0, newAddedLines, 81 newCapacity - addedLinesLength, addedLinesLength); 82 addedLines = newAddedLines; 83 return (newCapacity - addedLinesLength); } 85 86 public Element getElement(int index) { 87 if (index < 0) { 88 throw new IndexOutOfBoundsException ("Invalid line index=" + index + " < 0"); } 90 int elementCount = getElementCount(); 91 if (index >= elementCount) { 92 throw new IndexOutOfBoundsException ("Invalid line index=" + index + " >= lineCount=" + elementCount); } 95 96 LineElement elem = (LineElement)super.getElement(index); 97 assert (elem != null); 98 return elem; 99 } 100 101 UndoableEdit insertUpdate(int insertOffset, int insertLength) { 102 int lastInsertedCharOffset = insertOffset + insertLength - 1; 103 CharSequence text = DocumentUtilities.getText(doc); 104 Edit edit = null; 105 106 int index = -1; Element [] removeElements = null; int firstAddedLineIndex = addedLines.length; 111 int offset = lastInsertedCharOffset; 112 boolean insertAtPrevLineEndOffset; 115 int beforeInsertOffset; if (insertOffset == 0) { beforeInsertOffset = 0; 118 insertAtPrevLineEndOffset = false; 119 } else { beforeInsertOffset = insertOffset - 1; insertAtPrevLineEndOffset = (text.charAt(beforeInsertOffset) == '\n'); 122 } 123 124 try { 125 Position futureAddedLineEndPos = null; 128 while (offset >= beforeInsertOffset) { 129 if (text.charAt(offset) == '\n') { boolean addLine = true; if (futureAddedLineEndPos == null) { 132 index = getElementIndex(insertOffset); 134 LineElement removeLine = (LineElement)getElement(index); 135 if (insertAtPrevLineEndOffset) { if (offset == lastInsertedCharOffset) { removeElements = new Element [] { removeLine }; 142 futureAddedLineEndPos = removeLine.getEndPosition(); 143 addLine = false; } else { 145 LineElement nextRemoveLine = (LineElement)getElement(index + 1); 146 removeElements = new Element [] { 147 removeLine, 148 nextRemoveLine 149 }; 150 futureAddedLineEndPos = nextRemoveLine.getEndPosition(); 151 } 152 153 } else { removeElements = new Element [] { removeLine }; 155 futureAddedLineEndPos = removeLine.getEndPosition(); 156 } 157 } 158 159 if (addLine) { 160 if (firstAddedLineIndex == 0) { firstAddedLineIndex = doubleAddedLinesCapacity(); 162 } 163 firstAddedLineIndex--; Position lineStartPos = doc.createPosition(offset + 1); 165 addedLines[firstAddedLineIndex] = new LineElement( 166 this, lineStartPos, futureAddedLineEndPos); 167 futureAddedLineEndPos = lineStartPos; 168 } 169 } 170 offset--; 171 } 172 173 if (futureAddedLineEndPos != null) { int addedLineCount = addedLines.length - firstAddedLineIndex; 176 Element [] addElements = new Element [addedLineCount + 1]; 177 System.arraycopy(addedLines, firstAddedLineIndex, addElements, 1, addedLineCount); 178 addElements[0] = new LineElement( 179 this, 180 ((LineElement)removeElements[0]).getStartPosition(), 181 futureAddedLineEndPos 182 ); 183 184 replace(index, removeElements.length, addElements); 185 edit = new Edit (index, removeElements, addElements); 186 } 187 188 } catch (BadLocationException e) { 189 ErrorManager.getDefault().notify(ErrorManager.ERROR, e); 193 } 194 return edit; 196 } 197 198 UndoableEdit removeUpdate(int removeOffset, int removeLength) { 199 Edit edit = null; 204 int removeEndOffset = removeOffset + removeLength; 205 int line0 = getElementIndex(removeOffset); 206 int line1 = getElementIndex(removeEndOffset); 207 if (line0 != line1) { 208 line1++; Element [] removeElements = new Element [line1 - line0]; 211 copyElements(line0, line1, removeElements, 0); 212 Element [] addElements = new Element [] { 213 new LineElement(this, 214 ((LineElement)removeElements[0]).getStartPosition(), 215 ((LineElement)removeElements[removeElements.length - 1]).getEndPosition() 216 ) 217 }; 218 219 replace(line0, removeElements.length, addElements); 220 edit = new Edit (line0, removeElements, addElements); 221 } 222 return edit; 224 } 225 226 231 232 public Document getDocument() { 233 return doc; 234 } 235 236 public Element getParentElement() { 237 return null; 238 } 239 240 public String getName() { 241 return NAME; 242 } 243 244 public AttributeSet getAttributes() { 245 return StyleContext.getDefaultStyleContext().getEmptySet(); 246 } 247 248 public int getStartOffset() { 249 return 0; 250 } 251 252 public int getEndOffset() { 253 return doc.getLength() + 1; 254 } 255 256 public int getElementIndex(int offset) { 257 if (offset == 0) { return 0; 259 } 260 261 return super.getElementIndex(offset); 262 } 263 264 private void checkConsistency() { 265 int lineCount = getElementCount(); 266 assert (lineCount > 0); int prevLineEndOffset = 0; 268 for (int i = 0; i < lineCount; i++) { 269 LineElement elem = (LineElement)getElement(i); 270 assert (prevLineEndOffset == elem.getStartOffset()); 271 assert (prevLineEndOffset < elem.getEndOffset()) 272 : "Line " + i + " of " + lineCount + ": " + lineToString(elem); prevLineEndOffset = elem.getEndOffset(); 274 } 275 assert (prevLineEndOffset == (doc.getLength() + 1)); 276 } 277 278 private String lineToString(Element line) { 279 return "<" + line.getStartOffset() + ", " + line.getEndOffset() + ">"; } 282 283 } 284 | Popular Tags |