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.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 }
|