Mercurial > projects > dwt-addons
annotate dwtx/jface/text/projection/ProjectionDocument.d @ 200:eb3414669eb0 default tip
fix for dmd 1.041 and tango 0.99.8
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 28 Mar 2009 03:09:57 +0100 |
parents | 1a5b8f8129df |
children |
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.projection.ProjectionDocument; | |
14 | |
131 | 15 import dwtx.jface.text.projection.ProjectionMapping; // packageimport |
16 import dwtx.jface.text.projection.ChildDocumentManager; // packageimport | |
17 import dwtx.jface.text.projection.SegmentUpdater; // packageimport | |
18 import dwtx.jface.text.projection.Segment; // packageimport | |
19 import dwtx.jface.text.projection.FragmentUpdater; // packageimport | |
20 import dwtx.jface.text.projection.ProjectionDocumentEvent; // packageimport | |
21 import dwtx.jface.text.projection.ChildDocument; // packageimport | |
22 import dwtx.jface.text.projection.IMinimalMapping; // packageimport | |
23 import dwtx.jface.text.projection.Fragment; // packageimport | |
24 import dwtx.jface.text.projection.ProjectionTextStore; // packageimport | |
25 import dwtx.jface.text.projection.ProjectionDocumentManager; // packageimport | |
26 | |
27 | |
129 | 28 import dwt.dwthelper.utils; |
29 | |
153
f70d9508c95c
Fix java Collection imports
Frank Benoit <benoit@tionex.de>
parents:
146
diff
changeset
|
30 import dwtx.dwtxhelper.Collection; |
f70d9508c95c
Fix java Collection imports
Frank Benoit <benoit@tionex.de>
parents:
146
diff
changeset
|
31 |
129 | 32 |
33 import dwtx.jface.text.AbstractDocument; | |
34 import dwtx.jface.text.BadLocationException; | |
35 import dwtx.jface.text.BadPositionCategoryException; | |
36 import dwtx.jface.text.DefaultLineTracker; | |
37 import dwtx.jface.text.DocumentEvent; | |
38 import dwtx.jface.text.IDocument; | |
39 import dwtx.jface.text.IDocumentExtension; | |
40 import dwtx.jface.text.IDocumentInformationMapping; | |
41 import dwtx.jface.text.IDocumentListener; | |
42 import dwtx.jface.text.ILineTracker; | |
43 import dwtx.jface.text.IRegion; | |
44 import dwtx.jface.text.ITextStore; | |
45 import dwtx.jface.text.Position; | |
46 import dwtx.jface.text.Region; | |
47 import dwtx.jface.text.TextUtilities; | |
48 | |
49 | |
50 /** | |
51 * A <code>ProjectionDocument</code> represents a projection of its master | |
52 * document. The contents of a projection document is a sequence of fragments of | |
53 * the master document, i.e. the projection document can be thought as being | |
54 * constructed from the master document by not copying the whole master document | |
55 * but omitting several ranges of the master document. | |
56 * <p> | |
57 * The projection document indirectly utilizes its master document as | |
58 * <code>ITextStore</code> by means of a <code>ProjectionTextStore</code>. | |
59 * <p> | |
60 * The content of a projection document can be changed in two ways. Either by a | |
61 * text replace applied to the master document or the projection document. Or by | |
62 * changing the projection between the master document and the projection | |
63 * document. For the latter the two methods <code>addMasterDocumentRange</code> | |
64 * and <code>removeMasterDocumentRange</code> are provided. For any | |
65 * manipulation, the projection document sends out a | |
66 * {@link dwtx.jface.text.projection.ProjectionDocumentEvent} describing | |
67 * the change. | |
68 * <p> | |
69 * Clients are not supposed to directly instantiate this class. In order to | |
70 * obtain a projection document, a | |
71 * {@link dwtx.jface.text.projection.ProjectionDocumentManager}should be | |
72 * used. This class is not intended to be subclassed outside of its origin | |
73 * package.</p> | |
74 * | |
75 * @since 3.0 | |
76 * @noinstantiate This class is not intended to be instantiated by clients. | |
77 * @noextend This class is not intended to be subclassed by clients. | |
78 */ | |
79 public class ProjectionDocument : AbstractDocument { | |
80 | |
81 | |
82 /** | |
83 * Prefix of the name of the position category used to keep track of the master | |
84 * document's fragments that correspond to the segments of the projection | |
85 * document. | |
86 */ | |
146 | 87 private const static String FRAGMENTS_CATEGORY_PREFIX= "__fragmentsCategory"; //$NON-NLS-1$ |
129 | 88 |
89 /** | |
90 * Name of the position category used to keep track of the project | |
91 * document's segments that correspond to the fragments of the master | |
92 * document. | |
93 */ | |
146 | 94 private const static String SEGMENTS_CATEGORY= "__segmentsCategory"; //$NON-NLS-1$ |
129 | 95 |
96 | |
97 /** The master document */ | |
98 private IDocument fMasterDocument; | |
99 /** The master document as document extension */ | |
100 private IDocumentExtension fMasterDocumentExtension; | |
101 /** The fragments' position category */ | |
102 private String fFragmentsCategory; | |
103 /** The segment's position category */ | |
104 private String fSegmentsCategory; | |
105 /** The document event issued by the master document */ | |
106 private DocumentEvent fMasterEvent; | |
107 /** The document event to be issued by the projection document */ | |
108 private ProjectionDocumentEvent fSlaveEvent; | |
109 /** The original document event generated by a direct manipulation of this projection document */ | |
110 private DocumentEvent fOriginalEvent; | |
111 /** Indicates whether the projection document initiated a master document update or not */ | |
112 private bool fIsUpdating= false; | |
113 /** Indicated whether the projection document is in auto expand mode nor not */ | |
114 private bool fIsAutoExpanding= false; | |
115 /** The position updater for the segments */ | |
116 private SegmentUpdater fSegmentUpdater; | |
117 /** The position updater for the fragments */ | |
118 private FragmentUpdater fFragmentsUpdater; | |
119 /** The projection mapping */ | |
120 private ProjectionMapping fMapping; | |
121 | |
122 /** | |
123 * Creates a projection document for the given master document. | |
124 * | |
125 * @param masterDocument the master document | |
126 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
127 public this(IDocument masterDocument) { |
129 | 128 super(); |
129 | |
130 fMasterDocument= masterDocument; | |
138 | 131 if ( cast(IDocumentExtension)fMasterDocument ) |
134 | 132 fMasterDocumentExtension= cast(IDocumentExtension) fMasterDocument; |
129 | 133 |
134 fSegmentsCategory= SEGMENTS_CATEGORY; | |
162 | 135 fFragmentsCategory= FRAGMENTS_CATEGORY_PREFIX ~ Integer.toString(toHash()); |
129 | 136 fMasterDocument.addPositionCategory(fFragmentsCategory); |
137 fFragmentsUpdater= new FragmentUpdater(fFragmentsCategory); | |
138 fMasterDocument.addPositionUpdater(fFragmentsUpdater); | |
139 | |
140 fMapping= new ProjectionMapping(masterDocument, fFragmentsCategory, this, fSegmentsCategory); | |
141 | |
142 ITextStore s= new ProjectionTextStore(masterDocument, fMapping); | |
143 ILineTracker tracker= new DefaultLineTracker(); | |
144 | |
145 setTextStore(s); | |
146 setLineTracker(tracker); | |
147 | |
148 completeInitialization(); | |
149 | |
150 initializeProjection(); | |
151 tracker.set(s.get(0, s.getLength())); | |
152 } | |
153 | |
154 /** | |
155 * Disposes this projection document. | |
156 */ | |
157 public void dispose() { | |
158 fMasterDocument.removePositionUpdater(fFragmentsUpdater); | |
159 try { | |
160 fMasterDocument.removePositionCategory(fFragmentsCategory); | |
161 } catch (BadPositionCategoryException x) { | |
162 // allow multiple dispose calls | |
163 } | |
164 } | |
165 | |
166 private void internalError() { | |
167 throw new IllegalStateException(); | |
168 } | |
169 | |
170 /** | |
171 * Returns the fragments of the master documents. | |
172 * | |
173 * @return the fragment of the master document | |
174 */ | |
175 protected final Position[] getFragments() { | |
176 try { | |
177 return fMasterDocument.getPositions(fFragmentsCategory); | |
178 } catch (BadPositionCategoryException e) { | |
179 internalError(); | |
180 } | |
181 // unreachable | |
182 return null; | |
183 } | |
184 | |
185 /** | |
186 * Returns the segments of this projection document. | |
187 * | |
188 * @return the segments of this projection document | |
189 */ | |
190 protected final Position[] getSegments() { | |
191 try { | |
192 return getPositions(fSegmentsCategory); | |
193 } catch (BadPositionCategoryException e) { | |
194 internalError(); | |
195 } | |
196 // unreachable | |
197 return null; | |
198 } | |
199 | |
200 /** | |
201 * Returns the projection mapping used by this document. | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
202 * |
129 | 203 * @return the projection mapping used by this document |
204 * @deprecated As of 3.4, replaced by {@link #getDocumentInformationMapping()} | |
205 */ | |
206 public ProjectionMapping getProjectionMapping(){ | |
207 return fMapping; | |
208 } | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
209 |
129 | 210 /** |
211 * Returns the projection mapping used by this document. | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
212 * |
129 | 213 * @return the projection mapping used by this document |
214 * @since 3.4 | |
215 */ | |
216 public IDocumentInformationMapping getDocumentInformationMapping() { | |
217 return fMapping; | |
218 } | |
219 | |
220 /** | |
221 * Returns the master document of this projection document. | |
222 * | |
223 * @return the master document of this projection document | |
224 */ | |
225 public IDocument getMasterDocument() { | |
226 return fMasterDocument; | |
227 } | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
228 |
129 | 229 /* |
230 * @see dwtx.jface.text.IDocumentExtension4#getDefaultLineDelimiter() | |
231 * @since 3.1 | |
232 */ | |
233 public String getDefaultLineDelimiter() { | |
234 return TextUtilities.getDefaultLineDelimiter(fMasterDocument); | |
235 } | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
236 |
129 | 237 /** |
238 * Initializes the projection document from the master document based on | |
239 * the master's fragments. | |
240 */ | |
241 private void initializeProjection() { | |
242 | |
243 try { | |
244 | |
245 addPositionCategory(fSegmentsCategory); | |
246 fSegmentUpdater= new SegmentUpdater(fSegmentsCategory); | |
247 addPositionUpdater(fSegmentUpdater); | |
248 | |
249 int offset= 0; | |
250 Position[] fragments= getFragments(); | |
251 for (int i= 0; i < fragments.length; i++) { | |
134 | 252 Fragment fragment= cast(Fragment) fragments[i]; |
129 | 253 Segment segment= new Segment(offset, fragment.getLength()); |
254 segment.fragment= fragment; | |
255 addPosition(fSegmentsCategory, segment); | |
256 offset += fragment.length; | |
257 } | |
258 | |
259 } catch (BadPositionCategoryException x) { | |
260 internalError(); | |
261 } catch (BadLocationException x) { | |
262 internalError(); | |
263 } | |
264 } | |
265 | |
266 /** | |
267 * Creates a segment for the given fragment at the given position inside the list of segments. | |
268 * | |
269 * @param fragment the corresponding fragment | |
270 * @param index the index in the list of segments | |
271 * @return the created segment | |
272 * @throws BadLocationException in case the fragment is invalid | |
273 * @throws BadPositionCategoryException in case the segment category is invalid | |
274 */ | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
275 private Segment createSegmentFor(Fragment fragment, int index) { |
129 | 276 |
277 int offset= 0; | |
278 if (index > 0) { | |
279 Position[] segments= getSegments(); | |
134 | 280 Segment segment= cast(Segment) segments[index - 1]; |
129 | 281 offset= segment.getOffset() + segment.getLength(); |
282 } | |
283 | |
284 Segment segment= new Segment(offset, 0); | |
285 segment.fragment= fragment; | |
286 fragment.segment= segment; | |
287 addPosition(fSegmentsCategory, segment); | |
288 return segment; | |
289 } | |
290 | |
291 /** | |
292 * Adds the given range of the master document to this projection document. | |
293 * | |
294 * @param offsetInMaster offset of the master document range | |
295 * @param lengthInMaster length of the master document range | |
296 * @param masterDocumentEvent the master document event that causes this | |
297 * projection change or <code>null</code> if none | |
298 * @throws BadLocationException if the given range is invalid in the master | |
299 * document | |
300 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
301 private void internalAddMasterDocumentRange(int offsetInMaster, int lengthInMaster, DocumentEvent masterDocumentEvent) { |
129 | 302 if (lengthInMaster is 0) |
303 return; | |
304 | |
305 try { | |
306 | |
307 Position[] fragments= getFragments(); | |
308 int index= fMasterDocument.computeIndexInCategory(fFragmentsCategory, offsetInMaster); | |
309 | |
310 Fragment left= null; | |
311 Fragment right= null; | |
312 | |
313 if (index < fragments.length) { | |
134 | 314 Fragment fragment= cast(Fragment) fragments[index]; |
129 | 315 if (offsetInMaster is fragment.offset) |
316 if (fragment.length is 0) // the fragment does not overlap - it is a zero-length fragment at the same offset | |
317 left= fragment; | |
318 else | |
319 throw new IllegalArgumentException("overlaps with existing fragment"); //$NON-NLS-1$ | |
320 if (offsetInMaster + lengthInMaster is fragment.offset) | |
321 right= fragment; | |
322 } | |
323 | |
324 if (0 < index && index <= fragments.length) { | |
134 | 325 Fragment fragment= cast(Fragment) fragments[index - 1]; |
129 | 326 if (fragment.includes(offsetInMaster)) |
327 throw new IllegalArgumentException("overlaps with existing fragment"); //$NON-NLS-1$ | |
328 if (fragment.getOffset() + fragment.getLength() is offsetInMaster) | |
329 left= fragment; | |
330 } | |
331 | |
332 int offsetInSlave= 0; | |
333 if (index > 0) { | |
134 | 334 Fragment fragment= cast(Fragment) fragments[index - 1]; |
129 | 335 Segment segment= fragment.segment; |
336 offsetInSlave= segment.getOffset() + segment.getLength(); | |
337 } | |
338 | |
339 ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, offsetInSlave, 0, fMasterDocument.get(offsetInMaster, lengthInMaster), offsetInMaster, lengthInMaster, masterDocumentEvent); | |
340 super.fireDocumentAboutToBeChanged(event); | |
341 | |
342 // check for neighboring fragment | |
343 if (left !is null && right !is null) { | |
344 | |
345 int endOffset= right.getOffset() + right.getLength(); | |
346 left.setLength(endOffset - left.getOffset()); | |
347 left.segment.setLength(left.segment.getLength() + right.segment.getLength()); | |
348 | |
349 removePosition(fSegmentsCategory, right.segment); | |
350 fMasterDocument.removePosition(fFragmentsCategory, right); | |
351 | |
352 } else if (left !is null) { | |
353 int endOffset= offsetInMaster +lengthInMaster; | |
354 left.setLength(endOffset - left.getOffset()); | |
355 left.segment.markForStretch(); | |
356 | |
357 } else if (right !is null) { | |
358 right.setOffset(right.getOffset() - lengthInMaster); | |
359 right.setLength(right.getLength() + lengthInMaster); | |
360 right.segment.markForStretch(); | |
361 | |
362 } else { | |
363 // create a new segment | |
364 Fragment fragment= new Fragment(offsetInMaster, lengthInMaster); | |
365 fMasterDocument.addPosition(fFragmentsCategory, fragment); | |
366 Segment segment= createSegmentFor(fragment, index); | |
367 segment.markForStretch(); | |
368 } | |
369 | |
370 getTracker().replace(event.getOffset(), event.getLength(), event.getText()); | |
371 super.fireDocumentChanged(event); | |
372 | |
373 } catch (BadPositionCategoryException x) { | |
374 internalError(); | |
375 } | |
376 } | |
377 | |
378 /** | |
379 * Finds the fragment of the master document that represents the given range. | |
380 * | |
381 * @param offsetInMaster the offset of the range in the master document | |
382 * @param lengthInMaster the length of the range in the master document | |
383 * @return the fragment representing the given master document range | |
384 */ | |
385 private Fragment findFragment(int offsetInMaster, int lengthInMaster) { | |
386 Position[] fragments= getFragments(); | |
387 for (int i= 0; i < fragments.length; i++) { | |
134 | 388 Fragment f= cast(Fragment) fragments[i]; |
129 | 389 if (f.getOffset() <= offsetInMaster && offsetInMaster + lengthInMaster <= f.getOffset() + f.getLength()) |
390 return f; | |
391 } | |
392 return null; | |
393 } | |
394 | |
395 /** | |
396 * Removes the given range of the master document from this projection | |
397 * document. | |
398 * | |
399 * @param offsetInMaster the offset of the range in the master document | |
400 * @param lengthInMaster the length of the range in the master document | |
401 * | |
402 * @throws BadLocationException if the given range is not valid in the | |
403 * master document | |
404 * @throws IllegalArgumentException if the given range is not projected in | |
405 * this projection document or is not completely comprised by | |
406 * an existing fragment | |
407 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
408 private void internalRemoveMasterDocumentRange(int offsetInMaster, int lengthInMaster) { |
129 | 409 try { |
410 | |
411 IRegion imageRegion= fMapping.toExactImageRegion(new Region(offsetInMaster, lengthInMaster)); | |
412 if (imageRegion is null) | |
162 | 413 throw new IllegalArgumentException(null); |
129 | 414 |
415 Fragment fragment= findFragment(offsetInMaster, lengthInMaster); | |
416 if (fragment is null) | |
162 | 417 throw new IllegalArgumentException(null); |
129 | 418 |
419 ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, imageRegion.getOffset(), imageRegion.getLength(), "", offsetInMaster, lengthInMaster); //$NON-NLS-1$ | |
420 super.fireDocumentAboutToBeChanged(event); | |
421 | |
422 if (fragment.getOffset() is offsetInMaster) { | |
423 fragment.setOffset(offsetInMaster + lengthInMaster); | |
424 fragment.setLength(fragment.getLength() - lengthInMaster); | |
425 } else if (fragment.getOffset() + fragment.getLength() is offsetInMaster + lengthInMaster) { | |
426 fragment.setLength(fragment.getLength() - lengthInMaster); | |
427 } else { | |
428 // split fragment into three fragments, let position updater remove it | |
429 | |
430 // add fragment for the region to be removed | |
431 Fragment newFragment= new Fragment(offsetInMaster, lengthInMaster); | |
432 Segment segment= new Segment(imageRegion.getOffset(), imageRegion.getLength()); | |
433 newFragment.segment= segment; | |
434 segment.fragment= newFragment; | |
435 fMasterDocument.addPosition(fFragmentsCategory, newFragment); | |
436 addPosition(fSegmentsCategory, segment); | |
437 | |
438 // add fragment for the remainder right of the deleted range in the original fragment | |
439 int offset= offsetInMaster + lengthInMaster; | |
440 newFragment= new Fragment(offset, fragment.getOffset() + fragment.getLength() - offset); | |
441 offset= imageRegion.getOffset() + imageRegion.getLength(); | |
442 segment= new Segment(offset, fragment.segment.getOffset() + fragment.segment.getLength() - offset); | |
443 newFragment.segment= segment; | |
444 segment.fragment= newFragment; | |
445 fMasterDocument.addPosition(fFragmentsCategory, newFragment); | |
446 addPosition(fSegmentsCategory, segment); | |
447 | |
448 // adjust length of initial fragment (the left one) | |
449 fragment.setLength(offsetInMaster - fragment.getOffset()); | |
450 fragment.segment.setLength(imageRegion.getOffset() - fragment.segment.getOffset()); | |
451 } | |
452 | |
453 getTracker().replace(event.getOffset(), event.getLength(), event.getText()); | |
454 super.fireDocumentChanged(event); | |
455 | |
456 } catch (BadPositionCategoryException x) { | |
457 internalError(); | |
458 } | |
459 } | |
460 | |
461 /** | |
462 * Returns the sequence of all master document regions which are contained | |
463 * in the given master document range and which are not yet part of this | |
464 * projection document. | |
465 * | |
466 * @param offsetInMaster the range offset in the master document | |
467 * @param lengthInMaster the range length in the master document | |
468 * @return the sequence of regions which are not yet part of the projection | |
469 * document | |
470 * @throws BadLocationException in case the given range is invalid in the | |
471 * master document | |
472 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
473 public final IRegion[] computeUnprojectedMasterRegions(int offsetInMaster, int lengthInMaster) { |
129 | 474 |
475 IRegion[] fragments= null; | |
476 IRegion imageRegion= fMapping.toImageRegion(new Region(offsetInMaster, lengthInMaster)); | |
477 if (imageRegion !is null) | |
478 fragments= fMapping.toExactOriginRegions(imageRegion); | |
479 | |
480 if (fragments is null || fragments.length is 0) | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
481 return [ new Region(offsetInMaster, lengthInMaster) ]; |
129 | 482 |
483 List gaps= new ArrayList(); | |
484 | |
485 IRegion region= fragments[0]; | |
486 if (offsetInMaster < region.getOffset()) | |
487 gaps.add(new Region(offsetInMaster, region.getOffset() - offsetInMaster)); | |
488 | |
489 for (int i= 0; i < fragments.length - 1; i++) { | |
490 IRegion left= fragments[i]; | |
491 IRegion right= fragments[i + 1]; | |
492 int leftEnd= left.getOffset() + left.getLength(); | |
493 if (leftEnd < right.getOffset()) | |
494 gaps.add(new Region(leftEnd, right.getOffset() - leftEnd)); | |
495 } | |
496 | |
497 region= fragments[fragments.length - 1]; | |
498 int leftEnd= region.getOffset() + region.getLength(); | |
499 int rightEnd= offsetInMaster + lengthInMaster; | |
500 if (leftEnd < rightEnd) | |
501 gaps.add(new Region(leftEnd, rightEnd - leftEnd)); | |
502 | |
162 | 503 return arraycast!(IRegion)(gaps.toArray()); |
129 | 504 } |
505 | |
506 /** | |
507 * Returns the first master document region which is contained in the given | |
508 * master document range and which is not yet part of this projection | |
509 * document. | |
510 * | |
511 * @param offsetInMaster the range offset in the master document | |
512 * @param lengthInMaster the range length in the master document | |
513 * @return the first region that is not yet part of the projection document | |
514 * @throws BadLocationException in case the given range is invalid in the | |
515 * master document | |
516 * @since 3.1 | |
517 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
518 private IRegion computeFirstUnprojectedMasterRegion(int offsetInMaster, int lengthInMaster) { |
129 | 519 |
520 IRegion[] fragments= null; | |
521 IRegion imageRegion= fMapping.toImageRegion(new Region(offsetInMaster, lengthInMaster)); | |
522 if (imageRegion !is null) | |
523 fragments= fMapping.toExactOriginRegions(imageRegion); | |
524 | |
525 if (fragments is null || fragments.length is 0) | |
526 return new Region(offsetInMaster, lengthInMaster); | |
527 | |
528 IRegion region= fragments[0]; | |
529 if (offsetInMaster < region.getOffset()) | |
530 return new Region(offsetInMaster, region.getOffset() - offsetInMaster); | |
531 | |
532 for (int i= 0; i < fragments.length - 1; i++) { | |
533 IRegion left= fragments[i]; | |
534 IRegion right= fragments[i + 1]; | |
535 int leftEnd= left.getOffset() + left.getLength(); | |
536 if (leftEnd < right.getOffset()) | |
537 return new Region(leftEnd, right.getOffset() - leftEnd); | |
538 } | |
539 | |
540 region= fragments[fragments.length - 1]; | |
541 int leftEnd= region.getOffset() + region.getLength(); | |
542 int rightEnd= offsetInMaster + lengthInMaster; | |
543 if (leftEnd < rightEnd) | |
544 return new Region(leftEnd, rightEnd - leftEnd); | |
545 | |
546 return null; | |
547 } | |
548 | |
549 /** | |
550 * Ensures that the given range of the master document is part of this | |
551 * projection document. | |
552 * | |
553 * @param offsetInMaster the offset of the master document range | |
554 * @param lengthInMaster the length of the master document range | |
555 * @throws BadLocationException in case the master event is not valid | |
556 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
557 public void addMasterDocumentRange(int offsetInMaster, int lengthInMaster) { |
129 | 558 addMasterDocumentRange(offsetInMaster, lengthInMaster, null); |
559 } | |
560 | |
561 /** | |
562 * Ensures that the given range of the master document is part of this | |
563 * projection document. | |
564 * | |
565 * @param offsetInMaster the offset of the master document range | |
566 * @param lengthInMaster the length of the master document range | |
567 * @param masterDocumentEvent the master document event which causes this | |
568 * projection change, or <code>null</code> if none | |
569 * @throws BadLocationException in case the master event is not valid | |
570 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
571 private void addMasterDocumentRange(int offsetInMaster, int lengthInMaster, DocumentEvent masterDocumentEvent) { |
129 | 572 /* |
573 * Calling internalAddMasterDocumentRange may cause other master ranges | |
574 * to become unfolded, resulting in re-entrant calls to this method. In | |
575 * order to not add a region twice, we have to compute the next region | |
576 * to add in every iteration. | |
577 * | |
578 * To place an upper bound on the number of iterations, we use the number | |
579 * of fragments * 2 as the limit. | |
580 */ | |
581 int limit= Math.max(getFragments().length * 2, 20); | |
582 while (true) { | |
583 if (limit-- < 0) | |
584 throw new IllegalArgumentException("safety loop termination"); //$NON-NLS-1$ | |
585 | |
586 IRegion gap= computeFirstUnprojectedMasterRegion(offsetInMaster, lengthInMaster); | |
587 if (gap is null) | |
588 return; | |
589 | |
590 internalAddMasterDocumentRange(gap.getOffset(), gap.getLength(), masterDocumentEvent); | |
591 } | |
592 } | |
593 | |
594 /** | |
595 * Ensures that the given range of the master document is not part of this | |
596 * projection document. | |
597 * | |
598 * @param offsetInMaster the offset of the master document range | |
599 * @param lengthInMaster the length of the master document range | |
600 * @throws BadLocationException in case the master event is not valid | |
601 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
602 public void removeMasterDocumentRange(int offsetInMaster, int lengthInMaster) { |
129 | 603 IRegion[] fragments= computeProjectedMasterRegions(offsetInMaster, lengthInMaster); |
604 if (fragments is null || fragments.length is 0) | |
605 return; | |
606 | |
607 for (int i= 0; i < fragments.length; i++) { | |
608 IRegion fragment= fragments[i]; | |
609 internalRemoveMasterDocumentRange(fragment.getOffset(), fragment.getLength()); | |
610 } | |
611 } | |
612 | |
613 /** | |
614 * Returns the sequence of all master document regions with are contained in the given master document | |
615 * range and which are part of this projection document. May return <code>null</code> if no such | |
616 * regions exist. | |
617 * | |
618 * @param offsetInMaster the range offset in the master document | |
619 * @param lengthInMaster the range length in the master document | |
620 * @return the sequence of regions which are part of the projection document or <code>null</code> | |
621 * @throws BadLocationException in case the given range is invalid in the master document | |
622 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
623 public final IRegion[] computeProjectedMasterRegions(int offsetInMaster, int lengthInMaster) { |
129 | 624 IRegion imageRegion= fMapping.toImageRegion(new Region(offsetInMaster, lengthInMaster)); |
625 return imageRegion !is null ? fMapping.toExactOriginRegions(imageRegion) : null; | |
626 } | |
627 | |
628 /** | |
629 * Returns whether this projection is being updated. | |
630 * | |
631 * @return <code>true</code> if the document is updating | |
632 */ | |
633 protected bool isUpdating() { | |
634 return fIsUpdating; | |
635 } | |
636 | |
637 /* | |
638 * @see dwtx.jface.text.IDocument#replace(int, int, java.lang.String) | |
639 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
640 public void replace(int offset, int length, String text) { |
129 | 641 try { |
642 fIsUpdating= true; | |
643 if (fMasterDocumentExtension !is null) | |
644 fMasterDocumentExtension.stopPostNotificationProcessing(); | |
645 | |
646 super.replace(offset, length, text); | |
647 | |
648 } finally { | |
649 fIsUpdating= false; | |
650 if (fMasterDocumentExtension !is null) | |
651 fMasterDocumentExtension.resumePostNotificationProcessing(); | |
652 } | |
653 } | |
654 | |
655 /* | |
656 * @see dwtx.jface.text.IDocument#set(java.lang.String) | |
657 */ | |
658 public void set(String text) { | |
659 try { | |
660 fIsUpdating= true; | |
661 if (fMasterDocumentExtension !is null) | |
662 fMasterDocumentExtension.stopPostNotificationProcessing(); | |
663 | |
664 super.set(text); | |
665 | |
666 } finally { | |
667 fIsUpdating= false; | |
668 if (fMasterDocumentExtension !is null) | |
669 fMasterDocumentExtension.resumePostNotificationProcessing(); | |
670 } | |
671 } | |
672 | |
673 /** | |
674 * Transforms a document event of the master document into a projection | |
675 * document based document event. | |
676 * | |
677 * @param masterEvent the master document event | |
678 * @return the slave document event | |
679 * @throws BadLocationException in case the master event is not valid | |
680 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
681 private ProjectionDocumentEvent normalize(DocumentEvent masterEvent) { |
129 | 682 if (!isUpdating()) { |
683 IRegion imageRegion= fMapping.toExactImageRegion(new Region(masterEvent.getOffset(), masterEvent.getLength())); | |
684 if (imageRegion !is null) | |
685 return new ProjectionDocumentEvent(this, imageRegion.getOffset(), imageRegion.getLength(), masterEvent.getText(), masterEvent); | |
686 return null; | |
687 } | |
688 | |
689 ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, fOriginalEvent.getOffset(), fOriginalEvent.getLength(), fOriginalEvent.getText(), masterEvent); | |
690 fOriginalEvent= null; | |
691 return event; | |
692 } | |
693 | |
694 /** | |
695 * Ensures that when the master event affects this projection document, that the whole region described by the | |
696 * event is part of this projection document. | |
697 * | |
698 * @param masterEvent the master document event | |
699 * @return <code>true</code> if masterEvent affects this projection document | |
700 * @throws BadLocationException in case the master event is not valid | |
701 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
702 protected final bool adaptProjectionToMasterChange(DocumentEvent masterEvent) { |
129 | 703 if (!isUpdating() && fFragmentsUpdater.affectsPositions(masterEvent) || fIsAutoExpanding && masterEvent.getLength() > 0) { |
704 | |
705 addMasterDocumentRange(masterEvent.getOffset(), masterEvent.getLength(), masterEvent); | |
706 return true; | |
707 | |
708 } else if (fMapping.getImageLength() is 0 && masterEvent.getLength() is 0) { | |
709 | |
710 Position[] fragments= getFragments(); | |
711 if (fragments.length is 0) { | |
712 // there is no segment in this projection document, thus one must be created | |
713 // need to bypass the usual infrastructure as the new segment/fragment would be of length 0 and thus the segmentation be not well formed | |
714 try { | |
715 Fragment fragment= new Fragment(0, 0); | |
716 fMasterDocument.addPosition(fFragmentsCategory, fragment); | |
717 createSegmentFor(fragment, 0); | |
718 } catch (BadPositionCategoryException x) { | |
719 internalError(); | |
720 } | |
721 } | |
722 } | |
723 | |
724 return isUpdating(); | |
725 } | |
726 | |
727 /** | |
728 * When called, this projection document is informed about a forthcoming | |
729 * change of its master document. This projection document checks whether | |
730 * the master document change affects it and if so informs all document | |
731 * listeners. | |
732 * | |
733 * @param masterEvent the master document event | |
734 */ | |
735 public void masterDocumentAboutToBeChanged(DocumentEvent masterEvent) { | |
736 try { | |
737 | |
738 bool assertNotNull= adaptProjectionToMasterChange(masterEvent); | |
739 fSlaveEvent= normalize(masterEvent); | |
740 if (assertNotNull && fSlaveEvent is null) | |
741 internalError(); | |
742 | |
743 fMasterEvent= masterEvent; | |
744 if (fSlaveEvent !is null) | |
745 delayedFireDocumentAboutToBeChanged(); | |
746 | |
747 } catch (BadLocationException e) { | |
748 internalError(); | |
749 } | |
750 } | |
751 | |
752 /** | |
753 * When called, this projection document is informed about a change of its | |
754 * master document. If this projection document is affected it informs all | |
755 * of its document listeners. | |
756 * | |
757 * @param masterEvent the master document event | |
758 */ | |
759 public void masterDocumentChanged(DocumentEvent masterEvent) { | |
760 if ( !isUpdating() && masterEvent is fMasterEvent) { | |
761 if (fSlaveEvent !is null) { | |
762 try { | |
763 getTracker().replace(fSlaveEvent.getOffset(), fSlaveEvent.getLength(), fSlaveEvent.getText()); | |
764 fireDocumentChanged(fSlaveEvent); | |
765 } catch (BadLocationException e) { | |
766 internalError(); | |
767 } | |
768 } else if (ensureWellFormedSegmentation(masterEvent.getOffset())) | |
769 fMapping.projectionChanged(); | |
770 } | |
771 } | |
772 | |
773 /* | |
774 * @see dwtx.jface.text.AbstractDocument#fireDocumentAboutToBeChanged(dwtx.jface.text.DocumentEvent) | |
775 */ | |
776 protected void fireDocumentAboutToBeChanged(DocumentEvent event) { | |
777 fOriginalEvent= event; | |
778 // delay it until there is a notification from the master document | |
779 // at this point, it is expensive to construct the master document information | |
780 } | |
781 | |
782 /** | |
783 * Fires the slave document event as about-to-be-changed event to all registered listeners. | |
784 */ | |
785 private void delayedFireDocumentAboutToBeChanged() { | |
786 super.fireDocumentAboutToBeChanged(fSlaveEvent); | |
787 } | |
788 | |
789 /** | |
790 * Ignores the given event and sends the semantically equal slave document event instead. | |
791 * | |
792 * @param event the event to be ignored | |
793 */ | |
794 protected void fireDocumentChanged(DocumentEvent event) { | |
795 super.fireDocumentChanged(fSlaveEvent); | |
796 } | |
797 | |
798 /* | |
799 * @see dwtx.jface.text.AbstractDocument#updateDocumentStructures(dwtx.jface.text.DocumentEvent) | |
800 */ | |
801 protected void updateDocumentStructures(DocumentEvent event) { | |
802 super.updateDocumentStructures(event); | |
803 ensureWellFormedSegmentation(computeAnchor(event)); | |
804 fMapping.projectionChanged(); | |
805 } | |
806 | |
807 private int computeAnchor(DocumentEvent event) { | |
138 | 808 if ( cast(ProjectionDocumentEvent)event ) { |
134 | 809 ProjectionDocumentEvent slave= cast(ProjectionDocumentEvent) event; |
129 | 810 Object changeType= slave.getChangeType(); |
811 if (ProjectionDocumentEvent.CONTENT_CHANGE is changeType) { | |
812 DocumentEvent master= slave.getMasterEvent(); | |
813 if (master !is null) | |
814 return master.getOffset(); | |
815 } else if (ProjectionDocumentEvent.PROJECTION_CHANGE is changeType) { | |
816 return slave.getMasterOffset(); | |
817 } | |
818 } | |
819 return -1; | |
820 } | |
821 | |
822 private bool ensureWellFormedSegmentation(int anchorOffset) { | |
823 bool changed= false; | |
824 Position[] segments= getSegments(); | |
825 for (int i= 0; i < segments.length; i++) { | |
134 | 826 Segment segment= cast(Segment) segments[i]; |
129 | 827 if (segment.isDeleted() || segment.getLength() is 0) { |
828 try { | |
829 removePosition(fSegmentsCategory, segment); | |
830 fMasterDocument.removePosition(fFragmentsCategory, segment.fragment); | |
831 changed= true; | |
832 } catch (BadPositionCategoryException e) { | |
833 internalError(); | |
834 } | |
835 } else if (i < segments.length - 1) { | |
134 | 836 Segment next= cast(Segment) segments[i + 1]; |
129 | 837 if (next.isDeleted() || next.getLength() is 0) |
838 continue; | |
839 Fragment fragment= segment.fragment; | |
840 if (fragment.getOffset() + fragment.getLength() is next.fragment.getOffset()) { | |
841 // join fragments and their corresponding segments | |
842 segment.setLength(segment.getLength() + next.getLength()); | |
843 fragment.setLength(fragment.getLength() + next.fragment.getLength()); | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
844 next.delete_(); |
129 | 845 } |
846 } | |
847 } | |
848 | |
849 if (changed && anchorOffset !is -1) { | |
850 Position[] changedSegments= getSegments(); | |
851 if (changedSegments is null || changedSegments.length is 0) { | |
852 Fragment fragment= new Fragment(anchorOffset, 0); | |
853 try { | |
854 fMasterDocument.addPosition(fFragmentsCategory, fragment); | |
855 createSegmentFor(fragment, 0); | |
856 } catch (BadLocationException e) { | |
857 internalError(); | |
858 } catch (BadPositionCategoryException e) { | |
859 internalError(); | |
860 } | |
861 } | |
862 } | |
863 | |
864 return changed; | |
865 } | |
866 | |
867 /* | |
868 * @see IDocumentExtension#registerPostNotificationReplace(IDocumentListener, IDocumentExtension.IReplace) | |
869 */ | |
870 public void registerPostNotificationReplace(IDocumentListener owner, IDocumentExtension.IReplace replace) { | |
871 if (!isUpdating()) | |
872 throw new UnsupportedOperationException(); | |
873 super.registerPostNotificationReplace(owner, replace); | |
874 } | |
875 | |
876 /** | |
877 * Sets the auto expand mode for this document. | |
878 * | |
879 * @param autoExpandMode <code>true</code> if auto-expanding | |
880 */ | |
881 public void setAutoExpandMode(bool autoExpandMode) { | |
882 fIsAutoExpanding= autoExpandMode; | |
883 } | |
884 | |
885 /** | |
886 * Replaces all master document ranges with the given master document range. | |
887 * | |
888 * @param offsetInMaster the offset in the master document | |
889 * @param lengthInMaster the length in the master document | |
890 * @throws BadLocationException if the given range of the master document is not valid | |
891 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
892 public void replaceMasterDocumentRanges(int offsetInMaster, int lengthInMaster) { |
129 | 893 try { |
894 | |
895 ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, 0, fMapping.getImageLength(), fMasterDocument.get(offsetInMaster, lengthInMaster), offsetInMaster, lengthInMaster); | |
896 super.fireDocumentAboutToBeChanged(event); | |
897 | |
898 Position[] fragments= getFragments(); | |
899 for (int i= 0; i < fragments.length; i++) { | |
134 | 900 Fragment fragment= cast(Fragment) fragments[i]; |
129 | 901 fMasterDocument.removePosition(fFragmentsCategory, fragment); |
902 removePosition(fSegmentsCategory, fragment.segment); | |
903 } | |
904 | |
905 Fragment fragment= new Fragment(offsetInMaster, lengthInMaster); | |
906 Segment segment= new Segment(0, 0); | |
907 segment.fragment= fragment; | |
908 fragment.segment= segment; | |
909 fMasterDocument.addPosition(fFragmentsCategory, fragment); | |
910 addPosition(fSegmentsCategory, segment); | |
911 | |
912 getTracker().set(fMasterDocument.get(offsetInMaster, lengthInMaster)); | |
913 super.fireDocumentChanged(event); | |
914 | |
915 } catch (BadPositionCategoryException x) { | |
916 internalError(); | |
917 } | |
918 } | |
919 } |