1 11 package org.eclipse.jface.text.link; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.HashSet ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 import java.util.Map ; 19 import java.util.Set ; 20 21 import org.eclipse.core.runtime.Assert; 22 23 import org.eclipse.text.edits.MalformedTreeException; 24 import org.eclipse.text.edits.TextEdit; 25 26 import org.eclipse.jface.text.BadLocationException; 27 import org.eclipse.jface.text.BadPositionCategoryException; 28 import org.eclipse.jface.text.DocumentEvent; 29 import org.eclipse.jface.text.IDocument; 30 import org.eclipse.jface.text.IDocumentExtension; 31 import org.eclipse.jface.text.IDocumentListener; 32 import org.eclipse.jface.text.IPositionUpdater; 33 import org.eclipse.jface.text.Position; 34 import org.eclipse.jface.text.IDocumentExtension.IReplace; 35 36 67 public class LinkedModeModel { 68 69 76 public static boolean hasInstalledModel(IDocument document) { 77 return LinkedModeManager.hasManager(document); 79 } 80 81 89 public static boolean hasInstalledModel(IDocument[] documents) { 90 return LinkedModeManager.hasManager(documents); 92 } 93 94 101 public static void closeAllModels(IDocument document) { 102 LinkedModeManager.cancelManager(document); 103 } 104 105 116 public static LinkedModeModel getModel(IDocument document, int offset) { 117 if (!hasInstalledModel(document)) 118 return null; 119 120 LinkedModeManager mgr= LinkedModeManager.getLinkedManager(new IDocument[] {document}, false); 121 if (mgr != null) 122 return mgr.getTopEnvironment(); 123 return null; 124 } 125 126 130 private class Replace implements IReplace { 131 132 133 private TextEdit fEdit; 134 135 140 public Replace(TextEdit edit) { 141 fEdit= edit; 142 } 143 144 147 public void perform(IDocument document, IDocumentListener owner) throws RuntimeException , MalformedTreeException { 148 document.removeDocumentListener(owner); 149 fIsChanging= true; 150 try { 151 fEdit.apply(document, TextEdit.UPDATE_REGIONS | TextEdit.CREATE_UNDO); 152 } catch (BadLocationException e) { 153 156 throw new RuntimeException (e); 157 } finally { 158 document.addDocumentListener(owner); 159 fIsChanging= false; 160 } 161 } 162 163 } 164 165 169 private class DocumentListener implements IDocumentListener { 170 171 private boolean fExit= false; 172 173 179 public void documentAboutToBeChanged(DocumentEvent event) { 180 if (fParentEnvironment != null && fParentEnvironment.isChanging()) 182 return; 183 184 for (Iterator it= fGroups.iterator(); it.hasNext(); ) { 185 LinkedPositionGroup group= (LinkedPositionGroup) it.next(); 186 if (!group.isLegalEvent(event)) { 187 fExit= true; 188 return; 189 } 190 } 191 } 192 193 198 public void documentChanged(DocumentEvent event) { 199 if (fExit) { 200 LinkedModeModel.this.exit(ILinkedModeListener.EXTERNAL_MODIFICATION); 201 return; 202 } 203 fExit= false; 204 205 if (fParentEnvironment != null && fParentEnvironment.isChanging()) 207 return; 208 209 Map result= null; 211 for (Iterator it= fGroups.iterator(); it.hasNext();) { 212 LinkedPositionGroup group= (LinkedPositionGroup) it.next(); 213 214 Map map= group.handleEvent(event); 215 if (result != null && map != null) { 216 LinkedModeModel.this.exit(ILinkedModeListener.EXTERNAL_MODIFICATION); 218 return; 219 } 220 if (map != null) 221 result= map; 222 } 223 224 if (result != null) { 225 for (Iterator it2= result.keySet().iterator(); it2.hasNext(); ) { 227 IDocument doc= (IDocument) it2.next(); 228 TextEdit edit= (TextEdit) result.get(doc); 229 Replace replace= new Replace(edit); 230 231 if (doc == event.getDocument()) { 235 if (doc instanceof IDocumentExtension) { 236 ((IDocumentExtension) doc).registerPostNotificationReplace(this, replace); 237 } else { 238 } 240 } else { 241 replace.perform(doc, this); 242 } 243 } 244 } 245 } 246 247 } 248 249 250 private final List fGroups= new ArrayList (); 251 252 private final Set fDocuments= new HashSet (); 253 254 private final IPositionUpdater fUpdater= new InclusivePositionUpdater(getCategory()); 255 256 private final DocumentListener fDocumentListener= new DocumentListener(); 257 258 private LinkedModeModel fParentEnvironment; 259 264 private LinkedPosition fParentPosition= null; 265 269 private boolean fIsSealed= false; 270 271 private boolean fIsChanging= false; 272 273 private final List fListeners= new ArrayList (); 274 275 private boolean fIsActive= true; 276 280 private List fPositionSequence= new ArrayList (); 281 282 289 private boolean isChanging() { 290 return fIsChanging || fParentEnvironment != null && fParentEnvironment.isChanging(); 291 } 292 293 301 private void enforceDisjoint(LinkedPositionGroup group) throws BadLocationException { 302 for (Iterator it= fGroups.iterator(); it.hasNext(); ) { 303 LinkedPositionGroup g= (LinkedPositionGroup) it.next(); 304 g.enforceDisjoint(group); 305 } 306 } 307 308 314 public void exit(int flags) { 315 if (!fIsActive) 316 return; 317 318 fIsActive= false; 319 320 for (Iterator it= fDocuments.iterator(); it.hasNext(); ) { 321 IDocument doc= (IDocument) it.next(); 322 try { 323 doc.removePositionCategory(getCategory()); 324 } catch (BadPositionCategoryException e) { 325 Assert.isTrue(false); 327 } 328 doc.removePositionUpdater(fUpdater); 329 doc.removeDocumentListener(fDocumentListener); 330 } 331 332 fDocuments.clear(); 333 fGroups.clear(); 334 335 List listeners= new ArrayList (fListeners); 336 fListeners.clear(); 337 for (Iterator it= listeners.iterator(); it.hasNext(); ) { 338 ILinkedModeListener listener= (ILinkedModeListener) it.next(); 339 listener.left(this, flags); 340 } 341 342 343 if (fParentEnvironment != null) 344 fParentEnvironment.resume(flags); 345 } 346 347 355 public void stopForwarding(int flags) { 356 fDocumentListener.fExit= true; 357 } 358 359 366 private void manageDocument(IDocument document) { 367 if (!fDocuments.contains(document)) { 368 fDocuments.add(document); 369 document.addPositionCategory(getCategory()); 370 document.addPositionUpdater(fUpdater); 371 document.addDocumentListener(fDocumentListener); 372 } 373 374 } 375 376 381 private String getCategory() { 382 return toString(); 383 } 384 385 407 public void addGroup(LinkedPositionGroup group) throws BadLocationException { 408 if (group == null) 409 throw new IllegalArgumentException ("group may not be null"); if (fIsSealed) 411 throw new IllegalStateException ("model is already installed"); if (fGroups.contains(group)) 413 return; 415 416 enforceDisjoint(group); 417 group.seal(); 418 fGroups.add(group); 419 } 420 421 425 public LinkedModeModel() { 426 } 427 428 441 public void forceInstall() throws BadLocationException { 442 if (!install(true)) 443 Assert.isTrue(false); 444 } 445 446 462 public boolean tryInstall() throws BadLocationException { 463 return install(false); 464 } 465 466 482 private boolean install(boolean force) throws BadLocationException { 483 if (fIsSealed) 484 throw new IllegalStateException ("model is already installed"); enforceNotEmpty(); 486 487 IDocument[] documents= getDocuments(); 488 LinkedModeManager manager= LinkedModeManager.getLinkedManager(documents, force); 489 Assert.isTrue(!(force && manager == null)); 491 if (manager == null) 492 return false; 493 494 if (!manager.nestEnvironment(this, force)) 495 if (force) 496 Assert.isTrue(false); 497 else 498 return false; 499 500 fIsSealed= true; 503 if (fParentEnvironment != null) 504 fParentEnvironment.suspend(); 505 506 try { 508 for (Iterator it= fGroups.iterator(); it.hasNext(); ) { 509 LinkedPositionGroup group= (LinkedPositionGroup) it.next(); 510 group.register(this); 511 } 512 return true; 513 } catch (BadLocationException e){ 514 exit(ILinkedModeListener.NONE); 516 throw e; 517 } 518 } 519 520 524 private void enforceNotEmpty() { 525 boolean hasPosition= false; 526 for (Iterator it= fGroups.iterator(); it.hasNext(); ) 527 if (!((LinkedPositionGroup) it.next()).isEmpty()) { 528 hasPosition= true; 529 break; 530 } 531 if (!hasPosition) 532 throw new IllegalStateException ("must specify at least one linked position"); 534 } 535 536 540 private IDocument[] getDocuments() { 541 Set docs= new HashSet (); 542 for (Iterator it= fGroups.iterator(); it.hasNext(); ) { 543 LinkedPositionGroup group= (LinkedPositionGroup) it.next(); 544 docs.addAll(Arrays.asList(group.getDocuments())); 545 } 546 return (IDocument[]) docs.toArray(new IDocument[docs.size()]); 547 } 548 549 557 boolean canNestInto(LinkedModeModel parent) { 558 for (Iterator it= fGroups.iterator(); it.hasNext(); ) { 559 LinkedPositionGroup group= (LinkedPositionGroup) it.next(); 560 if (!enforceNestability(group, parent)) { 561 fParentPosition= null; 562 return false; 563 } 564 } 565 566 Assert.isNotNull(fParentPosition); 567 fParentEnvironment= parent; 568 return true; 569 } 570 571 580 private boolean enforceNestability(LinkedPositionGroup group, LinkedModeModel model) { 581 Assert.isNotNull(model); 582 Assert.isNotNull(group); 583 584 try { 585 for (Iterator it= model.fGroups.iterator(); it.hasNext(); ) { 586 LinkedPositionGroup pg= (LinkedPositionGroup) it.next(); 587 LinkedPosition pos; 588 pos= pg.adopt(group); 589 if (pos != null && fParentPosition != null && fParentPosition != pos) 590 return false; else if (fParentPosition == null && pos != null) 592 fParentPosition= pos; 593 } 594 } catch (BadLocationException e) { 595 return false; 596 } 597 598 return fParentPosition != null; 600 } 601 602 613 public boolean isNested() { 614 return fParentEnvironment != null; 615 } 616 617 629 public List getTabStopSequence() { 630 return fPositionSequence; 631 } 632 633 639 public void addLinkingListener(ILinkedModeListener listener) { 640 Assert.isNotNull(listener); 641 if (!fListeners.contains(listener)) 642 fListeners.add(listener); 643 } 644 645 651 public void removeLinkingListener(ILinkedModeListener listener) { 652 fListeners.remove(listener); 653 } 654 655 669 public LinkedPosition findPosition(LinkedPosition toFind) { 670 LinkedPosition position= null; 671 for (Iterator it= fGroups.iterator(); it.hasNext(); ) { 672 LinkedPositionGroup group= (LinkedPositionGroup) it.next(); 673 position= group.getPosition(toFind); 674 if (position != null) 675 break; 676 } 677 return position; 678 } 679 680 688 void register(LinkedPosition position) throws BadLocationException { 689 Assert.isNotNull(position); 690 691 IDocument document= position.getDocument(); 692 manageDocument(document); 693 try { 694 document.addPosition(getCategory(), position); 695 } catch (BadPositionCategoryException e) { 696 Assert.isTrue(false); 698 } 699 int seqNr= position.getSequenceNumber(); 700 if (seqNr != LinkedPositionGroup.NO_STOP) { 701 fPositionSequence.add(position); 702 } 703 } 704 705 708 private void suspend() { 709 List l= new ArrayList (fListeners); 710 for (Iterator it= l.iterator(); it.hasNext(); ) { 711 ILinkedModeListener listener= (ILinkedModeListener) it.next(); 712 listener.suspend(this); 713 } 714 } 715 716 722 private void resume(int flags) { 723 List l= new ArrayList (fListeners); 724 for (Iterator it= l.iterator(); it.hasNext(); ) { 725 ILinkedModeListener listener= (ILinkedModeListener) it.next(); 726 listener.resume(this, flags); 727 } 728 } 729 730 739 public boolean anyPositionContains(int offset) { 740 for (Iterator it= fGroups.iterator(); it.hasNext(); ) { 741 LinkedPositionGroup group= (LinkedPositionGroup) it.next(); 742 if (group.contains(offset)) 743 return true; 746 } 747 return false; 748 } 749 750 767 public LinkedPositionGroup getGroupForPosition(Position position) { 768 for (Iterator it= fGroups.iterator(); it.hasNext(); ) { 769 LinkedPositionGroup group= (LinkedPositionGroup) it.next(); 770 if (group.contains(position)) 771 return group; 772 } 773 return null; 774 } 775 } 776 | Popular Tags |