Mercurial > projects > dwt-addons
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 } |