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