View | Details | Raw Unified | Return to bug 372128 | Differences between
and this patch

Collapse All | Expand All

(-)a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/DefaultCharacterPairMatcher.java (-50 / +175 lines)
Lines 9-17 Link Here
9
 *     Christian Plesner Hansen (plesner@quenta.org) - initial API and implementation
9
 *     Christian Plesner Hansen (plesner@quenta.org) - initial API and implementation
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.jface.text.source;
11
package org.eclipse.jface.text.source;
12
import java.util.HashSet;
13
import java.util.Set;
14
15
import org.eclipse.core.runtime.Assert;
12
import org.eclipse.core.runtime.Assert;
16
13
17
import org.eclipse.jface.text.BadLocationException;
14
import org.eclipse.jface.text.BadLocationException;
Lines 132-169 Link Here
132
		if (document == null || offset < 0 || offset > document.getLength())
129
		if (document == null || offset < 0 || offset > document.getLength())
133
			return null;
130
			return null;
134
131
135
		int start;
132
		//maybe a bracket is selected
136
		int end;
133
		IRegion region= match(document, offset, length);
137
		if (length >= 0) {
134
		fAnchor= ICharacterPairMatcher.LEFT; //always set the anchor to LEFT
138
			start= offset;
135
		if (region != null) {
139
			end= offset + length;
136
			return region;
140
		} else {
141
			end= offset;
142
			start= offset + length;
143
		}
137
		}
144
138
145
		int sourceCaretOffset= offset + length;
139
		//bracket is not selected
146
		int adjustment= getOffsetAdjustment(document, sourceCaretOffset, length);
147
		sourceCaretOffset+= adjustment;
148
149
		try {
140
		try {
150
			for (int offset1= sourceCaretOffset; offset1 >= 0; offset1--) {
141
			final String partition1= TextUtilities.getContentType(document, fPartitioning, offset, false);
151
				char prevChar= document.getChar(Math.max(offset1 - 1, 0));
142
			final DocumentPartitionAccessor partDoc= new DocumentPartitionAccessor(document, fPartitioning, partition1);
152
				if (fPairs.contains(prevChar) && fPairs.isStartCharacter(prevChar)) {
143
			return findEnclosingPeers(document, partDoc, offset, length, 0, document.getLength());
153
					IRegion match= performMatch(document, offset1);
154
					if (match != null) {
155
						int matchOffset= match.getOffset();
156
						int matchLength= match.getLength();
157
						if ((matchOffset <= start) && (matchOffset + matchLength > start) && (matchOffset < end) && (matchOffset + matchLength >= end)) {
158
							return match;
159
						}
160
					}
161
				}
162
			}
163
		} catch (BadLocationException ble) {
144
		} catch (BadLocationException ble) {
145
			fAnchor= -1;
164
			return null;
146
			return null;
165
		}
147
		}
166
		return null;
148
	}
149
150
	/**
151
	 * @see org.eclipse.jface.text.source.ICharacterPairMatcherExtension#isMatchedChar(char)
152
	 * @since 3.8
153
	 */
154
	public boolean isMatchedChar(char ch) {
155
		return fPairs.contains(ch);
156
	}
157
158
	/**
159
	 * @see org.eclipse.jface.text.source.ICharacterPairMatcherExtension#isMatchedChar(char,
160
	 *      org.eclipse.jface.text.IDocument, int)
161
	 * @since 3.8
162
	 */
163
	public boolean isMatchedChar(char ch, IDocument document, int offset) {
164
		return isMatchedChar(ch);
165
	}
166
167
	/**
168
	 * @see org.eclipse.jface.text.source.ICharacterPairMatcherExtension#isRecomputationOfEnclosingPairRequired(org.eclipse.jface.text.IDocument,
169
	 *      org.eclipse.jface.text.IRegion, org.eclipse.jface.text.IRegion)
170
	 * @since 3.8
171
	 */
