1 11 package org.eclipse.jface.text.source.projection; 12 13 14 import java.util.ArrayList ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 18 import org.eclipse.swt.SWTError; 19 import org.eclipse.swt.custom.ST; 20 import org.eclipse.swt.custom.StyledText; 21 import org.eclipse.swt.dnd.Clipboard; 22 import org.eclipse.swt.dnd.DND; 23 import org.eclipse.swt.dnd.TextTransfer; 24 import org.eclipse.swt.dnd.Transfer; 25 import org.eclipse.swt.events.VerifyEvent; 26 import org.eclipse.swt.graphics.Point; 27 import org.eclipse.swt.widgets.Composite; 28 import org.eclipse.swt.widgets.Display; 29 30 import org.eclipse.core.runtime.Assert; 31 import org.eclipse.core.runtime.NullProgressMonitor; 32 33 import org.eclipse.jface.text.BadLocationException; 34 import org.eclipse.jface.text.DocumentEvent; 35 import org.eclipse.jface.text.FindReplaceDocumentAdapter; 36 import org.eclipse.jface.text.IDocument; 37 import org.eclipse.jface.text.IDocumentInformationMappingExtension; 38 import org.eclipse.jface.text.IDocumentListener; 39 import org.eclipse.jface.text.IRegion; 40 import org.eclipse.jface.text.ISlaveDocumentManager; 41 import org.eclipse.jface.text.ITextViewerExtension5; 42 import org.eclipse.jface.text.Position; 43 import org.eclipse.jface.text.Region; 44 import org.eclipse.jface.text.TextUtilities; 45 import org.eclipse.jface.text.projection.ProjectionDocument; 46 import org.eclipse.jface.text.projection.ProjectionDocumentEvent; 47 import org.eclipse.jface.text.projection.ProjectionDocumentManager; 48 import org.eclipse.jface.text.source.Annotation; 49 import org.eclipse.jface.text.source.AnnotationModelEvent; 50 import org.eclipse.jface.text.source.CompositeRuler; 51 import org.eclipse.jface.text.source.IAnnotationModel; 52 import org.eclipse.jface.text.source.IAnnotationModelExtension; 53 import org.eclipse.jface.text.source.IAnnotationModelListener; 54 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension; 55 import org.eclipse.jface.text.source.IOverviewRuler; 56 import org.eclipse.jface.text.source.IVerticalRuler; 57 import org.eclipse.jface.text.source.IVerticalRulerColumn; 58 import org.eclipse.jface.text.source.SourceViewer; 59 60 61 75 public class ProjectionViewer extends SourceViewer implements ITextViewerExtension5 { 76 77 private static final int BASE= INFORMATION; 79 80 public static final int EXPAND= BASE + 1; 81 82 public static final int COLLAPSE= BASE + 2; 83 84 public static final int TOGGLE= BASE + 3; 85 86 public static final int EXPAND_ALL= BASE + 4; 87 92 public static final int COLLAPSE_ALL= BASE + 5; 93 94 97 private class AnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension { 98 99 102 public void modelChanged(IAnnotationModel model) { 103 processModelChanged(model, null); 104 } 105 106 109 public void modelChanged(AnnotationModelEvent event) { 110 processModelChanged(event.getAnnotationModel(), event); 111 } 112 113 private void processModelChanged(IAnnotationModel model, AnnotationModelEvent event) { 114 if (model == fProjectionAnnotationModel) { 115 116 if (fProjectionSummary != null) 117 fProjectionSummary.updateSummaries(new NullProgressMonitor()); 118 processCatchupRequest(event); 119 120 } else if (model == getAnnotationModel() && fProjectionSummary != null) 121 fProjectionSummary.updateSummaries(new NullProgressMonitor()); 122 } 123 } 124 125 128 private class ReplaceVisibleDocumentExecutor implements IDocumentListener { 129 130 private IDocument fSlaveDocument; 131 private IDocument fExecutionTrigger; 132 133 138 public ReplaceVisibleDocumentExecutor(IDocument slaveDocument) { 139 fSlaveDocument= slaveDocument; 140 } 141 142 147 public void install(IDocument executionTrigger) { 148 if (executionTrigger != null && fSlaveDocument != null) { 149 fExecutionTrigger= executionTrigger; 150 fExecutionTrigger.addDocumentListener(this); 151 } 152 } 153 154 157 public void documentAboutToBeChanged(DocumentEvent event) { 158 } 159 160 163 public void documentChanged(DocumentEvent event) { 164 fExecutionTrigger.removeDocumentListener(this); 165 executeReplaceVisibleDocument(fSlaveDocument); 166 } 167 } 168 169 174 private static class ProjectionCommand { 175 176 final static int ADD= 0; 177 final static int REMOVE= 1; 178 final static int INVALIDATE_PRESENTATION= 2; 179 180 ProjectionDocument fProjection; 181 int fType; 182 int fOffset; 183 int fLength; 184 185 ProjectionCommand(ProjectionDocument projection, int type, int offset, int length) { 186 fProjection= projection; 187 fType= type; 188 fOffset= offset; 189 fLength= length; 190 } 191 192 ProjectionCommand(int offset, int length) { 193 fType= INVALIDATE_PRESENTATION; 194 fOffset= offset; 195 fLength= length; 196 } 197 198 int computeExpectedCosts() { 199 200 switch(fType) { 201 case ADD: { 202 try { 203 IRegion[] gaps= fProjection.computeUnprojectedMasterRegions(fOffset, fLength); 204 return gaps == null ? 0 : gaps.length; 205 } catch (BadLocationException x) { 206 } 207 break; 208 } 209 case REMOVE: { 210 try { 211 IRegion[] fragments= fProjection.computeProjectedMasterRegions(fOffset, fLength); 212 return fragments == null ? 0 : fragments.length; 213 } catch (BadLocationException x) { 214 } 215 break; 216 } 217 } 218 return 0; 219 } 220 } 221 222 225 private static class ProjectionCommandQueue { 226 227 final static int REDRAW_COSTS= 15; 228 final static int INVALIDATION_COSTS= 10; 229 230 List fList= new ArrayList (15); 231 int fExpectedExecutionCosts= -1; 232 233 234 void add(ProjectionCommand command) { 235 fList.add(command); 236 } 237 238 Iterator iterator() { 239 return fList.iterator(); 240 } 241 242 void clear() { 243 fList.clear(); 244 fExpectedExecutionCosts= -1; 245 } 246 247 boolean passedRedrawCostsThreshold() { 248 if (fExpectedExecutionCosts == -1) 249 computeExpectedExecutionCosts(); 250 return fExpectedExecutionCosts > REDRAW_COSTS; 251 } 252 253 boolean passedInvalidationCostsThreshold() { 254 if (fExpectedExecutionCosts == -1) 255 computeExpectedExecutionCosts(); 256 return fExpectedExecutionCosts > INVALIDATION_COSTS; 257 } 258 259 private void computeExpectedExecutionCosts() { 260 int max_costs= Math.max(REDRAW_COSTS, INVALIDATION_COSTS); 261 fExpectedExecutionCosts= fList.size(); 262 if (fExpectedExecutionCosts <= max_costs) { 263 ProjectionCommand command; 264 Iterator e= fList.iterator(); 265 while (e.hasNext()) { 266 command= (ProjectionCommand) e.next(); 267 fExpectedExecutionCosts += command.computeExpectedCosts(); 268 if (fExpectedExecutionCosts > max_costs) 269 break; 270 } 271 } 272 } 273 } 274 275 276 private ProjectionAnnotationModel fProjectionAnnotationModel; 277 278 private IAnnotationModelListener fAnnotationModelListener= new AnnotationModelListener(); 279 280 private ProjectionSummary fProjectionSummary; 281 282 private boolean fPendingAnnotationWorldChange= false; 283 284 private boolean fHandleProjectionChanges= true; 285 286 private List fProjectionListeners; 287 288 private Object fLock= new Object (); 289 290 private List fPendingRequests= new ArrayList (); 291 292 private IDocument fReplaceVisibleDocumentExecutionTrigger; 293 294 private boolean fWasProjectionEnabled; 295 296 private ProjectionCommandQueue fCommandQueue; 297 302 private int fDeletedLines; 303 304 305 314 public ProjectionViewer(Composite parent, IVerticalRuler ruler, IOverviewRuler overviewRuler, boolean showsAnnotationOverview, int styles) { 315 super(parent, ruler, overviewRuler, showsAnnotationOverview, styles); 316 } 317 318 323 public void setProjectionSummary(ProjectionSummary projectionSummary) { 324 fProjectionSummary= projectionSummary; 325 } 326 327 332 private void addProjectionAnnotationModel(IAnnotationModel model) { 333 if (model instanceof IAnnotationModelExtension) { 334 IAnnotationModelExtension extension= (IAnnotationModelExtension) model; 335 extension.addAnnotationModel(ProjectionSupport.PROJECTION, fProjectionAnnotationModel); 336 model.addAnnotationModelListener(fAnnotationModelListener); 337 } 338 } 339 340 346 private IAnnotationModel removeProjectionAnnotationModel(IAnnotationModel model) { 347 if (model instanceof IAnnotationModelExtension) { 348 model.removeAnnotationModelListener(fAnnotationModelListener); 349 IAnnotationModelExtension extension= (IAnnotationModelExtension) model; 350 return extension.removeAnnotationModel(ProjectionSupport.PROJECTION); 351 } 352 return null; 353 } 354 355 358 public void setDocument(IDocument document, IAnnotationModel annotationModel, int modelRangeOffset, int modelRangeLength) { 359 boolean wasProjectionEnabled= false; 360 361 synchronized (fLock) { 362 fPendingRequests.clear(); 363 } 364 365 if (fProjectionAnnotationModel != null) { 366 wasProjectionEnabled= removeProjectionAnnotationModel(getVisualAnnotationModel()) != null; 367 fProjectionAnnotationModel= null; 368 } 369 370 super.setDocument(document, annotationModel, modelRangeOffset, modelRangeLength); 371 372 if (wasProjectionEnabled && document != null) 373 enableProjection(); 374 } 375 376 379 protected IAnnotationModel createVisualAnnotationModel(IAnnotationModel annotationModel) { 380 IAnnotationModel model= super.createVisualAnnotationModel(annotationModel); 381 fProjectionAnnotationModel= new ProjectionAnnotationModel(); 382 return model; 383 } 384 385 390 public ProjectionAnnotationModel getProjectionAnnotationModel() { 391 IAnnotationModel model= getVisualAnnotationModel(); 392 if (model instanceof IAnnotationModelExtension) { 393 IAnnotationModelExtension extension= (IAnnotationModelExtension) model; 394 return (ProjectionAnnotationModel) extension.getAnnotationModel(ProjectionSupport.PROJECTION); 395 } 396 return null; 397 } 398 399 402 protected ISlaveDocumentManager createSlaveDocumentManager() { 403 return new ProjectionDocumentManager(); 404 } 405 406 409 protected boolean updateSlaveDocument(IDocument slaveDocument, int modelRangeOffset, int modelRangeLength) throws BadLocationException { 410 if (slaveDocument instanceof ProjectionDocument) { 411 ProjectionDocument projection= (ProjectionDocument) slaveDocument; 412 413 int offset= modelRangeOffset; 414 int length= modelRangeLength; 415 416 if (!isProjectionMode()) { 417 IDocument master= projection.getMasterDocument(); 419 int line= master.getLineOfOffset(modelRangeOffset); 420 offset= master.getLineOffset(line); 421 length= (modelRangeOffset - offset) + modelRangeLength; 422 423 } 424 425 try { 426 fHandleProjectionChanges= false; 427 projection.replaceMasterDocumentRanges(offset, length); 428 } finally { 429 fHandleProjectionChanges= true; 430 } 431 return true; 432 } 433 return false; 434 } 435 436 443 public void addProjectionListener(IProjectionListener listener) { 444 445 Assert.isNotNull(listener); 446 447 if (fProjectionListeners == null) 448 fProjectionListeners= new ArrayList (); 449 450 if (!fProjectionListeners.contains(listener)) 451 fProjectionListeners.add(listener); 452 } 453 454 461 public void removeProjectionListener(IProjectionListener listener) { 462 463 Assert.isNotNull(listener); 464 465 if (fProjectionListeners != null) { 466 fProjectionListeners.remove(listener); 467 if (fProjectionListeners.size() == 0) 468 fProjectionListeners= null; 469 } 470 } 471 472 476 protected void fireProjectionEnabled() { 477 if (fProjectionListeners != null) { 478 Iterator e= new ArrayList (fProjectionListeners).iterator(); 479 while (e.hasNext()) { 480 IProjectionListener l= (IProjectionListener) e.next(); 481 l.projectionEnabled(); 482 } 483 } 484 } 485 486 490 protected void fireProjectionDisabled() { 491 if (fProjectionListeners != null) { 492 Iterator e= new ArrayList (fProjectionListeners).iterator(); 493 while (e.hasNext()) { 494 IProjectionListener l= (IProjectionListener) e.next(); 495 l.projectionDisabled(); 496 } 497 } 498 } 499 500 506 public final boolean isProjectionMode() { 507 return getProjectionAnnotationModel() != null; 508 } 509 510 513 public final void disableProjection() { 514 if (isProjectionMode()) { 515 removeProjectionAnnotationModel(getVisualAnnotationModel()); 516 fProjectionAnnotationModel.removeAllAnnotations(); 517 fFindReplaceDocumentAdapter= null; 518 fireProjectionDisabled(); 519 } 520 } 521 522 525 public final void enableProjection() { 526 if (!isProjectionMode()) { 527 addProjectionAnnotationModel(getVisualAnnotationModel()); 528 fFindReplaceDocumentAdapter= null; 529 fireProjectionEnabled(); 530 } 531 } 532 533 private void expandAll() { 534 int offset= 0; 535 IDocument doc= getDocument(); 536 int length= doc == null ? 0 : doc.getLength(); 537 if (isProjectionMode()) { 538 fProjectionAnnotationModel.expandAll(offset, length); 539 } 540 } 541 542 private void expand() { 543 if (isProjectionMode()) { 544 Position found= null; 545 Annotation bestMatch= null; 546 Point selection= getSelectedRange(); 547 for (Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); e.hasNext();) { 548 ProjectionAnnotation annotation= (ProjectionAnnotation) e.next(); 549 if (annotation.isCollapsed()) { 550 Position position= fProjectionAnnotationModel.getPosition(annotation); 551 if (position != null && touches(selection, position)) 553 if (found == null || position.includes(found.offset) && position.includes(found.offset + found.length)) { 554 found= position; 555 bestMatch= annotation; 556 } 557 } 558 } 559 560 if (bestMatch != null) { 561 fProjectionAnnotationModel.expand(bestMatch); 562 revealRange(selection.x, selection.y); 563 } 564 } 565 } 566 567 private boolean touches(Point selection, Position position) { 568 return position.overlapsWith(selection.x, selection.y) || selection.y == 0 && position.offset + position.length == selection.x + selection.y; 569 } 570 571 private void collapse() { 572 if (isProjectionMode()) { 573 Position found= null; 574 Annotation bestMatch= null; 575 Point selection= getSelectedRange(); 576 for (Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); e.hasNext();) { 577 ProjectionAnnotation annotation= (ProjectionAnnotation) e.next(); 578 if (!annotation.isCollapsed()) { 579 Position position= fProjectionAnnotationModel.getPosition(annotation); 580 if (position != null && touches(selection, position)) 582 if (found == null || found.includes(position.offset) && found.includes(position.offset + position.length)) { 583 found= position; 584 bestMatch= annotation; 585 } 586 } 587 } 588 589 if (bestMatch != null) { 590 fProjectionAnnotationModel.collapse(bestMatch); 591 revealRange(selection.x, selection.y); 592 } 593 } 594 } 595 596 599 private void collapseAll() { 600 int offset= 0; 601 IDocument doc= getDocument(); 602 int length= doc == null ? 0 : doc.getLength(); 603 if (isProjectionMode()) { 604 fProjectionAnnotationModel.collapseAll(offset, length); 605 } 606 } 607 608 620 private void addMasterDocumentRange(ProjectionDocument projection, int offset, int length) throws BadLocationException { 621 622 if (fCommandQueue != null) { 623 fCommandQueue.add(new ProjectionCommand(projection, ProjectionCommand.ADD, offset, length)); 624 } else { 625 try { 626 fHandleProjectionChanges= false; 627 int end= offset + length; 630 offset= toLineStart(projection.getMasterDocument(), offset, false); 631 length= toLineStart(projection.getMasterDocument(), end, true) - offset; 632 projection.addMasterDocumentRange(offset, length); 633 } finally { 634 fHandleProjectionChanges= true; 635 } 636 } 637 } 638 639 651 private void removeMasterDocumentRange(ProjectionDocument projection, int offset, int length) throws BadLocationException { 652 if (fCommandQueue != null) { 653 fCommandQueue.add(new ProjectionCommand(projection, ProjectionCommand.REMOVE, offset, length)); 654 } else { 655 try { 656 fHandleProjectionChanges= false; 657 int end= offset + length; 660 offset= toLineStart(projection.getMasterDocument(), offset, false); 661 length= toLineStart(projection.getMasterDocument(), end, true) - offset; 662 projection.removeMasterDocumentRange(offset, length); 663 } finally { 664 fHandleProjectionChanges= true; 665 } 666 } 667 } 668 669 680 private int toLineStart(IDocument document, int offset, boolean testLastLine) throws BadLocationException { 681 if (document == null) 682 return offset; 683 684 if (testLastLine && offset >= document.getLineInformationOfOffset(document.getLength() - 1).getOffset()) 685 return offset; 686 687 return document.getLineInformationOfOffset(offset).getOffset(); 688 } 689 690 693 public void setVisibleRegion(int start, int length) { 694 if (!isSegmented()) 695 fWasProjectionEnabled= isProjectionMode(); 696 disableProjection(); 697 super.setVisibleRegion(start, length); 698 } 699 700 703 protected void setVisibleDocument(IDocument document) { 704 if (!isProjectionMode()) { 705 super.setVisibleDocument(document); 706 return; 707 } 708 709 FindReplaceDocumentAdapter adapter= fFindReplaceDocumentAdapter; 711 super.setVisibleDocument(document); 712 fFindReplaceDocumentAdapter= adapter; 713 } 714 715 718 public void resetVisibleRegion() { 719 super.resetVisibleRegion(); 720 if (fWasProjectionEnabled) 721 enableProjection(); 722 } 723 724 727 public IRegion getVisibleRegion() { 728 disableProjection(); 729 IRegion visibleRegion= getModelCoverage(); 730 if (visibleRegion == null) 731 visibleRegion= new Region(0, 0); 732 733 return visibleRegion; 734 } 735 736 739 public boolean overlapsWithVisibleRegion(int offset, int length) { 740 disableProjection(); 741 IRegion coverage= getModelCoverage(); 742 if (coverage == null) 743 return false; 744 745 boolean appending= (offset == coverage.getOffset() + coverage.getLength()) && length == 0; 746 return appending || TextUtilities.overlaps(coverage, new Region(offset, length)); 747 } 748 749 755 private void replaceVisibleDocument(IDocument slave) { 756 if (fReplaceVisibleDocumentExecutionTrigger != null) { 757 ReplaceVisibleDocumentExecutor executor= new ReplaceVisibleDocumentExecutor(slave); 758 executor.install(fReplaceVisibleDocumentExecutionTrigger); 759 } else 760 executeReplaceVisibleDocument(slave); 761 } 762 763 764 private void executeReplaceVisibleDocument(IDocument visibleDocument) { 765 StyledText textWidget= getTextWidget(); 766 try { 767 if (textWidget != null && !textWidget.isDisposed()) 768 textWidget.setRedraw(false); 769 770 int topIndex= getTopIndex(); 771 Point selection= getSelectedRange(); 772 setVisibleDocument(visibleDocument); 773 Point currentSelection= getSelectedRange(); 774 if (currentSelection.x != selection.x || currentSelection.y != selection.y) 775 setSelectedRange(selection.x, selection.y); 776 setTopIndex(topIndex); 777 778 } finally { 779 if (textWidget != null && !textWidget.isDisposed()) 780 textWidget.setRedraw(true); 781 } 782 } 783 784 792 private void collapse(int offset, int length, boolean fireRedraw) throws BadLocationException { 793 ProjectionDocument projection= null; 794 795 IDocument visibleDocument= getVisibleDocument(); 796 if (visibleDocument instanceof ProjectionDocument) 797 projection= (ProjectionDocument) visibleDocument; 798 else { 799 IDocument master= getDocument(); 800 IDocument slave= createSlaveDocument(getDocument()); 801 if (slave instanceof ProjectionDocument) { 802 projection= (ProjectionDocument) slave; 803 addMasterDocumentRange(projection, 0, master.getLength()); 804 replaceVisibleDocument(projection); 805 } 806 } 807 808 if (projection != null) 809 removeMasterDocumentRange(projection, offset, length); 810 811 if (projection != null && fireRedraw) { 812 IDocument document= getDocument(); 814 int line= document.getLineOfOffset(offset); 815 if (line > 0) { 816 IRegion info= document.getLineInformation(line - 1); 817 internalInvalidateTextPresentation(info.getOffset(), info.getLength()); 818 } 819 } 820 } 821 822 832 private void expand(int offset, int length, boolean fireRedraw) throws BadLocationException { 833 IDocument slave= getVisibleDocument(); 834 if (slave instanceof ProjectionDocument) { 835 ProjectionDocument projection= (ProjectionDocument) slave; 836 837 addMasterDocumentRange(projection, offset, length); 839 840 ProjectionAnnotation[] collapsed= computeCollapsedNestedAnnotations(offset, length); 842 if (collapsed != null) { 843 for (int i= 0; i < collapsed.length; i++) { 844 IRegion[] regions= computeCollapsedRegions(fProjectionAnnotationModel.getPosition(collapsed[i])); 845 if (regions != null) 846 for (int j= 0; j < regions.length; j++) 847 removeMasterDocumentRange(projection, regions[j].getOffset(), regions[j].getLength()); 848 } 849 } 850 851 if (fireRedraw) 853 internalInvalidateTextPresentation(offset, length); 854 } 855 } 856 857 863 protected final void processCatchupRequest(AnnotationModelEvent event) { 864 if (Display.getCurrent() != null) { 865 boolean run= false; 866 synchronized (fLock) { 867 run= fPendingRequests.isEmpty(); 868 } 869 if (run) { 870 871 try { 872 catchupWithProjectionAnnotationModel(event); 873 } catch (BadLocationException x) { 874 throw new IllegalArgumentException (); 875 } 876 877 } else 878 postCatchupRequest(event); 879 } else { 880 postCatchupRequest(event); 881 } 882 } 883 884 889 protected final void postCatchupRequest(final AnnotationModelEvent event) { 890 synchronized (fLock) { 891 fPendingRequests.add(event); 892 if (fPendingRequests.size() == 1) { 893 StyledText widget= getTextWidget(); 894 if (widget != null) { 895 Display display= widget.getDisplay(); 896 if (display != null) { 897 display.asyncExec(new Runnable () { 898 public void run() { 899 try { 900 while (true) { 901 AnnotationModelEvent ame= null; 902 synchronized (fLock) { 903 if (fPendingRequests.size() == 0) 904 return; 905 ame= (AnnotationModelEvent) fPendingRequests.remove(0); 906 } 907 catchupWithProjectionAnnotationModel(ame); 908 } 909 } catch (BadLocationException x) { 910 try { 911 catchupWithProjectionAnnotationModel(null); 912 } catch (BadLocationException x1) { 913 throw new IllegalArgumentException (); 914 } finally { 915 synchronized (fLock) { 916 fPendingRequests.clear(); 917 } 918 } 919 } 920 } 921 }); 922 } 923 } 924 } 925 } 926 } 927 928 936 private boolean isVisibleMasterDocumentSameAsDocument() { 937 IDocument visibleDocument= getVisibleDocument(); 938 return (visibleDocument instanceof ProjectionDocument) && ((ProjectionDocument)visibleDocument).getMasterDocument() == getDocument(); 939 } 940 941 949 private void catchupWithProjectionAnnotationModel(AnnotationModelEvent event) throws BadLocationException { 950 951 if (event == null || !isVisibleMasterDocumentSameAsDocument()) { 952 953 fPendingAnnotationWorldChange= false; 954 reinitializeProjection(); 955 956 } else if (event.isWorldChange()) { 957 958 if (event.isValid()) { 959 fPendingAnnotationWorldChange= false; 960 reinitializeProjection(); 961 } else 962 fPendingAnnotationWorldChange= true; 963 964 } else if (fPendingAnnotationWorldChange) { 965 if (event.isValid()) { 966 fPendingAnnotationWorldChange= false; 967 reinitializeProjection(); 968 } 969 } else { 970 971 Annotation[] addedAnnotations= event.getAddedAnnotations(); 972 Annotation[] changedAnnotation= event.getChangedAnnotations(); 973 Annotation[] removedAnnotations= event.getRemovedAnnotations(); 974 975 fCommandQueue= new ProjectionCommandQueue(); 976 977 boolean isRedrawing= redraws(); 978 int topIndex= isRedrawing ? getTopIndex() : -1; 979 980 processDeletions(event, removedAnnotations, true); 981 List coverage= new ArrayList (); 982 processChanges(addedAnnotations, true, coverage); 983 processChanges(changedAnnotation, true, coverage); 984 985 ProjectionCommandQueue commandQueue= fCommandQueue; 986 fCommandQueue= null; 987 988 if (commandQueue.passedRedrawCostsThreshold()) { 989 setRedraw(false); 990 try { 991 executeProjectionCommands(commandQueue, false); 992 } catch (IllegalArgumentException x) { 993 reinitializeProjection(); 994 } finally { 995 setRedraw(true, topIndex); 996 } 997 } else { 998 try { 999 boolean fireRedraw= !commandQueue.passedInvalidationCostsThreshold(); 1000 executeProjectionCommands(commandQueue, fireRedraw); 1001 if (!fireRedraw) 1002 invalidateTextPresentation(); 1003 } catch (IllegalArgumentException x) { 1004 reinitializeProjection(); 1005 } 1006 } 1007 } 1008 } 1009 1010 private void executeProjectionCommands(ProjectionCommandQueue commandQueue, boolean fireRedraw) throws BadLocationException { 1011 1012 ProjectionCommand command; 1013 Iterator e= commandQueue.iterator(); 1014 while (e.hasNext()) { 1015 command= (ProjectionCommand) e.next(); 1016 switch (command.fType) { 1017 case ProjectionCommand.ADD: 1018 addMasterDocumentRange(command.fProjection, command.fOffset, command.fLength); 1019 break; 1020 case ProjectionCommand.REMOVE: 1021 removeMasterDocumentRange(command.fProjection, command.fOffset, command.fLength); 1022 break; 1023 case ProjectionCommand.INVALIDATE_PRESENTATION: 1024 if (fireRedraw) 1025 invalidateTextPresentation(command.fOffset, command.fLength); 1026 break; 1027 } 1028 } 1029 1030 commandQueue.clear(); 1031 } 1032 1033 private boolean covers(int offset, int length, Position position) { 1034 if (!(position.offset == offset && position.length == length) && !position.isDeleted()) 1035 return offset <= position.getOffset() && position.getOffset() + position.getLength() <= offset + length; 1036 return false; 1037 } 1038 1039 private ProjectionAnnotation[] computeCollapsedNestedAnnotations(int offset, int length) { 1040 List annotations= new ArrayList (5); 1041 Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); 1042 while (e.hasNext()) { 1043 ProjectionAnnotation annotation= (ProjectionAnnotation) e.next(); 1044 if (annotation.isCollapsed()) { 1045 Position position= fProjectionAnnotationModel.getPosition(annotation); 1046 if (position == null) { 1047 continue; 1049 } 1050 if (covers(offset, length, position)) 1051 annotations.add(annotation); 1052 } 1053 } 1054 1055 if (annotations.size() > 0) { 1056 ProjectionAnnotation[] result= new ProjectionAnnotation[annotations.size()]; 1057 annotations.toArray(result); 1058 return result; 1059 } 1060 1061 return null; 1062 } 1063 1064 private void internalInvalidateTextPresentation(int offset, int length) { 1065 if (fCommandQueue != null) { 1066 fCommandQueue.add(new ProjectionCommand(offset, length)); 1067 } else { 1068 invalidateTextPresentation(offset, length); 1069 } 1070 } 1071 1072 1075 private void processDeletions(AnnotationModelEvent event, Annotation[] removedAnnotations, boolean fireRedraw) throws BadLocationException { 1076 for (int i= 0; i < removedAnnotations.length; i++) { 1077 ProjectionAnnotation annotation= (ProjectionAnnotation) removedAnnotations[i]; 1078 if (annotation.isCollapsed()) { 1079 Position expanded= event.getPositionOfRemovedAnnotation(annotation); 1080 expand(expanded.getOffset(), expanded.getLength(), fireRedraw); 1081 } 1082 } 1083 } 1084 1085 1092 public IRegion computeCollapsedRegion(Position position) { 1093 try { 1094 IDocument document= getDocument(); 1095 if (document == null) 1096 return null; 1097 1098 int line= document.getLineOfOffset(position.getOffset()); 1099 int offset= document.getLineOffset(line + 1); 1100 1101 int length= position.getLength() - (offset - position.getOffset()); 1102 if (length > 0) 1103 return new Region(offset, length); 1104 } catch (BadLocationException x) { 1105 } 1106 1107 return null; 1108 } 1109 1110 1119 IRegion[] computeCollapsedRegions(Position position) { 1120 try { 1121 IDocument document= getDocument(); 1122 if (document == null) 1123 return null; 1124 1125 if (position instanceof IProjectionPosition) { 1126 IProjectionPosition projPosition= (IProjectionPosition) position; 1127 return projPosition.computeProjectionRegions(document); 1128 } 1129 1130 int line= document.getLineOfOffset(position.getOffset()); 1131 int offset= document.getLineOffset(line + 1); 1132 1133 int length= position.getLength() - (offset - position.getOffset()); 1134 if (length > 0) 1135 return new IRegion[] {new Region(offset, length)}; 1136 1137 return null; 1138 } catch (BadLocationException x) { 1139 return null; 1140 } 1141 } 1142 1143 1152 public Position computeCollapsedRegionAnchor(Position position) { 1153 try { 1154 IDocument document= getDocument(); 1155 if (document == null) 1156 return null; 1157 1158 int captionOffset= position.getOffset(); 1159 if (position instanceof IProjectionPosition) 1160 captionOffset+= ((IProjectionPosition) position).computeCaptionOffset(document); 1161 1162 IRegion lineInfo= document.getLineInformationOfOffset(captionOffset); 1163 return new Position(lineInfo.getOffset() + lineInfo.getLength(), 0); 1164 } catch (BadLocationException x) { 1165 } 1166 return null; 1167 } 1168 1169 private void processChanges(Annotation[] annotations, boolean fireRedraw, List coverage) throws BadLocationException { 1170 for (int i= 0; i < annotations.length; i++) { 1171 ProjectionAnnotation annotation= (ProjectionAnnotation) annotations[i]; 1172 Position position= fProjectionAnnotationModel.getPosition(annotation); 1173 1174 if (position == null) 1175 continue; 1176 1177 if (!covers(coverage, position)) { 1178 if (annotation.isCollapsed()) { 1179 coverage.add(position); 1180 IRegion[] regions= computeCollapsedRegions(position); 1181 if (regions != null) 1182 for (int j= 0; j < regions.length; j++) 1183 collapse(regions[j].getOffset(), regions[j].getLength(), fireRedraw); 1184 } else { 1185 expand(position.getOffset(), position.getLength(), fireRedraw); 1186 } 1187 } 1188 } 1189 } 1190 1191 private boolean covers(List coverage, Position position) { 1192 Iterator e= coverage.iterator(); 1193 while (e.hasNext()) { 1194 Position p= (Position) e.next(); 1195 if (p.getOffset() <= position.getOffset() && position.getOffset() + position.getLength() <= p.getOffset() + p.getLength()) 1196 return true; 1197 } 1198 return false; 1199 } 1200 1201 1207 public final void reinitializeProjection() throws BadLocationException { 1208 1209 ProjectionDocument projection= null; 1210 1211 ISlaveDocumentManager manager= getSlaveDocumentManager(); 1212 if (manager != null) { 1213 IDocument master= getDocument(); 1214 if (master != null) { 1215 IDocument slave= manager.createSlaveDocument(master); 1216 if (slave instanceof ProjectionDocument) { 1217 projection= (ProjectionDocument) slave; 1218 addMasterDocumentRange(projection, 0, master.getLength()); 1219 } 1220 } 1221 } 1222 1223 if (projection != null) { 1224 Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); 1225 while (e.hasNext()) { 1226 ProjectionAnnotation annotation= (ProjectionAnnotation) e.next(); 1227 if (annotation.isCollapsed()) { 1228 Position position= fProjectionAnnotationModel.getPosition(annotation); 1229 if (position != null) { 1230 IRegion[] regions= computeCollapsedRegions(position); 1231 if (regions != null) 1232 for (int i= 0; i < regions.length; i++) 1233 removeMasterDocumentRange(projection, regions[i].getOffset(), regions[i].getLength()); 1234 } 1235 } 1236 } 1237 1238 } 1239 1240 replaceVisibleDocument(projection); 1241 } 1242 1243 1246 protected void handleVerifyEvent(VerifyEvent e) { 1247 IRegion modelRange= event2ModelRange(e); 1248 if (exposeModelRange(modelRange)) 1249 e.doit= false; 1250 else 1251 super.handleVerifyEvent(e); 1252 } 1253 1254 1259 public void addVerticalRulerColumn(IVerticalRulerColumn column) { 1260 IVerticalRuler ruler= getVerticalRuler(); 1261 if (ruler instanceof CompositeRuler) { 1262 CompositeRuler compositeRuler= (CompositeRuler) ruler; 1263 compositeRuler.addDecorator(99, column); 1264 } 1265 } 1266 1267 1272 public void removeVerticalRulerColumn(IVerticalRulerColumn column) { 1273 IVerticalRuler ruler= getVerticalRuler(); 1274 if (ruler instanceof CompositeRuler) { 1275 CompositeRuler compositeRuler= (CompositeRuler) ruler; 1276 compositeRuler.removeDecorator(column); 1277 } 1278 } 1279 1280 1283 public boolean exposeModelRange(IRegion modelRange) { 1284 if (isProjectionMode()) 1285 return fProjectionAnnotationModel.expandAll(modelRange.getOffset(), modelRange.getLength()); 1286 1287 if (!overlapsWithVisibleRegion(modelRange.getOffset(), modelRange.getLength())) { 1288 resetVisibleRegion(); 1289 return true; 1290 } 1291 1292 return false; 1293 } 1294 1295 1298 public void setRangeIndication(int offset, int length, boolean moveCursor) { 1299 1300 if (getRangeIndication() != null) { 1301 List expand= new ArrayList (2); 1302 if (moveCursor && fProjectionAnnotationModel != null) { 1303 1304 Iterator iterator= fProjectionAnnotationModel.getAnnotationIterator(); 1306 while (iterator.hasNext()) { 1307 ProjectionAnnotation annotation= (ProjectionAnnotation) iterator.next(); 1308 if (annotation.isCollapsed() && willAutoExpand(fProjectionAnnotationModel.getPosition(annotation), offset, length)) 1309 expand.add(annotation); 1310 } 1311 1312 if (!expand.isEmpty()) { 1313 Iterator e= expand.iterator(); 1314 while (e.hasNext()) 1315 fProjectionAnnotationModel.expand((Annotation) e.next()); 1316 } 1317 } 1318 } 1319 1320 super.setRangeIndication(offset, length, moveCursor); 1321 } 1322 1323 private boolean willAutoExpand(Position position, int offset, int length) { 1324 if (position == null || position.isDeleted()) 1325 return false; 1326 if (position.getOffset() == offset || position.getOffset() + position.getLength() == offset + length) 1328 return true; 1329 if (position.getOffset() < offset && offset + length < position.getOffset() + position.getLength()) 1331 return true; 1332 return false; 1333 } 1334 1335 1339 protected void handleDispose() { 1340 fWasProjectionEnabled= false; 1341 super.handleDispose(); 1342 } 1343 1344 1347 protected void handleVisibleDocumentChanged(DocumentEvent event) { 1348 if (fHandleProjectionChanges && event instanceof ProjectionDocumentEvent && isProjectionMode()) { 1349 ProjectionDocumentEvent e= (ProjectionDocumentEvent) event; 1350 1351 DocumentEvent master= e.getMasterEvent(); 1352 if (master != null) 1353 fReplaceVisibleDocumentExecutionTrigger= master.getDocument(); 1354 1355 try { 1356 1357 int replaceLength= e.getText() == null ? 0 : e.getText().length(); 1358 if (ProjectionDocumentEvent.PROJECTION_CHANGE == e.getChangeType()) { 1359 if (e.getLength() == 0 && replaceLength != 0) 1360 fProjectionAnnotationModel.expandAll(e.getMasterOffset(), e.getMasterLength()); 1361 } else if (master != null && (replaceLength > 0 || fDeletedLines > 1)) { 1362 try { 1363 int numberOfLines= e.getDocument().getNumberOfLines(e.getOffset(), replaceLength); 1364 if (numberOfLines > 1 || fDeletedLines > 1) 1365 fProjectionAnnotationModel.expandAll(master.getOffset(), master.getLength()); 1366 } catch (BadLocationException x) { 1367 } 1368 } 1369 1370 } finally { 1371 fReplaceVisibleDocumentExecutionTrigger= null; 1372 } 1373 1374 } 1375 } 1376 1377 1381 protected void handleVisibleDocumentAboutToBeChanged(DocumentEvent event) { 1382 if (fHandleProjectionChanges && event instanceof ProjectionDocumentEvent && isProjectionMode()) { 1383 int deletedLines; 1384 try { 1385 deletedLines= event.getDocument().getNumberOfLines(event.getOffset(), event.getLength()); 1386 } catch (BadLocationException e1) { 1387 deletedLines= 0; 1388 } 1389 fDeletedLines= deletedLines; 1390 } 1391 } 1392 1393 1396 public IRegion[] getCoveredModelRanges(IRegion modelRange) { 1397 if (fInformationMapping == null) 1398 return new IRegion[] { new Region(modelRange.getOffset(), modelRange.getLength()) }; 1399 1400 if (fInformationMapping instanceof IDocumentInformationMappingExtension) { 1401 IDocumentInformationMappingExtension extension= (IDocumentInformationMappingExtension) fInformationMapping; 1402 try { 1403 return extension.getExactCoverage(modelRange); 1404 } catch (BadLocationException x) { 1405 } 1406 } 1407 1408 return null; 1409 } 1410 1411 1414 public void doOperation(int operation) { 1415 switch (operation) { 1416 case TOGGLE: 1417 if (canDoOperation(TOGGLE)) { 1418 if (!isProjectionMode()) { 1419 enableProjection(); 1420 } else { 1421 expandAll(); 1422 disableProjection(); 1423 } 1424 return; 1425 } 1426 } 1427 1428 if (!isProjectionMode()) { 1429 super.doOperation(operation); 1430 return; 1431 } 1432 1433 StyledText textWidget= getTextWidget(); 1434 if (textWidget == null) 1435 return; 1436 1437 Point selection= null; 1438 switch (operation) { 1439 1440 case CUT: 1441 1442 if (redraws()) { 1443 selection= getSelectedRange(); 1444 if (exposeModelRange(new Region(selection.x, selection.y))) 1445 return; 1446 1447 if (selection.y == 0) 1448 copyMarkedRegion(true); 1449 else 1450 copyToClipboard(selection.x, selection.y, true, textWidget); 1451 1452 selection= textWidget.getSelectionRange(); 1453 fireSelectionChanged(selection.x, selection.y); 1454 } 1455 break; 1456 1457 case COPY: 1458 1459 if (redraws()) { 1460 selection= getSelectedRange(); 1461 if (selection.y == 0) 1462 copyMarkedRegion(false); 1463 else 1464 copyToClipboard(selection.x, selection.y, false, textWidget); 1465 } 1466 break; 1467 1468 case DELETE: 1469 1470 if (redraws()) { 1471 try { 1472 selection= getSelectedRange(); 1473 Point widgetSelection= textWidget.getSelectionRange(); 1474 if (selection.y == 0 || selection.y == widgetSelection.y) 1475 getTextWidget().invokeAction(ST.DELETE_NEXT); 1476 else 1477 deleteTextRange(selection.x, selection.y, textWidget); 1478 1479 selection= textWidget.getSelectionRange(); 1480 fireSelectionChanged(selection.x, selection.y); 1481 1482 } catch (BadLocationException x) { 1483 } 1485 } 1486 break; 1487 1488 1489 case EXPAND_ALL: 1490 if (redraws()) 1491 expandAll(); 1492 break; 1493 1494 case EXPAND: 1495 if (redraws()) { 1496 expand(); 1497 } 1498 break; 1499 1500 case COLLAPSE_ALL: 1501 if (redraws()) 1502 collapseAll(); 1503 break; 1504 1505 case COLLAPSE: 1506 if (redraws()) { 1507 collapse(); 1508 } 1509 break; 1510 1511 default: 1512 super.doOperation(operation); 1513 } 1514 } 1515 1516 1519 public boolean canDoOperation(int operation) { 1520 1521 switch (operation) { 1522 case COLLAPSE: 1523 case COLLAPSE_ALL: 1524 case EXPAND: 1525 case EXPAND_ALL: 1526 return isProjectionMode(); 1527 case TOGGLE: 1528 return isProjectionMode() || !isSegmented(); 1529 } 1530 1531 return super.canDoOperation(operation); 1532 } 1533 1534 private boolean isSegmented() { 1535 IDocument document= getDocument(); 1536 int length= document == null ? 0 : document.getLength(); 1537 IRegion visible= getModelCoverage(); 1538 boolean isSegmented= visible != null && !visible.equals(new Region(0, length)); 1539 return isSegmented; 1540 } 1541 1542 private IRegion getMarkedRegion() { 1543 if (getTextWidget() == null) 1544 return null; 1545 1546 if (fMarkPosition == null || fMarkPosition.isDeleted()) 1547 return null; 1548 1549 int start= fMarkPosition.getOffset(); 1550 int end= getSelectedRange().x; 1551 1552 return start > end ? new Region (end, start - end) : new Region(start, end - start); 1553 } 1554 1555 1558 protected void copyMarkedRegion(boolean delete) { 1559 IRegion markedRegion= getMarkedRegion(); 1560 if (markedRegion != null) 1561 copyToClipboard(markedRegion.getOffset(), markedRegion.getLength(), delete, getTextWidget()); 1562 } 1563 1564 private void copyToClipboard(int offset, int length, boolean delete, StyledText textWidget) { 1565 1566 String copyText= null; 1567 1568 try { 1569 IDocument document= getDocument(); 1570 copyText= document.get(offset, length); 1571 } catch (BadLocationException ex) { 1572 textWidget.copy(); 1575 } 1576 1577 if (copyText != null && copyText.equals(textWidget.getSelectionText())) { 1578 1582 textWidget.copy(); 1583 } else if (copyText != null) { 1584 1585 Clipboard clipboard= new Clipboard(textWidget.getDisplay()); 1586 1587 try { 1588 Transfer[] dataTypes= new Transfer[] { TextTransfer.getInstance() }; 1589 Object [] data= new Object [] { copyText }; 1590 try { 1591 clipboard.setContents(data, dataTypes); 1592 } catch (SWTError e) { 1593 if (e.code != DND.ERROR_CANNOT_SET_CLIPBOARD) 1594 throw e; 1595 1600 return; 1601 } 1602 1603 } finally { 1604 clipboard.dispose(); 1605 } 1606 } 1607 1608 if (delete) { 1609 try { 1610 deleteTextRange(offset, length, textWidget); 1611 } catch (BadLocationException x) { 1612 } 1614 } 1615 } 1616 1617 private void deleteTextRange(int offset, int length, StyledText textWidget) throws BadLocationException { 1618 getDocument().replace(offset, length, ""); int widgetCaret= modelOffset2WidgetOffset(offset); 1620 if (widgetCaret > -1) 1621 textWidget.setSelection(widgetCaret); 1622 } 1623 1624 1630 protected Point widgetSelection2ModelSelection(Point widgetSelection) { 1631 1632 if (!isProjectionMode()) 1633 return super.widgetSelection2ModelSelection(widgetSelection); 1634 1635 1661 IRegion modelSelection= widgetRange2ModelRange(new Region(widgetSelection.x, widgetSelection.y)); 1662 if (modelSelection == null) 1663 return null; 1664 1665 int modelOffset= modelSelection.getOffset(); 1666 int modelEndOffset= modelOffset + modelSelection.getLength(); 1667 1668 1669 if (widgetSelection.y == 0) 1670 return new Point(modelEndOffset, 0); 1671 1672 int widgetSelectionExclusiveEnd= widgetSelection.x + widgetSelection.y; 1673 Position[] annotationPositions= computeOverlappingAnnotationPositions(modelSelection); 1674 for (int i= 0; i < annotationPositions.length; i++) { 1675 IRegion[] regions= computeCollapsedRegions(annotationPositions[i]); 1676 if (regions == null) 1677 continue; 1678 for (int j= 0; j < regions.length; j++) { 1679 IRegion modelRange= regions[j]; 1680 IRegion widgetRange= modelRange2ClosestWidgetRange(modelRange); 1681 if (widgetRange != null && widgetRange.getLength() == 0) { 1683 int widgetOffset= widgetRange.getOffset(); 1684 if (widgetOffset == widgetSelection.x) 1686 modelOffset= Math.min(modelOffset, modelRange.getOffset()); 1687 else if (widgetOffset == widgetSelectionExclusiveEnd) 1689 modelEndOffset= Math.max(modelEndOffset, modelRange.getOffset() + modelRange.getLength()); 1690 } 1691 } 1692 } 1693 return new Point(modelOffset, modelEndOffset - modelOffset); 1694 } 1695 1696 1704 private Position[] computeOverlappingAnnotationPositions(IRegion modelSelection) { 1705 List positions= new ArrayList (); 1706 for (Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); e.hasNext();) { 1707 ProjectionAnnotation annotation= (ProjectionAnnotation) e.next(); 1708 Position position= fProjectionAnnotationModel.getPosition(annotation); 1709 if (position != null && position.overlapsWith(modelSelection.getOffset(), modelSelection.getLength()) && modelRange2WidgetRange(position) != null) 1710 positions.add(position); 1711 } 1712 return (Position[]) positions.toArray(new Position[positions.size()]); 1713 } 1714 1715 1718 protected FindReplaceDocumentAdapter getFindReplaceDocumentAdapter() { 1719 if (fFindReplaceDocumentAdapter == null) { 1720 IDocument document= isProjectionMode() ? getDocument() : getVisibleDocument(); 1721 fFindReplaceDocumentAdapter= new FindReplaceDocumentAdapter(document); 1722 } 1723 return fFindReplaceDocumentAdapter; 1724 } 1725 1726 1729 protected int findAndSelect(int startPosition, String findString, boolean forwardSearch, boolean caseSensitive, boolean wholeWord, boolean regExSearch) { 1730 1731 if (!isProjectionMode()) 1732 return super.findAndSelect(startPosition, findString, forwardSearch, caseSensitive, wholeWord, regExSearch); 1733 1734 StyledText textWidget= getTextWidget(); 1735 if (textWidget == null) 1736 return -1; 1737 1738 try { 1739 1740 IRegion matchRegion= getFindReplaceDocumentAdapter().find(startPosition, findString, forwardSearch, caseSensitive, wholeWord, regExSearch); 1741 if (matchRegion != null) { 1742 exposeModelRange(matchRegion); 1743 revealRange(matchRegion.getOffset(), matchRegion.getLength()); 1744 setSelectedRange(matchRegion.getOffset(), matchRegion.getLength()); 1745 return matchRegion.getOffset(); 1746 } 1747 1748 } catch (BadLocationException x) { 1749 } 1750 1751 return -1; 1752 } 1753 1754 1757 protected int findAndSelectInRange(int startPosition, String findString, boolean forwardSearch, boolean caseSensitive, boolean wholeWord, int rangeOffset, int rangeLength, boolean regExSearch) { 1758 1759 if (!isProjectionMode()) 1760 return super.findAndSelectInRange(startPosition, findString, forwardSearch, caseSensitive, wholeWord, rangeOffset, rangeLength, regExSearch); 1761 1762 StyledText textWidget= getTextWidget(); 1763 if (textWidget == null) 1764 return -1; 1765 1766 try { 1767 1768 int modelOffset= startPosition; 1769 if (forwardSearch && (startPosition == -1 || startPosition < rangeOffset)) { 1770 modelOffset= rangeOffset; 1771 } else if (!forwardSearch && (startPosition == -1 || startPosition > rangeOffset + rangeLength)) { 1772 modelOffset= rangeOffset + rangeLength; 1773 } 1774 1775 IRegion matchRegion= getFindReplaceDocumentAdapter().find(modelOffset, findString, forwardSearch, caseSensitive, wholeWord, regExSearch); 1776 if (matchRegion != null) { 1777 int offset= matchRegion.getOffset(); 1778 int length= matchRegion.getLength(); 1779 if (rangeOffset <= offset && offset + length <= rangeOffset + rangeLength) { 1780 exposeModelRange(matchRegion); 1781 revealRange(offset, length); 1782 setSelectedRange(offset, length); 1783 return offset; 1784 } 1785 } 1786 1787 } catch (BadLocationException x) { 1788 } 1789 1790 return -1; 1791 } 1792} 1793 | Popular Tags |