KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > javaeditor > SemanticHighlightingPresenter


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jdt.internal.ui.javaeditor;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Arrays JavaDoc;
16 import java.util.List JavaDoc;
17
18 import org.eclipse.swt.custom.StyleRange;
19
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.BadPositionCategoryException;
22 import org.eclipse.jface.text.DocumentEvent;
23 import org.eclipse.jface.text.IDocument;
24 import org.eclipse.jface.text.IDocumentListener;
25 import org.eclipse.jface.text.IPositionUpdater;
26 import org.eclipse.jface.text.IRegion;
27 import org.eclipse.jface.text.ISynchronizable;
28 import org.eclipse.jface.text.ITextInputListener;
29 import org.eclipse.jface.text.ITextPresentationListener;
30 import org.eclipse.jface.text.Position;
31 import org.eclipse.jface.text.Region;
32 import org.eclipse.jface.text.TextPresentation;
33
34 import org.eclipse.jdt.internal.ui.JavaPlugin;
35 import org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingManager.HighlightedPosition;
36 import org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingManager.Highlighting;
37 import org.eclipse.jdt.internal.ui.text.JavaPresentationReconciler;
38
39
40 /**
41  * Semantic highlighting presenter - UI thread implementation.
42  *
43  * @since 3.0
44  */

