1 11 package org.eclipse.ui.internal.console; 12 13 import java.util.ArrayList ; 14 import java.util.Iterator ; 15 import java.util.List ; 16 import java.util.regex.Matcher ; 17 import java.util.regex.Pattern ; 18 19 import org.eclipse.core.runtime.Assert; 20 import org.eclipse.jface.text.BadLocationException; 21 import org.eclipse.jface.text.DocumentEvent; 22 import org.eclipse.jface.text.IDocument; 23 import org.eclipse.jface.text.IDocumentAdapter; 24 import org.eclipse.jface.text.IDocumentListener; 25 import org.eclipse.swt.custom.TextChangeListener; 26 import org.eclipse.swt.custom.TextChangedEvent; 27 import org.eclipse.swt.custom.TextChangingEvent; 28 29 38 public class ConsoleDocumentAdapter implements IDocumentAdapter, IDocumentListener { 39 40 private int consoleWidth = -1; 41 private List textChangeListeners; 42 private IDocument document; 43 44 int[] offsets = new int[5000]; 45 int[] lengths = new int[5000]; 46 private int regionCount = 1; 47 private Pattern pattern = Pattern.compile("$", Pattern.MULTILINE); 49 50 public ConsoleDocumentAdapter(int width) { 51 textChangeListeners = new ArrayList (); 52 consoleWidth = width; 53 } 54 55 59 private void repairLines(int eventOffset) { 60 if (document == null) { 61 return; 62 } 63 try { 64 int docLine = document.getLineOfOffset(eventOffset); 65 int docLineOffset = document.getLineOffset(docLine); 66 int widgetLine = getLineAtOffset(docLineOffset); 67 68 for (int i=regionCount-1; i>=widgetLine; i--) { 69 regionCount--; 70 } 71 72 int numLinesInDoc = document.getNumberOfLines(); 73 74 int nextOffset = document.getLineOffset(docLine); 75 for (int i = docLine; i<numLinesInDoc; i++) { 76 int offset = nextOffset; 77 int length = document.getLineLength(i); 78 nextOffset += length; 79 80 if (length == 0) { 81 addRegion(offset, 0); 82 } else { 83 while (length > 0) { 84 int trimmedLength = length; 85 String lineDelimiter = document.getLineDelimiter(i); 86 int lineDelimiterLength = 0; 87 if (lineDelimiter != null) { 88 lineDelimiterLength = lineDelimiter.length(); 89 trimmedLength -= lineDelimiterLength; 90 } 91 92 if (consoleWidth > 0 && consoleWidth < trimmedLength) { 93 addRegion(offset, consoleWidth); 94 offset += consoleWidth; 95 length -= consoleWidth; 96 } else { 97 addRegion(offset, length); 98 offset += length; 99 length -= length; 100 } 101 } 102 } 103 } 104 } catch (BadLocationException e) { 105 } 106 107 if (regionCount == 0) { 108 addRegion(0, document.getLength()); 109 } 110 } 111 112 private void addRegion(int offset, int length) { 113 if (regionCount == 0) { 114 offsets[0] = offset; 115 lengths[0] = length; 116 } else { 117 if (regionCount == offsets.length) { 118 growRegionArray(regionCount * 2); 119 } 120 offsets[regionCount] = offset; 121 lengths[regionCount] = length; 122 } 123 regionCount++; 124 } 125 126 129 public void setDocument(IDocument doc) { 130 if (document != null) { 131 document.removeDocumentListener(this); 132 } 133 134 document = doc; 135 136 if (document != null) { 137 document.addDocumentListener(this); 138 repairLines(0); 139 } 140 } 141 142 145 public synchronized void addTextChangeListener(TextChangeListener listener) { 146 Assert.isNotNull(listener); 147 if (!textChangeListeners.contains(listener)) { 148 textChangeListeners.add(listener); 149 } 150 } 151 152 155 public synchronized void removeTextChangeListener(TextChangeListener listener) { 156 if(textChangeListeners != null) { 157 Assert.isNotNull(listener); 158 textChangeListeners.remove(listener); 159 } 160 } 161 162 165 public int getCharCount() { 166 return document.getLength(); 167 } 168 169 172 public String getLine(int lineIndex) { 173 try { 174 StringBuffer line = new StringBuffer (document.get(offsets[lineIndex], lengths[lineIndex])); 175 int index = line.length() - 1; 176 while(index > -1 && (line.charAt(index)=='\n' || line.charAt(index)=='\r')) { 177 index--; 178 } 179 return new String (line.substring(0, index+1)); 180 } catch (BadLocationException e) { 181 } 182 return ""; } 184 185 188 public int getLineAtOffset(int offset) { 189 if (offset == 0 || regionCount <= 1) { 190 return 0; 191 } 192 193 if (offset == document.getLength()) { 194 return regionCount-1; 195 } 196 197 int left= 0; 198 int right= regionCount-1; 199 int midIndex = 0; 200 201 while (left <= right) { 202 if(left == right) { 203 return right; 204 } 205 midIndex = (left + right) / 2; 206 207 if (offset < offsets[midIndex]) { 208 right = midIndex; 209 } else if (offset >= offsets[midIndex] + lengths[midIndex]) { 210 left = midIndex + 1; 211 } else { 212 return midIndex; 213 } 214 } 215 216 return midIndex; 217 } 218 219 222 public int getLineCount() { 223 return regionCount; 224 } 225 226 229 public String getLineDelimiter() { 230 return System.getProperty("line.separator"); } 232 233 236 public int getOffsetAtLine(int lineIndex) { 237 return offsets[lineIndex]; 238 } 239 240 243 public String getTextRange(int start, int length) { 244 try { 245 return document.get(start, length); 246 } catch (BadLocationException e) { 247 } 248 return null; 249 } 250 251 254 public void replaceTextRange(int start, int replaceLength, String text) { 255 try { 256 document.replace(start, replaceLength, text); 257 } catch (BadLocationException e) { 258 } 259 } 260 261 264 public synchronized void setText(String text) { 265 TextChangedEvent changeEvent = new TextChangedEvent(this); 266 for (Iterator iter = textChangeListeners.iterator(); iter.hasNext();) { 267 TextChangeListener element = (TextChangeListener) iter.next(); 268 element.textSet(changeEvent); 269 } 270 } 271 272 275 public synchronized void documentAboutToBeChanged(DocumentEvent event) { 276 if (document == null) { 277 return; 278 } 279 280 TextChangingEvent changeEvent = new TextChangingEvent(this); 281 changeEvent.start = event.fOffset; 282 changeEvent.newText = (event.fText == null ? "" : event.fText); changeEvent.replaceCharCount = event.fLength; 284 changeEvent.newCharCount = (event.fText == null ? 0 : event.fText.length()); 285 286 int first = getLineAtOffset(event.fOffset); 287 int lOffset = Math.max(event.fOffset + event.fLength - 1, 0); 288 int last = getLineAtOffset(lOffset); 289 changeEvent.replaceLineCount = Math.max(last - first, 0); 290 291 int newLineCount = countNewLines(event.fText); 292 changeEvent.newLineCount = newLineCount >= 0 ? newLineCount : 0; 293 294 if (changeEvent.newLineCount > offsets.length-regionCount) { 295 growRegionArray(changeEvent.newLineCount); 296 } 297 298 for (Iterator iter = textChangeListeners.iterator(); iter.hasNext();) { 299 TextChangeListener element = (TextChangeListener) iter.next(); 300 element.textChanging(changeEvent); 301 } 302 } 303 304 private void growRegionArray(int minSize) { 305 int size = Math.max(offsets.length*2, minSize*2); 306 int[] newOffsets = new int[size]; 307 System.arraycopy(offsets, 0, newOffsets, 0, regionCount); 308 offsets = newOffsets; 309 int[] newLengths = new int[size]; 310 System.arraycopy(lengths, 0, newLengths, 0, regionCount); 311 lengths = newLengths; 312 } 313 314 private int countNewLines(String string) { 315 int count = 0; 316 317 if (string.length() == 0) return 0; 318 319 int offset = string.length() - 1; 323 while (string.charAt(offset) == '\r') { 324 offset--; 325 count++; 326 } 327 if (offset < (string.length() - 1)) { 328 string = string.substring(0, offset); 329 } 330 331 int lastIndex = 0; 332 int index = 0; 333 334 Matcher matcher = pattern.matcher(string); 335 336 while (matcher.find()) { 337 index = matcher.start(); 338 339 if (index == 0) 340 count++; 341 else if (index!=string.length()) 342 count++; 343 344 if (consoleWidth > 0) { 345 int lineLen = index - lastIndex + 1; 346 if (index == 0) lineLen += lengths[regionCount-1]; 347 count += lineLen/consoleWidth; 348 } 349 350 lastIndex = index; 351 } 352 return count; 353 } 354 355 356 359 public synchronized void documentChanged(DocumentEvent event) { 360 if (document == null) { 361 return; 362 } 363 364 repairLines(event.fOffset); 365 366 TextChangedEvent changeEvent = new TextChangedEvent(this); 367 368 for (Iterator iter = textChangeListeners.iterator(); iter.hasNext();) { 369 TextChangeListener element = (TextChangeListener) iter.next(); 370 element.textChanged(changeEvent); 371 } 372 } 373 374 378 public void setWidth(int width) { 379 if (width != consoleWidth) { 380 consoleWidth = width; 381 repairLines(0); 382 TextChangedEvent changeEvent = new TextChangedEvent(this); 383 for (Iterator iter = textChangeListeners.iterator(); iter.hasNext();) { 384 TextChangeListener element = (TextChangeListener) iter.next(); 385 element.textSet(changeEvent); 386 } 387 } 388 } 389 } 390 | Popular Tags |