Mercurial > projects > dwt-addons
annotate dwtx/jface/text/source/projection/ProjectionViewer.d @ 138:b6bad70d540a
Regex instanceof changes
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 24 Aug 2008 02:26:23 +0200 |
parents | 6dcb0baaa031 |
children | 53b889547456 |
rev | line source |
---|---|
129 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2008 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 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.jface.text.source.projection.ProjectionViewer; | |
14 | |
131 | 15 import dwtx.jface.text.source.projection.ProjectionSupport; // packageimport |
16 import dwtx.jface.text.source.projection.IProjectionPosition; // packageimport | |
17 import dwtx.jface.text.source.projection.AnnotationBag; // packageimport | |
18 import dwtx.jface.text.source.projection.ProjectionSummary; // packageimport | |
19 import dwtx.jface.text.source.projection.ProjectionAnnotationHover; // packageimport | |
20 import dwtx.jface.text.source.projection.ProjectionRulerColumn; // packageimport | |
21 import dwtx.jface.text.source.projection.ProjectionAnnotationModel; // packageimport | |
22 import dwtx.jface.text.source.projection.SourceViewerInformationControl; // packageimport | |
23 import dwtx.jface.text.source.projection.IProjectionListener; // packageimport | |
24 import dwtx.jface.text.source.projection.ProjectionAnnotation; // packageimport | |
25 | |
26 | |
129 | 27 import dwt.dwthelper.utils; |
28 | |
29 import java.util.ArrayList; | |
30 import java.util.Iterator; | |
31 import java.util.List; | |
32 | |
33 import dwt.DWTError; | |
34 import dwt.custom.ST; | |
35 import dwt.custom.StyledText; | |
36 import dwt.dnd.Clipboard; | |
37 import dwt.dnd.DND; | |
38 import dwt.dnd.TextTransfer; | |
39 import dwt.dnd.Transfer; | |
40 import dwt.events.VerifyEvent; | |
41 import dwt.graphics.Point; | |
42 import dwt.widgets.Composite; | |
43 import dwt.widgets.Display; | |
44 import dwtx.core.runtime.Assert; | |
45 import dwtx.jface.text.BadLocationException; | |
46 import dwtx.jface.text.DocumentEvent; | |
47 import dwtx.jface.text.FindReplaceDocumentAdapter; | |
48 import dwtx.jface.text.IDocument; | |
49 import dwtx.jface.text.IDocumentInformationMappingExtension; | |
50 import dwtx.jface.text.IDocumentListener; | |
51 import dwtx.jface.text.IRegion; | |
52 import dwtx.jface.text.ISlaveDocumentManager; | |
53 import dwtx.jface.text.ITextViewerExtension5; | |
54 import dwtx.jface.text.Position; | |
55 import dwtx.jface.text.Region; | |
56 import dwtx.jface.text.TextUtilities; | |
57 import dwtx.jface.text.projection.ProjectionDocument; | |
58 import dwtx.jface.text.projection.ProjectionDocumentEvent; | |
59 import dwtx.jface.text.projection.ProjectionDocumentManager; | |
60 import dwtx.jface.text.source.Annotation; | |
61 import dwtx.jface.text.source.AnnotationModelEvent; | |
62 import dwtx.jface.text.source.CompositeRuler; | |
63 import dwtx.jface.text.source.IAnnotationModel; | |
64 import dwtx.jface.text.source.IAnnotationModelExtension; | |
65 import dwtx.jface.text.source.IAnnotationModelListener; | |
66 import dwtx.jface.text.source.IAnnotationModelListenerExtension; | |
67 import dwtx.jface.text.source.IOverviewRuler; | |
68 import dwtx.jface.text.source.IVerticalRuler; | |
69 import dwtx.jface.text.source.IVerticalRulerColumn; | |
70 import dwtx.jface.text.source.SourceViewer; | |
71 | |
72 | |
73 /** | |
74 * A projection source viewer is a source viewer which supports multiple visible | |
75 * regions which can dynamically be changed. | |
76 * <p> | |
77 * A projection source viewer uses a <code>ProjectionDocumentManager</code> | |
78 * for the management of the visible document.</p> | |
79 * <p> | |
80 * NOTE: The <code>ProjectionViewer</code> only supports projections that cover full lines. | |
81 * </p> | |
82 * <p> | |
83 * This class should not be subclassed.</p> | |
84 * | |
85 * @since 3.0 | |
86 * @noextend This class is not intended to be subclassed by clients. | |
87 */ | |
88 public class ProjectionViewer : SourceViewer , ITextViewerExtension5 { | |
89 | |
90 private static final int BASE= INFORMATION; // see ISourceViewer.INFORMATION | |
91 | |
92 /** Operation constant for the expand operation. */ | |
93 public static final int EXPAND= BASE + 1; | |
94 /** Operation constant for the collapse operation. */ | |
95 public static final int COLLAPSE= BASE + 2; | |
96 /** Operation constant for the toggle projection operation. */ | |
97 public static final int TOGGLE= BASE + 3; | |
98 /** Operation constant for the expand all operation. */ | |
99 public static final int EXPAND_ALL= BASE + 4; | |
100 /** | |
101 * Operation constant for the collapse all operation. | |
102 * | |
103 * @since 3.2 | |
104 */ | |
105 public static final int COLLAPSE_ALL= BASE + 5; | |
106 | |
107 /** | |
108 * Internal listener to changes of the annotation model. | |
109 */ | |
110 private class AnnotationModelListener : IAnnotationModelListener, IAnnotationModelListenerExtension { | |
111 | |
112 /* | |
113 * @see dwtx.jface.text.source.IAnnotationModelListener#modelChanged(dwtx.jface.text.source.IAnnotationModel) | |
114 */ | |
115 public void modelChanged(IAnnotationModel model) { | |
116 processModelChanged(model, null); | |
117 } | |
118 | |
119 /* | |
120 * @see dwtx.jface.text.source.IAnnotationModelListenerExtension#modelChanged(dwtx.jface.text.source.AnnotationModelEvent) | |
121 */ | |
122 public void modelChanged(AnnotationModelEvent event) { | |
123 processModelChanged(event.getAnnotationModel(), event); | |
124 } | |
125 | |
126 private void processModelChanged(IAnnotationModel model, AnnotationModelEvent event) { | |
127 if (model is fProjectionAnnotationModel) { | |
128 | |
129 if (fProjectionSummary !is null) | |
130 fProjectionSummary.updateSummaries(); | |
131 processCatchupRequest(event); | |
132 | |
133 } else if (model is getAnnotationModel() && fProjectionSummary !is null) | |
134 fProjectionSummary.updateSummaries(); | |
135 } | |
136 } | |
137 | |
138 /** | |
139 * Executes the 'replaceVisibleDocument' operation when called the first time. Self-destructs afterwards. | |
140 */ | |
141 private class ReplaceVisibleDocumentExecutor : IDocumentListener { | |
142 | |
143 private IDocument fSlaveDocument; | |
144 private IDocument fExecutionTrigger; | |
145 | |
146 /** | |
147 * Creates a new executor in order to free the given slave document. | |
148 * | |
149 * @param slaveDocument the slave document to free | |
150 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
151 public this(IDocument slaveDocument) { |
129 | 152 fSlaveDocument= slaveDocument; |
153 } | |
154 | |
155 /** | |
156 * Installs this executor on the given trigger document. | |
157 * | |
158 * @param executionTrigger the trigger document | |
159 */ | |
160 public void install(IDocument executionTrigger) { | |
161 if (executionTrigger !is null && fSlaveDocument !is null) { | |
162 fExecutionTrigger= executionTrigger; | |
163 fExecutionTrigger.addDocumentListener(this); | |
164 } | |
165 } | |
166 | |
167 /* | |
168 * @see dwtx.jface.text.IDocumentListener#documentAboutToBeChanged(dwtx.jface.text.DocumentEvent) | |
169 */ | |
170 public void documentAboutToBeChanged(DocumentEvent event) { | |
171 } | |
172 | |
173 /* | |
174 * @see dwtx.jface.text.IDocumentListener#documentChanged(dwtx.jface.text.DocumentEvent) | |
175 */ | |
176 public void documentChanged(DocumentEvent event) { | |
177 fExecutionTrigger.removeDocumentListener(this); | |
178 executeReplaceVisibleDocument(fSlaveDocument); | |
179 } | |
180 } | |
181 | |
182 /** | |
183 * A command representing a change of the projection document. This can be either | |
184 * adding a master document range, removing a master document change, or invalidating | |
185 * the viewer text presentation. | |
186 */ | |
187 private static class ProjectionCommand { | |
188 | |
189 final static int ADD= 0; | |
190 final static int REMOVE= 1; | |
191 final static int INVALIDATE_PRESENTATION= 2; | |
192 | |
193 ProjectionDocument fProjection; | |
194 int fType; | |
195 int fOffset; | |
196 int fLength; | |
197 | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
198 this(ProjectionDocument projection, int type, int offset, int length) { |
129 | 199 fProjection= projection; |
200 fType= type; | |
201 fOffset= offset; | |
202 fLength= length; | |
203 } | |
204 | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
205 this(int offset, int length) { |
129 | 206 fType= INVALIDATE_PRESENTATION; |
207 fOffset= offset; | |
208 fLength= length; | |
209 } | |
210 | |
211 int computeExpectedCosts() { | |
212 | |
213 switch(fType) { | |
214 case ADD: { | |
215 try { | |
216 IRegion[] gaps= fProjection.computeUnprojectedMasterRegions(fOffset, fLength); | |
217 return gaps is null ? 0 : gaps.length; | |
218 } catch (BadLocationException x) { | |
219 } | |
220 break; | |
221 } | |
222 case REMOVE: { | |
223 try { | |
224 IRegion[] fragments= fProjection.computeProjectedMasterRegions(fOffset, fLength); | |
225 return fragments is null ? 0 : fragments.length; | |
226 } catch (BadLocationException x) { | |
227 } | |
228 break; | |
229 } | |
230 } | |
231 return 0; | |
232 } | |
233 } | |
234 | |
235 /** | |
236 * The queue of projection command objects. | |
237 */ | |
238 private static class ProjectionCommandQueue { | |
239 | |
240 final static int REDRAW_COSTS= 15; | |
241 final static int INVALIDATION_COSTS= 10; | |
242 | |
243 List fList= new ArrayList(15); | |
244 int fExpectedExecutionCosts= -1; | |
245 | |
246 | |
247 void add(ProjectionCommand command) { | |
248 fList.add(command); | |
249 } | |
250 | |
251 Iterator iterator() { | |
252 return fList.iterator(); | |
253 } | |
254 | |
255 void clear() { | |
256 fList.clear(); | |
257 fExpectedExecutionCosts= -1; | |
258 } | |
259 | |
260 bool passedRedrawCostsThreshold() { | |
261 if (fExpectedExecutionCosts is -1) | |
262 computeExpectedExecutionCosts(); | |
263 return fExpectedExecutionCosts > REDRAW_COSTS; | |
264 } | |
265 | |
266 bool passedInvalidationCostsThreshold() { | |
267 if (fExpectedExecutionCosts is -1) | |
268 computeExpectedExecutionCosts(); | |
269 return fExpectedExecutionCosts > INVALIDATION_COSTS; | |
270 } | |
271 | |
272 private void computeExpectedExecutionCosts() { | |
273 int max_costs= Math.max(REDRAW_COSTS, INVALIDATION_COSTS); | |
274 fExpectedExecutionCosts= fList.size(); | |
275 if (fExpectedExecutionCosts <= max_costs) { | |
276 ProjectionCommand command; | |
277 Iterator e= fList.iterator(); | |
278 while (e.hasNext()) { | |
134 | 279 command= cast(ProjectionCommand) e.next(); |
129 | 280 fExpectedExecutionCosts += command.computeExpectedCosts(); |
281 if (fExpectedExecutionCosts > max_costs) | |
282 break; | |
283 } | |
284 } | |
285 } | |
286 } | |
287 | |
288 /** The projection annotation model used by this viewer. */ | |
289 private ProjectionAnnotationModel fProjectionAnnotationModel; | |
290 /** The annotation model listener */ | |
291 private IAnnotationModelListener fAnnotationModelListener= new AnnotationModelListener(); | |
292 /** The projection summary. */ | |
293 private ProjectionSummary fProjectionSummary; | |
294 /** Indication that an annotation world change has not yet been processed. */ | |
295 private bool fPendingAnnotationWorldChange= false; | |
296 /** Indication whether projection changes in the visible document should be considered. */ | |
297 private bool fHandleProjectionChanges= true; | |
298 /** The list of projection listeners. */ | |
299 private List fProjectionListeners; | |
300 /** Internal lock for protecting the list of pending requests */ | |
301 private Object fLock= new Object(); | |
302 /** The list of pending requests */ | |
303 private List fPendingRequests= new ArrayList(); | |
304 /** The replace-visible-document execution trigger */ | |
305 private IDocument fReplaceVisibleDocumentExecutionTrigger; | |
306 /** <code>true</code> if projection was on the last time we switched to segmented mode. */ | |
307 private bool fWasProjectionEnabled; | |
308 /** The queue of projection commands used to assess the costs of projection changes. */ | |
309 private ProjectionCommandQueue fCommandQueue; | |
310 /** | |
311 * The amount of lines deleted by the last document event issued by the | |
312 * visible document event. | |
313 * @since 3.1 | |
314 */ | |
315 private int fDeletedLines; | |
316 | |
317 | |
318 /** | |
319 * Creates a new projection source viewer. | |
320 * | |
321 * @param parent the DWT parent control | |
322 * @param ruler the vertical ruler | |
323 * @param overviewRuler the overview ruler | |
324 * @param showsAnnotationOverview <code>true</code> if the overview ruler should be shown | |
325 * @param styles the DWT style bits | |
326 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
327 public this(Composite parent, IVerticalRuler ruler, IOverviewRuler overviewRuler, bool showsAnnotationOverview, int styles) { |
129 | 328 super(parent, ruler, overviewRuler, showsAnnotationOverview, styles); |
329 } | |
330 | |
331 /** | |
332 * Sets the projection summary for this viewer. | |
333 * | |
334 * @param projectionSummary the projection summary. | |
335 */ | |
336 public void setProjectionSummary(ProjectionSummary projectionSummary) { | |
337 fProjectionSummary= projectionSummary; | |
338 } | |
339 | |
340 /** | |
341 * Adds the projection annotation model to the given annotation model. | |
342 * | |
343 * @param model the model to which the projection annotation model is added | |
344 */ | |
345 private void addProjectionAnnotationModel(IAnnotationModel model) { | |
138 | 346 if ( cast(IAnnotationModelExtension)model ) { |
134 | 347 IAnnotationModelExtension extension= cast(IAnnotationModelExtension) model; |
129 | 348 extension.addAnnotationModel(ProjectionSupport.PROJECTION, fProjectionAnnotationModel); |
349 model.addAnnotationModelListener(fAnnotationModelListener); | |
350 } | |
351 } | |
352 | |
353 /** | |
354 * Removes the projection annotation model from the given annotation model. | |
355 * | |
356 * @param model the mode from which the projection annotation model is removed | |
357 * @return the removed projection annotation model or <code>null</code> if there was none | |
358 */ | |
359 private IAnnotationModel removeProjectionAnnotationModel(IAnnotationModel model) { | |
138 | 360 if ( cast(IAnnotationModelExtension)model ) { |
129 | 361 model.removeAnnotationModelListener(fAnnotationModelListener); |
134 | 362 IAnnotationModelExtension extension= cast(IAnnotationModelExtension) model; |
129 | 363 return extension.removeAnnotationModel(ProjectionSupport.PROJECTION); |
364 } | |
365 return null; | |
366 } | |
367 | |
368 /* | |
369 * @see dwtx.jface.text.source.SourceViewer#setDocument(dwtx.jface.text.IDocument, dwtx.jface.text.source.IAnnotationModel, int, int) | |
370 */ | |
371 public void setDocument(IDocument document, IAnnotationModel annotationModel, int modelRangeOffset, int modelRangeLength) { | |
372 bool wasProjectionEnabled= false; | |
373 | |
374 synchronized (fLock) { | |
375 fPendingRequests.clear(); | |
376 } | |
377 | |
378 if (fProjectionAnnotationModel !is null) { | |
379 wasProjectionEnabled= removeProjectionAnnotationModel(getVisualAnnotationModel()) !is null; | |
380 fProjectionAnnotationModel= null; | |
381 } | |
382 | |
383 super.setDocument(document, annotationModel, modelRangeOffset, modelRangeLength); | |
384 | |
385 if (wasProjectionEnabled && document !is null) | |
386 enableProjection(); | |
387 } | |
388 | |
389 /* | |
390 * @see dwtx.jface.text.source.SourceViewer#createVisualAnnotationModel(dwtx.jface.text.source.IAnnotationModel) | |
391 */ | |
392 protected IAnnotationModel createVisualAnnotationModel(IAnnotationModel annotationModel) { | |
393 IAnnotationModel model= super.createVisualAnnotationModel(annotationModel); | |
394 fProjectionAnnotationModel= new ProjectionAnnotationModel(); | |
395 return model; | |
396 } | |
397 | |
398 /** | |
399 * Returns the projection annotation model. | |
400 * | |
401 * @return the projection annotation model | |
402 */ | |
403 public ProjectionAnnotationModel getProjectionAnnotationModel() { | |
404 IAnnotationModel model= getVisualAnnotationModel(); | |
138 | 405 if ( cast(IAnnotationModelExtension)model ) { |
134 | 406 IAnnotationModelExtension extension= cast(IAnnotationModelExtension) model; |
407 return cast(ProjectionAnnotationModel) extension.getAnnotationModel(ProjectionSupport.PROJECTION); | |
129 | 408 } |
409 return null; | |
410 } | |
411 | |
412 /* | |
413 * @see dwtx.jface.text.TextViewer#createSlaveDocumentManager() | |
414 */ | |
415 protected ISlaveDocumentManager createSlaveDocumentManager() { | |
416 return new ProjectionDocumentManager(); | |
417 } | |
418 | |
419 /* | |
420 * @see dwtx.jface.text.TextViewer#updateSlaveDocument(dwtx.jface.text.IDocument, int, int) | |
421 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
422 protected bool updateSlaveDocument(IDocument slaveDocument, int modelRangeOffset, int modelRangeLength) { |
138 | 423 if ( cast(ProjectionDocument)slaveDocument ) { |
134 | 424 ProjectionDocument projection= cast(ProjectionDocument) slaveDocument; |
129 | 425 |
426 int offset= modelRangeOffset; | |
427 int length= modelRangeLength; | |
428 | |
429 if (!isProjectionMode()) { | |
430 // mimic original TextViewer behavior | |
431 IDocument master= projection.getMasterDocument(); | |
432 int line= master.getLineOfOffset(modelRangeOffset); | |
433 offset= master.getLineOffset(line); | |
434 length= (modelRangeOffset - offset) + modelRangeLength; | |
435 | |
436 } | |
437 | |
438 try { | |
439 fHandleProjectionChanges= false; | |
440 projection.replaceMasterDocumentRanges(offset, length); | |
441 } finally { | |
442 fHandleProjectionChanges= true; | |
443 } | |
444 return true; | |
445 } | |
446 return false; | |
447 } | |
448 | |
449 /** | |
450 * Adds a projection annotation listener to this viewer. The listener may | |
451 * not be <code>null</code>. If the listener is already registered, this method | |
452 * does not have any effect. | |
453 * | |
454 * @param listener the listener to add | |
455 */ | |
456 public void addProjectionListener(IProjectionListener listener) { | |
457 | |
458 Assert.isNotNull(listener); | |
459 | |
460 if (fProjectionListeners is null) | |
461 fProjectionListeners= new ArrayList(); | |
462 | |
463 if (!fProjectionListeners.contains(listener)) | |
464 fProjectionListeners.add(listener); | |
465 } | |
466 | |
467 /** | |
468 * Removes the given listener from this viewer. The listener may not be | |
469 * <code>null</code>. If the listener is not registered with this viewer, | |
470 * this method is without effect. | |
471 * | |
472 * @param listener the listener to remove | |
473 */ | |
474 public void removeProjectionListener(IProjectionListener listener) { | |
475 | |
476 Assert.isNotNull(listener); | |
477 | |
478 if (fProjectionListeners !is null) { | |
479 fProjectionListeners.remove(listener); | |
480 if (fProjectionListeners.size() is 0) | |
481 fProjectionListeners= null; | |
482 } | |
483 } | |
484 | |
485 /** | |
486 * Notifies all registered projection listeners | |
487 * that projection mode has been enabled. | |
488 */ | |
489 protected void fireProjectionEnabled() { | |
490 if (fProjectionListeners !is null) { | |
491 Iterator e= new ArrayList(fProjectionListeners).iterator(); | |
492 while (e.hasNext()) { | |
134 | 493 IProjectionListener l= cast(IProjectionListener) e.next(); |
129 | 494 l.projectionEnabled(); |
495 } | |
496 } | |
497 } | |
498 | |
499 /** | |
500 * Notifies all registered projection listeners | |
501 * that projection mode has been disabled. | |
502 */ | |
503 protected void fireProjectionDisabled() { | |
504 if (fProjectionListeners !is null) { | |
505 Iterator e= new ArrayList(fProjectionListeners).iterator(); | |
506 while (e.hasNext()) { | |
134 | 507 IProjectionListener l= cast(IProjectionListener) e.next(); |
129 | 508 l.projectionDisabled(); |
509 } | |
510 } | |
511 } | |
512 | |
513 /** | |
514 * Returns whether this viewer is in projection mode. | |
515 * | |
516 * @return <code>true</code> if this viewer is in projection mode, | |
517 * <code>false</code> otherwise | |
518 */ | |
519 public final bool isProjectionMode() { | |
520 return getProjectionAnnotationModel() !is null; | |
521 } | |
522 | |
523 /** | |
524 * Disables the projection mode. | |
525 */ | |
526 public final void disableProjection() { | |
527 if (isProjectionMode()) { | |
528 removeProjectionAnnotationModel(getVisualAnnotationModel()); | |
529 fProjectionAnnotationModel.removeAllAnnotations(); | |
530 fFindReplaceDocumentAdapter= null; | |
531 fireProjectionDisabled(); | |
532 } | |
533 } | |
534 | |
535 /** | |
536 * Enables the projection mode. | |
537 */ | |
538 public final void enableProjection() { | |
539 if (!isProjectionMode()) { | |
540 addProjectionAnnotationModel(getVisualAnnotationModel()); | |
541 fFindReplaceDocumentAdapter= null; | |
542 fireProjectionEnabled(); | |
543 } | |
544 } | |
545 | |
546 private void expandAll() { | |
547 int offset= 0; | |
548 IDocument doc= getDocument(); | |
549 int length= doc is null ? 0 : doc.getLength(); | |
550 if (isProjectionMode()) { | |
551 fProjectionAnnotationModel.expandAll(offset, length); | |
552 } | |
553 } | |
554 | |
555 private void expand() { | |
556 if (isProjectionMode()) { | |
557 Position found= null; | |
558 Annotation bestMatch= null; | |
559 Point selection= getSelectedRange(); | |
560 for (Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); e.hasNext();) { | |
134 | 561 ProjectionAnnotation annotation= cast(ProjectionAnnotation) e.next(); |
129 | 562 if (annotation.isCollapsed()) { |
563 Position position= fProjectionAnnotationModel.getPosition(annotation); | |
564 // take the first most fine grained match | |
565 if (position !is null && touches(selection, position)) | |
566 if (found is null || position.includes(found.offset) && position.includes(found.offset + found.length)) { | |
567 found= position; | |
568 bestMatch= annotation; | |
569 } | |
570 } | |
571 } | |
572 | |
573 if (bestMatch !is null) { | |
574 fProjectionAnnotationModel.expand(bestMatch); | |
575 revealRange(selection.x, selection.y); | |
576 } | |
577 } | |
578 } | |
579 | |
580 private bool touches(Point selection, Position position) { | |
581 return position.overlapsWith(selection.x, selection.y) || selection.y is 0 && position.offset + position.length is selection.x + selection.y; | |
582 } | |
583 | |
584 private void collapse() { | |
585 if (isProjectionMode()) { | |
586 Position found= null; | |
587 Annotation bestMatch= null; | |
588 Point selection= getSelectedRange(); | |
589 for (Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); e.hasNext();) { | |
134 | 590 ProjectionAnnotation annotation= cast(ProjectionAnnotation) e.next(); |
129 | 591 if (!annotation.isCollapsed()) { |
592 Position position= fProjectionAnnotationModel.getPosition(annotation); | |
593 // take the first most fine grained match | |
594 if (position !is null && touches(selection, position)) | |
595 if (found is null || found.includes(position.offset) && found.includes(position.offset + position.length)) { | |
596 found= position; | |
597 bestMatch= annotation; | |
598 } | |
599 } | |
600 } | |
601 | |
602 if (bestMatch !is null) { | |
603 fProjectionAnnotationModel.collapse(bestMatch); | |
604 revealRange(selection.x, selection.y); | |
605 } | |
606 } | |
607 } | |
608 | |
609 /* | |
610 * @since 3.2 | |
611 */ | |
612 private void collapseAll() { | |
613 int offset= 0; | |
614 IDocument doc= getDocument(); | |
615 int length= doc is null ? 0 : doc.getLength(); | |
616 if (isProjectionMode()) { | |
617 fProjectionAnnotationModel.collapseAll(offset, length); | |
618 } | |
619 } | |
620 | |
621 /** | |
622 * Adds the given master range to the given projection document. While the | |
623 * modification is processed, the viewer no longer handles projection | |
624 * changes, as it is causing them. | |
625 * | |
626 * @param projection the projection document | |
627 * @param offset the offset in the master document | |
628 * @param length the length in the master document | |
629 * @throws BadLocationException in case the specified range is invalid | |
630 * | |
631 * @see ProjectionDocument#addMasterDocumentRange(int, int) | |
632 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
633 private void addMasterDocumentRange(ProjectionDocument projection, int offset, int length) { |
129 | 634 |
635 if (fCommandQueue !is null) { | |
636 fCommandQueue.add(new ProjectionCommand(projection, ProjectionCommand.ADD, offset, length)); | |
637 } else { | |
638 try { | |
639 fHandleProjectionChanges= false; | |
640 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=108258 | |
641 // make sure the document range is strictly line based | |
642 int end= offset + length; | |
643 offset= toLineStart(projection.getMasterDocument(), offset, false); | |
644 length= toLineStart(projection.getMasterDocument(), end, true) - offset; | |
645 projection.addMasterDocumentRange(offset, length); | |
646 } finally { | |
647 fHandleProjectionChanges= true; | |
648 } | |
649 } | |
650 } | |
651 | |
652 /** | |
653 * Removes the given master range from the given projection document. While the | |
654 * modification is processed, the viewer no longer handles projection | |
655 * changes, as it is causing them. | |
656 * | |
657 * @param projection the projection document | |
658 * @param offset the offset in the master document | |
659 * @param length the length in the master document | |
660 * @throws BadLocationException in case the specified range is invalid | |
661 * | |
662 * @see ProjectionDocument#removeMasterDocumentRange(int, int) | |
663 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
664 private void removeMasterDocumentRange(ProjectionDocument projection, int offset, int length) { |
129 | 665 if (fCommandQueue !is null) { |
666 fCommandQueue.add(new ProjectionCommand(projection, ProjectionCommand.REMOVE, offset, length)); | |
667 } else { | |
668 try { | |
669 fHandleProjectionChanges= false; | |
670 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=108258 | |
671 // make sure the document range is strictly line based | |
672 int end= offset + length; | |
673 offset= toLineStart(projection.getMasterDocument(), offset, false); | |
674 length= toLineStart(projection.getMasterDocument(), end, true) - offset; | |
675 projection.removeMasterDocumentRange(offset, length); | |
676 } finally { | |
677 fHandleProjectionChanges= true; | |
678 } | |
679 } | |
680 } | |
681 | |
682 /** | |
683 * Returns the first line offset <= <code>offset</code>. If <code>testLastLine</code> | |
684 * is <code>true</code> and the offset is on last line then <code>offset</code> is returned. | |
685 * | |
686 * @param document the document | |
687 * @param offset the master document offset | |
688 * @param testLastLine <code>true</code> if the test for the last line should be performed | |
689 * @return the closest line offset >= <code>offset</code> | |
690 * @throws BadLocationException if the offset is invalid | |
691 * @since 3.2 | |
692 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
693 private int toLineStart(IDocument document, int offset, bool testLastLine) { |
129 | 694 if (document is null) |
695 return offset; | |
696 | |
697 if (testLastLine && offset >= document.getLineInformationOfOffset(document.getLength() - 1).getOffset()) | |
698 return offset; | |
699 | |
700 return document.getLineInformationOfOffset(offset).getOffset(); | |
701 } | |
702 | |
703 /* | |
704 * @see dwtx.jface.text.TextViewer#setVisibleRegion(int, int) | |
705 */ | |
706 public void setVisibleRegion(int start, int length) { | |
707 fWasProjectionEnabled= isProjectionMode(); | |
708 disableProjection(); | |
709 super.setVisibleRegion(start, length); | |
710 } | |
711 | |
712 /* | |
713 * @see dwtx.jface.text.TextViewer#setVisibleDocument(dwtx.jface.text.IDocument) | |
714 */ | |
715 protected void setVisibleDocument(IDocument document) { | |
716 if (!isProjectionMode()) { | |
717 super.setVisibleDocument(document); | |
718 return; | |
719 } | |
720 | |
721 // In projection mode we don't want to throw away the find/replace document adapter | |
722 FindReplaceDocumentAdapter adapter= fFindReplaceDocumentAdapter; | |
723 super.setVisibleDocument(document); | |
724 fFindReplaceDocumentAdapter= adapter; | |
725 } | |
726 | |
727 /* | |
728 * @see dwtx.jface.text.TextViewer#resetVisibleRegion() | |
729 */ | |
730 public void resetVisibleRegion() { | |
731 super.resetVisibleRegion(); | |
732 if (fWasProjectionEnabled) | |
733 enableProjection(); | |
734 } | |
735 | |
736 /* | |
737 * @see dwtx.jface.text.ITextViewer#getVisibleRegion() | |
738 */ | |
739 public IRegion getVisibleRegion() { | |
740 disableProjection(); | |
741 IRegion visibleRegion= getModelCoverage(); | |
742 if (visibleRegion is null) | |
743 visibleRegion= new Region(0, 0); | |
744 | |
745 return visibleRegion; | |
746 } | |
747 | |
748 /* | |
749 * @see dwtx.jface.text.ITextViewer#overlapsWithVisibleRegion(int,int) | |
750 */ | |
751 public bool overlapsWithVisibleRegion(int offset, int length) { | |
752 disableProjection(); | |
753 IRegion coverage= getModelCoverage(); | |
754 if (coverage is null) | |
755 return false; | |
756 | |
757 bool appending= (offset is coverage.getOffset() + coverage.getLength()) && length is 0; | |
758 return appending || TextUtilities.overlaps(coverage, new Region(offset, length)); | |
759 } | |
760 | |
761 /** | |
762 * Replace the visible document with the given document. Maintains the | |
763 * scroll offset and the selection. | |
764 * | |
765 * @param slave the visible document | |
766 */ | |
767 private void replaceVisibleDocument(IDocument slave) { | |
768 if (fReplaceVisibleDocumentExecutionTrigger !is null) { | |
769 ReplaceVisibleDocumentExecutor executor= new ReplaceVisibleDocumentExecutor(slave); | |
770 executor.install(fReplaceVisibleDocumentExecutionTrigger); | |
771 } else | |
772 executeReplaceVisibleDocument(slave); | |
773 } | |
774 | |
775 | |
776 private void executeReplaceVisibleDocument(IDocument visibleDocument) { | |
777 StyledText textWidget= getTextWidget(); | |
778 try { | |
779 if (textWidget !is null && !textWidget.isDisposed()) | |
780 textWidget.setRedraw(false); | |
781 | |
782 int topIndex= getTopIndex(); | |
783 Point selection= getSelectedRange(); | |
784 setVisibleDocument(visibleDocument); | |
785 Point currentSelection= getSelectedRange(); | |
786 if (currentSelection.x !is selection.x || currentSelection.y !is selection.y) | |
787 setSelectedRange(selection.x, selection.y); | |
788 setTopIndex(topIndex); | |
789 | |
790 } finally { | |
791 if (textWidget !is null && !textWidget.isDisposed()) | |
792 textWidget.setRedraw(true); | |
793 } | |
794 } | |
795 | |
796 /** | |
797 * Hides the given range by collapsing it. If requested, a redraw request is issued. | |
798 * | |
799 * @param offset the offset of the range to hide | |
800 * @param length the length of the range to hide | |
801 * @param fireRedraw <code>true</code> if a redraw request should be issued, <code>false</code> otherwise | |
802 * @throws BadLocationException in case the range is invalid | |
803 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
804 private void collapse(int offset, int length, bool fireRedraw) { |
129 | 805 ProjectionDocument projection= null; |
806 | |
807 IDocument visibleDocument= getVisibleDocument(); | |
138 | 808 if ( cast(ProjectionDocument)visibleDocument ) |
134 | 809 projection= cast(ProjectionDocument) visibleDocument; |
129 | 810 else { |
811 IDocument master= getDocument(); | |
812 IDocument slave= createSlaveDocument(getDocument()); | |
138 | 813 if ( cast(ProjectionDocument)slave ) { |
134 | 814 projection= cast(ProjectionDocument) slave; |
129 | 815 addMasterDocumentRange(projection, 0, master.getLength()); |
816 replaceVisibleDocument(projection); | |
817 } | |
818 } | |
819 | |
820 if (projection !is null) | |
821 removeMasterDocumentRange(projection, offset, length); | |
822 | |
823 if (projection !is null && fireRedraw) { | |
824 // repaint line above to get the folding box | |
825 IDocument document= getDocument(); | |
826 int line= document.getLineOfOffset(offset); | |
827 if (line > 0) { | |
828 IRegion info= document.getLineInformation(line - 1); | |
829 internalInvalidateTextPresentation(info.getOffset(), info.getLength()); | |
830 } | |
831 } | |
832 } | |
833 | |
834 /** | |
835 * Makes the given range visible again while not changing the folding state of any contained | |
836 * ranges. If requested, a redraw request is issued. | |
837 * | |
838 * @param offset the offset of the range to be expanded | |
839 * @param length the length of the range to be expanded | |
840 * @param fireRedraw <code>true</code> if a redraw request should be issued, | |
841 * <code>false</code> otherwise | |
842 * @throws BadLocationException in case the range is invalid | |
843 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
844 private void expand(int offset, int length, bool fireRedraw) { |
129 | 845 IDocument slave= getVisibleDocument(); |
138 | 846 if ( cast(ProjectionDocument)slave ) { |
134 | 847 ProjectionDocument projection= cast(ProjectionDocument) slave; |
129 | 848 |
849 // expand | |
850 addMasterDocumentRange(projection, offset, length); | |
851 | |
852 // collapse contained regions | |
853 ProjectionAnnotation[] collapsed= computeCollapsedNestedAnnotations(offset, length); | |
854 if (collapsed !is null) { | |
855 for (int i= 0; i < collapsed.length; i++) { | |
856 IRegion[] regions= computeCollapsedRegions(fProjectionAnnotationModel.getPosition(collapsed[i])); | |
857 if (regions !is null) | |
858 for (int j= 0; j < regions.length; j++) | |
859 removeMasterDocumentRange(projection, regions[j].getOffset(), regions[j].getLength()); | |
860 } | |
861 } | |
862 | |
863 // redraw if requested | |
864 if (fireRedraw) | |
865 internalInvalidateTextPresentation(offset, length); | |
866 } | |
867 } | |
868 | |
869 /** | |
870 * Processes the request for catch up with the annotation model in the UI thread. If the current | |
871 * thread is not the UI thread or there are pending catch up requests, a new request is posted. | |
872 * | |
873 * @param event the annotation model event | |
874 */ | |
875 protected final void processCatchupRequest(AnnotationModelEvent event) { | |
876 if (Display.getCurrent() !is null) { | |
877 bool run= false; | |
878 synchronized (fLock) { | |
879 run= fPendingRequests.isEmpty(); | |
880 } | |
881 if (run) { | |
882 | |
883 try { | |
884 catchupWithProjectionAnnotationModel(event); | |
885 } catch (BadLocationException x) { | |
886 throw new IllegalArgumentException(); | |
887 } | |
888 | |
889 } else | |
890 postCatchupRequest(event); | |
891 } else { | |
892 postCatchupRequest(event); | |
893 } | |
894 } | |
895 | |
896 /** | |
897 * Posts the request for catch up with the annotation model into the UI thread. | |
898 * | |
899 * @param event the annotation model event | |
900 */ | |
901 protected final void postCatchupRequest(final AnnotationModelEvent event) { | |
902 synchronized (fLock) { | |
903 fPendingRequests.add(event); | |
904 if (fPendingRequests.size() is 1) { | |
905 StyledText widget= getTextWidget(); | |
906 if (widget !is null) { | |
907 Display display= widget.getDisplay(); | |
908 if (display !is null) { | |
135 | 909 display.asyncExec(new class() Runnable { |
129 | 910 public void run() { |
911 try { | |
912 while (true) { | |
913 AnnotationModelEvent ame= null; | |
914 synchronized (fLock) { | |
915 if (fPendingRequests.size() is 0) | |
916 return; | |
134 | 917 ame= cast(AnnotationModelEvent) fPendingRequests.remove(0); |
129 | 918 } |
919 catchupWithProjectionAnnotationModel(ame); | |
920 } | |
921 } catch (BadLocationException x) { | |
922 try { | |
923 catchupWithProjectionAnnotationModel(null); | |
924 } catch (BadLocationException x1) { | |
925 throw new IllegalArgumentException(); | |
926 } finally { | |
927 synchronized (fLock) { | |
928 fPendingRequests.clear(); | |
929 } | |
930 } | |
931 } | |
932 } | |
933 }); | |
934 } | |
935 } | |
936 } | |
937 } | |
938 } | |
939 | |
940 /** | |
941 * Tests whether the visible document's master document | |
942 * is identical to this viewer's document. | |
943 * | |
944 * @return <code>true</code> if the visible document's master is | |
945 * identical to this viewer's document | |
946 * @since 3.1 | |
947 */ | |
948 private bool isVisibleMasterDocumentSameAsDocument() { | |
949 IDocument visibleDocument= getVisibleDocument(); | |
138 | 950 return ( cast(ProjectionDocument)visibleDocument ) && (cast(ProjectionDocument)visibleDocument).getMasterDocument() is getDocument(); |
129 | 951 } |
952 | |
953 /** | |
954 * Adapts the slave visual document of this viewer to the changes described | |
955 * in the annotation model event. When the event is <code>null</code>, | |
956 * this is identical to a world change event. | |
957 * | |
958 * @param event the annotation model event or <code>null</code> | |
959 * @exception BadLocationException in case the annotation model event is no longer in synchronization with the document | |
960 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
961 private void catchupWithProjectionAnnotationModel(AnnotationModelEvent event) { |
129 | 962 |
963 if (event is null || !isVisibleMasterDocumentSameAsDocument()) { | |
964 | |
965 fPendingAnnotationWorldChange= false; | |
966 reinitializeProjection(); | |
967 | |
968 } else if (event.isWorldChange()) { | |
969 | |
970 if (event.isValid()) { | |
971 fPendingAnnotationWorldChange= false; | |
972 reinitializeProjection(); | |
973 } else | |
974 fPendingAnnotationWorldChange= true; | |
975 | |
976 } else if (fPendingAnnotationWorldChange) { | |
977 if (event.isValid()) { | |
978 fPendingAnnotationWorldChange= false; | |
979 reinitializeProjection(); | |
980 } | |
981 } else { | |
982 | |
983 Annotation[] addedAnnotations= event.getAddedAnnotations(); | |
984 Annotation[] changedAnnotation= event.getChangedAnnotations(); | |
985 Annotation[] removedAnnotations= event.getRemovedAnnotations(); | |
986 | |
987 fCommandQueue= new ProjectionCommandQueue(); | |
988 | |
989 bool isRedrawing= redraws(); | |
990 int topIndex= isRedrawing ? getTopIndex() : -1; | |
991 | |
992 processDeletions(event, removedAnnotations, true); | |
993 List coverage= new ArrayList(); | |
994 processChanges(addedAnnotations, true, coverage); | |
995 processChanges(changedAnnotation, true, coverage); | |
996 | |
997 ProjectionCommandQueue commandQueue= fCommandQueue; | |
998 fCommandQueue= null; | |
999 | |
1000 if (commandQueue.passedRedrawCostsThreshold()) { | |
1001 setRedraw(false); | |
1002 try { | |
1003 executeProjectionCommands(commandQueue, false); | |
1004 } catch (IllegalArgumentException x) { | |
1005 reinitializeProjection(); | |
1006 } finally { | |
1007 setRedraw(true, topIndex); | |
1008 } | |
1009 } else { | |
1010 try { | |
1011 bool fireRedraw= !commandQueue.passedInvalidationCostsThreshold(); | |
1012 executeProjectionCommands(commandQueue, fireRedraw); | |
1013 if (!fireRedraw) | |
1014 invalidateTextPresentation(); | |
1015 } catch (IllegalArgumentException x) { | |
1016 reinitializeProjection(); | |
1017 } | |
1018 } | |
1019 } | |
1020 } | |
1021 | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
1022 private void executeProjectionCommands(ProjectionCommandQueue commandQueue, bool fireRedraw) { |
129 | 1023 |
1024 ProjectionCommand command; | |
1025 Iterator e= commandQueue.iterator(); | |
1026 while (e.hasNext()) { | |
134 | 1027 command= cast(ProjectionCommand) e.next(); |
129 | 1028 switch (command.fType) { |
1029 case ProjectionCommand.ADD: | |
1030 addMasterDocumentRange(command.fProjection, command.fOffset, command.fLength); | |
1031 break; | |
1032 case ProjectionCommand.REMOVE: | |
1033 removeMasterDocumentRange(command.fProjection, command.fOffset, command.fLength); | |
1034 break; | |
1035 case ProjectionCommand.INVALIDATE_PRESENTATION: | |
1036 if (fireRedraw) | |
1037 invalidateTextPresentation(command.fOffset, command.fLength); | |
1038 break; | |
1039 } | |
1040 } | |
1041 | |
1042 commandQueue.clear(); | |
1043 } | |
1044 | |
1045 private bool covers(int offset, int length, Position position) { | |
1046 if (!(position.offset is offset && position.length is length) && !position.isDeleted()) | |
1047 return offset <= position.getOffset() && position.getOffset() + position.getLength() <= offset + length; | |
1048 return false; | |
1049 } | |
1050 | |
1051 private ProjectionAnnotation[] computeCollapsedNestedAnnotations(int offset, int length) { | |
1052 List annotations= new ArrayList(5); | |
1053 Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); | |
1054 while (e.hasNext()) { | |
134 | 1055 ProjectionAnnotation annotation= cast(ProjectionAnnotation) e.next(); |
129 | 1056 if (annotation.isCollapsed()) { |
1057 Position position= fProjectionAnnotationModel.getPosition(annotation); | |
1058 if (position is null) { | |
1059 // annotation might already be deleted, we will be informed later on about this deletion | |
1060 continue; | |
1061 } | |
1062 if (covers(offset, length, position)) | |
1063 annotations.add(annotation); | |
1064 } | |
1065 } | |
1066 | |
1067 if (annotations.size() > 0) { | |
1068 ProjectionAnnotation[] result= new ProjectionAnnotation[annotations.size()]; | |
1069 annotations.toArray(result); | |
1070 return result; | |
1071 } | |
1072 | |
1073 return null; | |
1074 } | |
1075 | |
1076 private void internalInvalidateTextPresentation(int offset, int length) { | |
1077 if (fCommandQueue !is null) { | |
1078 fCommandQueue.add(new ProjectionCommand(offset, length)); | |
1079 } else { | |
1080 invalidateTextPresentation(offset, length); | |
1081 } | |
1082 } | |
1083 | |
1084 /* | |
1085 * We pass the removed annotation into this method for performance reasons only. Otherwise, they could be fetch from the event. | |
1086 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
1087 private void processDeletions(AnnotationModelEvent event, Annotation[] removedAnnotations, bool fireRedraw) { |
129 | 1088 for (int i= 0; i < removedAnnotations.length; i++) { |
134 | 1089 ProjectionAnnotation annotation= cast(ProjectionAnnotation) removedAnnotations[i]; |
129 | 1090 if (annotation.isCollapsed()) { |
1091 Position expanded= event.getPositionOfRemovedAnnotation(annotation); | |
1092 expand(expanded.getOffset(), expanded.getLength(), fireRedraw); | |
1093 } | |
1094 } | |
1095 } | |
1096 | |
1097 /** | |
1098 * Computes the region that must be collapsed when the given position is the | |
1099 * position of an expanded projection annotation. | |
1100 * | |
1101 * @param position the position | |
1102 * @return the range that must be collapsed | |
1103 */ | |
1104 public IRegion computeCollapsedRegion(Position position) { | |
1105 try { | |
1106 IDocument document= getDocument(); | |
1107 if (document is null) | |
1108 return null; | |
1109 | |
1110 int line= document.getLineOfOffset(position.getOffset()); | |
1111 int offset= document.getLineOffset(line + 1); | |
1112 | |
1113 int length= position.getLength() - (offset - position.getOffset()); | |
1114 if (length > 0) | |
1115 return new Region(offset, length); | |
1116 } catch (BadLocationException x) { | |
1117 } | |
1118 | |
1119 return null; | |
1120 } | |
1121 | |
1122 /** | |
1123 * Computes the regions that must be collapsed when the given position is | |
1124 * the position of an expanded projection annotation. | |
1125 * | |
1126 * @param position the position | |
1127 * @return the ranges that must be collapsed, or <code>null</code> if | |
1128 * there are none | |
1129 * @since 3.1 | |
1130 */ | |
1131 IRegion[] computeCollapsedRegions(Position position) { | |
1132 try { | |
1133 IDocument document= getDocument(); | |
1134 if (document is null) | |
1135 return null; | |
1136 | |
138 | 1137 if ( cast(IProjectionPosition)position ) { |
134 | 1138 IProjectionPosition projPosition= cast(IProjectionPosition) position; |
129 | 1139 return projPosition.computeProjectionRegions(document); |
1140 } | |
1141 | |
1142 int line= document.getLineOfOffset(position.getOffset()); | |
1143 int offset= document.getLineOffset(line + 1); | |
1144 | |
1145 int length= position.getLength() - (offset - position.getOffset()); | |
1146 if (length > 0) | |
1147 return new IRegion[] {new Region(offset, length)}; | |
1148 | |
1149 return null; | |
1150 } catch (BadLocationException x) { | |
1151 return null; | |
1152 } | |
1153 } | |
1154 | |
1155 /** | |
1156 * Computes the collapsed region anchor for the given position. Assuming | |
1157 * that the position is the position of an expanded projection annotation, | |
1158 * the anchor is the region that is still visible after the projection | |
1159 * annotation has been collapsed. | |
1160 * | |
1161 * @param position the position | |
1162 * @return the collapsed region anchor | |
1163 */ | |
1164 public Position computeCollapsedRegionAnchor(Position position) { | |
1165 try { | |
1166 IDocument document= getDocument(); | |
1167 if (document is null) | |
1168 return null; | |
1169 | |
1170 int captionOffset= position.getOffset(); | |
138 | 1171 if ( cast(IProjectionPosition)position ) |
134 | 1172 captionOffset+= (cast(IProjectionPosition) position).computeCaptionOffset(document); |
129 | 1173 |
1174 IRegion lineInfo= document.getLineInformationOfOffset(captionOffset); | |
1175 return new Position(lineInfo.getOffset() + lineInfo.getLength(), 0); | |
1176 } catch (BadLocationException x) { | |
1177 } | |
1178 return null; | |
1179 } | |
1180 | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
1181 private void processChanges(Annotation[] annotations, bool fireRedraw, List coverage) { |
129 | 1182 for (int i= 0; i < annotations.length; i++) { |
134 | 1183 ProjectionAnnotation annotation= cast(ProjectionAnnotation) annotations[i]; |
129 | 1184 Position position= fProjectionAnnotationModel.getPosition(annotation); |
1185 | |
1186 if (position is null) | |
1187 continue; | |
1188 | |
1189 if (!covers(coverage, position)) { | |
1190 if (annotation.isCollapsed()) { | |
1191 coverage.add(position); | |
1192 IRegion[] regions= computeCollapsedRegions(position); | |
1193 if (regions !is null) | |
1194 for (int j= 0; j < regions.length; j++) | |
1195 collapse(regions[j].getOffset(), regions[j].getLength(), fireRedraw); | |
1196 } else { | |
1197 expand(position.getOffset(), position.getLength(), fireRedraw); | |
1198 } | |
1199 } | |
1200 } | |
1201 } | |
1202 | |
1203 private bool covers(List coverage, Position position) { | |
1204 Iterator e= coverage.iterator(); | |
1205 while (e.hasNext()) { | |
134 | 1206 Position p= cast(Position) e.next(); |
129 | 1207 if (p.getOffset() <= position.getOffset() && position.getOffset() + position.getLength() <= p.getOffset() + p.getLength()) |
1208 return true; | |
1209 } | |
1210 return false; | |
1211 } | |
1212 | |
1213 /** | |
1214 * Forces this viewer to throw away any old state and to initialize its content | |
1215 * from its projection annotation model. | |
1216 * | |
1217 * @throws BadLocationException in case something goes wrong during initialization | |
1218 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
1219 public final void reinitializeProjection() { |
129 | 1220 |
1221 ProjectionDocument projection= null; | |
1222 | |
1223 ISlaveDocumentManager manager= getSlaveDocumentManager(); | |
1224 if (manager !is null) { | |
1225 IDocument master= getDocument(); | |
1226 if (master !is null) { | |
1227 IDocument slave= manager.createSlaveDocument(master); | |
138 | 1228 if ( cast(ProjectionDocument)slave ) { |
134 | 1229 projection= cast(ProjectionDocument) slave; |
129 | 1230 addMasterDocumentRange(projection, 0, master.getLength()); |
1231 } | |
1232 } | |
1233 } | |
1234 | |
1235 if (projection !is null) { | |
1236 Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); | |
1237 while (e.hasNext()) { | |
134 | 1238 ProjectionAnnotation annotation= cast(ProjectionAnnotation) e.next(); |
129 | 1239 if (annotation.isCollapsed()) { |
1240 Position position= fProjectionAnnotationModel.getPosition(annotation); | |
1241 if (position !is null) { | |
1242 IRegion[] regions= computeCollapsedRegions(position); | |
1243 if (regions !is null) | |
1244 for (int i= 0; i < regions.length; i++) | |
1245 removeMasterDocumentRange(projection, regions[i].getOffset(), regions[i].getLength()); | |
1246 } | |
1247 } | |
1248 } | |
1249 | |
1250 } | |
1251 | |
1252 replaceVisibleDocument(projection); | |
1253 } | |
1254 | |
1255 /* | |
1256 * @see dwtx.jface.text.TextViewer#handleVerifyEvent(dwt.events.VerifyEvent) | |
1257 */ | |
1258 protected void handleVerifyEvent(VerifyEvent e) { | |
1259 IRegion modelRange= event2ModelRange(e); | |
1260 if (exposeModelRange(modelRange)) | |
1261 e.doit= false; | |
1262 else | |
1263 super.handleVerifyEvent(e); | |
1264 } | |
1265 | |
1266 /** | |
1267 * Adds the give column as last column to this viewer's vertical ruler. | |
1268 * | |
1269 * @param column the column to be added | |
1270 */ | |
1271 public void addVerticalRulerColumn(IVerticalRulerColumn column) { | |
1272 IVerticalRuler ruler= getVerticalRuler(); | |
138 | 1273 if ( cast(CompositeRuler)ruler ) { |
134 | 1274 CompositeRuler compositeRuler= cast(CompositeRuler) ruler; |
129 | 1275 compositeRuler.addDecorator(99, column); |
1276 } | |
1277 } | |
1278 | |
1279 /** | |
1280 * Removes the give column from this viewer's vertical ruler. | |
1281 * | |
1282 * @param column the column to be removed | |
1283 */ | |
1284 public void removeVerticalRulerColumn(IVerticalRulerColumn column) { | |
1285 IVerticalRuler ruler= getVerticalRuler(); | |
138 | 1286 if ( cast(CompositeRuler)ruler ) { |
134 | 1287 CompositeRuler compositeRuler= cast(CompositeRuler) ruler; |
129 | 1288 compositeRuler.removeDecorator(column); |
1289 } | |
1290 } | |
1291 | |
1292 /* | |
1293 * @see dwtx.jface.text.ITextViewerExtension5#exposeModelRange(dwtx.jface.text.IRegion) | |
1294 */ | |
1295 public bool exposeModelRange(IRegion modelRange) { | |
1296 if (isProjectionMode()) | |
1297 return fProjectionAnnotationModel.expandAll(modelRange.getOffset(), modelRange.getLength()); | |
1298 | |
1299 if (!overlapsWithVisibleRegion(modelRange.getOffset(), modelRange.getLength())) { | |
1300 resetVisibleRegion(); | |
1301 return true; | |
1302 } | |
1303 | |
1304 return false; | |
1305 } | |
1306 | |
1307 /* | |
1308 * @see dwtx.jface.text.source.SourceViewer#setRangeIndication(int, int, bool) | |
1309 */ | |
1310 public void setRangeIndication(int offset, int length, bool moveCursor) { | |
1311 IRegion rangeIndication= getRangeIndication(); | |
1312 if (moveCursor && fProjectionAnnotationModel !is null && (rangeIndication is null || offset !is rangeIndication.getOffset() || length !is rangeIndication.getLength())) { | |
1313 List expand= new ArrayList(2); | |
1314 // expand the immediate effected collapsed regions | |
1315 Iterator iterator= fProjectionAnnotationModel.getAnnotationIterator(); | |
1316 while (iterator.hasNext()) { | |
134 | 1317 ProjectionAnnotation annotation= cast(ProjectionAnnotation)iterator.next(); |
129 | 1318 if (annotation.isCollapsed() && willAutoExpand(fProjectionAnnotationModel.getPosition(annotation), offset, length)) |
1319 expand.add(annotation); | |
1320 } | |
1321 | |
1322 if (!expand.isEmpty()) { | |
1323 Iterator e= expand.iterator(); | |
1324 while (e.hasNext()) | |
134 | 1325 fProjectionAnnotationModel.expand(cast(Annotation)e.next()); |
129 | 1326 } |
1327 } | |
1328 super.setRangeIndication(offset, length, moveCursor); | |
1329 } | |
1330 | |
1331 private bool willAutoExpand(Position position, int offset, int length) { | |
1332 if (position is null || position.isDeleted()) | |
1333 return false; | |
1334 // right or left boundary | |
1335 if (position.getOffset() is offset || position.getOffset() + position.getLength() is offset + length) | |
1336 return true; | |
1337 // completely embedded in given position | |
1338 if (position.getOffset() < offset && offset + length < position.getOffset() + position.getLength()) | |
1339 return true; | |
1340 return false; | |
1341 } | |
1342 | |
1343 /* | |
1344 * @see dwtx.jface.text.source.SourceViewer#handleDispose() | |
1345 * @since 3.0 | |
1346 */ | |
1347 protected void handleDispose() { | |
1348 fWasProjectionEnabled= false; | |
1349 super.handleDispose(); | |
1350 } | |
1351 | |
1352 /* | |
1353 * @see dwtx.jface.text.TextViewer#handleVisibleDocumentAboutToBeChanged(dwtx.jface.text.DocumentEvent) | |
1354 */ | |
1355 protected void handleVisibleDocumentChanged(DocumentEvent event) { | |
1356 if (fHandleProjectionChanges && event instanceof ProjectionDocumentEvent && isProjectionMode()) { | |
134 | 1357 ProjectionDocumentEvent e= cast(ProjectionDocumentEvent) event; |
129 | 1358 |
1359 DocumentEvent master= e.getMasterEvent(); | |
1360 if (master !is null) | |
1361 fReplaceVisibleDocumentExecutionTrigger= master.getDocument(); | |
1362 | |
1363 try { | |
1364 | |
1365 int replaceLength= e.getText() is null ? 0 : e.getText().length(); | |
1366 if (ProjectionDocumentEvent.PROJECTION_CHANGE is e.getChangeType()) { | |
1367 if (e.getLength() is 0 && replaceLength !is 0) | |
1368 fProjectionAnnotationModel.expandAll(e.getMasterOffset(), e.getMasterLength()); | |
1369 } else if (master !is null && (replaceLength > 0 || fDeletedLines > 1)) { | |
1370 try { | |
1371 int numberOfLines= e.getDocument().getNumberOfLines(e.getOffset(), replaceLength); | |
1372 if (numberOfLines > 1 || fDeletedLines > 1) | |
1373 fProjectionAnnotationModel.expandAll(master.getOffset(), master.getLength()); | |
1374 } catch (BadLocationException x) { | |
1375 } | |
1376 } | |
1377 | |
1378 } finally { | |
1379 fReplaceVisibleDocumentExecutionTrigger= null; | |
1380 } | |
1381 | |
1382 } | |
1383 } | |
1384 | |
1385 /* | |
1386 * @see dwtx.jface.text.TextViewer#handleVisibleDocumentAboutToBeChanged(dwtx.jface.text.DocumentEvent) | |
1387 * @since 3.1 | |
1388 */ | |
1389 protected void handleVisibleDocumentAboutToBeChanged(DocumentEvent event) { | |
1390 if (fHandleProjectionChanges && event instanceof ProjectionDocumentEvent && isProjectionMode()) { | |
1391 int deletedLines; | |
1392 try { | |
1393 deletedLines= event.getDocument().getNumberOfLines(event.getOffset(), event.getLength()); | |
1394 } catch (BadLocationException e1) { | |
1395 deletedLines= 0; | |
1396 } | |
1397 fDeletedLines= deletedLines; | |
1398 } | |
1399 } | |
1400 | |
1401 /* | |
1402 * @see dwtx.jface.text.ITextViewerExtension5#getCoveredModelRanges(dwtx.jface.text.IRegion) | |
1403 */ | |
1404 public IRegion[] getCoveredModelRanges(IRegion modelRange) { | |
1405 if (fInformationMapping is null) | |
1406 return new IRegion[] { new Region(modelRange.getOffset(), modelRange.getLength()) }; | |
1407 | |
138 | 1408 if ( cast(IDocumentInformationMappingExtension)fInformationMapping ) { |
134 | 1409 IDocumentInformationMappingExtension extension= cast(IDocumentInformationMappingExtension) fInformationMapping; |
129 | 1410 try { |
1411 return extension.getExactCoverage(modelRange); | |
1412 } catch (BadLocationException x) { | |
1413 } | |
1414 } | |
1415 | |
1416 return null; | |
1417 } | |
1418 | |
1419 /* | |
1420 * @see dwtx.jface.text.ITextOperationTarget#doOperation(int) | |
1421 */ | |
1422 public void doOperation(int operation) { | |
1423 switch (operation) { | |
1424 case TOGGLE: | |
1425 if (canDoOperation(TOGGLE)) { | |
1426 if (!isProjectionMode()) { | |
1427 enableProjection(); | |
1428 } else { | |
1429 expandAll(); | |
1430 disableProjection(); | |
1431 } | |
1432 return; | |
1433 } | |
1434 } | |
1435 | |
1436 if (!isProjectionMode()) { | |
1437 super.doOperation(operation); | |
1438 return; | |
1439 } | |
1440 | |
1441 StyledText textWidget= getTextWidget(); | |
1442 if (textWidget is null) | |
1443 return; | |
1444 | |
1445 Point selection= null; | |
1446 switch (operation) { | |
1447 | |
1448 case CUT: | |
1449 | |
1450 if (redraws()) { | |
1451 selection= getSelectedRange(); | |
1452 if (exposeModelRange(new Region(selection.x, selection.y))) | |
1453 return; | |
1454 | |
1455 if (selection.y is 0) | |
1456 copyMarkedRegion(true); | |
1457 else | |
1458 copyToClipboard(selection.x, selection.y, true, textWidget); | |
1459 | |
1460 selection= textWidget.getSelectionRange(); | |
1461 fireSelectionChanged(selection.x, selection.y); | |
1462 } | |
1463 break; | |
1464 | |
1465 case COPY: | |
1466 | |
1467 if (redraws()) { | |
1468 selection= getSelectedRange(); | |
1469 if (selection.y is 0) | |
1470 copyMarkedRegion(false); | |
1471 else | |
1472 copyToClipboard(selection.x, selection.y, false, textWidget); | |
1473 } | |
1474 break; | |
1475 | |
1476 case DELETE: | |
1477 | |
1478 if (redraws()) { | |
1479 try { | |
1480 selection= getSelectedRange(); | |
1481 Point widgetSelection= textWidget.getSelectionRange(); | |
1482 if (selection.y is 0 || selection.y is widgetSelection.y) | |
1483 getTextWidget().invokeAction(ST.DELETE_NEXT); | |
1484 else | |
1485 deleteTextRange(selection.x, selection.y, textWidget); | |
1486 | |
1487 selection= textWidget.getSelectionRange(); | |
1488 fireSelectionChanged(selection.x, selection.y); | |
1489 | |
1490 } catch (BadLocationException x) { | |
1491 // ignore | |
1492 } | |
1493 } | |
1494 break; | |
1495 | |
1496 | |
1497 case EXPAND_ALL: | |
1498 if (redraws()) | |
1499 expandAll(); | |
1500 break; | |
1501 | |
1502 case EXPAND: | |
1503 if (redraws()) { | |
1504 expand(); | |
1505 } | |
1506 break; | |
1507 | |
1508 case COLLAPSE_ALL: | |
1509 if (redraws()) | |
1510 collapseAll(); | |
1511 break; | |
1512 | |
1513 case COLLAPSE: | |
1514 if (redraws()) { | |
1515 collapse(); | |
1516 } | |
1517 break; | |
1518 | |
1519 default: | |
1520 super.doOperation(operation); | |
1521 } | |
1522 } | |
1523 | |
1524 /* | |
1525 * @see dwtx.jface.text.source.SourceViewer#canDoOperation(int) | |
1526 */ | |
1527 public bool canDoOperation(int operation) { | |
1528 | |
1529 switch (operation) { | |
1530 case COLLAPSE: | |
1531 case COLLAPSE_ALL: | |
1532 case EXPAND: | |
1533 case EXPAND_ALL: | |
1534 return isProjectionMode(); | |
1535 case TOGGLE: | |
1536 return isProjectionMode() || !isSegmented(); | |
1537 } | |
1538 | |
1539 return super.canDoOperation(operation); | |
1540 } | |
1541 | |
1542 private bool isSegmented() { | |
1543 IDocument document= getDocument(); | |
1544 int length= document is null ? 0 : document.getLength(); | |
1545 IRegion visible= getModelCoverage(); | |
1546 bool isSegmented= visible !is null && !visible.equals(new Region(0, length)); | |
1547 return isSegmented; | |
1548 } | |
1549 | |
1550 private IRegion getMarkedRegion() { | |
1551 if (getTextWidget() is null) | |
1552 return null; | |
1553 | |
1554 if (fMarkPosition is null || fMarkPosition.isDeleted()) | |
1555 return null; | |
1556 | |
1557 int start= fMarkPosition.getOffset(); | |
1558 int end= getSelectedRange().x; | |
1559 | |
1560 return start > end ? new Region (end, start - end) : new Region(start, end - start); | |
1561 } | |
1562 | |
1563 /* | |
1564 * @see dwtx.jface.text.TextViewer#copyMarkedRegion(bool) | |
1565 */ | |
1566 protected void copyMarkedRegion(bool delete) { | |
1567 IRegion markedRegion= getMarkedRegion(); | |
1568 if (markedRegion !is null) | |
1569 copyToClipboard(markedRegion.getOffset(), markedRegion.getLength(), delete, getTextWidget()); | |
1570 } | |
1571 | |
1572 private void copyToClipboard(int offset, int length, bool delete, StyledText textWidget) { | |
1573 | |
1574 String copyText= null; | |
1575 | |
1576 try { | |
1577 IDocument document= getDocument(); | |
1578 copyText= document.get(offset, length); | |
1579 } catch (BadLocationException ex) { | |
1580 // XXX: should log here, but JFace Text has no Log | |
1581 // As a fallback solution let the widget handle this | |
1582 textWidget.copy(); | |
1583 } | |
1584 | |
1585 if (copyText !is null && copyText.equals(textWidget.getSelectionText())) { | |
1586 /* | |
1587 * XXX: Reduce pain of https://bugs.eclipse.org/bugs/show_bug.cgi?id=64498 | |
1588 * by letting the widget handle the copy operation in this special case. | |
1589 */ | |
1590 textWidget.copy(); | |
1591 } else if (copyText !is null) { | |
1592 | |
1593 Clipboard clipboard= new Clipboard(textWidget.getDisplay()); | |
1594 | |
1595 try { | |
1596 Transfer[] dataTypes= new Transfer[] { TextTransfer.getInstance() }; | |
1597 Object[] data= new Object[] { copyText }; | |
1598 try { | |
1599 clipboard.setContents(data, dataTypes); | |
1600 } catch (DWTError e) { | |
1601 if (e.code !is DND.ERROR_CANNOT_SET_CLIPBOARD) | |
1602 throw e; | |
1603 /* | |
1604 * TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59459 | |
1605 * we should either log and/or inform the user | |
1606 * silently fail for now. | |
1607 */ | |
1608 return; | |
1609 } | |
1610 | |
1611 } finally { | |
1612 clipboard.dispose(); | |
1613 } | |
1614 } | |
1615 | |
1616 if (delete) { | |
1617 try { | |
1618 deleteTextRange(offset, length, textWidget); | |
1619 } catch (BadLocationException x) { | |
1620 // XXX: should log here, but JFace Text has no Log | |
1621 } | |
1622 } | |
1623 } | |
1624 | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
1625 private void deleteTextRange(int offset, int length, StyledText textWidget) { |
129 | 1626 getDocument().replace(offset, length, ""); //$NON-NLS-1$ |
1627 int widgetCaret= modelOffset2WidgetOffset(offset); | |
1628 if (widgetCaret > -1) | |
1629 textWidget.setSelection(widgetCaret); | |
1630 } | |
1631 | |
1632 /** | |
1633 * Adapts the behavior of the super class to respect line based folding. | |
1634 * | |
1635 * @param widgetSelection the widget selection | |
1636 * @return the model selection while respecting line based folding | |
1637 */ | |
1638 protected Point widgetSelection2ModelSelection(Point widgetSelection) { | |
1639 | |
1640 if (!isProjectionMode()) | |
1641 return super.widgetSelection2ModelSelection(widgetSelection); | |
1642 | |
1643 /* | |
1644 * There is one requirement that governs preservation of logical | |
1645 * positions: | |
1646 * | |
1647 * 1) a selection with widget_length is 0 should never expand to have | |
1648 * model_length > 0. | |
1649 * | |
1650 * There are a number of ambiguities to resolve with projection regions. | |
1651 * A projected region P has a widget-length of zero. Its widget offset | |
1652 * may interact with the selection S in various ways: | |
1653 * | |
1654 * A) P.widget_offset lies at the caret, S.widget_length is zero. | |
1655 * Requirement 1 applies. S is *behind* P (done so by widgetRange2ModelRange). | |
1656 * | |
1657 * B) P.widget_offset lies inside the widget selection. This case is | |
1658 * easy: P is included in S, which is automatically done so by | |
1659 * widgetRange2ModelRange. | |
1660 * | |
1661 * C) P.widget_offset lies at S.widget_end: This is | |
1662 * arguable - our policy is to include P if it belongs to a projection | |
1663 * annotation that overlaps with the widget selection. | |
1664 * | |
1665 * D) P.widget_offset lies at S.widget_offset: Arguable - our policy | |
1666 * is to include P if it belongs to a projection annotation that | |
1667 * overlaps with the widget selection | |
1668 */ | |
1669 IRegion modelSelection= widgetRange2ModelRange(new Region(widgetSelection.x, widgetSelection.y)); | |
1670 if (modelSelection is null) | |
1671 return null; | |
1672 | |
1673 int modelOffset= modelSelection.getOffset(); | |
1674 int modelEndOffset= modelOffset + modelSelection.getLength(); | |
1675 | |
1676 /* Case A: never expand a zero-length selection. S is *behind* P. */ | |
1677 if (widgetSelection.y is 0) | |
1678 return new Point(modelEndOffset, 0); | |
1679 | |
1680 int widgetSelectionExclusiveEnd= widgetSelection.x + widgetSelection.y; | |
1681 Position[] annotationPositions= computeOverlappingAnnotationPositions(modelSelection); | |
1682 for (int i= 0; i < annotationPositions.length; i++) { | |
1683 IRegion[] regions= computeCollapsedRegions(annotationPositions[i]); | |
1684 if (regions is null) | |
1685 continue; | |
1686 for (int j= 0; j < regions.length; j++) { | |
1687 IRegion modelRange= regions[j]; | |
1688 IRegion widgetRange= modelRange2ClosestWidgetRange(modelRange); | |
1689 // only take collapsed ranges, i.e. widget length is 0 | |
1690 if (widgetRange !is null && widgetRange.getLength() is 0) { | |
1691 int widgetOffset= widgetRange.getOffset(); | |
1692 // D) region is collapsed at S.widget_offset | |
1693 if (widgetOffset is widgetSelection.x) | |
1694 modelOffset= Math.min(modelOffset, modelRange.getOffset()); | |
1695 // C) region is collapsed at S.widget_end | |
1696 else if (widgetOffset is widgetSelectionExclusiveEnd) | |
1697 modelEndOffset= Math.max(modelEndOffset, modelRange.getOffset() + modelRange.getLength()); | |
1698 } | |
1699 } | |
1700 } | |
1701 return new Point(modelOffset, modelEndOffset - modelOffset); | |
1702 } | |
1703 | |
1704 /** | |
1705 * Returns the positions of all annotations that intersect with | |
1706 * <code>modelSelection</code> and that are at least partly visible. | |
1707 * @param modelSelection a model range | |
1708 * @return the positions of all annotations that intersect with | |
1709 * <code>modelSelection</code> | |
1710 * @since 3.1 | |
1711 */ | |
1712 private Position[] computeOverlappingAnnotationPositions(IRegion modelSelection) { | |
1713 List positions= new ArrayList(); | |
1714 for (Iterator e= fProjectionAnnotationModel.getAnnotationIterator(); e.hasNext();) { | |
134 | 1715 ProjectionAnnotation annotation= cast(ProjectionAnnotation) e.next(); |
129 | 1716 Position position= fProjectionAnnotationModel.getPosition(annotation); |
1717 if (position !is null && position.overlapsWith(modelSelection.getOffset(), modelSelection.getLength()) && modelRange2WidgetRange(position) !is null) | |
1718 positions.add(position); | |
1719 } | |
1720 return (Position[]) positions.toArray(new Position[positions.size()]); | |
1721 } | |
1722 | |
1723 /* | |
1724 * @see dwtx.jface.text.TextViewer#getFindReplaceDocumentAdapter() | |
1725 */ | |
1726 protected FindReplaceDocumentAdapter getFindReplaceDocumentAdapter() { | |
1727 if (fFindReplaceDocumentAdapter is null) { | |
1728 IDocument document= isProjectionMode() ? getDocument() : getVisibleDocument(); | |
1729 fFindReplaceDocumentAdapter= new FindReplaceDocumentAdapter(document); | |
1730 } | |
1731 return fFindReplaceDocumentAdapter; | |
1732 } | |
1733 | |
1734 /* | |
1735 * @see dwtx.jface.text.TextViewer#findAndSelect(int, java.lang.String, bool, bool, bool, bool) | |
1736 */ | |
1737 protected int findAndSelect(int startPosition, String findString, bool forwardSearch, bool caseSensitive, bool wholeWord, bool regExSearch) { | |
1738 | |
1739 if (!isProjectionMode()) | |
1740 return super.findAndSelect(startPosition, findString, forwardSearch, caseSensitive, wholeWord, regExSearch); | |
1741 | |
1742 StyledText textWidget= getTextWidget(); | |
1743 if (textWidget is null) | |
1744 return -1; | |
1745 | |
1746 try { | |
1747 | |
1748 IRegion matchRegion= getFindReplaceDocumentAdapter().find(startPosition, findString, forwardSearch, caseSensitive, wholeWord, regExSearch); | |
1749 if (matchRegion !is null) { | |
1750 exposeModelRange(matchRegion); | |
1751 revealRange(matchRegion.getOffset(), matchRegion.getLength()); | |
1752 setSelectedRange(matchRegion.getOffset(), matchRegion.getLength()); | |
1753 return matchRegion.getOffset(); | |
1754 } | |
1755 | |
1756 } catch (BadLocationException x) { | |
1757 } | |
1758 | |
1759 return -1; | |
1760 } | |
1761 | |
1762 /* | |
1763 * @see dwtx.jface.text.TextViewer#findAndSelectInRange(int, java.lang.String, bool, bool, bool, int, int, bool) | |
1764 */ | |
1765 protected int findAndSelectInRange(int startPosition, String findString, bool forwardSearch, bool caseSensitive, bool wholeWord, int rangeOffset, int rangeLength, bool regExSearch) { | |
1766 | |
1767 if (!isProjectionMode()) | |
1768 return super.findAndSelectInRange(startPosition, findString, forwardSearch, caseSensitive, wholeWord, rangeOffset, rangeLength, regExSearch); | |
1769 | |
1770 StyledText textWidget= getTextWidget(); | |
1771 if (textWidget is null) | |
1772 return -1; | |
1773 | |
1774 try { | |
1775 | |
1776 int modelOffset= startPosition; | |
1777 if (forwardSearch && (startPosition is -1 || startPosition < rangeOffset)) { | |
1778 modelOffset= rangeOffset; | |
1779 } else if (!forwardSearch && (startPosition is -1 || startPosition > rangeOffset + rangeLength)) { | |
1780 modelOffset= rangeOffset + rangeLength; | |
1781 } | |
1782 | |
1783 IRegion matchRegion= getFindReplaceDocumentAdapter().find(modelOffset, findString, forwardSearch, caseSensitive, wholeWord, regExSearch); | |
1784 if (matchRegion !is null) { | |
1785 int offset= matchRegion.getOffset(); | |
1786 int length= matchRegion.getLength(); | |
1787 if (rangeOffset <= offset && offset + length <= rangeOffset + rangeLength) { | |
1788 exposeModelRange(matchRegion); | |
1789 revealRange(offset, length); | |
1790 setSelectedRange(offset, length); | |
1791 return offset; | |
1792 } | |
1793 } | |
1794 | |
1795 } catch (BadLocationException x) { | |
1796 } | |
1797 | |
1798 return -1; | |
1799 } | |
1800 } |