45 public class SemanticHighlightingPresenter implements ITextPresentationListener, ITextInputListener, IDocumentListener {
46
47     /**
48      * Semantic highlighting position updater.
49      */

50     private class HighlightingPositionUpdater implements IPositionUpdater {
51
52         /** The position category. */
53         private final String JavaDoc fCategory;
54
55         /**
56          * Creates a new updater for the given <code>category</code>.
57          *
58          * @param category the new category.
59          */

60         public HighlightingPositionUpdater(String JavaDoc category) {
61             fCategory= category;
62         }
63
64         /*
65          * @see org.eclipse.jface.text.IPositionUpdater#update(org.eclipse.jface.text.DocumentEvent)
66          */

67         public void update(DocumentEvent event) {
68
69             int eventOffset= event.getOffset();
70             int eventOldLength= event.getLength();
71             int eventEnd= eventOffset + eventOldLength;
72
73             try {
74                 Position[] positions= event.getDocument().getPositions(fCategory);
75
76                 for (int i= 0; i != positions.length; i++) {
77
78                     HighlightedPosition position= (HighlightedPosition) positions[i];
79
80                     // Also update deleted positions because they get deleted by the background thread and removed/invalidated only in the UI runnable
81
// if (position.isDeleted())
82
// continue;
83

84                     int offset= position.getOffset();
85                     int length= position.getLength();
86                     int end= offset + length;
87
88                     if (offset > eventEnd)
89                         updateWithPrecedingEvent(position, event);
90                     else if (end < eventOffset)
91                         updateWithSucceedingEvent(position, event);
92                     else if (offset <= eventOffset && end >= eventEnd)
93                         updateWithIncludedEvent(position, event);
94                     else if (offset <= eventOffset)
95                         updateWithOverEndEvent(position, event);
96                     else if (end >= eventEnd)
97                         updateWithOverStartEvent(position, event);
98                     else
99                         updateWithIncludingEvent(position, event);
100                 }
101             } catch (BadPositionCategoryException e) {
102                 // ignore and return
103
}
104         }
105
106         /**
107          * Update the given position with the given event. The event precedes the position.
108          *
109          * @param position The position
110          * @param event The event
111          */

112         private void updateWithPrecedingEvent(HighlightedPosition position, DocumentEvent event) {
113             String JavaDoc newText= event.getText();
114             int eventNewLength= newText != null ? newText.length() : 0;
115             int deltaLength= eventNewLength - event.getLength();
116
117             position.setOffset(position.getOffset() + deltaLength);
118         }
119
120         /**
121          * Update the given position with the given event. The event succeeds the position.
122          *
123          * @param position The position
124          * @param event The event
125          */

126         private void updateWithSucceedingEvent(HighlightedPosition position, DocumentEvent event) {
127         }
128
129         /**
130          * Update the given position with the given event. The event is included by the position.
131          *
132          * @param position The position
133          * @param event The event
134          */

135         private void updateWithIncludedEvent(HighlightedPosition position, DocumentEvent event) {
136             int eventOffset= event.getOffset();
137             String JavaDoc newText= event.getText();
138             if (newText == null)
139                 newText= ""; //$NON-NLS-1$
140
int eventNewLength= newText.length();
141
142             int deltaLength= eventNewLength - event.getLength();
143
144             int offset= position.getOffset();
145             int length= position.getLength();
146             int end= offset + length;
147
148             int includedLength= 0;
149             while (includedLength < eventNewLength && Character.isJavaIdentifierPart(newText.charAt(includedLength)))
150                 includedLength++;
151             if (includedLength == eventNewLength)
152                 position.setLength(length + deltaLength);
153             else {
154                 int newLeftLength= eventOffset - offset + includedLength;
155
156                 int excludedLength= eventNewLength;
157                 while (excludedLength > 0 && Character.isJavaIdentifierPart(newText.charAt(excludedLength - 1)))
158                     excludedLength--;
159                 int newRightOffset= eventOffset + excludedLength;
160                 int newRightLength= end + deltaLength - newRightOffset;
161
162                 if (newRightLength == 0) {
163                     position.setLength(newLeftLength);
164                 } else {
165                     if (newLeftLength == 0) {
166                         position.update(newRightOffset, newRightLength);
167                     } else {
168                         position.setLength(newLeftLength);
169                         addPositionFromUI(newRightOffset, newRightLength, position.getHighlighting());
170                     }
171                 }
172             }
173         }
174
175         /**
176          * Update the given position with the given event. The event overlaps with the end of the position.
177          *
178          * @param position The position
179          * @param event The event
180          */

181         private void updateWithOverEndEvent(HighlightedPosition position, DocumentEvent event) {
182             String JavaDoc newText= event.getText();
183             if (newText == null)
184                 newText= ""; //$NON-NLS-1$
185
int eventNewLength= newText.length();
186
187             int includedLength= 0;
188             while (includedLength < eventNewLength && Character.isJavaIdentifierPart(newText.charAt(includedLength)))
189                 includedLength++;
190             position.setLength(event.getOffset() - position.getOffset() + includedLength);
191         }
192
193         /**
194          * Update the given position with the given event. The event overlaps with the start of the position.
195          *
196          * @param position The position
197          * @param event The event
198          */

199         private void updateWithOverStartEvent(HighlightedPosition position, DocumentEvent event) {
200             int eventOffset= event.getOffset();
201             int eventEnd= eventOffset + event.getLength();
202
203             String JavaDoc newText= event.getText();
204             if (newText == null)
205                 newText= ""; //$NON-NLS-1$
206
int eventNewLength= newText.length();
207
208             int excludedLength= eventNewLength;
209             while (excludedLength > 0 && Character.isJavaIdentifierPart(newText.charAt(excludedLength - 1)))
210                 excludedLength--;
211             int deleted= eventEnd - position.getOffset();
212             int inserted= eventNewLength - excludedLength;
213             position.update(eventOffset + excludedLength, position.getLength() - deleted + inserted);
214         }
215
216         /**
217          * Update the given position with the given event. The event includes the position.
218          *
219          * @param position The position
220          * @param event The event
221          */

222         private void updateWithIncludingEvent(HighlightedPosition position, DocumentEvent event) {
223             position.delete();
224             position.update(event.getOffset(), 0);
225         }
226     }
227
228     /** Position updater */
229     private IPositionUpdater fPositionUpdater= new HighlightingPositionUpdater(getPositionCategory());
230
231     /** The source viewer this semantic highlighting reconciler is installed on */
232     private JavaSourceViewer fSourceViewer;
233     /** The background presentation reconciler */
234     private JavaPresentationReconciler fPresentationReconciler;
235
236     /** UI's current highlighted positions - can contain <code>null</code> elements */
237     private List JavaDoc fPositions= new ArrayList JavaDoc();
238     /** UI position lock */
239     private Object JavaDoc fPositionLock= new Object JavaDoc();
240
241     /** <code>true</code> iff the current reconcile is canceled. */
242     private boolean fIsCanceled= false;
243
244     /**
245      * Creates and returns a new highlighted position with the given offset, length and highlighting.
246      * <p>
247      * NOTE: Also called from background thread.
248      * </p>
249      *
250      * @param offset The offset
251      * @param length The length
252      * @param highlighting The highlighting
253      * @return The new highlighted position
254      */

255     public HighlightedPosition createHighlightedPosition(int offset, int length, Highlighting highlighting) {
256         // TODO: reuse deleted positions
257
return new HighlightedPosition(offset, length, highlighting, fPositionUpdater);
258     }
259
260     /**
261      * Adds all current positions to the given list.
262      * <p>
263      * NOTE: Called from background thread.
264      * </p>
265      *
266      * @param list The list
267      */

268     public void addAllPositions(List JavaDoc list) {
269         synchronized (fPositionLock) {
270             list.addAll(fPositions);
271         }
272     }
273
274     /**
275      * Create a text presentation in the background.
276      * <p>
277      * NOTE: Called from background thread.
278      * </p>
279      *
280      * @param addedPositions the added positions
281      * @param removedPositions the removed positions
282      * @return the text presentation or <code>null</code>, if reconciliation should be canceled
283      */

284     public TextPresentation createPresentation(List JavaDoc addedPositions, List JavaDoc removedPositions) {
285         JavaSourceViewer sourceViewer= fSourceViewer;
286         JavaPresentationReconciler presentationReconciler= fPresentationReconciler;
287         if (sourceViewer == null || presentationReconciler == null)
288             return null;
289
290         if (isCanceled())
291             return null;
292
293         IDocument document= sourceViewer.getDocument();
294         if (document == null)
295             return null;
296
297         int minStart= Integer.MAX_VALUE;
298         int maxEnd= Integer.MIN_VALUE;
299         for (int i= 0, n= removedPositions.size(); i < n; i++) {
300             Position position= (Position) removedPositions.get(i);
301             int offset= position.getOffset();
302             minStart= Math.min(minStart, offset);
303             maxEnd= Math.max(maxEnd, offset + position.getLength());
304         }
305         for (int i= 0, n= addedPositions.size(); i < n; i++) {
306             Position position= (Position) addedPositions.get(i);
307             int offset= position.getOffset();
308             minStart= Math.min(minStart, offset);
309             maxEnd= Math.max(maxEnd, offset + position.getLength());
310         }
311
312         if (minStart < maxEnd)
313             try {
314                 return presentationReconciler.createRepairDescription(new Region(minStart, maxEnd - minStart), document);
315             } catch (RuntimeException JavaDoc e) {
316                 // Assume concurrent modification from UI thread
317
}
318
319         return null;
320     }
321
322     /**
323      * Create a runnable for updating the presentation.
324      * <p>
325      * NOTE: Called from background thread.
326      * </p>
327      * @param textPresentation the text presentation
328      * @param addedPositions the added positions
329      * @param removedPositions the removed positions
330      * @return the runnable or <code>null</code>, if reconciliation should be canceled
331      */

332     public Runnable JavaDoc createUpdateRunnable(final TextPresentation textPresentation, List JavaDoc addedPositions, List JavaDoc removedPositions) {
333         if (fSourceViewer == null || textPresentation == null)
334             return null;
335
336         // TODO: do clustering of positions and post multiple fast runnables
337
final HighlightedPosition[] added= new SemanticHighlightingManager.HighlightedPosition[addedPositions.size()];
338         addedPositions.toArray(added);
339         final SemanticHighlightingManager.HighlightedPosition[] removed= new SemanticHighlightingManager.HighlightedPosition[removedPositions.size()];
340         removedPositions.toArray(removed);
341
342         if (isCanceled())
343             return null;
344
345         Runnable JavaDoc runnable= new Runnable JavaDoc() {
346             public void run() {
347                 updatePresentation(textPresentation, added, removed);
348             }
349         };
350         return runnable;
351     }
352
353     /**
354      * Invalidate the presentation of the positions based on the given added positions and the existing deleted positions.
355      * Also unregisters the deleted positions from the document and patches the positions of this presenter.
356      * <p>
357      * NOTE: Indirectly called from background thread by UI runnable.
358      * </p>
359      * @param textPresentation the text presentation or <code>null</code>, if the presentation should computed in the UI thread
360      * @param addedPositions the added positions
361      * @param removedPositions the removed positions
362      */

363     public void updatePresentation(TextPresentation textPresentation, HighlightedPosition[] addedPositions, HighlightedPosition[] removedPositions) {
364         if (fSourceViewer == null)
365             return;
366
367 // checkOrdering("added positions: ", Arrays.asList(addedPositions)); //$NON-NLS-1$
368
// checkOrdering("removed positions: ", Arrays.asList(removedPositions)); //$NON-NLS-1$
369
// checkOrdering("old positions: ", fPositions); //$NON-NLS-1$
370

371         // TODO: double-check consistency with document.getPositions(...)
372
// TODO: reuse removed positions
373
if (isCanceled())
374             return;
375
376         IDocument document= fSourceViewer.getDocument();
377         if (document == null)
378             return;
379
380         String JavaDoc positionCategory= getPositionCategory();
381
382         List JavaDoc removedPositionsList= Arrays.asList(removedPositions);
383
384         try {
385             synchronized (fPositionLock) {
386                 List JavaDoc oldPositions= fPositions;
387                 int newSize= Math.max(fPositions.size() + addedPositions.length - removedPositions.length, 10);
388                 
389                 /*
390                  * The following loop is a kind of merge sort: it merges two List<Position>, each
391                  * sorted by position.offset, into one new list. The first of the two is the
392                  * previous list of positions (oldPositions), from which any deleted positions get
393                  * removed on the fly. The second of two is the list of added positions. The result
394                  * is stored in newPositions.
395                  */

396                 List JavaDoc newPositions= new ArrayList JavaDoc(newSize);
397                 Position position= null;
398                 Position addedPosition= null;
399                 for (int i= 0, j= 0, n= oldPositions.size(), m= addedPositions.length; i < n || position != null || j < m || addedPosition != null;) {
400                     // loop variant: i + j < old(i + j)
401

402                     // a) find the next non-deleted Position from the old list
403
while (position == null && i < n) {
404                         position= (Position) oldPositions.get(i++);
405                         if (position.isDeleted() || contain(removedPositionsList, position)) {
406                             document.removePosition(positionCategory, position);
407                             position= null;
408                         }
409                     }
410                     
411                     // b) find the next Position from the added list
412
if (addedPosition == null && j < m) {
413                         addedPosition= addedPositions[j++];
414                         document.addPosition(positionCategory, addedPosition);
415                     }
416                     
417                     // c) merge: add the next of position/addedPosition with the lower offset
418
if (position != null) {
419                         if (addedPosition != null)
420                             if (position.getOffset() <= addedPosition.getOffset()) {
421                                 newPositions.add(position);
422                                 position= null;
423                             } else {
424                                 newPositions.add(addedPosition);
425                                 addedPosition= null;
426                             }
427                         else {
428                             newPositions.add(position);
429                             position= null;
430                         }
431                     } else if (addedPosition != null) {
432                         newPositions.add(addedPosition);
433                         addedPosition= null;
434                     }
435                 }
436                 fPositions= newPositions;
437             }
438         } catch (BadPositionCategoryException e) {
439             // Should not happen
440
JavaPlugin.log(e);
441         } catch (BadLocationException e) {
442             // Should not happen
443
JavaPlugin.log(e);
444         }
445 // checkOrdering("new positions: ", fPositions); //$NON-NLS-1$
446

447         if (textPresentation != null)
448             fSourceViewer.changeTextPresentation(textPresentation, false);
449         else
450             fSourceViewer.invalidateTextPresentation();
451     }
452
453 // private void checkOrdering(String s, List positions) {
454
// Position previous= null;
455
// for (int i= 0, n= positions.size(); i < n; i++) {
456
// Position current= (Position) positions.get(i);
457
// if (previous != null && previous.getOffset() + previous.getLength() > current.getOffset())
458
// return;
459
// }
460
// }
461

462     /**
463      * Returns <code>true</code> iff the positions contain the position.
464      * @param positions the positions, must be ordered by offset but may overlap
465      * @param position the position
466      * @return <code>true</code> iff the positions contain the position
467      */

468     private boolean contain(List JavaDoc positions, Position position) {
469         return indexOf(positions, position) != -1;
470     }
471
472     /**
473      * Returns index of the position in the positions, <code>-1</code> if not found.
474      * @param positions the positions, must be ordered by offset but may overlap
475      * @param position the position
476      * @return the index
477      */

478     private int indexOf(List JavaDoc positions, Position position) {
479         int index= computeIndexAtOffset(positions, position.getOffset());
480         int size= positions.size();
481         while (index < size) {
482             if (positions.get(index) == position)
483                 return index;
484             index++;
485         }
486         return -1;
487     }
488
489     /**
490      * Insert the given position in <code>fPositions</code>, s.t. the offsets remain in linear order.
491      *
492      * @param position The position for insertion
493      */

494     private void insertPosition(Position position) {
495         int i= computeIndexAfterOffset(fPositions, position.getOffset());
496         fPositions.add(i, position);
497     }
498
499     /**
500      * Returns the index of the first position with an offset greater than the given offset.
501      *
502      * @param positions the positions, must be ordered by offset and must not overlap
503      * @param offset the offset
504      * @return the index of the last position with an offset greater than the given offset
505      */

506     private int computeIndexAfterOffset(List JavaDoc positions, int offset) {
507         int i= -1;
508         int j= positions.size();
509         while (j - i > 1) {
510             int k= (i + j) >> 1;
511             Position position= (Position) positions.get(k);
512             if (position.getOffset() > offset)
513                 j= k;
514             else
515                 i= k;
516         }
517         return j;
518     }
519
520     /**
521      * Returns the index of the first position with an offset equal or greater than the given offset.
522      *
523      * @param positions the positions, must be ordered by offset and must not overlap
524      * @param offset the offset
525      * @return the index of the last position with an offset equal or greater than the given offset
526      */

527     private int computeIndexAtOffset(List JavaDoc positions, int offset) {
528         int i= -1;
529         int j= positions.size();
530         while (j - i > 1) {
531             int k= (i + j) >> 1;
532             Position position= (Position) positions.get(k);
533             if (position.getOffset() >= offset)
534                 j= k;
535             else
536                 i= k;
537         }
538         return j;
539     }
540
541     /*
542      * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation)
543      */

544     public void applyTextPresentation(TextPresentation textPresentation) {
545         IRegion region= textPresentation.getExtent();
546         int i= computeIndexAtOffset(fPositions, region.getOffset()), n= computeIndexAtOffset(fPositions, region.getOffset() + region.getLength());
547         if (n - i > 2) {
548             List JavaDoc ranges= new ArrayList JavaDoc(n - i);
549             for (; i < n; i++) {
550                 HighlightedPosition position= (HighlightedPosition) fPositions.get(i);
551                 if (!position.isDeleted())
552                     ranges.add(position.createStyleRange());
553             }
554             StyleRange[] array= new StyleRange[ranges.size()];
555             array= (StyleRange[]) ranges.toArray(array);
556             textPresentation.replaceStyleRanges(array);
557         } else {
558             for (; i < n; i++) {
559                 HighlightedPosition position= (HighlightedPosition) fPositions.get(i);
560                 if (!position.isDeleted())
561                     textPresentation.replaceStyleRange(position.createStyleRange());
562             }
563         }
564     }
565
566     /*
567      * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
568      */

569     public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
570         setCanceled(true);
571         releaseDocument(oldInput);
572         resetState();
573     }
574
575     /*
576      * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
577      */