172
	public boolean isRecomputationOfEnclosingPairRequired(IDocument document, IRegion currentSelection, IRegion previousSelection) {
173
		int previousCaretOffset= previousSelection.getOffset() + previousSelection.getLength();
174
		int currentCaretOffset= currentSelection.getOffset() + currentSelection.getLength();
175
176
		try {
177
			String prevContentType= TextUtilities.getContentType(document, fPartitioning, previousCaretOffset, false);
178
			String currContentType= TextUtilities.getContentType(document, fPartitioning, currentCaretOffset, false);
179
180
			if (!prevContentType.equals(currContentType))
181
				return true;
182
183
			int start;
184
			int end;
185
			if (currentCaretOffset > previousCaretOffset) {
186
				start= previousCaretOffset;
187
				end= currentCaretOffset;
188
			} else {
189
				start= currentCaretOffset;
190
				end= previousCaretOffset;
191
			}
192
			for (int i= start; i < end; i++) {
193
				if (isMatchedChar(document.getChar(i))) {
194
					return true;
195
				}
196
			}
197
		} catch (BadLocationException e) {
198
			//do nothing
199
		}
200
		return false;
167
	}
201
	}
168
202
169
	/**
203
	/**
Lines 261-266 Link Here
261
		return -1;
295
		return -1;
262
	}
296
	}
263
297
298
	/*
299
	 * Performs the actual work of finding enclosing peer characters for #findEnclosingPeerCharacters(IDocument, int, int).
300
	 */
301
	private IRegion findEnclosingPeers(IDocument document, DocumentPartitionAccessor doc, int offset, int length, int lowerBoundary, int upperBoundary) throws BadLocationException {
302
		char[] pairs= fPairs.fPairs;
303
	
304
		int start;
305
		int end;
306
		if (length >= 0) {
307
			start= offset;
308
			end= offset + length;
309
		} else {
310
			end= offset;
311
			start= offset + length;
312
		}
313
	
314
		boolean lowerFound= false;
315
		boolean upperFound= false;
316
		int[][] counts= new int[pairs.length][2];
317
		int pos1= doc.getNextPosition(start, false);
318
		int pos2= start;
319
	
320
		while ((pos1 >= lowerBoundary && !lowerFound) || (pos2 < upperBoundary && !upperFound)) {
321
			for (int i= 0; i < counts.length; i++) {
322
				counts[i][0]= counts[i][1]= 0;
323
			}
324
	
325
			outer1: while (pos1 >= lowerBoundary && !lowerFound) {
326
				final char c= doc.getChar(pos1);
327
				int i= getCharacterIndex(c, document, pos1);
328
				if (i != -1 && doc.inPartition(pos1)) {
329
					if (i % 2 == 0) {
330
						counts[i / 2][0]--; //start
331
					} else {
332
						counts[i / 2][0]++; //end
333
					}
334
					for (int j= 0; j < counts.length; j++) {
335
						if (counts[j][0] == -1) {
336
							lowerFound= true;
337
							break outer1;
338
						}
339
					}
340
				}
341
				pos1= doc.getNextPosition(pos1, false);
342
			}
343
	
344
			outer2: while (pos2 < upperBoundary && !upperFound) {
345
				final char c= doc.getChar(pos2);
346
				int i= getCharacterIndex(c, document, pos2);
347
				if (i != -1 && doc.inPartition(pos2)) {
348
					if (i % 2 == 0) {
349
						counts[i / 2][1]++; //start
350
					} else {
351
						counts[i / 2][1]--; //end
352
					}
353
					for (int j= 0; j < counts.length; j++) {
354
						if (counts[j][1] == -1 && counts[j][0] == -1) {
355
							upperFound= true;
356
							break outer2;
357
						}
358
					}
359
				}
360
				pos2= doc.getNextPosition(pos2, true);
361
			}
362
	
363
			if (pos1 > start || pos2 < end) {
364
				//match inside selection => discard
365
				pos1= doc.getNextPosition(pos1, false);
366
				pos2= doc.getNextPosition(pos2, true);
367
				lowerFound= false;
368
				upperFound= false;
369
			}
370
		}
371
		pos2++;
372
		if (pos1 < lowerBoundary || pos2 > upperBoundary)
373
			return null;
374
		return new Region(pos1, pos2 - pos1);
375
	}
