1 11 package org.eclipse.jface.text.reconciler; 12 13 14 import org.eclipse.core.runtime.Assert; 15 import org.eclipse.core.runtime.IProgressMonitor; 16 17 import org.eclipse.jface.text.DocumentEvent; 18 import org.eclipse.jface.text.IDocument; 19 import org.eclipse.jface.text.IDocumentListener; 20 import org.eclipse.jface.text.ITextInputListener; 21 import org.eclipse.jface.text.ITextViewer; 22 23 24 47 abstract public class AbstractReconciler implements IReconciler { 48 49 50 53 class BackgroundThread extends Thread { 54 55 56 private boolean fCanceled= false; 57 58 private boolean fReset= false; 59 60 private boolean fIsDirty= false; 61 62 private boolean fIsActive= false; 63 64 70 public BackgroundThread(String name) { 71 super(name); 72 setPriority(Thread.MIN_PRIORITY); 73 setDaemon(true); 74 } 75 76 81 public boolean isActive() { 82 return fIsActive; 83 } 84 85 91 public synchronized boolean isDirty() { 92 return fIsDirty; 93 } 94 95 98 public void cancel() { 99 fCanceled= true; 100 IProgressMonitor pm= fProgressMonitor; 101 if (pm != null) 102 pm.setCanceled(true); 103 synchronized (fDirtyRegionQueue) { 104 fDirtyRegionQueue.notifyAll(); 105 } 106 } 107 108 112 public void suspendCallerWhileDirty() { 113 boolean isDirty; 114 do { 115 synchronized (fDirtyRegionQueue) { 116 isDirty= fDirtyRegionQueue.getSize() > 0; 117 if (isDirty) { 118 try { 119 fDirtyRegionQueue.wait(); 120 } catch (InterruptedException x) { 121 } 122 } 123 } 124 } while (isDirty); 125 } 126 127 130 public void reset() { 131 132 if (fDelay > 0) { 133 134 synchronized (this) { 135 fIsDirty= true; 136 fReset= true; 137 } 138 139 } else { 140 141 synchronized (this) { 142 fIsDirty= true; 143 } 144 145 synchronized (fDirtyRegionQueue) { 146 fDirtyRegionQueue.notifyAll(); 147 } 148 } 149 150 reconcilerReset(); 151 } 152 153 161 public void run() { 162 163 synchronized (fDirtyRegionQueue) { 164 try { 165 fDirtyRegionQueue.wait(fDelay); 166 } catch (InterruptedException x) { 167 } 168 } 169 170 initialProcess(); 171 172 while (!fCanceled) { 173 174 synchronized (fDirtyRegionQueue) { 175 try { 176 fDirtyRegionQueue.wait(fDelay); 177 } catch (InterruptedException x) { 178 } 179 } 180 181 if (fCanceled) 182 break; 183 184 if (!isDirty()) 185 continue; 186 187 synchronized (this) { 188 if (fReset) { 189 fReset= false; 190 continue; 191 } 192 } 193 194 DirtyRegion r= null; 195 synchronized (fDirtyRegionQueue) { 196 r= fDirtyRegionQueue.removeNextDirtyRegion(); 197 } 198 199 fIsActive= true; 200 201 if (fProgressMonitor != null) 202 fProgressMonitor.setCanceled(false); 203 204 process(r); 205 206 synchronized (fDirtyRegionQueue) { 207 if (0 == fDirtyRegionQueue.getSize()) { 208 synchronized (this) { 209 fIsDirty= fProgressMonitor != null ? fProgressMonitor.isCanceled() : false; 210 } 211 fDirtyRegionQueue.notifyAll(); 212 } 213 } 214 215 fIsActive= false; 216 } 217 } 218 } 219 220 223 class Listener implements IDocumentListener, ITextInputListener { 224 225 228 public void documentAboutToBeChanged(DocumentEvent e) { 229 } 230 231 234 public void documentChanged(DocumentEvent e) { 235 236 if (!fThread.isDirty() && fThread.isAlive()) { 237 if (!fIsAllowedToModifyDocument && Thread.currentThread() == fThread) 238 throw new UnsupportedOperationException ("The reconciler thread is not allowed to modify the document"); aboutToBeReconciled(); 240 } 241 242 246 if (fProgressMonitor != null && (fThread.isActive() || fThread.isDirty() && fThread.isAlive())) 247 fProgressMonitor.setCanceled(true); 248 249 if (fIsIncrementalReconciler) 250 createDirtyRegion(e); 251 252 fThread.reset(); 253 254 } 255 256 259 public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { 260 261 if (oldInput == fDocument) { 262 263 if (fDocument != null) 264 fDocument.removeDocumentListener(this); 265 266 if (fIsIncrementalReconciler) { 267 synchronized (fDirtyRegionQueue) { 268 fDirtyRegionQueue.purgeQueue(); 269 } 270 if (fDocument != null && fDocument.getLength() > 0) { 271 DocumentEvent e= new DocumentEvent(fDocument, 0, fDocument.getLength(), ""); createDirtyRegion(e); 273 fThread.reset(); 274 fThread.suspendCallerWhileDirty(); 275 } 276 } 277 278 fDocument= null; 279 } 280 } 281 282 285 public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { 286 287 fDocument= newInput; 288 if (fDocument == null) 289 return; 290 291 292 reconcilerDocumentChanged(fDocument); 293 294 fDocument.addDocumentListener(this); 295 296 if (!fThread.isDirty()) 297 aboutToBeReconciled(); 298 299 if (fIsIncrementalReconciler) { 300 DocumentEvent e= new DocumentEvent(fDocument, 0, 0, fDocument.get()); 301 createDirtyRegion(e); 302 } 303 304 startReconciling(); 305 } 306 } 307 308 309 private DirtyRegionQueue fDirtyRegionQueue; 310 311 private BackgroundThread fThread; 312 313 private Listener fListener; 314 315 private int fDelay= 500; 316 317 private boolean fIsIncrementalReconciler= true; 318 319 private IProgressMonitor fProgressMonitor; 320 324 private boolean fIsAllowedToModifyDocument= true; 325 326 327 328 private IDocument fDocument; 329 330 private ITextViewer fViewer; 331 332 333 341 abstract protected void process(DirtyRegion dirtyRegion); 342 343 351 abstract protected void reconcilerDocumentChanged(IDocument newDocument); 352 353 354 357 protected AbstractReconciler() { 358 super(); 359 } 360 361 367 public void setDelay(int delay) { 368 fDelay= delay; 369 } 370 371 383 public void setIsIncrementalReconciler(boolean isIncremental) { 384 fIsIncrementalReconciler= isIncremental; 385 } 386 387 398 public void setIsAllowedToModifyDocument(boolean isAllowedToModify) { 399 fIsAllowedToModifyDocument= isAllowedToModify; 400 } 401 402 407 public void setProgressMonitor(IProgressMonitor monitor) { 408 fProgressMonitor= monitor; 409 } 410 411 419 protected boolean isIncrementalReconciler() { 420 return fIsIncrementalReconciler; 421 } 422 423 428 protected IDocument getDocument() { 429 return fDocument; 430 } 431 432 437 protected ITextViewer getTextViewer() { 438 return fViewer; 439 } 440 441 446 protected IProgressMonitor getProgressMonitor() { 447 return fProgressMonitor; 448 } 449 450 453 public void install(ITextViewer textViewer) { 454 455 Assert.isNotNull(textViewer); 456 fViewer= textViewer; 457 458 synchronized (this) { 459 if (fThread != null) 460 return; 461 fThread= new BackgroundThread(getClass().getName()); 462 } 463 464 fDirtyRegionQueue= new DirtyRegionQueue(); 465 466 fListener= new Listener(); 467 fViewer.addTextInputListener(fListener); 468 469 IDocument document= textViewer.getDocument(); 476 if (document != null) { 477 fListener.inputDocumentAboutToBeChanged(fDocument, document); 478 fListener.inputDocumentChanged(fDocument, document); 479 } 480 } 481 482 485 public void uninstall() { 486 if (fListener != null) { 487 488 fViewer.removeTextInputListener(fListener); 489 if (fDocument != null) { 490 fListener.inputDocumentAboutToBeChanged(fDocument, null); 491 fListener.inputDocumentChanged(fDocument, null); 492 } 493 fListener= null; 494 495 synchronized (this) { 496 BackgroundThread bt= fThread; 498 fThread= null; 499 bt.cancel(); 500 } 501 } 502 } 503 504 509 private void createDirtyRegion(DocumentEvent e) { 510 synchronized (fDirtyRegionQueue) { 511 if (e.getLength() == 0 && e.getText() != null) { 512 fDirtyRegionQueue.addDirtyRegion(new DirtyRegion(e.getOffset(), e.getText().length(), DirtyRegion.INSERT, e.getText())); 514 515 } else if (e.getText() == null || e.getText().length() == 0) { 516 fDirtyRegionQueue.addDirtyRegion(new DirtyRegion(e.getOffset(), e.getLength(), DirtyRegion.REMOVE, null)); 518 519 } else { 520 fDirtyRegionQueue.addDirtyRegion(new DirtyRegion(e.getOffset(), e.getLength(), DirtyRegion.REMOVE, null)); 522 fDirtyRegionQueue.addDirtyRegion(new DirtyRegion(e.getOffset(), e.getText().length(), DirtyRegion.INSERT, e.getText())); 523 } 524 } 525 } 526 527 536 protected void aboutToBeReconciled() { 537 } 538 539 543 protected void initialProcess() { 544 } 545 546 550 protected void forceReconciling() { 551 552 if (fDocument != null) { 553 554 if (!fThread.isDirty()&& fThread.isAlive()) 555 aboutToBeReconciled(); 556 557 if (fProgressMonitor != null && fThread.isActive()) 558 fProgressMonitor.setCanceled(true); 559 560 if (fIsIncrementalReconciler) { 561 DocumentEvent e= new DocumentEvent(fDocument, 0, fDocument.getLength(), fDocument.get()); 562 createDirtyRegion(e); 563 } 564 565 startReconciling(); 566 } 567 } 568 569 573 protected synchronized void startReconciling() { 574 if (fThread == null) 575 return; 576 577 if (!fThread.isAlive()) { 578 try { 579 fThread.start(); 580 } catch (IllegalThreadStateException e) { 581 } 586 } else { 587 fThread.reset(); 588 } 589 } 590 591 594 protected void reconcilerReset() { 595 } 596 } 597 | Popular Tags |