578     public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
579         manageDocument(newInput);
580     }
581
582     /*
583      * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
584      */

585     public void documentAboutToBeChanged(DocumentEvent event) {
586         setCanceled(true);
587     }
588
589     /*
590      * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
591      */

592     public void documentChanged(DocumentEvent event) {
593     }
594
595     /**
596      * @return Returns <code>true</code> iff the current reconcile is canceled.
597      * <p>
598      * NOTE: Also called from background thread.
599      * </p>
600      */

601     public boolean isCanceled() {
602         IDocument document= fSourceViewer != null ? fSourceViewer.getDocument() : null;
603         if (document == null)
604             return fIsCanceled;
605
606         synchronized (getLockObject(document)) {
607             return fIsCanceled;
608         }
609     }
610
611     /**
612      * Set whether or not the current reconcile is canceled.
613      *
614      * @param isCanceled <code>true</code> iff the current reconcile is canceled
615      */

616     public void setCanceled(boolean isCanceled) {
617         IDocument document= fSourceViewer != null ? fSourceViewer.getDocument() : null;
618         if (document == null) {
619             fIsCanceled= isCanceled;
620             return;
621         }
622
623         synchronized (getLockObject(document)) {
624             fIsCanceled= isCanceled;
625         }
626     }
627
628     /**
629      * @param document the document
630      * @return the document's lock object
631      */

