comparison dwtx/jface/text/projection/ProjectionMapping.d @ 129:eb30df5ca28b

Added JFace Text sources
author Frank Benoit <benoit@tionex.de>
date Sat, 23 Aug 2008 19:10:48 +0200
parents
children c4fb132a086c
comparison
equal deleted inserted replaced
128:8df1d4193877 129:eb30df5ca28b
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.ProjectionMapping;
14
15 import dwt.dwthelper.utils;
16
17
18 import dwtx.core.runtime.Assert;
19 import dwtx.jface.text.BadLocationException;
20 import dwtx.jface.text.BadPositionCategoryException;
21 import dwtx.jface.text.IDocument;
22 import dwtx.jface.text.IDocumentInformationMapping;
23 import dwtx.jface.text.IDocumentInformationMappingExtension;
24 import dwtx.jface.text.IDocumentInformationMappingExtension2;
25 import dwtx.jface.text.IRegion;
26 import dwtx.jface.text.Position;
27 import dwtx.jface.text.Region;
28
29
30 /**
31 * Internal class. Do not use. Only public for testing purposes.
32 * <p>
33 * Implementation of {@link dwtx.jface.text.IDocumentInformationMapping}
34 * for the projection mapping between a master and a slave document.
35 *
36 * @since 3.0
37 * @noinstantiate This class is not intended to be instantiated by clients.
38 * @noextend This class is not intended to be subclassed by clients.
39 */
40 public class ProjectionMapping : IDocumentInformationMapping , IDocumentInformationMappingExtension, IDocumentInformationMappingExtension2, IMinimalMapping {
41
42 private static final int LEFT= -1;
43 private static final int NONE= 0;
44 private static final int RIGHT= +1;
45
46 /** The master document */
47 private IDocument fMasterDocument;
48 /** The position category used to manage the projection fragments inside the master document */
49 private String fFragmentsCategory;
50 /** The projection document */
51 private IDocument fSlaveDocument;
52 /** The position category to manage the projection segments inside the slave document. */
53 private String fSegmentsCategory;
54 /** Cached segments */
55 private Position[] fCachedSegments;
56 /** Cached fragments */
57 private Position[] fCachedFragments;
58
59 /**
60 * Creates a new mapping between the given parent document and the given projection document.
61 *
62 * @param masterDocument the master document
63 * @param fragmentsCategory the position category of the parent document used to manage the projected regions
64 * @param slaveDocument the slave document
65 * @param segmentsCategory the position category of the projection document used to manage the fragments
66 */
67 public ProjectionMapping(IDocument masterDocument, String fragmentsCategory, IDocument slaveDocument, String segmentsCategory) {
68 fMasterDocument= masterDocument;
69 fFragmentsCategory= fragmentsCategory;
70 fSlaveDocument= slaveDocument;
71 fSegmentsCategory= segmentsCategory;
72 }
73
74 /**
75 * Notifies this projection mapping that there was a projection change.
76 */
77 public void projectionChanged() {
78 fCachedSegments= null;
79 fCachedFragments= null;
80 }
81
82 private Position[] getSegments() {
83 if (fCachedSegments is null) {
84 try {
85 fCachedSegments= fSlaveDocument.getPositions(fSegmentsCategory);
86 } catch (BadPositionCategoryException e) {
87 return new Position[0];
88 }
89 }
90 return fCachedSegments;
91 }
92
93 private Position[] getFragments() {
94 if (fCachedFragments is null) {
95 try {
96 fCachedFragments= fMasterDocument.getPositions(fFragmentsCategory);
97 } catch (BadPositionCategoryException e) {
98 return new Position[0];
99 }
100 }
101 return fCachedFragments;
102 }
103
104 private int findSegmentIndex(int offset) throws BadLocationException {
105 Position[] segments= getSegments();
106 if (segments.length is 0) {
107 if (offset > 0)
108 throw new BadLocationException();
109 return -1;
110 }
111
112 try {
113 int index= fSlaveDocument.computeIndexInCategory(fSegmentsCategory, offset);
114 if (index is segments.length && offset > exclusiveEnd(segments[index-1]))
115 throw new BadLocationException();
116
117 if (index < segments.length && offset is segments[index].offset)
118 return index;
119
120 if (index > 0)
121 index--;
122
123 return index;
124
125 } catch (BadPositionCategoryException e) {
126 throw new IllegalStateException();
127 }
128 }
129
130 private Segment findSegment(int offset) throws BadLocationException {
131
132 checkImageOffset(offset);
133
134 int index= findSegmentIndex(offset);
135 if (index is -1) {
136
137 Segment s= new Segment(0, 0);
138 Fragment f= new Fragment(0, 0);
139 s.fragment= f;
140 f.segment= s;
141 return s;
142 }
143
144 Position[] segments= getSegments();
145 return (Segment) segments[index];
146 }
147
148 /**
149 * Computes the fragment index given an origin offset. Returns the index of
150 * the fragment that contains <code>offset</code>, or <code>-1</code>
151 * if no fragment contains <code>offset</code>.
152 * <p>
153 * If <code>extensionDirection</code> is set to <code>RIGHT</code> or
154 * <code>LEFT</code>, the next fragment in that direction is returned if
155 * there is no fragment containing <code>offset</code>. Note that if
156 * <code>offset</code> occurs before any fragment and
157 * <code>extensionDirection</code> is <code>LEFT</code>,
158 * <code>-1</code> is also returned. The same applies for an offset after
159 * the last fragment and <code>extensionDirection</code> set to
160 * <code>RIGHT</code>.
161 * </p>
162 *
163 * @param offset an origin offset
164 * @param extensionDirection the direction in which to extend the search, or
165 * <code>NONE</code>
166 * @return the index of the fragment containing <code>offset</code>, or
167 * <code>-1</code>
168 * @throws BadLocationException if the index is not valid on the master
169 * document
170 */
171 private int findFragmentIndex(int offset, int extensionDirection) throws BadLocationException {
172 try {
173
174 Position[] fragments= getFragments();
175 if (fragments.length is 0)
176 return -1;
177
178 int index= fMasterDocument.computeIndexInCategory(fFragmentsCategory, offset);
179
180 if (index < fragments.length && offset is fragments[index].offset)
181 return index;
182
183 if (0 < index && index <= fragments.length && fragments[index - 1].includes(offset))
184 return index - 1;
185
186 switch (extensionDirection) {
187 case LEFT:
188 return index - 1;
189 case RIGHT:
190 if (index < fragments.length)
191 return index;
192 }
193
194 return -1;
195
196 } catch (BadPositionCategoryException e) {
197 throw new IllegalStateException();
198 }
199 }
200
201 private Fragment findFragment(int offset) throws BadLocationException {
202 checkOriginOffset(offset);
203
204 int index= findFragmentIndex(offset, NONE);
205 Position[] fragments= getFragments();
206 if (index is -1) {
207 if (fragments.length > 0) {
208 Fragment last= (Fragment) fragments[fragments.length - 1];
209 if (exclusiveEnd(last) is offset)
210 return last;
211 }
212 return null;
213 }
214 return (Fragment) fragments[index];
215 }
216
217 /**
218 * Returns the image region for <code>originRegion</code>.
219 *
220 * @param originRegion the region to get the image for
221 * @param exact if <code>true</code>, the begin and end offsets of
222 * <code>originRegion</code> must be projected, otherwise
223 * <code>null</code> is returned. If <code>false</code>, the
224 * begin and end range that is not visible is simply clipped.
225 * @param takeClosestImage if <code>false</code>, <code>null</code> is
226 * returned if <code>originRegion</code> is completely invisible.
227 * If <code>true</code>, the zero-length region is returned that
228 * "covers" the hidden origin region
229 * @return the image region of <code>originRegion</code>
230 * @throws BadLocationException if the region is not a valid origin region
231 */
232 private IRegion toImageRegion(IRegion originRegion, bool exact, bool takeClosestImage) throws BadLocationException {
233 if (originRegion.getLength() is 0 && !takeClosestImage) {
234 int imageOffset= toImageOffset(originRegion.getOffset());
235 return imageOffset is -1 ? null : new Region(imageOffset, 0);
236 }
237
238 Fragment[] fragments= findFragments(originRegion, exact, takeClosestImage);
239 if (fragments is null) {
240 if (takeClosestImage) {
241 // originRegion may before the first or after the last fragment
242 Position[] allFragments= getFragments();
243 if (allFragments.length > 0) {
244 // before the first
245 if (exclusiveEnd(originRegion) <= allFragments[0].getOffset())
246 return new Region(0, 0);
247 // after last
248 Position last= allFragments[allFragments.length - 1];
249 if (originRegion.getOffset() >= exclusiveEnd(last))
250 return new Region(exclusiveEnd(((Fragment) last).segment), 0);
251 }
252 return new Region(0, 0);
253 }
254 return null;
255 }
256
257 int imageOffset, exclusiveImageEndOffset;
258
259 // translate start offset
260 int relative= originRegion.getOffset() - fragments[0].getOffset();
261 if (relative < 0) {
262 Assert.isTrue(!exact);
263 relative= 0;
264 }
265 imageOffset= fragments[0].segment.getOffset() + relative;
266
267 // translate end offset
268 relative= exclusiveEnd(originRegion) - fragments[1].getOffset();
269 if (relative > fragments[1].getLength()) {
270 Assert.isTrue(!exact);
271 relative= fragments[1].getLength();
272 }
273 exclusiveImageEndOffset= fragments[1].segment.getOffset() + relative;
274
275 return new Region(imageOffset, exclusiveImageEndOffset - imageOffset);
276 }
277
278 /**
279 * Returns the two fragments containing the begin and end offsets of
280 * <code>originRegion</code>.
281 *
282 * @param originRegion the region to get the fragments for
283 * @param exact if <code>true</code>, only the fragments that contain the
284 * begin and end offsets are returned; if <code>false</code>, the
285 * first fragment after the begin offset and the last fragment before
286 * the end offset are returned if the offsets are not projected
287 * @param takeClosestImage if <code>true</code>, the method will return
288 * fragments also if <code>originRegion</code> completely lies in
289 * an unprojected region.
290 * @return the two fragments containing the begin and end offset of
291 * <code>originRegion</code>, or <code>null</code> if these do
292 * not exist
293 * @throws BadLocationException if the region is not a valid origin region
294 */
295 private Fragment[] findFragments(IRegion originRegion, bool exact, bool takeClosestImage) throws BadLocationException {
296 Position[] fragments= getFragments();
297 if (fragments.length is 0)
298 return null;
299
300 checkOriginRegion(originRegion);
301
302 int startFragmentIdx= findFragmentIndex(originRegion.getOffset(), exact ? NONE : RIGHT);
303 if (startFragmentIdx is -1)
304 return null;
305
306 int endFragmentIdx= findFragmentIndex(inclusiveEnd(originRegion), exact ? NONE : LEFT);
307 if (!takeClosestImage && startFragmentIdx > endFragmentIdx || endFragmentIdx is -1)
308 return null;
309
310 Fragment[] result= {(Fragment) fragments[startFragmentIdx], (Fragment) fragments[endFragmentIdx]};
311 return result;
312 }
313
314 private IRegion createOriginStartRegion(Segment image, int offsetShift) {
315 return new Region(image.fragment.getOffset() + offsetShift, image.fragment.getLength() - offsetShift);
316 }
317
318 private IRegion createOriginRegion(Segment image) {
319 return new Region(image.fragment.getOffset(), image.fragment.getLength());
320 }
321
322 private IRegion createOriginEndRegion(Segment image, int lengthReduction) {
323 return new Region(image.fragment.getOffset(), image.fragment.getLength() - lengthReduction);
324 }
325
326 private IRegion createImageStartRegion(Fragment origin, int offsetShift) {
327 int shift= offsetShift > 0 ? offsetShift : 0;
328 return new Region(origin.segment.getOffset() + shift, origin.segment.getLength() - shift);
329 }
330
331 private IRegion createImageRegion(Fragment origin) {
332 return new Region(origin.segment.getOffset(), origin.segment.getLength());
333 }
334
335 private IRegion createImageEndRegion(Fragment origin, int lengthReduction) {
336 int reduction= lengthReduction > 0 ? lengthReduction : 0;
337 return new Region(origin.segment.getOffset(), origin.segment.getLength() - reduction);
338 }
339
340 private IRegion createOriginStartRegion(Fragment origin, int offsetShift) {
341 int shift= offsetShift > 0 ? offsetShift : 0;
342 return new Region(origin.getOffset() + shift, origin.getLength() - shift);
343 }
344
345 private IRegion createOriginRegion(Fragment origin) {
346 return new Region(origin.getOffset(), origin.getLength());
347 }
348
349 private IRegion createOriginEndRegion(Fragment origin, int lengthReduction) {
350 int reduction= lengthReduction > 0 ? lengthReduction : 0;
351 return new Region(origin.getOffset(), origin.getLength() - reduction);
352 }
353
354 private IRegion getIntersectingRegion(IRegion left, IRegion right) {
355 int offset= Math.max(left.getOffset(), right.getOffset());
356 int exclusiveEndOffset= Math.min(exclusiveEnd(left), exclusiveEnd(right));
357 if (exclusiveEndOffset < offset)
358 return null;
359 return new Region(offset, exclusiveEndOffset - offset);
360 }
361
362 /*
363 * @see dwtx.jface.text.IDocumentInformationMapping#getCoverage()
364 */
365 public IRegion getCoverage() {
366 Position[] fragments= getFragments();
367 if (fragments !is null && fragments.length > 0) {
368 Position first=fragments[0];
369 Position last= fragments[fragments.length -1];
370 return new Region(first.offset, exclusiveEnd(last) - first.offset);
371 }
372 return new Region(0, 0);
373 }
374
375 /*
376 * @see dwtx.jface.text.IDocumentInformationMapping#toOriginOffset(int)
377 */
378 public int toOriginOffset(int imageOffset) throws BadLocationException {
379 Segment segment= findSegment(imageOffset);
380 int relative= imageOffset - segment.offset;
381 return segment.fragment.offset + relative;
382 }
383
384 /*
385 * @see dwtx.jface.text.IDocumentInformationMapping#toOriginRegion(dwtx.jface.text.IRegion)
386 */
387 public IRegion toOriginRegion(IRegion imageRegion) throws BadLocationException {
388 int imageOffset= imageRegion.getOffset();
389 int imageLength= imageRegion.getLength();
390
391 if (imageLength is 0) {
392 if (imageOffset is 0) {
393 Position[] fragments= getFragments();
394 if (fragments.length is 0 || (fragments.length is 1 && fragments[0].getOffset() is 0 && fragments[0].getLength() is 0))
395 return new Region(0, fMasterDocument.getLength());
396 }
397 return new Region(toOriginOffset(imageOffset), 0);
398 }
399
400 int originOffset= toOriginOffset(imageOffset);
401 int inclusiveImageEndOffset= imageOffset + imageLength -1;
402 int inclusiveOriginEndOffset= toOriginOffset(inclusiveImageEndOffset);
403
404 return new Region(originOffset, (inclusiveOriginEndOffset + 1) - originOffset);
405 }
406
407 /*
408 * @see dwtx.jface.text.IDocumentInformationMapping#toOriginLines(int)
409 */
410 public IRegion toOriginLines(int imageLine) throws BadLocationException {
411 IRegion imageRegion= fSlaveDocument.getLineInformation(imageLine);
412 IRegion originRegion= toOriginRegion(imageRegion);
413
414 int originStartLine= fMasterDocument.getLineOfOffset(originRegion.getOffset());
415 if (originRegion.getLength() is 0)
416 return new Region(originStartLine, 1);
417
418 int originEndLine= fMasterDocument.getLineOfOffset(inclusiveEnd(originRegion));
419 return new Region(originStartLine, (originEndLine + 1) - originStartLine);
420 }
421
422 /*
423 * @see dwtx.jface.text.IDocumentInformationMapping#toOriginLine(int)
424 */
425 public int toOriginLine(int imageLine) throws BadLocationException {
426 IRegion lines= toOriginLines(imageLine);
427 return (lines.getLength() > 1 ? -1 : lines.getOffset());
428 }
429
430 /*
431 * @see dwtx.jface.text.IDocumentInformationMapping#toImageOffset(int)
432 */
433 public int toImageOffset(int originOffset) throws BadLocationException {
434 Fragment fragment= findFragment(originOffset);
435 if (fragment !is null) {
436 int relative= originOffset - fragment.offset;
437 return fragment.segment.offset + relative;
438 }
439 return -1;
440 }
441
442 /*
443 * @see dwtx.jface.text.IDocumentInformationMappingExtension#toExactImageRegion(dwtx.jface.text.IRegion)
444 */
445 public IRegion toExactImageRegion(IRegion originRegion) throws BadLocationException {
446 return toImageRegion(originRegion, true, false);
447 }
448
449 /*
450 * @see dwtx.jface.text.IDocumentInformationMapping#toImageRegion(dwtx.jface.text.IRegion)
451 */
452 public IRegion toImageRegion(IRegion originRegion) throws BadLocationException {
453 return toImageRegion(originRegion, false, false);
454 }
455
456 /*
457 * @see dwtx.jface.text.IDocumentInformationMappingExtension2#toClosestImageRegion(dwtx.jface.text.IRegion)
458 * @since 3.1
459 */
460 public IRegion toClosestImageRegion(IRegion originRegion) throws BadLocationException {
461 return toImageRegion(originRegion, false, true);
462 }
463
464 /*
465 * @see dwtx.jface.text.IDocumentInformationMapping#toImageLine(int)
466 */
467 public int toImageLine(int originLine) throws BadLocationException {
468 IRegion originRegion= fMasterDocument.getLineInformation(originLine);
469 IRegion imageRegion= toImageRegion(originRegion);
470 if (imageRegion is null) {
471 int imageOffset= toImageOffset(originRegion.getOffset());
472 if (imageOffset > -1)
473 imageRegion= new Region(imageOffset, 0);
474 else
475 return -1;
476 }
477
478 int startLine= fSlaveDocument.getLineOfOffset(imageRegion.getOffset());
479 if (imageRegion.getLength() is 0)
480 return startLine;
481
482 int endLine= fSlaveDocument.getLineOfOffset(imageRegion.getOffset() + imageRegion.getLength());
483 if (endLine !is startLine)
484 throw new IllegalStateException();
485
486 return startLine;
487 }
488
489 /*
490 * @see dwtx.jface.text.IDocumentInformationMapping#toClosestImageLine(int)
491 */
492 public int toClosestImageLine(int originLine) throws BadLocationException {
493 try {
494
495 int imageLine= toImageLine(originLine);
496 if (imageLine > -1)
497 return imageLine;
498
499 Position[] fragments= getFragments();
500 if (fragments.length is 0)
501 return -1;
502
503 IRegion originLineRegion= fMasterDocument.getLineInformation(originLine);
504 int index= fMasterDocument.computeIndexInCategory(fFragmentsCategory, originLineRegion.getOffset());
505
506 if (0 < index && index < fragments.length) {
507 Fragment left= (Fragment) fragments[index - 1];
508 int leftDistance= originLineRegion.getOffset() - (exclusiveEnd(left));
509 Fragment right= (Fragment) fragments[index];
510 int rightDistance= right.getOffset() - (exclusiveEnd(originLineRegion));
511
512 if (leftDistance <= rightDistance)
513 originLine= fMasterDocument.getLineOfOffset(left.getOffset() + Math.max(left.getLength() - 1, 0));
514 else
515 originLine= fMasterDocument.getLineOfOffset(right.getOffset());
516
517 } else if (index is 0) {
518 Fragment right= (Fragment) fragments[index];
519 originLine= fMasterDocument.getLineOfOffset(right.getOffset());
520 } else if (index is fragments.length) {
521 Fragment left= (Fragment) fragments[index - 1];
522 originLine= fMasterDocument.getLineOfOffset(exclusiveEnd(left));
523 }
524
525 return toImageLine(originLine);
526
527 } catch (BadPositionCategoryException x) {
528 }
529
530 return -1;
531 }
532
533 /*
534 * @see dwtx.jface.text.IDocumentInformationMappingExtension#toExactOriginRegions(dwtx.jface.text.IRegion)
535 */
536 public IRegion[] toExactOriginRegions(IRegion imageRegion) throws BadLocationException {
537
538 if (imageRegion.getLength() is 0)
539 return new IRegion[] { new Region(toOriginOffset(imageRegion.getOffset()), 0) };
540
541 int endOffset= exclusiveEnd(imageRegion);
542 Position[] segments= getSegments();
543 int firstIndex= findSegmentIndex(imageRegion.getOffset());
544 int lastIndex= findSegmentIndex(endOffset - 1);
545
546 int resultLength= lastIndex - firstIndex + 1;
547 IRegion[] result= new IRegion[resultLength];
548
549 // first
550 result[0]= createOriginStartRegion((Segment) segments[firstIndex], imageRegion.getOffset() - segments[firstIndex].getOffset());
551 // middles
552 for (int i= 1; i < resultLength - 1; i++)
553 result[i]= createOriginRegion((Segment) segments[firstIndex + i]);
554 // last
555 Segment last= (Segment) segments[lastIndex];
556 int segmentEndOffset= exclusiveEnd(last);
557 IRegion lastRegion= createOriginEndRegion(last, segmentEndOffset - endOffset);
558 if (resultLength > 1) {
559 // first !is last
560 result[resultLength - 1]= lastRegion;
561 } else {
562 // merge first and last
563 IRegion intersection= getIntersectingRegion(result[0], lastRegion);
564 if (intersection is null)
565 result= new IRegion[0];
566 else
567 result[0]= intersection;
568 }
569
570 return result;
571 }
572
573 /*
574 * @see dwtx.jface.text.IDocumentInformationMappingExtension#getImageLength()
575 */
576 public int getImageLength() {
577 Position[] segments= getSegments();
578 int length= 0;
579 for (int i= 0; i < segments.length; i++)
580 length += segments[i].length;
581 return length;
582 }
583
584 /*
585 * @see dwtx.jface.text.IDocumentInformationMappingExtension#toExactImageRegions(dwtx.jface.text.IRegion)
586 */
587 public IRegion[] toExactImageRegions(IRegion originRegion) throws BadLocationException {
588
589 int offset= originRegion.getOffset();
590 if (originRegion.getLength() is 0) {
591 int imageOffset= toImageOffset(offset);
592 return imageOffset > -1 ? new IRegion[] { new Region(imageOffset, 0) } : null;
593 }
594
595 int endOffset= exclusiveEnd(originRegion);
596 Position[] fragments= getFragments();
597 int firstIndex= findFragmentIndex(offset, RIGHT);
598 int lastIndex= findFragmentIndex(endOffset - 1, LEFT);
599
600 if (firstIndex is -1 || firstIndex > lastIndex)
601 return null;
602
603 int resultLength= lastIndex - firstIndex + 1;
604 IRegion[] result= new IRegion[resultLength];
605
606 // first
607 result[0]= createImageStartRegion((Fragment) fragments[firstIndex], offset - fragments[firstIndex].getOffset());
608 // middles
609 for (int i= 1; i < resultLength - 1; i++)
610 result[i]= createImageRegion((Fragment) fragments[firstIndex + i]);
611 // last
612 Fragment last= (Fragment) fragments[lastIndex];
613 int fragmentEndOffset= exclusiveEnd(last);
614 IRegion lastRegion= createImageEndRegion(last, fragmentEndOffset - endOffset);
615 if (resultLength > 1) {
616 // first !is last
617 result[resultLength - 1]= lastRegion;
618 } else {
619 // merge first and last
620 IRegion intersection= getIntersectingRegion(result[0], lastRegion);
621 if (intersection is null)
622 return null;
623 result[0]= intersection;
624 }
625
626 return result;
627 }
628
629 /*
630 * @see dwtx.jface.text.IDocumentInformationMappingExtension#getExactCoverage(dwtx.jface.text.IRegion)
631 */
632 public IRegion[] getExactCoverage(IRegion originRegion) throws BadLocationException {
633
634 int originOffset= originRegion.getOffset();
635 int originLength= originRegion.getLength();
636
637 if (originLength is 0) {
638 int imageOffset= toImageOffset(originOffset);
639 return imageOffset > -1 ? new IRegion[] { new Region(originOffset, 0) } : null;
640 }
641
642 int endOffset= originOffset + originLength;
643 Position[] fragments= getFragments();
644 int firstIndex= findFragmentIndex(originOffset, RIGHT);
645 int lastIndex= findFragmentIndex(endOffset - 1, LEFT);
646
647 if (firstIndex is -1 || firstIndex > lastIndex)
648 return null;
649
650 int resultLength= lastIndex - firstIndex + 1;
651 IRegion[] result= new IRegion[resultLength];
652
653 // first
654 result[0]= createOriginStartRegion((Fragment) fragments[firstIndex], originOffset - fragments[firstIndex].getOffset());
655 // middles
656 for (int i= 1; i < resultLength - 1; i++)
657 result[i]= createOriginRegion((Fragment) fragments[firstIndex + i]);
658 // last
659 Fragment last= (Fragment) fragments[lastIndex];
660 int fragmentEndOffset= exclusiveEnd(last);
661 IRegion lastRegion= createOriginEndRegion(last, fragmentEndOffset - endOffset);
662 if (resultLength > 1) {
663 // first !is last
664 result[resultLength - 1]= lastRegion;
665 } else {
666 // merge first and last
667 IRegion intersection= getIntersectingRegion(result[0], lastRegion);
668 if (intersection is null)
669 return null;
670 result[0]= intersection;
671 }
672
673 return result;
674 }
675
676 private final void checkOriginRegion(IRegion originRegion) throws BadLocationException {
677 int offset= originRegion.getOffset();
678 int endOffset= inclusiveEnd(originRegion);
679 int max= fMasterDocument.getLength();
680 if (offset < 0 || offset > max || endOffset < 0 || endOffset > max)
681 throw new BadLocationException();
682 }
683
684 private final void checkOriginOffset(int originOffset) throws BadLocationException {
685 if (originOffset < 0 || originOffset > fMasterDocument.getLength())
686 throw new BadLocationException();
687 }
688
689 private final void checkImageOffset(int imageOffset) throws BadLocationException {
690 if (imageOffset < 0 || imageOffset > getImageLength())
691 throw new BadLocationException();
692 }
693
694 private final int exclusiveEnd(Position position) {
695 return position.offset + position.length;
696 }
697
698 private final int exclusiveEnd(IRegion region) {
699 return region.getOffset() + region.getLength();
700 }
701
702 private final int inclusiveEnd(IRegion region) {
703 int length= region.getLength();
704 if (length is 0)
705 return region.getOffset();
706 return region.getOffset() + length - 1;
707 }
708
709
710 }