Mercurial > projects > dwt-addons
annotate dwtx/jface/text/TextPresentation.d @ 162:1a5b8f8129df
...
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 08 Sep 2008 00:51:37 +0200 |
parents | 25f1f92fa3df |
children |
rev | line source |
---|---|
129 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2007 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.TextPresentation; | |
14 | |
131 | 15 import dwtx.jface.text.IDocumentPartitioningListener; // packageimport |
16 import dwtx.jface.text.DefaultTextHover; // packageimport | |
17 import dwtx.jface.text.AbstractInformationControl; // packageimport | |
18 import dwtx.jface.text.TextUtilities; // packageimport | |
19 import dwtx.jface.text.IInformationControlCreatorExtension; // packageimport | |
20 import dwtx.jface.text.AbstractInformationControlManager; // packageimport | |
21 import dwtx.jface.text.ITextViewerExtension2; // packageimport | |
22 import dwtx.jface.text.IDocumentPartitioner; // packageimport | |
23 import dwtx.jface.text.DefaultIndentLineAutoEditStrategy; // packageimport | |
24 import dwtx.jface.text.ITextSelection; // packageimport | |
25 import dwtx.jface.text.Document; // packageimport | |
26 import dwtx.jface.text.FindReplaceDocumentAdapterContentProposalProvider; // packageimport | |
27 import dwtx.jface.text.ITextListener; // packageimport | |
28 import dwtx.jface.text.BadPartitioningException; // packageimport | |
29 import dwtx.jface.text.ITextViewerExtension5; // packageimport | |
30 import dwtx.jface.text.IDocumentPartitionerExtension3; // packageimport | |
31 import dwtx.jface.text.IUndoManager; // packageimport | |
32 import dwtx.jface.text.ITextHoverExtension2; // packageimport | |
33 import dwtx.jface.text.IRepairableDocument; // packageimport | |
34 import dwtx.jface.text.IRewriteTarget; // packageimport | |
35 import dwtx.jface.text.DefaultPositionUpdater; // packageimport | |
36 import dwtx.jface.text.RewriteSessionEditProcessor; // packageimport | |
37 import dwtx.jface.text.TextViewerHoverManager; // packageimport | |
38 import dwtx.jface.text.DocumentRewriteSession; // packageimport | |
39 import dwtx.jface.text.TextViewer; // packageimport | |
40 import dwtx.jface.text.ITextViewerExtension8; // packageimport | |
41 import dwtx.jface.text.RegExMessages; // packageimport | |
42 import dwtx.jface.text.IDelayedInputChangeProvider; // packageimport | |
43 import dwtx.jface.text.ITextOperationTargetExtension; // packageimport | |
44 import dwtx.jface.text.IWidgetTokenOwner; // packageimport | |
45 import dwtx.jface.text.IViewportListener; // packageimport | |
46 import dwtx.jface.text.GapTextStore; // packageimport | |
47 import dwtx.jface.text.MarkSelection; // packageimport | |
48 import dwtx.jface.text.IDocumentPartitioningListenerExtension; // packageimport | |
49 import dwtx.jface.text.IDocumentAdapterExtension; // packageimport | |
50 import dwtx.jface.text.IInformationControlExtension; // packageimport | |
51 import dwtx.jface.text.IDocumentPartitioningListenerExtension2; // packageimport | |
52 import dwtx.jface.text.DefaultDocumentAdapter; // packageimport | |
53 import dwtx.jface.text.ITextViewerExtension3; // packageimport | |
54 import dwtx.jface.text.IInformationControlCreator; // packageimport | |
55 import dwtx.jface.text.TypedRegion; // packageimport | |
56 import dwtx.jface.text.ISynchronizable; // packageimport | |
57 import dwtx.jface.text.IMarkRegionTarget; // packageimport | |
58 import dwtx.jface.text.TextViewerUndoManager; // packageimport | |
59 import dwtx.jface.text.IRegion; // packageimport | |
60 import dwtx.jface.text.IInformationControlExtension2; // packageimport | |
61 import dwtx.jface.text.IDocumentExtension4; // packageimport | |
62 import dwtx.jface.text.IDocumentExtension2; // packageimport | |
63 import dwtx.jface.text.IDocumentPartitionerExtension2; // packageimport | |
64 import dwtx.jface.text.DefaultInformationControl; // packageimport | |
65 import dwtx.jface.text.IWidgetTokenOwnerExtension; // packageimport | |
66 import dwtx.jface.text.DocumentClone; // packageimport | |
67 import dwtx.jface.text.DefaultUndoManager; // packageimport | |
68 import dwtx.jface.text.IFindReplaceTarget; // packageimport | |
69 import dwtx.jface.text.IAutoEditStrategy; // packageimport | |
70 import dwtx.jface.text.ILineTrackerExtension; // packageimport | |
71 import dwtx.jface.text.IUndoManagerExtension; // packageimport | |
72 import dwtx.jface.text.TextSelection; // packageimport | |
73 import dwtx.jface.text.DefaultAutoIndentStrategy; // packageimport | |
74 import dwtx.jface.text.IAutoIndentStrategy; // packageimport | |
75 import dwtx.jface.text.IPainter; // packageimport | |
76 import dwtx.jface.text.IInformationControl; // packageimport | |
77 import dwtx.jface.text.IInformationControlExtension3; // packageimport | |
78 import dwtx.jface.text.ITextViewerExtension6; // packageimport | |
79 import dwtx.jface.text.IInformationControlExtension4; // packageimport | |
80 import dwtx.jface.text.DefaultLineTracker; // packageimport | |
81 import dwtx.jface.text.IDocumentInformationMappingExtension; // packageimport | |
82 import dwtx.jface.text.IRepairableDocumentExtension; // packageimport | |
83 import dwtx.jface.text.ITextHover; // packageimport | |
84 import dwtx.jface.text.FindReplaceDocumentAdapter; // packageimport | |
85 import dwtx.jface.text.ILineTracker; // packageimport | |
86 import dwtx.jface.text.Line; // packageimport | |
87 import dwtx.jface.text.ITextViewerExtension; // packageimport | |
88 import dwtx.jface.text.IDocumentAdapter; // packageimport | |
89 import dwtx.jface.text.TextEvent; // packageimport | |
90 import dwtx.jface.text.BadLocationException; // packageimport | |
91 import dwtx.jface.text.AbstractDocument; // packageimport | |
92 import dwtx.jface.text.AbstractLineTracker; // packageimport | |
93 import dwtx.jface.text.TreeLineTracker; // packageimport | |
94 import dwtx.jface.text.ITextPresentationListener; // packageimport | |
95 import dwtx.jface.text.Region; // packageimport | |
96 import dwtx.jface.text.ITextViewer; // packageimport | |
97 import dwtx.jface.text.IDocumentInformationMapping; // packageimport | |
98 import dwtx.jface.text.MarginPainter; // packageimport | |
99 import dwtx.jface.text.IPaintPositionManager; // packageimport | |
100 import dwtx.jface.text.IFindReplaceTargetExtension; // packageimport | |
101 import dwtx.jface.text.ISlaveDocumentManagerExtension; // packageimport | |
102 import dwtx.jface.text.ISelectionValidator; // packageimport | |
103 import dwtx.jface.text.IDocumentExtension; // packageimport | |
104 import dwtx.jface.text.PropagatingFontFieldEditor; // packageimport | |
105 import dwtx.jface.text.ConfigurableLineTracker; // packageimport | |
106 import dwtx.jface.text.SlaveDocumentEvent; // packageimport | |
107 import dwtx.jface.text.IDocumentListener; // packageimport | |
108 import dwtx.jface.text.PaintManager; // packageimport | |
109 import dwtx.jface.text.IFindReplaceTargetExtension3; // packageimport | |
110 import dwtx.jface.text.ITextDoubleClickStrategy; // packageimport | |
111 import dwtx.jface.text.IDocumentExtension3; // packageimport | |
112 import dwtx.jface.text.Position; // packageimport | |
113 import dwtx.jface.text.TextMessages; // packageimport | |
114 import dwtx.jface.text.CopyOnWriteTextStore; // packageimport | |
115 import dwtx.jface.text.WhitespaceCharacterPainter; // packageimport | |
116 import dwtx.jface.text.IPositionUpdater; // packageimport | |
117 import dwtx.jface.text.DefaultTextDoubleClickStrategy; // packageimport | |
118 import dwtx.jface.text.ListLineTracker; // packageimport | |
119 import dwtx.jface.text.ITextInputListener; // packageimport | |
120 import dwtx.jface.text.BadPositionCategoryException; // packageimport | |
121 import dwtx.jface.text.IWidgetTokenKeeperExtension; // packageimport | |
122 import dwtx.jface.text.IInputChangedListener; // packageimport | |
123 import dwtx.jface.text.ITextOperationTarget; // packageimport | |
124 import dwtx.jface.text.IDocumentInformationMappingExtension2; // packageimport | |
125 import dwtx.jface.text.ITextViewerExtension7; // packageimport | |
126 import dwtx.jface.text.IInformationControlExtension5; // packageimport | |
127 import dwtx.jface.text.IDocumentRewriteSessionListener; // packageimport | |
128 import dwtx.jface.text.JFaceTextUtil; // packageimport | |
129 import dwtx.jface.text.AbstractReusableInformationControlCreator; // packageimport | |
130 import dwtx.jface.text.TabsToSpacesConverter; // packageimport | |
131 import dwtx.jface.text.CursorLinePainter; // packageimport | |
132 import dwtx.jface.text.ITextHoverExtension; // packageimport | |
133 import dwtx.jface.text.IEventConsumer; // packageimport | |
134 import dwtx.jface.text.IDocument; // packageimport | |
135 import dwtx.jface.text.IWidgetTokenKeeper; // packageimport | |
136 import dwtx.jface.text.DocumentCommand; // packageimport | |
137 import dwtx.jface.text.TypedPosition; // packageimport | |
138 import dwtx.jface.text.IEditingSupportRegistry; // packageimport | |
139 import dwtx.jface.text.IDocumentPartitionerExtension; // packageimport | |
140 import dwtx.jface.text.AbstractHoverInformationControlManager; // packageimport | |
141 import dwtx.jface.text.IEditingSupport; // packageimport | |
142 import dwtx.jface.text.IMarkSelection; // packageimport | |
143 import dwtx.jface.text.ISlaveDocumentManager; // packageimport | |
144 import dwtx.jface.text.DocumentEvent; // packageimport | |
145 import dwtx.jface.text.DocumentPartitioningChangedEvent; // packageimport | |
146 import dwtx.jface.text.ITextStore; // packageimport | |
147 import dwtx.jface.text.JFaceTextMessages; // packageimport | |
148 import dwtx.jface.text.DocumentRewriteSessionEvent; // packageimport | |
149 import dwtx.jface.text.SequentialRewriteTextStore; // packageimport | |
150 import dwtx.jface.text.DocumentRewriteSessionType; // packageimport | |
151 import dwtx.jface.text.TextAttribute; // packageimport | |
152 import dwtx.jface.text.ITextViewerExtension4; // packageimport | |
153 import dwtx.jface.text.ITypedRegion; // packageimport | |
154 | |
129 | 155 import dwt.dwthelper.utils; |
153
f70d9508c95c
Fix java Collection imports
Frank Benoit <benoit@tionex.de>
parents:
140
diff
changeset
|
156 import dwtx.dwtxhelper.Collection; |
162 | 157 import tango.core.Exception; |
153
f70d9508c95c
Fix java Collection imports
Frank Benoit <benoit@tionex.de>
parents:
140
diff
changeset
|
158 |
129 | 159 import dwt.DWT; |
160 import dwt.custom.StyleRange; | |
161 import dwt.custom.StyledText; | |
162 import dwtx.core.runtime.Assert; | |
163 | |
164 | |
165 /** | |
166 * Describes the presentation styles for a section of an indexed text such as a | |
167 * document or string. A text presentation defines a default style for the whole | |
168 * section and in addition style differences for individual subsections. Text | |
169 * presentations can be narrowed down to a particular result window. All methods | |
170 * are result window aware, i.e. ranges outside the result window are always | |
171 * ignored. | |
172 * <p> | |
173 * All iterators provided by a text presentation assume that they enumerate non | |
174 * overlapping, consecutive ranges inside the default range. Thus, all these | |
175 * iterators do not include the default range. The default style range must be | |
176 * explicitly asked for using <code>getDefaultStyleRange</code>. | |
177 */ | |
178 public class TextPresentation { | |
179 | |
180 /** | |
181 * Applies the given presentation to the given text widget. Helper method. | |
182 * | |
183 * @param presentation the style information | |
184 * @param text the widget to which to apply the style information | |
185 * @since 2.0 | |
186 */ | |
187 public static void applyTextPresentation(TextPresentation presentation, StyledText text) { | |
188 | |
189 StyleRange[] ranges= new StyleRange[presentation.getDenumerableRanges()]; | |
190 | |
191 int i= 0; | |
192 Iterator e= presentation.getAllStyleRangeIterator(); | |
193 while (e.hasNext()) | |
134 | 194 ranges[i++]= cast(StyleRange) e.next(); |
129 | 195 |
196 text.setStyleRanges(ranges); | |
197 } | |
198 | |
199 | |
200 | |
201 | |
202 /** | |
203 * Enumerates all the <code>StyleRange</code>s included in the presentation. | |
204 */ | |
205 class FilterIterator : Iterator { | |
206 | |
207 /** The index of the next style range to be enumerated */ | |
208 protected int fIndex; | |
209 /** The upper bound of the indices of style ranges to be enumerated */ | |
210 protected int fLength; | |
211 /** Indicates whether ranges similar to the default range should be enumerated */ | |
212 protected bool fSkipDefaults; | |
213 /** The result window */ | |
214 protected IRegion fWindow; | |
215 | |
216 /** | |
217 * <code>skipDefaults</code> tells the enumeration to skip all those style ranges | |
218 * which define the same style as the presentation's default style range. | |
219 * | |
220 * @param skipDefaults <code>false</code> if ranges similar to the default range should be enumerated | |
221 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
222 protected this(bool skipDefaults) { |
129 | 223 |
224 fSkipDefaults= skipDefaults; | |
225 | |
226 fWindow= fResultWindow; | |
227 fIndex= getFirstIndexInWindow(fWindow); | |
228 fLength= getFirstIndexAfterWindow(fWindow); | |
229 | |
230 if (fSkipDefaults) | |
231 computeIndex(); | |
232 } | |
233 | |
234 /* | |
235 * @see Iterator#next() | |
236 */ | |
237 public Object next() { | |
238 try { | |
134 | 239 StyleRange r= cast(StyleRange) fRanges.get(fIndex++); |
129 | 240 return createWindowRelativeRange(fWindow, r); |
241 } catch (ArrayIndexOutOfBoundsException x) { | |
162 | 242 throw new NoSuchElementException(null); |
129 | 243 } finally { |
244 if (fSkipDefaults) | |
245 computeIndex(); | |
246 } | |
247 } | |
248 | |
249 /* | |
250 * @see Iterator#hasNext() | |
251 */ | |
252 public bool hasNext() { | |
253 return fIndex < fLength; | |
254 } | |
255 | |
256 /* | |
257 * @see Iterator#remove() | |
258 */ | |
259 public void remove() { | |
260 throw new UnsupportedOperationException(); | |
261 } | |
262 | |
263 /** | |
264 * Returns whether the given object should be skipped. | |
265 * | |
266 * @param o the object to be checked | |
267 * @return <code>true</code> if the object should be skipped by the iterator | |
268 */ | |
269 protected bool skip(Object o) { | |
134 | 270 StyleRange r= cast(StyleRange) o; |
129 | 271 return r.similarTo(fDefaultRange); |
272 } | |
273 | |
274 /** | |
275 * Computes the index of the styled range that is the next to be enumerated. | |
276 */ | |
277 protected void computeIndex() { | |
278 while (fIndex < fLength && skip(fRanges.get(fIndex))) | |
279 ++ fIndex; | |
280 } | |
281 } | |
282 | |
283 /** The style information for the range covered by the whole presentation */ | |
284 private StyleRange fDefaultRange; | |
285 /** The member ranges of the presentation */ | |
286 private ArrayList fRanges; | |
287 /** A clipping region against which the presentation can be clipped when asked for results */ | |
288 private IRegion fResultWindow; | |
289 /** | |
290 * The optional extent for this presentation. | |
291 * @since 3.0 | |
292 */ | |
293 private IRegion fExtent; | |
294 | |
295 | |
296 /** | |
297 * Creates a new empty text presentation. | |
298 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
299 public this() { |
129 | 300 fRanges= new ArrayList(50); |
301 } | |
302 | |
303 /** | |
304 * Creates a new empty text presentation. <code>sizeHint</code> tells the | |
305 * expected size of this presentation. | |
306 * | |
307 * @param sizeHint the expected size of this presentation | |
308 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
309 public this(int sizeHint) { |
129 | 310 Assert.isTrue(sizeHint > 0); |
311 fRanges= new ArrayList(sizeHint); | |
312 } | |
313 | |
314 /** | |
315 * Creates a new empty text presentation with the given extent. | |
316 * <code>sizeHint</code> tells the expected size of this presentation. | |
317 * | |
318 * @param extent the extent of the created <code>TextPresentation</code> | |
319 * @param sizeHint the expected size of this presentation | |
320 * @since 3.0 | |
321 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
322 public this(IRegion extent, int sizeHint) { |
129 | 323 this(sizeHint); |
162 | 324 Assert.isNotNull(cast(Object)extent); |
129 | 325 fExtent= extent; |
326 } | |
327 | |
328 /** | |
329 * Sets the result window for this presentation. When dealing with | |
330 * this presentation all ranges which are outside the result window | |
331 * are ignored. For example, the size of the presentation is 0 | |
332 * when there is no range inside the window even if there are ranges | |
333 * outside the window. All methods are aware of the result window. | |
334 * | |
335 * @param resultWindow the result window | |
336 */ | |
337 public void setResultWindow(IRegion resultWindow) { | |
338 fResultWindow= resultWindow; | |
339 } | |
340 | |
341 /** | |
342 * Set the default style range of this presentation. | |
343 * The default style range defines the overall area covered | |
344 * by this presentation and its style information. | |
345 * | |
346 * @param range the range describing the default region | |
347 */ | |
348 public void setDefaultStyleRange(StyleRange range) { | |
349 fDefaultRange= range; | |
350 } | |
351 | |
352 /** | |
353 * Returns this presentation's default style range. The returned <code>StyleRange</code> | |
354 * is relative to the start of the result window. | |
355 * | |
356 * @return this presentation's default style range | |
357 */ | |
358 public StyleRange getDefaultStyleRange() { | |
359 StyleRange range= createWindowRelativeRange(fResultWindow, fDefaultRange); | |
360 if (range is null) | |
361 return null; | |
134 | 362 return cast(StyleRange)range.clone(); |
129 | 363 |
364 } | |
365 | |
366 /** | |
367 * Add the given range to the presentation. The range must be a | |
368 * subrange of the presentation's default range. | |
369 * | |
370 * @param range the range to be added | |
371 */ | |
372 public void addStyleRange(StyleRange range) { | |
373 checkConsistency(range); | |
374 fRanges.add(range); | |
375 } | |
376 | |
377 /** | |
378 * Replaces the given range in this presentation. The range must be a | |
379 * subrange of the presentation's default range. | |
380 * | |
381 * @param range the range to be added | |
382 * @since 3.0 | |
383 */ | |
384 public void replaceStyleRange(StyleRange range) { | |
385 applyStyleRange(range, false); | |
386 } | |
387 | |
388 /** | |
389 * Merges the given range into this presentation. The range must be a | |
390 * subrange of the presentation's default range. | |
391 * | |
392 * @param range the range to be added | |
393 * @since 3.0 | |
394 */ | |
395 public void mergeStyleRange(StyleRange range) { | |
396 applyStyleRange(range, true); | |
397 } | |
398 | |
399 /** | |
400 * Applies the given range to this presentation. The range must be a | |
401 * subrange of the presentation's default range. | |
402 * | |
403 * @param range the range to be added | |
404 * @param merge <code>true</code> if the style should be merged instead of replaced | |
405 * @since 3.0 | |
406 */ | |
407 private void applyStyleRange(StyleRange range, bool merge) { | |
408 if (range.length is 0) | |
409 return; | |
410 | |
411 checkConsistency(range); | |
412 | |
413 int start= range.start; | |
414 int length= range.length; | |
415 int end= start + length; | |
416 | |
417 if (fRanges.size() is 0) { | |
418 StyleRange defaultRange= getDefaultStyleRange(); | |
419 if (defaultRange is null) | |
420 defaultRange= range; | |
421 | |
422 defaultRange.start= start; | |
423 defaultRange.length= length; | |
424 applyStyle(range, defaultRange, merge); | |
425 fRanges.add(defaultRange); | |
426 } else { | |
427 IRegion rangeRegion= new Region(start, length); | |
428 int first= getFirstIndexInWindow(rangeRegion); | |
429 | |
430 if (first is fRanges.size()) { | |
431 StyleRange defaultRange= getDefaultStyleRange(); | |
432 if (defaultRange is null) | |
433 defaultRange= range; | |
434 defaultRange.start= start; | |
435 defaultRange.length= length; | |
436 applyStyle(range, defaultRange, merge); | |
437 fRanges.add(defaultRange); | |
438 return; | |
439 } | |
440 | |
441 int last= getFirstIndexAfterWindow(rangeRegion); | |
442 for (int i= first; i < last && length > 0; i++) { | |
443 | |
134 | 444 StyleRange current= cast(StyleRange)fRanges.get(i); |
129 | 445 int currentStart= current.start; |
446 int currentEnd= currentStart + current.length; | |
447 | |
448 if (end <= currentStart) { | |
449 fRanges.add(i, range); | |
450 return; | |
451 } | |
452 | |
453 if (start >= currentEnd) | |
454 continue; | |
455 | |
456 StyleRange currentCopy= null; | |
457 if (end < currentEnd) | |
134 | 458 currentCopy= cast(StyleRange)current.clone(); |
129 | 459 |
460 if (start < currentStart) { | |
461 // Apply style to new default range and add it | |
462 StyleRange defaultRange= getDefaultStyleRange(); | |
463 if (defaultRange is null) | |
464 defaultRange= new StyleRange(); | |
465 | |
466 defaultRange.start= start; | |
467 defaultRange.length= currentStart - start; | |
468 applyStyle(range, defaultRange, merge); | |
469 fRanges.add(i, defaultRange); | |
470 i++; last++; | |
471 | |
472 | |
473 // Apply style to first part of current range | |
474 current.length= Math.min(end, currentEnd) - currentStart; | |
475 applyStyle(range, current, merge); | |
476 } | |
477 | |
478 if (start >= currentStart) { | |
479 // Shorten the current range | |
480 current.length= start - currentStart; | |
481 | |
482 // Apply the style to the rest of the current range and add it | |
483 if (current.length > 0) { | |
134 | 484 current= cast(StyleRange)current.clone(); |
129 | 485 i++; last++; |
486 fRanges.add(i, current); | |
487 } | |
488 applyStyle(range, current, merge); | |
489 current.start= start; | |
490 current.length= Math.min(end, currentEnd) - start; | |
491 } | |
492 | |
493 if (end < currentEnd) { | |
494 // Add rest of current range | |
495 currentCopy.start= end; | |
496 currentCopy.length= currentEnd - end; | |
497 i++; last++; | |
498 fRanges.add(i, currentCopy); | |
499 } | |
500 | |
501 // Update range | |
502 range.start= currentEnd; | |
503 range.length= Math.max(end - currentEnd, 0); | |
504 start= range.start; | |
505 length= range.length; | |
506 } | |
507 if (length > 0) { | |
508 // Apply style to new default range and add it | |
509 StyleRange defaultRange= getDefaultStyleRange(); | |
510 if (defaultRange is null) | |
511 defaultRange= range; | |
512 defaultRange.start= start; | |
513 defaultRange.length= end - start; | |
514 applyStyle(range, defaultRange, merge); | |
515 fRanges.add(last, defaultRange); | |
516 } | |
517 } | |
518 } | |
519 | |
520 /** | |
521 * Replaces the given ranges in this presentation. Each range must be a | |
522 * subrange of the presentation's default range. The ranges must be ordered | |
523 * by increasing offset and must not overlap (but may be adjacent). | |
524 * | |
525 * @param ranges the ranges to be added | |
526 * @since 3.0 | |
527 */ | |
528 public void replaceStyleRanges(StyleRange[] ranges) { | |
529 applyStyleRanges(ranges, false); | |
530 } | |
531 | |
532 /** | |
533 * Merges the given ranges into this presentation. Each range must be a | |
534 * subrange of the presentation's default range. The ranges must be ordered | |
535 * by increasing offset and must not overlap (but may be adjacent). | |
536 * | |
537 * @param ranges the ranges to be added | |
538 * @since 3.0 | |
539 */ | |
540 public void mergeStyleRanges(StyleRange[] ranges) { | |
541 applyStyleRanges(ranges, true); | |
542 } | |
543 | |
544 /** | |
545 * Applies the given ranges to this presentation. Each range must be a | |
546 * subrange of the presentation's default range. The ranges must be ordered | |
547 * by increasing offset and must not overlap (but may be adjacent). | |
548 * | |
549 * @param ranges the ranges to be added | |
550 * @param merge <code>true</code> if the style should be merged instead of replaced | |
551 * @since 3.0 | |
552 */ | |
553 private void applyStyleRanges(StyleRange[] ranges, bool merge) { | |
554 int j= 0; | |
555 ArrayList oldRanges= fRanges; | |
556 ArrayList newRanges= new ArrayList(2*ranges.length + oldRanges.size()); | |
557 for (int i= 0, n= ranges.length; i < n; i++) { | |
558 StyleRange range= ranges[i]; | |
559 fRanges= oldRanges; // for getFirstIndexAfterWindow(...) | |
560 for (int m= getFirstIndexAfterWindow(new Region(range.start, range.length)); j < m; j++) | |
561 newRanges.add(oldRanges.get(j)); | |
562 fRanges= newRanges; // for mergeStyleRange(...) | |
563 applyStyleRange(range, merge); | |
564 } | |
565 for (int m= oldRanges.size(); j < m; j++) | |
566 newRanges.add(oldRanges.get(j)); | |
567 fRanges= newRanges; | |
568 } | |
569 | |
570 /** | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
571 * Applies the template_'s style to the target. |
129 | 572 * |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
573 * @param template_ the style range to be used as template_ |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
574 * @param target the style range to which to apply the template_ |
129 | 575 * @param merge <code>true</code> if the style should be merged instead of replaced |
576 * @since 3.0 | |
577 */ | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
578 private void applyStyle(StyleRange template_, StyleRange target, bool merge) { |
129 | 579 if (merge) { |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
580 if (template_.font !is null) |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
581 target.font= template_.font; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
582 target.fontStyle|= template_.fontStyle; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
583 |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
584 if (template_.metrics !is null) |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
585 target.metrics= template_.metrics; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
586 |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
587 if (template_.foreground !is null) |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
588 target.foreground= template_.foreground; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
589 if (template_.background !is null) |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
590 target.background= template_.background; |
129 | 591 |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
592 target.strikeout|= template_.strikeout; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
593 if (template_.strikeoutColor !is null) |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
594 target.strikeoutColor= template_.strikeoutColor; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
595 |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
596 target.underline|= template_.underline; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
597 if (template_.underlineStyle !is DWT.NONE) |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
598 target.underlineStyle= template_.underlineStyle; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
599 if (template_.underlineColor !is null) |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
600 target.underlineColor= template_.underlineColor; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
601 |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
602 if (template_.borderStyle !is DWT.NONE) |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
603 target.borderStyle= template_.borderStyle; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
604 if (template_.borderColor !is null) |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
605 target.borderColor= template_.borderColor; |
129 | 606 |
607 } else { | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
608 target.font= template_.font; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
609 target.fontStyle= template_.fontStyle; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
610 target.metrics= template_.metrics; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
611 target.foreground= template_.foreground; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
612 target.background= template_.background; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
613 target.strikeout= template_.strikeout; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
614 target.strikeoutColor= template_.strikeoutColor; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
615 target.underline= template_.underline; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
616 target.underlineStyle= template_.underlineStyle; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
617 target.underlineColor= template_.underlineColor; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
618 target.borderStyle= template_.borderStyle; |
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
134
diff
changeset
|
619 target.borderColor= template_.borderColor; |
129 | 620 } |
621 } | |
622 | |
623 /** | |
624 * Checks whether the given range is a subrange of the presentation's | |
625 * default style range. | |
626 * | |
627 * @param range the range to be checked | |
628 * @exception IllegalArgumentException if range is not a subrange of the presentation's default range | |
629 */ | |
630 private void checkConsistency(StyleRange range) { | |
631 | |
632 if (range is null) | |
162 | 633 throw new IllegalArgumentException(null); |
129 | 634 |
635 if (fDefaultRange !is null) { | |
636 | |
637 if (range.start < fDefaultRange.start) | |
638 range.start= fDefaultRange.start; | |
639 | |
640 int defaultEnd= fDefaultRange.start + fDefaultRange.length; | |
641 int end= range.start + range.length; | |
642 if (end > defaultEnd) | |
643 range.length -= (end - defaultEnd); | |
644 } | |
645 } | |
646 | |
647 /** | |
648 * Returns the index of the first range which overlaps with the | |
649 * specified window. | |
650 * | |
651 * @param window the window to be used for searching | |
652 * @return the index of the first range overlapping with the window | |
653 */ | |
654 private int getFirstIndexInWindow(IRegion window) { | |
655 if (window !is null) { | |
656 int start= window.getOffset(); | |
657 int i= -1, j= fRanges.size(); | |
658 while (j - i > 1) { | |
659 int k= (i + j) >> 1; | |
134 | 660 StyleRange r= cast(StyleRange) fRanges.get(k); |
129 | 661 if (r.start + r.length > start) |
662 j= k; | |
663 else | |
664 i= k; | |
665 } | |
666 return j; | |
667 } | |
668 return 0; | |
669 } | |
670 | |
671 /** | |
672 * Returns the index of the first range which comes after the specified window and does | |
673 * not overlap with this window. | |
674 * | |
675 * @param window the window to be used for searching | |
676 * @return the index of the first range behind the window and not overlapping with the window | |
677 */ | |
678 private int getFirstIndexAfterWindow(IRegion window) { | |
679 if (window !is null) { | |
680 int end= window.getOffset() + window.getLength(); | |
681 int i= -1, j= fRanges.size(); | |
682 while (j - i > 1) { | |
683 int k= (i + j) >> 1; | |
134 | 684 StyleRange r= cast(StyleRange) fRanges.get(k); |
129 | 685 if (r.start < end) |
686 i= k; | |
687 else | |
688 j= k; | |
689 } | |
690 return j; | |
691 } | |
692 return fRanges.size(); | |
693 } | |
694 | |
695 /** | |
696 * Returns a style range which is relative to the specified window and | |
697 * appropriately clipped if necessary. The original style range is not | |
698 * modified. | |
699 * | |
700 * @param window the reference window | |
701 * @param range the absolute range | |
702 * @return the window relative range based on the absolute range | |
703 */ | |
704 private StyleRange createWindowRelativeRange(IRegion window, StyleRange range) { | |
705 if (window is null || range is null) | |
706 return range; | |
707 | |
708 int start= range.start - window.getOffset(); | |
709 if (start < 0) | |
710 start= 0; | |
711 | |
712 int rangeEnd= range.start + range.length; | |
713 int windowEnd= window.getOffset() + window.getLength(); | |
714 int end= (rangeEnd > windowEnd ? windowEnd : rangeEnd); | |
715 end -= window.getOffset(); | |
716 | |
134 | 717 StyleRange newRange= cast(StyleRange) range.clone(); |
129 | 718 newRange.start= start; |
719 newRange.length= end - start; | |
720 return newRange; | |
721 } | |
722 | |
723 /** | |
724 * Returns the region which is relative to the specified window and | |
725 * appropriately clipped if necessary. | |
726 * | |
727 * @param coverage the absolute coverage | |
728 * @return the window relative region based on the absolute coverage | |
729 * @since 3.0 | |
730 */ | |
731 private IRegion createWindowRelativeRegion(IRegion coverage) { | |
732 if (fResultWindow is null || coverage is null) | |
733 return coverage; | |
734 | |
735 int start= coverage.getOffset() - fResultWindow.getOffset(); | |
736 if (start < 0) | |
737 start= 0; | |
738 | |
739 int rangeEnd= coverage.getOffset() + coverage.getLength(); | |
740 int windowEnd= fResultWindow.getOffset() + fResultWindow.getLength(); | |
741 int end= (rangeEnd > windowEnd ? windowEnd : rangeEnd); | |
742 end -= fResultWindow.getOffset(); | |
743 | |
744 return new Region(start, end - start); | |
745 } | |
746 | |
747 /** | |
748 * Returns an iterator which enumerates all style ranged which define a style | |
749 * different from the presentation's default style range. The default style range | |
750 * is not enumerated. | |
751 * | |
752 * @return a style range iterator | |
753 */ | |
754 public Iterator getNonDefaultStyleRangeIterator() { | |
755 return new FilterIterator(fDefaultRange !is null); | |
756 } | |
757 | |
758 /** | |
759 * Returns an iterator which enumerates all style ranges of this presentation | |
760 * except the default style range. The returned <code>StyleRange</code>s | |
761 * are relative to the start of the presentation's result window. | |
762 * | |
763 * @return a style range iterator | |
764 */ | |
765 public Iterator getAllStyleRangeIterator() { | |
766 return new FilterIterator(false); | |
767 } | |
768 | |
769 /** | |
770 * Returns whether this collection contains any style range including | |
771 * the default style range. | |
772 * | |
773 * @return <code>true</code> if there is no style range in this presentation | |
774 */ | |
775 public bool isEmpty() { | |
776 return (fDefaultRange is null && getDenumerableRanges() is 0); | |
777 } | |
778 | |
779 /** | |
780 * Returns the number of style ranges in the presentation not counting the default | |
781 * style range. | |
782 * | |
783 * @return the number of style ranges in the presentation excluding the default style range | |
784 */ | |
785 public int getDenumerableRanges() { | |
786 int size= getFirstIndexAfterWindow(fResultWindow) - getFirstIndexInWindow(fResultWindow); | |
787 return (size < 0 ? 0 : size); | |
788 } | |
789 | |
790 /** | |
791 * Returns the style range with the smallest offset ignoring the default style range or null | |
792 * if the presentation is empty. | |
793 * | |
794 * @return the style range with the smallest offset different from the default style range | |
795 */ | |
796 public StyleRange getFirstStyleRange() { | |
797 try { | |
798 | |
134 | 799 StyleRange range= cast(StyleRange) fRanges.get(getFirstIndexInWindow(fResultWindow)); |
129 | 800 return createWindowRelativeRange(fResultWindow, range); |
801 | |
802 } catch (NoSuchElementException x) { | |
803 } catch (IndexOutOfBoundsException x) { | |
804 } | |
805 | |
806 return null; | |
807 } | |
808 | |
809 /** | |
810 * Returns the style range with the highest offset ignoring the default style range. | |
811 * | |
812 * @return the style range with the highest offset different from the default style range | |
813 */ | |
814 public StyleRange getLastStyleRange() { | |
815 try { | |
816 | |
134 | 817 StyleRange range= cast(StyleRange) fRanges.get(getFirstIndexAfterWindow(fResultWindow) - 1); |
129 | 818 return createWindowRelativeRange(fResultWindow, range); |
819 | |
820 } catch (NoSuchElementException x) { | |
821 return null; | |
822 } catch (IndexOutOfBoundsException x) { | |
823 return null; | |
824 } | |
825 } | |
826 | |
827 /** | |
828 * Returns the coverage of this presentation as clipped by the presentation's | |
829 * result window. | |
830 * | |
831 * @return the coverage of this presentation | |
832 */ | |
833 public IRegion getCoverage() { | |
834 | |
835 if (fDefaultRange !is null) { | |
836 StyleRange range= getDefaultStyleRange(); | |
837 return new Region(range.start, range.length); | |
838 } | |
839 | |
840 StyleRange first= getFirstStyleRange(); | |
841 StyleRange last= getLastStyleRange(); | |
842 | |
843 if (first is null || last is null) | |
844 return null; | |
845 | |
846 return new Region(first.start, last.start - first. start + last.length); | |
847 } | |
848 | |
849 /** | |
850 * Returns the extent of this presentation clipped by the | |
851 * presentation's result window. | |
852 * | |
853 * @return the clipped extent | |
854 * @since 3.0 | |
855 */ | |
856 public IRegion getExtent() { | |
857 if (fExtent !is null) | |
858 return createWindowRelativeRegion(fExtent); | |
859 return getCoverage(); | |
860 } | |
861 | |
862 /** | |
863 * Clears this presentation by resetting all applied changes. | |
864 * @since 2.0 | |
865 */ | |
866 public void clear() { | |
867 fDefaultRange= null; | |
868 fResultWindow= null; | |
869 fRanges.clear(); | |
870 } | |
871 | |
872 | |
873 } |