632     private Object JavaDoc getLockObject(IDocument document) {
633         if (document instanceof ISynchronizable) {
634             Object JavaDoc lock= ((ISynchronizable)document).getLockObject();
635             if (lock != null)
636                 return lock;
637         }
638         return document;
639     }
640
641     /**
642      * Install this presenter on the given source viewer and background presentation
643      * reconciler.
644      *
645      * @param sourceViewer the source viewer
646      * @param backgroundPresentationReconciler the background presentation reconciler,
647      * can be <code>null</code>, in that case {@link SemanticHighlightingPresenter#createPresentation(List, List)}
648      * should not be called
649      */

650     public void install(JavaSourceViewer sourceViewer, JavaPresentationReconciler backgroundPresentationReconciler) {
651         fSourceViewer= sourceViewer;
652         fPresentationReconciler= backgroundPresentationReconciler;
653
654         fSourceViewer.prependTextPresentationListener(this);
655         fSourceViewer.addTextInputListener(this);
656         manageDocument(fSourceViewer.getDocument());
657     }
658
659     /**
660      * Uninstall this presenter.
661      */

662     public void uninstall() {
663         setCanceled(true);
664
665         if (fSourceViewer != null) {
666             fSourceViewer.removeTextPresentationListener(this);
667             releaseDocument(fSourceViewer.getDocument());
668             invalidateTextPresentation();
669             resetState();
670
671             fSourceViewer.removeTextInputListener(this);
672             fSourceViewer= null;
673         }
674     }
675
676     /**
677      * Invalidate text presentation of positions with the given highlighting.
678      *
679      * @param highlighting The highlighting
680      */