376
377
	/**
378
	 * Determines the index of the character in the char array passed to the constructor of the pair
379
	 * matcher.
380
	 * 
381
	 * @param ch the character
382
	 * @param document the document
383
	 * @param offset the offset in document
384
	 * @return the index of the character in the char array passed to the constructor of the pair
385
	 *         matcher, and -1 if the character is not one of the matched characters.
386
	 * @since 3.8
387
	 */
388
	private int getCharacterIndex(char ch, IDocument document, int offset) {
389
		char[] pairs= fPairs.fPairs;
390
		for (int i= 0; i < pairs.length; i++) {
391
			if (pairs[i] == ch && isMatchedChar(ch, document, offset)) {
392
				return i;
393
			}
394
		}
395
		return -1;
396
	}
397
264
	/* @see ICharacterPairMatcher#getAnchor() */
398
	/* @see ICharacterPairMatcher#getAnchor() */
265
	public int getAnchor() {
399
	public int getAnchor() {
266
		return fAnchor;
400
		return fAnchor;
Lines 285-290 Link Here
285
		private final IDocument fDocument;
419
		private final IDocument fDocument;
286
		private final String fPartitioning, fPartition;
420
		private final String fPartitioning, fPartition;
287
		private ITypedRegion fCachedPartition;
421
		private ITypedRegion fCachedPartition;
422
		private int fLength;
288
423
289
		/**
424
		/**
290
		 * Creates a new partitioned document for the specified document.
425
		 * Creates a new partitioned document for the specified document.
Lines 298-303 Link Here
298
			fDocument= doc;
433
			fDocument= doc;
299
			fPartitioning= partitioning;
434
			fPartitioning= partitioning;
300
			fPartition= partition;
435
			fPartition= partition;
436
			fLength= doc.getLength();
301
		}
437
		}
302
438
303
		/**
439
		/**
Lines 338-344 Link Here
338
		}
474
		}
339
475
340
		/**
476
		/**
341
		 * Returns the next position to query in the search.  The position
477
		 * Returns the next position to query in the search. The position
342
		 * is not guaranteed to be in this document's partition.
478
		 * is not guaranteed to be in this document's partition.
343
		 *
479
		 *
344
		 * @param pos an offset within the document
480
		 * @param pos an offset within the document
Lines 347-354 Link Here
347
		 */
483
		 */
348
		public int getNextPosition(int pos, boolean searchForward) {
484
		public int getNextPosition(int pos, boolean searchForward) {
349
			final ITypedRegion partition= getPartition(pos);
485
			final ITypedRegion partition= getPartition(pos);
350
			if (partition == null) return simpleIncrement(pos, searchForward);
486
			if (partition == null || fPartition.equals(partition.getType()))
351
			if (fPartition.equals(partition.getType()))
352
				return simpleIncrement(pos, searchForward);
487
				return simpleIncrement(pos, searchForward);
353
			if (searchForward) {
488
			if (searchForward) {
354
				int end= partition.getOffset() + partition.getLength();
489
				int end= partition.getOffset() + partition.getLength();
Lines 376-382 Link Here
376
		 */
511
		 */
377
		private ITypedRegion getPartition(int pos) {
512
		private ITypedRegion getPartition(int pos) {
378
			if (fCachedPartition == null || !contains(fCachedPartition, pos)) {
513
			if (fCachedPartition == null || !contains(fCachedPartition, pos)) {
379
				Assert.isTrue(pos >= 0 && pos <= fDocument.getLength());
514
				Assert.isTrue(pos >= 0 && pos <= fLength);
380
				try {
515
				try {
381
					fCachedPartition= TextUtilities.getPartition(fDocument, fPartitioning, pos, false);
516
					fCachedPartition= TextUtilities.getPartition(fDocument, fPartitioning, pos, false);
382
				} catch (BadLocationException e) {
517
				} catch (BadLocationException e) {
Lines 405-432 Link Here
405
		}
540
		}
406
541
407
		/**
542
		/**
408
		 * Returns true if the specified character pair occurs in one
543
		 * Returns true if the specified character occurs in one of the character pairs.
409
		 * of the character pairs.
544
		 * 
410
		 *
411
		 * @param c a character
545
		 * @param c a character
412
		 * @return true exactly if the character occurs in one of the pairs
546
		 * @return true exactly if the character occurs in one of the pairs
413
		 */
547
		 */
414
		public boolean contains(char c) {
548
		public boolean contains(char c) {
415
			return getAllCharacters().contains(new Character(c));
549
			char[] pairs= fPairs;
416
		}
550
			for (int i= 0, n= pairs.length; i < n; i++) {
417
551
				if (c == pairs[i])
418
		private Set/*<Character>*/ fCharsCache= null;
552
					return true;
419
		/**
420
		 * @return A set containing all characters occurring in character pairs.
421
		 */
422
		private Set/*<Character>*/ getAllCharacters() {
423
			if (fCharsCache == null) {
424
				Set/*<Character>*/ set= new HashSet/*<Character>*/();
425
				for (int i= 0; i < fPairs.length; i++)
426
					set.add(new Character(fPairs[i]));
427
				fCharsCache= set;
428
			}
553
			}
429
			return fCharsCache;
554
			return false;
430
		}
555
		}
431
556
432
		/**
557
		/**
(-)a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/ICharacterPairMatcherExtension.java (+44 lines)
Lines 49-52 Link Here
49
	 *         enclosing pair
49
	 *         enclosing pair
50
	 */
50
	 */
51
	IRegion findEnclosingPeerCharacters(IDocument document, int offset, int length);
51
	IRegion findEnclosingPeerCharacters(IDocument document, int offset, int length);
52
53
	/**
54
	 * Checks whether the character is one of the characters matched by the pair matcher.
55
	 * 
56
	 * @param ch the character
57
	 * @return <code>true</code> if the the character is one of the characters matched by the pair
58
	 *         matcher, and <code>false</code> otherwise
59
	 */
60
	boolean isMatchedChar(char ch);
61
62
	/**
63
	 * Checks whether the character is one of the characters matched by the pair matcher.
64
	 * 
65
	 * <p>
66
	 * Clients can use this method to handle characters which may have special meaning in some
67
	 * situations. E.g. in Java, '<' is used as an angular bracket and as well as less-than operator.
68
	 * </p>
69
	 * 
70
	 * @param ch the character
71
	 * @param document the document
72
	 * @param offset the offset in document
73
	 * @return <code>true</code> if the the character is one of the characters matched by the pair
74
	 *         matcher, and <code>false</code> otherwise
75
	 */
76
	boolean isMatchedChar(char ch, IDocument document, int offset);
77
78
	/**
79
	 * Computes whether a client needs to recompute the enclosing pair after a selection change in
80
	 * the document.
81
	 * 
82
	 * <p>
83
	 * This is intended to be quick test to determine whether a re-computation of enclosing pair is
84
	 * required, as the re-computation after each selection change via a
85
	 * {@link #findEnclosingPeerCharacters(IDocument, int, int)} call can be expensive for some
86
	 * clients.
87
	 * </p>
88
	 * 
89
	 * @param document the document to work on
90
	 * @param currentSelection the current selection in the document
91
	 * @param previousSelection the previous selection in the document
92
	 * @return <code>true</code> if the enclosing pair needs to be recomputed, <code>false</code>
93
	 *         otherwise
94
	 */
95
	boolean isRecomputationOfEnclosingPairRequired(IDocument document, IRegion currentSelection, IRegion previousSelection);
52
}
96
}
(-)a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/MatchingCharacterPainter.java (-13 / +192 lines)
Lines 20-40 Link Here
20
import org.eclipse.swt.graphics.Rectangle;
20
import org.eclipse.swt.graphics.Rectangle;
21
21
22
import org.eclipse.jface.text.BadLocationException;
22
import org.eclipse.jface.text.BadLocationException;
23
import org.eclipse.jface.text.DocumentEvent;
23
import org.eclipse.jface.text.IDocument;
24
import org.eclipse.jface.text.IDocument;
24
import org.eclipse.jface.text.IPaintPositionManager;
25
import org.eclipse.jface.text.IPaintPositionManager;
25
import org.eclipse.jface.text.IPainter;
26
import org.eclipse.jface.text.IPainter;
26
import org.eclipse.jface.text.IRegion;
27
import org.eclipse.jface.text.IRegion;
28
import org.eclipse.jface.text.ITextInputListener;
29
import org.eclipse.jface.text.ITextListener;
27
import org.eclipse.jface.text.ITextViewerExtension5;
30
import org.eclipse.jface.text.ITextViewerExtension5;
28
import org.eclipse.jface.text.Position;
31
import org.eclipse.jface.text.Position;
29
import org.eclipse.jface.text.Region;
32
import org.eclipse.jface.text.Region;
33
import org.eclipse.jface.text.TextEvent;
30
34
31
/**
35
/**
32
 * Highlights the peer character matching the character near the caret position.
36
 * Highlights the peer character matching the character near the caret position, or a pair of peer
33
 * This painter can be configured with an
37
 * characters enclosing the caret position. This painter can be configured with an
34
 * {@link org.eclipse.jface.text.source.ICharacterPairMatcher}.
38
 * {@link org.eclipse.jface.text.source.ICharacterPairMatcher} or an
39
 * {@link org.eclipse.jface.text.source.ICharacterPairMatcherExtension}.
35
 * <p>
40
 * <p>
36
 * Clients instantiate and configure object of this class.</p>
41
 * Clients instantiate and configure an object of this class.
37
 *
42
 * </p>
43
 * 
38
 * @since 2.1
44
 * @since 2.1
39
 */
45
 */
40
public final class MatchingCharacterPainter implements IPainter, PaintListener {
46
public final class MatchingCharacterPainter implements IPainter, PaintListener {
Lines 55-67 Link Here
55
	private Position fPairPosition= new Position(0, 0);
61
	private Position fPairPosition= new Position(0, 0);
56
	/** The anchor indicating whether the character is left or right of the caret */
62
	/** The anchor indicating whether the character is left or right of the caret */
57
	private int fAnchor;
63
	private int fAnchor;
58
	/** Whether to highlight enclosing peer characters or not. */
64
59
	private boolean fHighlightEnclosingPeerCharcters;
65
	/**
60
	/** Whether to highlight the character at caret location or not. */
66
	 * Whether to highlight enclosing peer characters or not.
67
	 * 
68
	 * @since 3.8
69
	 */
70
	private boolean fHighlightEnclosingPeerCharacters;
71
72
	/**
73
	 * Whether to highlight the character at caret location or not.
74
	 * 
75
	 * @since 3.8
76
	 */
61
	private boolean fHighlightCharacterAtCaretLocation;
77
	private boolean fHighlightCharacterAtCaretLocation;
62
	/** Whether a character is present at caret location or not. */
78
79
	/**
80
	 * Whether a character is present at caret location or not.
81
	 * 
82
	 * @since 3.8
83
	 */
63
	private boolean fCharacterPresentAtCaretLocation;
84
	private boolean fCharacterPresentAtCaretLocation;
64
85
86
	/**
87
	 * The document this painter is associated with.
88
	 * 
89
	 * @since 3.8
90
	 */
91
	private IDocument fDocument;
92
93
	/**
94
	 * The previous selection, used to determine the need for computing enclosing brackets.
95
	 * 
96
	 * @since 3.8
97
	 */
98
	private IRegion fPreviousSelection;
99
100
	/**
101
	 * Previous length of the document this painter is associated with.
102
	 * 
103
	 * @since 3.8
104
	 */
105
	private int fPreviousLengthOfDocument;
106
107
	/**
108
	 * Whether the input document has been replaced or not.
109
	 * 
110
	 * @since 3.8
111
	 */
112
	private boolean fDocumentChanged;
113
114
	/**
115
	 * The text viewer change listener.
116
	 * 
117
	 * @since 3.8
118
	 */
119
	private TextListener fTextListener;
65
120
66
	/**
121
	/**
67
	 * Creates a new MatchingCharacterPainter for the given source viewer using the given character
122
	 * Creates a new MatchingCharacterPainter for the given source viewer using the given character
Lines 75-80 Link Here
75
		fSourceViewer= sourceViewer;
130
		fSourceViewer= sourceViewer;
76
		fMatcher= matcher;
131
		fMatcher= matcher;
77
		fTextWidget= sourceViewer.getTextWidget();
132
		fTextWidget= sourceViewer.getTextWidget();
133
		fDocument= fSourceViewer.getDocument();
78
	}
134
	}
79
135
80
	/**
136
	/**
Lines 95-101 Link Here
95
	 * @since 3.8
151
	 * @since 3.8
96
	 */
152
	 */
97
	public void setHighlightEnclosingPeerCharacters(boolean highlightEnclosingPeerCharcters) {
153
	public void setHighlightEnclosingPeerCharacters(boolean highlightEnclosingPeerCharcters) {
98
		fHighlightEnclosingPeerCharcters= highlightEnclosingPeerCharcters;
154
		fHighlightEnclosingPeerCharacters= highlightEnclosingPeerCharcters;
155
		installUninstallTextListener(highlightEnclosingPeerCharcters);
99
	}
156
	}
100
157
101
	/**
158
	/**
Lines 112-117 Link Here
112
	 */
169
	 */
113
	public void dispose() {
170
	public void dispose() {
114
		if (fMatcher != null) {
171
		if (fMatcher != null) {
172
			if (fMatcher instanceof ICharacterPairMatcherExtension && fTextListener != null) {
173
				installUninstallTextListener(false);
174
			}
175
115
			fMatcher.clear();
176
			fMatcher.clear();
116
			fMatcher= null;
177
			fMatcher= null;
117
		}
178
		}
Lines 185-191 Link Here
185
			offset -= region.getOffset();
246
			offset -= region.getOffset();
186
		}
247
		}
187
248
188
		if (fHighlightCharacterAtCaretLocation || (fHighlightEnclosingPeerCharcters && !fCharacterPresentAtCaretLocation)) {
249
		if (fHighlightCharacterAtCaretLocation || (fHighlightEnclosingPeerCharacters && !fCharacterPresentAtCaretLocation)) {
189
			draw(gc, offset, 1);
250
			draw(gc, offset, 1);
190
			draw(gc, offset + length - 1, 1);
251
			draw(gc, offset + length - 1, 1);
191
		} else {
252
		} else {
Lines 262-268 Link Here
262
	 */
323
	 */
263
	public void paint(int reason) {
324
	public void paint(int reason) {
264
325
265
		IDocument document= fSourceViewer.getDocument();
326
		IDocument document= fDocument;
266
		if (document == null) {
327
		if (document == null) {
267
			deactivate(false);
328
			deactivate(false);
268
			return;
329
			return;
Lines 276-282 Link Here
276
			ICharacterPairMatcherExtension matcher= (ICharacterPairMatcherExtension)fMatcher;
337
			ICharacterPairMatcherExtension matcher= (ICharacterPairMatcherExtension)fMatcher;
277
			pair= matcher.match(document, selection.getOffset(), selection.getLength());
338
			pair= matcher.match(document, selection.getOffset(), selection.getLength());
278
			characterPresentAtCaretLocation= (pair != null);
339
			characterPresentAtCaretLocation= (pair != null);
279
			if (pair == null && fHighlightEnclosingPeerCharcters) {
340
			if (pair == null && fHighlightEnclosingPeerCharacters) {
341
342
				int length= document.getLength();
343
				boolean lengthChanged= length != fPreviousLengthOfDocument;
344
				fPreviousLengthOfDocument= length;
345
346
				if (reason != IPainter.CONFIGURATION && !fDocumentChanged && !lengthChanged && selection.equals(fPreviousSelection)) {
347
					return;
348
				}
349
350
				if (reason == IPainter.TEXT_CHANGE) {
351
					fPreviousSelection= selection;
352
					return;
353
				}
354
355
				fDocumentChanged= false;
356
				if (reason != IPainter.CONFIGURATION && !lengthChanged && fPreviousSelection != null && reason != IPainter.INTERNAL) {
357
					if (!matcher.isRecomputationOfEnclosingPairRequired(document, selection, fPreviousSelection)) {
358
						fPreviousSelection= selection;
359
						return;
360
					}
361
				}
280
				pair= matcher.findEnclosingPeerCharacters(document, selection.getOffset(), selection.getLength());
362
				pair= matcher.findEnclosingPeerCharacters(document, selection.getOffset(), selection.getLength());
281
			}
363
			}
282
		} else {
364
		} else {
Lines 288-293 Link Here
288
			characterPresentAtCaretLocation= (pair != null);
370
			characterPresentAtCaretLocation= (pair != null);
289
		}
371
		}
290
372
373
		fPreviousSelection= selection;
291
		if (pair == null) {
374
		if (pair == null) {
292
			deactivate(true);
375
			deactivate(true);
293
			return;
376
			return;
Lines 340-343 Link Here
340
	public void setPositionManager(IPaintPositionManager manager) {
423
	public void setPositionManager(IPaintPositionManager manager) {
341
		fPaintPositionManager= manager;
424
		fPaintPositionManager= manager;
342
	}
425
	}
426
427
	/**
428
	 * Installs or uninstalls the text listener depending on the boolean parameter.
429
	 * 
430
	 * @param install whether to install or uninstall the text listener
431
	 * 
432
	 * @since 3.8
433
	 */
434
	private void installUninstallTextListener(boolean install) {
435
		if (!(fMatcher instanceof ICharacterPairMatcherExtension))
436
			return;
437
	
438
		if (install) {
439
			fTextListener= new TextListener();
440
			fSourceViewer.addTextInputListener(fTextListener);
441
			fSourceViewer.addTextListener(fTextListener);
442
		} else {
443
			if (fTextListener != null) {
444
				fSourceViewer.removeTextInputListener(fTextListener);
445
				fSourceViewer.removeTextListener(fTextListener);
446
				fTextListener= null;
447
			}
448
		}
449
	}
450
451
	/**
452
	 * Listens to document changes and if required by those document changes causes a re-computation
453
	 * of matching characters.
454
	 * 
455
	 * @since 3.8
456
	 */
457
	private class TextListener implements ITextListener, ITextInputListener {
458
459
		/**
460
		 * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument,
461
		 *      org.eclipse.jface.text.IDocument)
462
		 * @since 3.8
463
		 */
464
		public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
465
			//do nothing
466
		}
467
468
		/**
469
		 * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument,
470
		 *      org.eclipse.jface.text.IDocument)
471
		 * @since 3.8
472
		 */
473
		public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
474
			fDocument= newInput;
475
			fDocumentChanged= true;
476
		}
477
478
		/**
479
		 * @see org.eclipse.jface.text.ITextListener#textChanged(org.eclipse.jface.text.TextEvent)
480
		 * @since 3.8
481
		 */
482
		public void textChanged(TextEvent event) {
483
			if (!fHighlightEnclosingPeerCharacters || !(fMatcher instanceof ICharacterPairMatcherExtension))
484
				return;
485
486
			String text= event.getText();
487
			String replacedText= event.getReplacedText();
488
489
			boolean viewerRedrawState= event.getViewerRedrawState();
490
			DocumentEvent documentEvent= event.getDocumentEvent();
491
			if (documentEvent == null && !viewerRedrawState)
492
				return;
493
494
			ICharacterPairMatcherExtension matcher= (ICharacterPairMatcherExtension)fMatcher;
495
			boolean found= searchForCharacters(text, matcher) || searchForCharacters(replacedText, matcher);
496
497
			if (found || (documentEvent == null && viewerRedrawState)) {
498
				paint(IPainter.INTERNAL);
499
			}
500
		}
501
502
		/**
503
		 * Searches for matched characters in the given string.
504
		 * 
505
		 * @param text the string to search
506
		 * @param matcher the pair matcher
507
		 * @return <code>true</code> if a matched character is found, <code>false</code> otherwise
508
		 * 
509
		 * @since 3.8
510
		 */
511
		private boolean searchForCharacters(String text, ICharacterPairMatcherExtension matcher) {
512
			if (text == null)
513
				return false;
514
			for (int i= 0; i < text.length(); i++) {
515
				if (matcher.isMatchedChar(text.charAt(i))) {
516
					return true;
517
				}
518
			}
519
			return false;
520
		}
521
	}
343
}
522
}

Return to bug 372128