Mercurial > projects > dwt-addons
comparison dwtx/jface/text/formatter/ContentFormatter.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, 2006 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 | |
14 module dwtx.jface.text.formatter.ContentFormatter; | |
15 | |
16 import dwt.dwthelper.utils; | |
17 | |
18 | |
19 import java.util.ArrayList; | |
20 import java.util.Collections; | |
21 import java.util.HashMap; | |
22 import java.util.List; | |
23 import java.util.Map; | |
24 | |
25 import dwtx.core.runtime.Assert; | |
26 import dwtx.jface.text.BadLocationException; | |
27 import dwtx.jface.text.BadPositionCategoryException; | |
28 import dwtx.jface.text.DefaultPositionUpdater; | |
29 import dwtx.jface.text.DocumentEvent; | |
30 import dwtx.jface.text.IDocument; | |
31 import dwtx.jface.text.IDocumentExtension3; | |
32 import dwtx.jface.text.IPositionUpdater; | |
33 import dwtx.jface.text.IRegion; | |
34 import dwtx.jface.text.ITypedRegion; | |
35 import dwtx.jface.text.Position; | |
36 import dwtx.jface.text.TextUtilities; | |
37 import dwtx.jface.text.TypedPosition; | |
38 | |
39 | |
40 /** | |
41 * Standard implementation of <code>IContentFormatter</code>. | |
42 * The formatter supports two operation modes: partition aware and | |
43 * partition unaware. <p> | |
44 * In the partition aware mode, the formatter determines the | |
45 * partitioning of the document region to be formatted. For each | |
46 * partition it determines all document positions which are affected | |
47 * when text changes are applied to the partition. Those which overlap | |
48 * with the partition are remembered as character positions. These | |
49 * character positions are passed over to the formatting strategy | |
50 * registered for the partition's content type. The formatting strategy | |
51 * returns a string containing the formatted document partition as well | |
52 * as the adapted character positions. The formatted partition replaces | |
53 * the old content of the partition. The remembered document positions | |
54 * are updated with the adapted character positions. In addition, all | |
55 * other document positions are accordingly adapted to the formatting | |
56 * changes.<p> | |
57 * In the partition unaware mode, the document's partitioning is ignored | |
58 * and the document is considered consisting of only one partition of | |
59 * the content type <code>IDocument.DEFAULT_CONTENT_TYPE</code>. The | |
60 * formatting process is similar to the partition aware mode, with the | |
61 * exception of having only one partition.<p> | |
62 * Usually, clients instantiate this class and configure it before using it. | |
63 * | |
64 * @see IContentFormatter | |
65 * @see IDocument | |
66 * @see ITypedRegion | |
67 * @see Position | |
68 */ | |
69 public class ContentFormatter : IContentFormatter { | |
70 | |
71 /** | |
72 * Defines a reference to either the offset or the end offset of | |
73 * a particular position. | |
74 */ | |
75 static class PositionReference : Comparable { | |
76 | |
77 /** The referenced position */ | |
78 protected Position fPosition; | |
79 /** The reference to either the offset or the end offset */ | |
80 protected bool fRefersToOffset; | |
81 /** The original category of the referenced position */ | |
82 protected String fCategory; | |
83 | |
84 /** | |
85 * Creates a new position reference. | |
86 * | |
87 * @param position the position to be referenced | |
88 * @param refersToOffset <code>true</code> if position offset should be referenced | |
89 * @param category the category the given position belongs to | |
90 */ | |
91 protected PositionReference(Position position, bool refersToOffset, String category) { | |
92 fPosition= position; | |
93 fRefersToOffset= refersToOffset; | |
94 fCategory= category; | |
95 } | |
96 | |
97 /** | |
98 * Returns the offset of the referenced position. | |
99 * | |
100 * @return the offset of the referenced position | |
101 */ | |
102 protected int getOffset() { | |
103 return fPosition.getOffset(); | |
104 } | |
105 | |
106 /** | |
107 * Manipulates the offset of the referenced position. | |
108 * | |
109 * @param offset the new offset of the referenced position | |
110 */ | |
111 protected void setOffset(int offset) { | |
112 fPosition.setOffset(offset); | |
113 } | |
114 | |
115 /** | |
116 * Returns the length of the referenced position. | |
117 * | |
118 * @return the length of the referenced position | |
119 */ | |
120 protected int getLength() { | |
121 return fPosition.getLength(); | |
122 } | |
123 | |
124 /** | |
125 * Manipulates the length of the referenced position. | |
126 * | |
127 * @param length the new length of the referenced position | |
128 */ | |
129 protected void setLength(int length) { | |
130 fPosition.setLength(length); | |
131 } | |
132 | |
133 /** | |
134 * Returns whether this reference points to the offset or end offset | |
135 * of the references position. | |
136 * | |
137 * @return <code>true</code> if the offset of the position is referenced, <code>false</code> otherwise | |
138 */ | |
139 protected bool refersToOffset() { | |
140 return fRefersToOffset; | |
141 } | |
142 | |
143 /** | |
144 * Returns the category of the referenced position. | |
145 * | |
146 * @return the category of the referenced position | |
147 */ | |
148 protected String getCategory() { | |
149 return fCategory; | |
150 } | |
151 | |
152 /** | |
153 * Returns the referenced position. | |
154 * | |
155 * @return the referenced position | |
156 */ | |
157 protected Position getPosition() { | |
158 return fPosition; | |
159 } | |
160 | |
161 /** | |
162 * Returns the referenced character position | |
163 * | |
164 * @return the referenced character position | |
165 */ | |
166 protected int getCharacterPosition() { | |
167 if (fRefersToOffset) | |
168 return getOffset(); | |
169 return getOffset() + getLength(); | |
170 } | |
171 | |
172 /* | |
173 * @see Comparable#compareTo(Object) | |
174 */ | |
175 public int compareTo(Object obj) { | |
176 | |
177 if (obj instanceof PositionReference) { | |
178 PositionReference r= (PositionReference) obj; | |
179 return getCharacterPosition() - r.getCharacterPosition(); | |
180 } | |
181 | |
182 throw new ClassCastException(); | |
183 } | |
184 } | |
185 | |
186 /** | |
187 * The position updater used to update the remembered partitions. | |
188 * | |
189 * @see IPositionUpdater | |
190 * @see DefaultPositionUpdater | |
191 */ | |
192 class NonDeletingPositionUpdater : DefaultPositionUpdater { | |
193 | |
194 /** | |
195 * Creates a new updater for the given category. | |
196 * | |
197 * @param category the category | |
198 */ | |
199 protected NonDeletingPositionUpdater(String category) { | |
200 super(category); | |
201 } | |
202 | |
203 /* | |
204 * @see DefaultPositionUpdater#notDeleted() | |
205 */ | |
206 protected bool notDeleted() { | |
207 return true; | |
208 } | |
209 } | |
210 | |
211 /** | |
212 * The position updater which runs as first updater on the document's positions. | |
213 * Used to remove all affected positions from their categories to avoid them | |
214 * from being regularly updated. | |
215 * | |
216 * @see IPositionUpdater | |
217 */ | |
218 class RemoveAffectedPositions : IPositionUpdater { | |
219 /* | |
220 * @see IPositionUpdater#update(DocumentEvent) | |
221 */ | |
222 public void update(DocumentEvent event) { | |
223 removeAffectedPositions(event.getDocument()); | |
224 } | |
225 } | |
226 | |
227 /** | |
228 * The position updater which runs as last updater on the document's positions. | |
229 * Used to update all affected positions and adding them back to their | |
230 * original categories. | |
231 * | |
232 * @see IPositionUpdater | |
233 */ | |
234 class UpdateAffectedPositions : IPositionUpdater { | |
235 | |
236 /** The affected positions */ | |
237 private int[] fPositions; | |
238 /** The offset */ | |
239 private int fOffset; | |
240 | |
241 /** | |
242 * Creates a new updater. | |
243 * | |
244 * @param positions the affected positions | |
245 * @param offset the offset | |
246 */ | |
247 public UpdateAffectedPositions(int[] positions, int offset) { | |
248 fPositions= positions; | |
249 fOffset= offset; | |
250 } | |
251 | |
252 /* | |
253 * @see IPositionUpdater#update(DocumentEvent) | |
254 */ | |
255 public void update(DocumentEvent event) { | |
256 updateAffectedPositions(event.getDocument(), fPositions, fOffset); | |
257 } | |
258 } | |
259 | |
260 | |
261 /** Internal position category used for the formatter partitioning */ | |
262 private final static String PARTITIONING= "__formatter_partitioning"; //$NON-NLS-1$ | |
263 | |
264 /** The map of <code>IFormattingStrategy</code> objects */ | |
265 private Map fStrategies; | |
266 /** The indicator of whether the formatter operates in partition aware mode or not */ | |
267 private bool fIsPartitionAware= true; | |
268 | |
269 /** The partition information managing document position categories */ | |
270 private String[] fPartitionManagingCategories; | |
271 /** The list of references to offset and end offset of all overlapping positions */ | |
272 private List fOverlappingPositionReferences; | |
273 /** Position updater used for partitioning positions */ | |
274 private IPositionUpdater fPartitioningUpdater; | |
275 /** | |
276 * The document partitioning used by this formatter. | |
277 * @since 3.0 | |
278 */ | |
279 private String fPartitioning; | |
280 /** | |
281 * The document this formatter works on. | |
282 * @since 3.0 | |
283 */ | |
284 private IDocument fDocument; | |
285 /** | |
286 * The external partition managing categories. | |
287 * @since 3.0 | |
288 */ | |
289 private String[] fExternalPartitonManagingCategories; | |
290 /** | |
291 * Indicates whether <code>fPartitionManagingCategories</code> must be computed. | |
292 * @since 3.0 | |
293 */ | |
294 private bool fNeedsComputation= true; | |
295 | |
296 | |
297 /** | |
298 * Creates a new content formatter. The content formatter operates by default | |
299 * in the partition-aware mode. There are no preconfigured formatting strategies. | |
300 * Will use the default document partitioning if not further configured. | |
301 */ | |
302 public ContentFormatter() { | |
303 fPartitioning= IDocumentExtension3.DEFAULT_PARTITIONING; | |
304 } | |
305 | |
306 /** | |
307 * Registers a strategy for a particular content type. If there is already a strategy | |
308 * registered for this type, the new strategy is registered instead of the old one. | |
309 * If the given content type is <code>null</code> the given strategy is registered for | |
310 * all content types as is called only once per formatting session. | |
311 * | |
312 * @param strategy the formatting strategy to register, or <code>null</code> to remove an existing one | |
313 * @param contentType the content type under which to register | |
314 */ | |
315 public void setFormattingStrategy(IFormattingStrategy strategy, String contentType) { | |
316 | |
317 Assert.isNotNull(contentType); | |
318 | |
319 if (fStrategies is null) | |
320 fStrategies= new HashMap(); | |
321 | |
322 if (strategy is null) | |
323 fStrategies.remove(contentType); | |
324 else | |
325 fStrategies.put(contentType, strategy); | |
326 } | |
327 | |
328 /** | |
329 * Informs this content formatter about the names of those position categories | |
330 * which are used to manage the document's partitioning information and thus should | |
331 * be ignored when this formatter updates positions. | |
332 * | |
333 * @param categories the categories to be ignored | |
334 * @deprecated incompatible with an open set of document partitionings. The provided information is only used | |
335 * if this formatter can not compute the partition managing position categories. | |
336 */ | |
337 public void setPartitionManagingPositionCategories(String[] categories) { | |
338 fExternalPartitonManagingCategories= TextUtilities.copy(categories); | |
339 } | |
340 | |
341 /** | |
342 * Sets the document partitioning to be used by this formatter. | |
343 * | |
344 * @param partitioning the document partitioning | |
345 * @since 3.0 | |
346 */ | |
347 public void setDocumentPartitioning(String partitioning) { | |
348 fPartitioning= partitioning; | |
349 } | |
350 | |
351 /** | |
352 * Sets the formatter's operation mode. | |
353 * | |
354 * @param enable indicates whether the formatting process should be partition ware | |
355 */ | |
356 public void enablePartitionAwareFormatting(bool enable) { | |
357 fIsPartitionAware= enable; | |
358 } | |
359 | |
360 /* | |
361 * @see IContentFormatter#getFormattingStrategy(String) | |
362 */ | |
363 public IFormattingStrategy getFormattingStrategy(String contentType) { | |
364 | |
365 Assert.isNotNull(contentType); | |
366 | |
367 if (fStrategies is null) | |
368 return null; | |
369 | |
370 return (IFormattingStrategy) fStrategies.get(contentType); | |
371 } | |
372 | |
373 /* | |
374 * @see IContentFormatter#format(IDocument, IRegion) | |
375 */ | |
376 public void format(IDocument document, IRegion region) { | |
377 fNeedsComputation= true; | |
378 fDocument= document; | |
379 try { | |
380 | |
381 if (fIsPartitionAware) | |
382 formatPartitions(region); | |
383 else | |
384 formatRegion(region); | |
385 | |
386 } finally { | |
387 fNeedsComputation= true; | |
388 fDocument= null; | |
389 } | |
390 } | |
391 | |
392 /** | |
393 * Determines the partitioning of the given region of the document. | |
394 * Informs the formatting strategies of each partition about the start, | |
395 * the process, and the termination of the formatting session. | |
396 * | |
397 * @param region the document region to be formatted | |
398 * @since 3.0 | |
399 */ | |
400 private void formatPartitions(IRegion region) { | |
401 | |
402 addPartitioningUpdater(); | |
403 | |
404 try { | |
405 | |
406 TypedPosition[] ranges= getPartitioning(region); | |
407 if (ranges !is null) { | |
408 start(ranges, getIndentation(region.getOffset())); | |
409 format(ranges); | |
410 stop(ranges); | |
411 } | |
412 | |
413 } catch (BadLocationException x) { | |
414 } | |
415 | |
416 removePartitioningUpdater(); | |
417 } | |
418 | |
419 /** | |
420 * Formats the given region with the strategy registered for the default | |
421 * content type. The strategy is informed about the start, the process, and | |
422 * the termination of the formatting session. | |
423 * | |
424 * @param region the region to be formatted | |
425 * @since 3.0 | |
426 */ | |
427 private void formatRegion(IRegion region) { | |
428 | |
429 IFormattingStrategy strategy= getFormattingStrategy(IDocument.DEFAULT_CONTENT_TYPE); | |
430 if (strategy !is null) { | |
431 strategy.formatterStarts(getIndentation(region.getOffset())); | |
432 format(strategy, new TypedPosition(region.getOffset(), region.getLength(), IDocument.DEFAULT_CONTENT_TYPE)); | |
433 strategy.formatterStops(); | |
434 } | |
435 } | |
436 | |
437 /** | |
438 * Returns the partitioning of the given region of the document to be formatted. | |
439 * As one partition after the other will be formatted and formatting will | |
440 * probably change the length of the formatted partition, it must be kept | |
441 * track of the modifications in order to submit the correct partition to all | |
442 * formatting strategies. For this, all partitions are remembered as positions | |
443 * in a dedicated position category. (As formatting strategies might rely on each | |
444 * other, calling them in reversed order is not an option.) | |
445 * | |
446 * @param region the region for which the partitioning must be determined | |
447 * @return the partitioning of the specified region | |
448 * @exception BadLocationException of region is invalid in the document | |
449 * @since 3.0 | |
450 */ | |
451 private TypedPosition[] getPartitioning(IRegion region) throws BadLocationException { | |
452 | |
453 ITypedRegion[] regions= TextUtilities.computePartitioning(fDocument, fPartitioning, region.getOffset(), region.getLength(), false); | |
454 TypedPosition[] positions= new TypedPosition[regions.length]; | |
455 | |
456 for (int i= 0; i < regions.length; i++) { | |
457 positions[i]= new TypedPosition(regions[i]); | |
458 try { | |
459 fDocument.addPosition(PARTITIONING, positions[i]); | |
460 } catch (BadPositionCategoryException x) { | |
461 // should not happen | |
462 } | |
463 } | |
464 | |
465 return positions; | |
466 } | |
467 | |
468 /** | |
469 * Fires <code>formatterStarts</code> to all formatter strategies | |
470 * which will be involved in the forthcoming formatting process. | |
471 * | |
472 * @param regions the partitioning of the document to be formatted | |
473 * @param indentation the initial indentation | |
474 */ | |
475 private void start(TypedPosition[] regions, String indentation) { | |
476 for (int i= 0; i < regions.length; i++) { | |
477 IFormattingStrategy s= getFormattingStrategy(regions[i].getType()); | |
478 if (s !is null) | |
479 s.formatterStarts(indentation); | |
480 } | |
481 } | |
482 | |
483 /** | |
484 * Formats one partition after the other using the formatter strategy registered for | |
485 * the partition's content type. | |
486 * | |
487 * @param ranges the partitioning of the document region to be formatted | |
488 * @since 3.0 | |
489 */ | |
490 private void format(TypedPosition[] ranges) { | |
491 for (int i= 0; i < ranges.length; i++) { | |
492 IFormattingStrategy s= getFormattingStrategy(ranges[i].getType()); | |
493 if (s !is null) { | |
494 format(s, ranges[i]); | |
495 } | |
496 } | |
497 } | |
498 | |
499 /** | |
500 * Formats the given region of the document using the specified formatting | |
501 * strategy. In order to maintain positions correctly, first all affected | |
502 * positions determined, after all document listeners have been informed about | |
503 * the coming change, the affected positions are removed to avoid that they | |
504 * are regularly updated. After all position updaters have run, the affected | |
505 * positions are updated with the formatter's information and added back to | |
506 * their categories, right before the first document listener is informed about | |
507 * that a change happened. | |
508 * | |
509 * @param strategy the strategy to be used | |
510 * @param region the region to be formatted | |
511 * @since 3.0 | |
512 */ | |
513 private void format(IFormattingStrategy strategy, TypedPosition region) { | |
514 try { | |
515 | |
516 final int offset= region.getOffset(); | |
517 int length= region.getLength(); | |
518 | |
519 String content= fDocument.get(offset, length); | |
520 final int[] positions= getAffectedPositions(offset, length); | |
521 String formatted= strategy.format(content, isLineStart(offset), getIndentation(offset), positions); | |
522 | |
523 if (formatted !is null && !formatted.equals(content)) { | |
524 | |
525 IPositionUpdater first= new RemoveAffectedPositions(); | |
526 fDocument.insertPositionUpdater(first, 0); | |
527 IPositionUpdater last= new UpdateAffectedPositions(positions, offset); | |
528 fDocument.addPositionUpdater(last); | |
529 | |
530 fDocument.replace(offset, length, formatted); | |
531 | |
532 fDocument.removePositionUpdater(first); | |
533 fDocument.removePositionUpdater(last); | |
534 } | |
535 | |
536 } catch (BadLocationException x) { | |
537 // should not happen | |
538 } | |
539 } | |
540 | |
541 /** | |
542 * Fires <code>formatterStops</code> to all formatter strategies which were | |
543 * involved in the formatting process which is about to terminate. | |
544 * | |
545 * @param regions the partitioning of the document which has been formatted | |
546 */ | |
547 private void stop(TypedPosition[] regions) { | |
548 for (int i= 0; i < regions.length; i++) { | |
549 IFormattingStrategy s= getFormattingStrategy(regions[i].getType()); | |
550 if (s !is null) | |
551 s.formatterStops(); | |
552 } | |
553 } | |
554 | |
555 /** | |
556 * Installs those updaters which the formatter needs to keep track of the partitions. | |
557 * @since 3.0 | |
558 */ | |
559 private void addPartitioningUpdater() { | |
560 fPartitioningUpdater= new NonDeletingPositionUpdater(PARTITIONING); | |
561 fDocument.addPositionCategory(PARTITIONING); | |
562 fDocument.addPositionUpdater(fPartitioningUpdater); | |
563 } | |
564 | |
565 /** | |
566 * Removes the formatter's internal position updater and category. | |
567 * | |
568 * @since 3.0 | |
569 */ | |
570 private void removePartitioningUpdater() { | |
571 | |
572 try { | |
573 | |
574 fDocument.removePositionUpdater(fPartitioningUpdater); | |
575 fDocument.removePositionCategory(PARTITIONING); | |
576 fPartitioningUpdater= null; | |
577 | |
578 } catch (BadPositionCategoryException x) { | |
579 // should not happen | |
580 } | |
581 } | |
582 | |
583 /** | |
584 * Returns the partition managing position categories for the formatted document. | |
585 * | |
586 * @return the position managing position categories | |
587 * @since 3.0 | |
588 */ | |
589 private String[] getPartitionManagingCategories() { | |
590 if (fNeedsComputation) { | |
591 fNeedsComputation= false; | |
592 fPartitionManagingCategories= TextUtilities.computePartitionManagingCategories(fDocument); | |
593 if (fPartitionManagingCategories is null) | |
594 fPartitionManagingCategories= fExternalPartitonManagingCategories; | |
595 } | |
596 return fPartitionManagingCategories; | |
597 } | |
598 | |
599 /** | |
600 * Determines whether the given document position category should be ignored | |
601 * by this formatter's position updating. | |
602 * | |
603 * @param category the category to check | |
604 * @return <code>true</code> if the category should be ignored, <code>false</code> otherwise | |
605 */ | |
606 private bool ignoreCategory(String category) { | |
607 | |
608 if (PARTITIONING.equals(category)) | |
609 return true; | |
610 | |
611 String[] categories= getPartitionManagingCategories(); | |
612 if (categories !is null) { | |
613 for (int i= 0; i < categories.length; i++) { | |
614 if (categories[i].equals(category)) | |
615 return true; | |
616 } | |
617 } | |
618 | |
619 return false; | |
620 } | |
621 | |
622 /** | |
623 * Determines all embracing, overlapping, and follow up positions | |
624 * for the given region of the document. | |
625 * | |
626 * @param offset the offset of the document region to be formatted | |
627 * @param length the length of the document to be formatted | |
628 * @since 3.0 | |
629 */ | |
630 private void determinePositionsToUpdate(int offset, int length) { | |
631 | |
632 String[] categories= fDocument.getPositionCategories(); | |
633 if (categories !is null) { | |
634 for (int i= 0; i < categories.length; i++) { | |
635 | |
636 if (ignoreCategory(categories[i])) | |
637 continue; | |
638 | |
639 try { | |
640 | |
641 Position[] positions= fDocument.getPositions(categories[i]); | |
642 | |
643 for (int j= 0; j < positions.length; j++) { | |
644 | |
645 Position p= positions[j]; | |
646 if (p.overlapsWith(offset, length)) { | |
647 | |
648 if (offset < p.getOffset()) | |
649 fOverlappingPositionReferences.add(new PositionReference(p, true, categories[i])); | |
650 | |
651 if (p.getOffset() + p.getLength() < offset + length) | |
652 fOverlappingPositionReferences.add(new PositionReference(p, false, categories[i])); | |
653 } | |
654 } | |
655 | |
656 } catch (BadPositionCategoryException x) { | |
657 // can not happen | |
658 } | |
659 } | |
660 } | |
661 } | |
662 | |
663 /** | |
664 * Returns all offset and the end offset of all positions overlapping with the | |
665 * specified document range. | |
666 * | |
667 * @param offset the offset of the document region to be formatted | |
668 * @param length the length of the document to be formatted | |
669 * @return all character positions of the interleaving positions | |
670 * @since 3.0 | |
671 */ | |
672 private int[] getAffectedPositions(int offset, int length) { | |
673 | |
674 fOverlappingPositionReferences= new ArrayList(); | |
675 | |
676 determinePositionsToUpdate(offset, length); | |
677 | |
678 Collections.sort(fOverlappingPositionReferences); | |
679 | |
680 int[] positions= new int[fOverlappingPositionReferences.size()]; | |
681 for (int i= 0; i < positions.length; i++) { | |
682 PositionReference r= (PositionReference) fOverlappingPositionReferences.get(i); | |
683 positions[i]= r.getCharacterPosition() - offset; | |
684 } | |
685 | |
686 return positions; | |
687 } | |
688 | |
689 /** | |
690 * Removes the affected positions from their categories to avoid | |
691 * that they are invalidly updated. | |
692 * | |
693 * @param document the document | |
694 */ | |
695 private void removeAffectedPositions(IDocument document) { | |
696 int size= fOverlappingPositionReferences.size(); | |
697 for (int i= 0; i < size; i++) { | |
698 PositionReference r= (PositionReference) fOverlappingPositionReferences.get(i); | |
699 try { | |
700 document.removePosition(r.getCategory(), r.getPosition()); | |
701 } catch (BadPositionCategoryException x) { | |
702 // can not happen | |
703 } | |
704 } | |
705 } | |
706 | |
707 /** | |
708 * Updates all the overlapping positions. Note, all other positions are | |
709 * automatically updated by their document position updaters. | |
710 * | |
711 * @param document the document to has been formatted | |
712 * @param positions the adapted character positions to be used to update the document positions | |
713 * @param offset the offset of the document region that has been formatted | |
714 */ | |
715 protected void updateAffectedPositions(IDocument document, int[] positions, int offset) { | |
716 | |
717 if (document !is fDocument) | |
718 return; | |
719 | |
720 if (positions.length is 0) | |
721 return; | |
722 | |
723 for (int i= 0; i < positions.length; i++) { | |
724 | |
725 PositionReference r= (PositionReference) fOverlappingPositionReferences.get(i); | |
726 | |
727 if (r.refersToOffset()) | |
728 r.setOffset(offset + positions[i]); | |
729 else | |
730 r.setLength((offset + positions[i]) - r.getOffset()); | |
731 | |
732 Position p= r.getPosition(); | |
733 String category= r.getCategory(); | |
734 if (!document.containsPosition(category, p.offset, p.length)) { | |
735 try { | |
736 if (positionAboutToBeAdded(document, category, p)) | |
737 document.addPosition(r.getCategory(), p); | |
738 } catch (BadPositionCategoryException x) { | |
739 // can not happen | |
740 } catch (BadLocationException x) { | |
741 // should not happen | |
742 } | |
743 } | |
744 | |
745 } | |
746 | |
747 fOverlappingPositionReferences= null; | |
748 } | |
749 | |
750 /** | |
751 * The given position is about to be added to the given position category of the given document. <p> | |
752 * This default implementation return <code>true</code>. | |
753 * | |
754 * @param document the document | |
755 * @param category the position category | |
756 * @param position the position that will be added | |
757 * @return <code>true</code> if the position can be added, <code>false</code> if it should be ignored | |
758 */ | |
759 protected bool positionAboutToBeAdded(IDocument document, String category, Position position) { | |
760 return true; | |
761 } | |
762 | |
763 /** | |
764 * Returns the indentation of the line of the given offset. | |
765 * | |
766 * @param offset the offset | |
767 * @return the indentation of the line of the offset | |
768 * @since 3.0 | |
769 */ | |
770 private String getIndentation(int offset) { | |
771 | |
772 try { | |
773 int start= fDocument.getLineOfOffset(offset); | |
774 start= fDocument.getLineOffset(start); | |
775 | |
776 int end= start; | |
777 char c= fDocument.getChar(end); | |
778 while ('\t' is c || ' ' is c) | |
779 c= fDocument.getChar(++end); | |
780 | |
781 return fDocument.get(start, end - start); | |
782 } catch (BadLocationException x) { | |
783 } | |
784 | |
785 return ""; //$NON-NLS-1$ | |
786 } | |
787 | |
788 /** | |
789 * Determines whether the offset is the beginning of a line in the given document. | |
790 * | |
791 * @param offset the offset | |
792 * @return <code>true</code> if offset is the beginning of a line | |
793 * @exception BadLocationException if offset is invalid in document | |
794 * @since 3.0 | |
795 */ | |
796 private bool isLineStart(int offset) throws BadLocationException { | |
797 int start= fDocument.getLineOfOffset(offset); | |
798 start= fDocument.getLineOffset(start); | |
799 return (start is offset); | |
800 } | |
801 } |