681     public void highlightingStyleChanged(Highlighting highlighting) {
682         for (int i= 0, n= fPositions.size(); i < n; i++) {
683             HighlightedPosition position= (HighlightedPosition) fPositions.get(i);
684             if (position.getHighlighting() == highlighting)
685                 fSourceViewer.invalidateTextPresentation(position.getOffset(), position.getLength());
686         }
687     }
688
689     /**
690      * Invalidate text presentation of all positions.
691      */

692     private void invalidateTextPresentation() {
693         for (int i= 0, n= fPositions.size(); i < n; i++) {
694             Position position= (Position) fPositions.get(i);
695             fSourceViewer.invalidateTextPresentation(position.getOffset(), position.getLength());
696         }
697     }
698
699     /**
700      * Add a position with the given range and highlighting unconditionally, only from UI thread.
701      * The position will also be registered on the document. The text presentation is not invalidated.
702      *
703      * @param offset The range offset
704      * @param length The range length
705      * @param highlighting
706      */

707     private void addPositionFromUI(int offset, int length, Highlighting highlighting) {
708         Position position= createHighlightedPosition(offset, length, highlighting);
709         synchronized (fPositionLock) {
710             insertPosition(position);
711         }
712
713         IDocument document= fSourceViewer.getDocument();
714         if (document == null)
715             return;
716         String JavaDoc positionCategory= getPositionCategory();
717         try {
718             document.addPosition(positionCategory, position);
719         } catch (BadLocationException e) {
720             // Should not happen
721
JavaPlugin.log(e);
722         } catch (BadPositionCategoryException e) {
723             // Should not happen
724
JavaPlugin.log(e);
725         }
726     }
727
728     /**
729      * Reset to initial state.
730      */

731     private void resetState() {
732         synchronized (fPositionLock) {
733             fPositions.clear();
734         }
735     }
736
737     /**
738      * Start managing the given document.
739      *
740      * @param document The document
741      */

742     private void manageDocument(IDocument document) {
743         if (document != null) {
744             document.addPositionCategory(getPositionCategory());
745             document.addPositionUpdater(fPositionUpdater);
746             document.addDocumentListener(this);
747         }
748     }
749
750     /**
751      * Stop managing the given document.
752      *
753      * @param document The document
754      */

755     private void releaseDocument(IDocument document) {
756         if (document != null) {
757             document.removeDocumentListener(this);
758             document.removePositionUpdater(fPositionUpdater);
759             try {
760                 document.removePositionCategory(getPositionCategory());
761             } catch (BadPositionCategoryException e) {
762                 // Should not happen
763
JavaPlugin.log(e);
764             }
765         }
766     }
767
768     /**
769      * @return The semantic reconciler position's category.
770      */

771     private String JavaDoc getPositionCategory() {
772         return toString();
773     }
774 }
775
Popular Tags