1 11 package org.eclipse.jface.text.source; 12 13 import java.util.ArrayList ; 14 import java.util.HashMap ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 import java.util.Map ; 18 import java.util.NoSuchElementException ; 19 20 import org.eclipse.core.runtime.Assert; 21 22 import org.eclipse.jface.text.BadLocationException; 23 import org.eclipse.jface.text.DocumentEvent; 24 import org.eclipse.jface.text.IDocument; 25 import org.eclipse.jface.text.IDocumentListener; 26 import org.eclipse.jface.text.ISynchronizable; 27 import org.eclipse.jface.text.Position; 28 29 30 38 public class AnnotationModel implements IAnnotationModel, IAnnotationModelExtension, ISynchronizable { 39 40 45 private static class MetaIterator implements Iterator { 46 47 48 private Iterator fSuperIterator; 49 50 private Iterator fCurrent; 51 52 private Object fCurrentElement; 53 54 55 public MetaIterator(Iterator iterator) { 56 fSuperIterator= iterator; 57 fCurrent= (Iterator ) fSuperIterator.next(); } 59 60 public void remove() { 61 throw new UnsupportedOperationException (); 62 } 63 64 public boolean hasNext() { 65 if (fCurrentElement != null) 66 return true; 67 68 if (fCurrent.hasNext()) { 69 fCurrentElement= fCurrent.next(); 70 return true; 71 } else if (fSuperIterator.hasNext()) { 72 fCurrent= (Iterator ) fSuperIterator.next(); 73 return hasNext(); 74 } else 75 return false; 76 } 77 78 public Object next() { 79 if (!hasNext()) 80 throw new NoSuchElementException (); 81 82 Object element= fCurrentElement; 83 fCurrentElement= null; 84 return element; 85 } 86 } 87 88 94 private class InternalModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension { 95 96 99 public void modelChanged(IAnnotationModel model) { 100 AnnotationModel.this.fireModelChanged(new AnnotationModelEvent(model, true)); 101 } 102 103 106 public void modelChanged(AnnotationModelEvent event) { 107 AnnotationModel.this.fireModelChanged(event); 108 } 109 } 110 111 115 protected Map fAnnotations; 116 117 protected ArrayList fAnnotationModelListeners; 118 119 protected IDocument fDocument; 120 121 private int fOpenConnections= 0; 122 123 private IDocumentListener fDocumentListener; 124 125 private boolean fDocumentChanged= true; 126 130 private Map fAttachments= new HashMap (); 131 135 private IAnnotationModelListener fModelListener= new InternalModelListener(); 136 140 private AnnotationModelEvent fModelEvent; 141 145 private Object fModificationStamp= new Object (); 146 147 151 public AnnotationModel() { 152 fAnnotations= new AnnotationMap(10); 153 fAnnotationModelListeners= new ArrayList (2); 154 155 fDocumentListener= new IDocumentListener() { 156 157 public void documentAboutToBeChanged(DocumentEvent event) { 158 } 159 160 public void documentChanged(DocumentEvent event) { 161 fDocumentChanged= true; 162 } 163 }; 164 } 165 166 172 protected IAnnotationMap getAnnotationMap() { 173 return (IAnnotationMap) fAnnotations; 174 } 175 176 180 public Object getLockObject() { 181 return getAnnotationMap().getLockObject(); 182 } 183 184 188 public void setLockObject(Object lockObject) { 189 getAnnotationMap().setLockObject(lockObject); 190 } 191 192 199 protected final AnnotationModelEvent getAnnotationModelEvent() { 200 synchronized (getLockObject()) { 201 if (fModelEvent == null) { 202 fModelEvent= createAnnotationModelEvent(); 203 fModelEvent.markWorldChange(false); 204 fModificationStamp= fModelEvent; 205 } 206 return fModelEvent; 207 } 208 } 209 210 213 public void addAnnotation(Annotation annotation, Position position) { 214 try { 215 addAnnotation(annotation, position, true); 216 } catch (BadLocationException e) { 217 } 219 } 220 221 225 public void replaceAnnotations(Annotation[] annotationsToRemove, Map annotationsToAdd) { 226 try { 227 replaceAnnotations(annotationsToRemove, annotationsToAdd, true); 228 } catch (BadLocationException x) { 229 } 230 } 231 232 244 protected void replaceAnnotations(Annotation[] annotationsToRemove, Map annotationsToAdd, boolean fireModelChanged) throws BadLocationException { 245 246 if (annotationsToRemove != null) { 247 for (int i= 0, length= annotationsToRemove.length; i < length; i++) 248 removeAnnotation(annotationsToRemove[i], false); 249 } 250 251 if (annotationsToAdd != null) { 252 Iterator iter= annotationsToAdd.entrySet().iterator(); 253 while (iter.hasNext()) { 254 Map.Entry mapEntry= (Map.Entry ) iter.next(); 255 Annotation annotation= (Annotation) mapEntry.getKey(); 256 Position position= (Position) mapEntry.getValue(); 257 addAnnotation(annotation, position, false); 258 } 259 } 260 261 if (fireModelChanged) 262 fireModelChanged(); 263 } 264 265 276 protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) throws BadLocationException { 277 if (!fAnnotations.containsKey(annotation)) { 278 279 addPosition(fDocument, position); 280 fAnnotations.put(annotation, position); 281 synchronized (getLockObject()) { 282 getAnnotationModelEvent().annotationAdded(annotation); 283 } 284 285 if (fireModelChanged) 286 fireModelChanged(); 287 } 288 } 289 290 293 public void addAnnotationModelListener(IAnnotationModelListener listener) { 294 if (!fAnnotationModelListeners.contains(listener)) { 295 fAnnotationModelListeners.add(listener); 296 if (listener instanceof IAnnotationModelListenerExtension) { 297 IAnnotationModelListenerExtension extension= (IAnnotationModelListenerExtension) listener; 298 AnnotationModelEvent event= createAnnotationModelEvent(); 299 event.markSealed(); 300 extension.modelChanged(event); 301 } else 302 listener.modelChanged(this); 303 } 304 } 305 306 314 protected void addPosition(IDocument document, Position position) throws BadLocationException { 315 if (document != null) 316 document.addPosition(position); 317 } 318 319 328 protected void removePosition(IDocument document, Position position) { 329 if (document != null) 330 document.removePosition(position); 331 } 332 333 336 public void connect(IDocument document) { 337 Assert.isTrue(fDocument == null || fDocument == document); 338 339 if (fDocument == null) { 340 fDocument= document; 341 Iterator e= getAnnotationMap().valuesIterator(); 342 while (e.hasNext()) 343 try { 344 addPosition(fDocument, (Position) e.next()); 345 } catch (BadLocationException x) { 346 } 348 } 349 350 ++ fOpenConnections; 351 if (fOpenConnections == 1) { 352 fDocument.addDocumentListener(fDocumentListener); 353 connected(); 354 } 355 356 for (Iterator it= fAttachments.keySet().iterator(); it.hasNext();) { 357 IAnnotationModel model= (IAnnotationModel) fAttachments.get(it.next()); 358 model.connect(document); 359 } 360 } 361 362 366 protected void connected() { 367 } 368 369 373 protected void disconnected() { 374 } 375 376 379 public void disconnect(IDocument document) { 380 381 Assert.isTrue(fDocument == document); 382 383 for (Iterator it= fAttachments.keySet().iterator(); it.hasNext();) { 384 IAnnotationModel model= (IAnnotationModel) fAttachments.get(it.next()); 385 model.disconnect(document); 386 } 387 388 -- fOpenConnections; 389 if (fOpenConnections == 0) { 390 391 disconnected(); 392 fDocument.removeDocumentListener(fDocumentListener); 393 394 if (fDocument != null) { 395 Iterator e= getAnnotationMap().valuesIterator(); 396 while (e.hasNext()) { 397 Position p= (Position) e.next(); 398 removePosition(fDocument, p); 399 } 400 fDocument= null; 401 } 402 } 403 } 404 405 408 protected void fireModelChanged() { 409 AnnotationModelEvent modelEvent= null; 410 411 synchronized(getLockObject()) { 412 if (fModelEvent != null) { 413 modelEvent= fModelEvent; 414 fModelEvent= null; 415 } 416 } 417 418 if (modelEvent != null) 419 fireModelChanged(modelEvent); 420 } 421 422 428 protected AnnotationModelEvent createAnnotationModelEvent() { 429 return new AnnotationModelEvent(this); 430 } 431 432 441 protected void fireModelChanged(AnnotationModelEvent event) { 442 443 event.markSealed(); 444 445 if (event.isEmpty()) 446 return; 447 448 ArrayList v= new ArrayList (fAnnotationModelListeners); 449 Iterator e= v.iterator(); 450 while (e.hasNext()) { 451 IAnnotationModelListener l= (IAnnotationModelListener) e.next(); 452 if (l instanceof IAnnotationModelListenerExtension) 453 ((IAnnotationModelListenerExtension) l).modelChanged(event); 454 else if (l != null) 455 l.modelChanged(this); 456 } 457 } 458 459 469 protected void removeAnnotations(List annotations, boolean fireModelChanged, boolean modelInitiated) { 470 if (annotations.size() > 0) { 471 Iterator e= annotations.iterator(); 472 while (e.hasNext()) 473 removeAnnotation((Annotation) e.next(), false); 474 475 if (fireModelChanged) 476 fireModelChanged(); 477 } 478 } 479 480 486 protected void cleanup(boolean fireModelChanged) { 487 cleanup(fireModelChanged, true); 488 } 489 490 499 private void cleanup(boolean fireModelChanged, boolean forkNotification) { 500 if (fDocumentChanged) { 501 fDocumentChanged= false; 502 503 ArrayList deleted= new ArrayList (); 504 Iterator e= getAnnotationMap().keySetIterator(); 505 while (e.hasNext()) { 506 Annotation a= (Annotation) e.next(); 507 Position p= (Position) fAnnotations.get(a); 508 if (p == null || p.isDeleted()) 509 deleted.add(a); 510 } 511 512 if (fireModelChanged && forkNotification) { 513 removeAnnotations(deleted, false, false); 514 synchronized (getLockObject()) { 515 if (fModelEvent != null) 516 new Thread () { 517 public void run() { 518 fireModelChanged(); 519 } 520 }.start(); 521 } 522 } else 523 removeAnnotations(deleted, fireModelChanged, false); 524 } 525 } 526 527 530 public Iterator getAnnotationIterator() { 531 return getAnnotationIterator(true, true); 532 } 533 534 545 private Iterator getAnnotationIterator(boolean cleanup, boolean recurse) { 546 547 if (!recurse || fAttachments.isEmpty()) 548 return getAnnotationIterator(cleanup); 549 550 List iterators= new ArrayList (fAttachments.size() + 1); 551 iterators.add(getAnnotationIterator(cleanup)); 552 for (Iterator it= fAttachments.keySet().iterator(); it.hasNext();) { 553 iterators.add(((IAnnotationModel) fAttachments.get(it.next())).getAnnotationIterator()); 554 } 555 556 return new MetaIterator(iterators.iterator()); 557 } 558 559 567 protected Iterator getAnnotationIterator(boolean cleanup) { 568 if (cleanup) 569 cleanup(true); 570 571 return getAnnotationMap().keySetIterator(); 572 } 573 574 577 public Position getPosition(Annotation annotation) { 578 Position position= (Position) fAnnotations.get(annotation); 579 if (position != null) 580 return position; 581 582 Iterator it= fAttachments.values().iterator(); 583 while (position == null && it.hasNext()) 584 position= ((IAnnotationModel) it.next()).getPosition(annotation); 585 return position; 586 } 587 588 592 public void removeAllAnnotations() { 593 removeAllAnnotations(true); 594 } 595 596 602 protected void removeAllAnnotations(boolean fireModelChanged) { 603 604 if (fDocument != null) { 605 Iterator e= getAnnotationMap().keySetIterator(); 606 while (e.hasNext()) { 607 Annotation a= (Annotation) e.next(); 608 Position p= (Position) fAnnotations.get(a); 609 removePosition(fDocument, p); 610 synchronized (getLockObject()) { 612 getAnnotationModelEvent().annotationRemoved(a, p); 613 } 614 } 615 } 616 617 fAnnotations.clear(); 618 619 if (fireModelChanged) 620 fireModelChanged(); 621 } 622 623 626 public void removeAnnotation(Annotation annotation) { 627 removeAnnotation(annotation, true); 628 } 629 630 637 protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) { 638 if (fAnnotations.containsKey(annotation)) { 639 640 Position p= null; 641 if (fDocument != null) { 642 p= (Position) fAnnotations.get(annotation); 643 removePosition(fDocument, p); 644 } 646 647 fAnnotations.remove(annotation); 648 synchronized (getLockObject()) { 649 getAnnotationModelEvent().annotationRemoved(annotation, p); 650 } 651 652 if (fireModelChanged) 653 fireModelChanged(); 654 } 655 } 656 657 661 public void modifyAnnotationPosition(Annotation annotation, Position position) { 662 modifyAnnotationPosition(annotation, position, true); 663 } 664 665 681 protected void modifyAnnotationPosition(Annotation annotation, Position position, boolean fireModelChanged) { 682 if (position == null) { 683 removeAnnotation(annotation, fireModelChanged); 684 } else { 685 Position p= (Position) fAnnotations.get(annotation); 686 if (p != null) { 687 688 if (position.getOffset() != p.getOffset() || position.getLength() != p.getLength()) { 689 p.setOffset(position.getOffset()); 690 p.setLength(position.getLength()); 691 } 692 synchronized (getLockObject()) { 693 getAnnotationModelEvent().annotationChanged(annotation); 694 } 695 if (fireModelChanged) 696 fireModelChanged(); 697 698 } else { 699 try { 700 addAnnotation(annotation, position, fireModelChanged); 701 } catch (BadLocationException x) { 702 } 704 } 705 } 706 } 707 708 719 protected void modifyAnnotation(Annotation annotation, boolean fireModelChanged) { 720 if (fAnnotations.containsKey(annotation)) { 721 synchronized (getLockObject()) { 722 getAnnotationModelEvent().annotationChanged(annotation); 723 } 724 if (fireModelChanged) 725 fireModelChanged(); 726 } 727 } 728 729 732 public void removeAnnotationModelListener(IAnnotationModelListener listener) { 733 fAnnotationModelListeners.remove(listener); 734 } 735 736 740 public void addAnnotationModel(Object key, IAnnotationModel attachment) { 741 Assert.isNotNull(attachment); 742 if (!fAttachments.containsValue(attachment)) { 743 fAttachments.put(key, attachment); 744 for (int i= 0; i < fOpenConnections; i++) 745 attachment.connect(fDocument); 746 attachment.addAnnotationModelListener(fModelListener); 747 } 748 } 749 750 754 public IAnnotationModel getAnnotationModel(Object key) { 755 return (IAnnotationModel) fAttachments.get(key); 756 } 757 758 762 public IAnnotationModel removeAnnotationModel(Object key) { 763 IAnnotationModel ret= (IAnnotationModel) fAttachments.remove(key); 764 if (ret != null) { 765 for (int i= 0; i < fOpenConnections; i++) 766 ret.disconnect(fDocument); 767 ret.removeAnnotationModelListener(fModelListener); 768 } 769 return ret; 770 } 771 772 776 public Object getModificationStamp() { 777 return fModificationStamp; 778 } 779 } 780 | Popular Tags |