Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 175181 Details for
Bug 119384
[api] Add new API to support memory efficient StyleRange support in StyledText
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Extended version of TextPresentation
TdTextPresentation.java (text/x-java-source), 39.84 KB, created by
Bill Fenlason
on 2010-07-25 14:40:06 EDT
(
hide
)
Description:
Extended version of TextPresentation
Filename:
MIME Type:
Creator:
Bill Fenlason
Created:
2010-07-25 14:40:06 EDT
Size:
39.84 KB
patch
obsolete
>/******************************************************************************* > * Copyright (c) 2000, 2008 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * > * Contributors: > * IBM Corporation - initial API and implementation > *******************************************************************************/ >/// All new or modified source code herein is made available under the terms >/// of the Eclipse Public License v1.0 by William Fenlason, July 25, 2010 > >/// This is a full replacement of TextPresentation, implemented as an extension > >/// Design notes (see bug 119384) >/// >/// All descriptive information is in line comments beginning with /// >/// which may be removed as desired. >/// >/// This is a revised version of the TextPresentation to take advantage of the >/// new (Eclipse 3.3) styled text widget interface. It is intended to be >/// fully compatible with the current TextPresentation implementation, and >/// no existing API is intentionally broken. >/// >/// The StyleRange object is problematic when it comes to performance and >/// storage usage. Each range object includes an offset, length and >/// style, and there are typically several ranges for each line in a file. >/// For very large files this can be a performance problem. The performance >/// improvement is caused by preventing the creation of a StyleRange object >/// (or other unnecessary objects) for each field or token. >/// >/// When this was recognized, the StyledText widget provided an >/// interface in which separate arrays of offset/length pairs and model >/// style ranges are passed to the widget for updating. >/// >/// This implementation allows for the use of that interface rather than >/// creating separate style range objects for each field in the file. >/// >/// In order to do this, a new version of addStyleRange() is provided to >/// allow the adding of a model (length zero) style range. >/// >/// The offset, length and model style range are separate arguments >/// rather than a single StyleRange object. Corresponding API for >/// range replacement and merging is provided. >/// >/// Three new iterators are provided, which return the model StyleRange, >/// range starting offset and range length respectively. >/// >/// The use of existing API including the current iterators to return the >/// sequence of style range objects is still allowed (but is sub optimal). > >package viewer; > >import java.util.ArrayList; >import java.util.Iterator; >import java.util.NoSuchElementException; > >import org.eclipse.swt.SWT; >import org.eclipse.swt.custom.StyleRange; >import org.eclipse.swt.custom.StyledText; > >import org.eclipse.core.runtime.Assert; > >/// Added >import java.lang.Integer; >import org.eclipse.jface.text.IRegion; >import org.eclipse.jface.text.Region; >import org.eclipse.jface.text.TextPresentation; >/// End additions > > >/** > * Describes the presentation styles for a section of an indexed text such as a > * document or string. A text presentation defines a default style for the whole > * section and in addition style differences for individual subsections. Text > * presentations can be narrowed down to a particular result window. All methods > * are result window aware, i.e. ranges outside the result window are always > * ignored. > * <p> > * All iterators provided by a text presentation assume that they enumerate non > * overlapping, consecutive ranges inside the default range. Thus, all these > * iterators do not include the default range. The default style range must be > * explicitly asked for using <code>getDefaultStyleRange</code>. > */ >/// Modified class name >public class TdTextPresentation extends TextPresentation { >/// End modification > > /** > * Applies the given presentation to the given text widget. Helper method. > * > * @param presentation the style information > * @param text the widget to which to apply the style information > * @since 2.0 > */ >/// Modified class name in argument > public static void applyTextPresentation(TdTextPresentation presentation, StyledText text) { >/// End modification > >/// Modified to use the new StyledText API. > >/// Similar code is suggested for callers (such as the TextViewer) that use the >/// AllStyleRangeIterator. > >/// Note that when this interface is used, the StyledText widget first clears >/// the full range of styles to a default style and then the ranges are applied. >/// As StyledText does not provide a way to specify the default style, the >/// default style processing in the TextPresentation is of limited use. > >/// Callers that use the NonDefaultStyleRangeIterator should be modified >/// as necessary. > > int size = presentation.getDenumerableRanges(); > if (size == 0) return; > > StyleRange[] ranges= new StyleRange[size]; > int[] bounds = new int[size *2]; > >/// Note that the OffsetIterator and LengthIterator include a nextInt() >/// method which returns the next integer value, not an Integer object. >/// include "package".TdTextPresentation.OffsetIterator; >/// include "package".TdTextPresentation.LengthIterator; > > Iterator e1 = presentation.getStyleRangeModelIterator(); > OffsetIterator e2 = presentation.getStyleRangeOffsetIterator(); > LengthIterator e3 = presentation.getStyleRangeLengthIterator(); > > for (int index = 0; e1.hasNext(); index += 1) { > ranges[index] = (StyleRange) e1.next(); > bounds[index *2] = e2.nextInt(); > bounds[1 + index *2] = e3.nextInt(); > } > > int start = bounds[0]; > int length = bounds[(size*2) -2] + bounds[(size *2) -1]; > > text.setStyleRanges(start, length, bounds, ranges); >/// End modification > > } > > > > > /** > * Enumerates all the <code>StyleRange</code>s included in the presentation. > */ > class FilterIterator implements Iterator { > > /** The index of the next style range to be enumerated */ > protected int fIndex; > /** The upper bound of the indices of style ranges to be enumerated */ > protected int fLength; > /** Indicates whether ranges similar to the default range should be enumerated */ > protected boolean fSkipDefaults; > /** The result window */ > protected IRegion fWindow; > > /** > * <code>skipDefaults</code> tells the enumeration to skip all those style ranges > * which define the same style as the presentation's default style range. > * > * @param skipDefaults <code>false</code> if ranges similar to the default range should be enumerated > */ > protected FilterIterator(boolean skipDefaults) { > > fSkipDefaults= skipDefaults; > > fWindow= fResultWindow; > fIndex= getFirstIndexInWindow(fWindow); > fLength= getFirstIndexAfterWindow(fWindow); > > if (fSkipDefaults) > computeIndex(); > } > > /* > * @see Iterator#next() > */ > public Object next() { > try { > StyleRange r= (StyleRange) fRanges.get(fIndex++); > >/// Modified to handle model style ranges > return createWindowRelativeRange(fWindow, r > , fRangeOffsets[fIndex -1], fRangeLengths[fIndex -1]); >/// End modification > > } catch (ArrayIndexOutOfBoundsException x) { > throw new NoSuchElementException(); > } finally { > if (fSkipDefaults) > computeIndex(); > } > } > > /* > * @see Iterator#hasNext() > */ > public boolean hasNext() { > return fIndex < fLength; > } > > /* > * @see Iterator#remove() > */ > public void remove() { > throw new UnsupportedOperationException(); > } > > /** > * Returns whether the given object should be skipped. > * > * @param o the object to be checked > * @return <code>true</code> if the object should be skipped by the iterator > */ > protected boolean skip(Object o) { > StyleRange r= (StyleRange) o; > return r.similarTo(fDefaultRange); > } > > /** > * Computes the index of the styled range that is the next to be enumerated. > */ > protected void computeIndex() { > while (fIndex < fLength && skip(fRanges.get(fIndex))) > ++ fIndex; > } > } > > /** The style information for the range covered by the whole presentation */ > private StyleRange fDefaultRange; > /** The member ranges of the presentation */ > private ArrayList fRanges; > /** A clipping region against which the presentation can be clipped when asked for results */ > private IRegion fResultWindow; > /** > * The optional extent for this presentation. > * @since 3.0 > */ > private IRegion fExtent; > > > /** > * Creates a new empty text presentation. > */ >/// Modified class name > public TdTextPresentation() { >/// End modification > >/// Modified to use a size hint of 50 > this(50); >/// End modification > > } > > /** > * Creates a new empty text presentation. <code>sizeHint</code> tells the > * expected size of this presentation. > * > * @param sizeHint the expected size of this presentation > */ >/// Modified class name > public TdTextPresentation(int sizeHint) { >/// End modification > >/// Modified to create minimum size of extended (replaced) superclass > super(1); >/// End modification > > Assert.isTrue(sizeHint > 0); > fRanges= new ArrayList(sizeHint); > >/// Modified to also allocate the offsets and lengths arrays > fRangeOffsets = new int[sizeHint]; > fRangeLengths = new int[sizeHint]; >// End modification > > } > > /** > * Creates a new empty text presentation with the given extent. > * <code>sizeHint</code> tells the expected size of this presentation. > * > * @param extent the extent of the created <code>TextPresentation</code> > * @param sizeHint the expected size of this presentation > * @since 3.0 > */ >/// Modified class name > public TdTextPresentation(IRegion extent, int sizeHint) { >/// End modification > > this(sizeHint); > Assert.isNotNull(extent); > fExtent= extent; > } > > /** > * Sets the result window for this presentation. When dealing with > * this presentation all ranges which are outside the result window > * are ignored. For example, the size of the presentation is 0 > * when there is no range inside the window even if there are ranges > * outside the window. All methods are aware of the result window. > * > * @param resultWindow the result window > */ > public void setResultWindow(IRegion resultWindow) { > fResultWindow= resultWindow; > } > > /** > * Set the default style range of this presentation. > * The default style range defines the overall area covered > * by this presentation and its style information. > * > * @param range the range describing the default region > */ > public void setDefaultStyleRange(StyleRange range) { > fDefaultRange= range; > } > > /** > * Returns this presentation's default style range. The returned <code>StyleRange</code> > * is relative to the start of the result window. > * > * @return this presentation's default style range > */ > public StyleRange getDefaultStyleRange() { > StyleRange range= createWindowRelativeRange(fResultWindow, fDefaultRange); > if (range == null) > return null; > return (StyleRange)range.clone(); > > } > > /** > * Add the given range to the presentation. The range must be a > * subrange of the presentation's default range. > * > * @param range the range to be added > */ > public void addStyleRange(StyleRange range) { > >/// Modified to apply the new range rather than appending it to the range >/// array list. That allows out of order additions to be processed >/// correctly rather than corrupting the array list. (see bug 138861) > >/// Note that this makes add and replace equivalent. > >/// Also note that both forms of applyStyleRange (with or without the >/// offset and length) may be used at any time. > applyStyleRange(range, false); >/// End modification > > } > > /** > * Replaces the given range in this presentation. The range must be a > * subrange of the presentation's default range. > * > * @param range the range to be added > * @since 3.0 > */ > public void replaceStyleRange(StyleRange range) { > applyStyleRange(range, false); > } > > /** > * Merges the given range into this presentation. The range must be a > * subrange of the presentation's default range. > * > * @param range the range to be added > * @since 3.0 > */ > public void mergeStyleRange(StyleRange range) { > applyStyleRange(range, true); > } > > /** > * Applies the given range to this presentation. The range must be a > * subrange of the presentation's default range. > * > * @param range the range to be added > * @param merge <code>true</code> if the style should be merged instead of replaced > * @since 3.0 > */ > private void applyStyleRange(StyleRange range, boolean merge) { > >/// Modified to use a new method with an explicit offset and length. > if (range == null) > throw new IllegalArgumentException(); > > if (range.length == 0) > return; > > applyStyleRange(range, range.start, range.length, merge); >/// End modification > > } > > > /** > * Replaces the given ranges in this presentation. Each range must be a > * subrange of the presentation's default range. The ranges must be ordered > * by increasing offset and must not overlap (but may be adjacent). > * > * @param ranges the ranges to be added > * @since 3.0 > */ > public void replaceStyleRanges(StyleRange[] ranges) { > applyStyleRanges(ranges, false); > } > > /** > * Merges the given ranges into this presentation. Each range must be a > * subrange of the presentation's default range. The ranges must be ordered > * by increasing offset and must not overlap (but may be adjacent). > * > * @param ranges the ranges to be added > * @since 3.0 > */ > public void mergeStyleRanges(StyleRange[] ranges) { > applyStyleRanges(ranges, true); > } > > /** > * Applies the given ranges to this presentation. Each range must be a > * subrange of the presentation's default range. The ranges must be ordered > * by increasing offset and must not overlap (but may be adjacent). > * > * @param ranges the ranges to be added > * @param merge <code>true</code> if the style should be merged instead of replaced > * @since 3.0 > */ > private void applyStyleRanges(StyleRange[] ranges, boolean merge) { > >/// Modified to simplify logic > for (int i= 0, n= ranges.length; i < n; i++) { > applyStyleRange(ranges[i], merge); > } >/// End modification > > } > > /** > * Applies the template's style to the target. > * > * @param template the style range to be used as template > * @param target the style range to which to apply the template > * @param merge <code>true</code> if the style should be merged instead of replaced > * @since 3.0 > */ > private void applyStyle(StyleRange template, StyleRange target, boolean merge) { > if (merge) { > if (template.font != null) > target.font= template.font; > target.fontStyle|= template.fontStyle; > > if (template.metrics != null) > target.metrics= template.metrics; > > if (template.foreground != null || template.underlineStyle == SWT.UNDERLINE_LINK) > target.foreground= template.foreground; > if (template.background != null) > target.background= template.background; > > target.strikeout|= template.strikeout; > if (template.strikeoutColor != null) > target.strikeoutColor= template.strikeoutColor; > > target.underline|= template.underline; > if (template.underlineStyle != SWT.NONE && target.underlineStyle != SWT.UNDERLINE_LINK) > target.underlineStyle= template.underlineStyle; > > if (template.underlineColor != null) > target.underlineColor= template.underlineColor; > > if (template.borderStyle != SWT.NONE) > target.borderStyle= template.borderStyle; > if (template.borderColor != null) > target.borderColor= template.borderColor; > > } else { > target.font= template.font; > target.fontStyle= template.fontStyle; > target.metrics= template.metrics; > target.foreground= template.foreground; > target.background= template.background; > target.strikeout= template.strikeout; > target.strikeoutColor= template.strikeoutColor; > target.underline= template.underline; > target.underlineStyle= template.underlineStyle; > target.underlineColor= template.underlineColor; > target.borderStyle= template.borderStyle; > target.borderColor= template.borderColor; > } > } > >/// Modified checkConsistency version which uses explicit offset and length. > >/// The original API documentation specified that an exception is thrown if >/// the range is not a subset of the default range (if defined), but did not >/// do that. > >/// This version enforces the API rather than forcing the range to fit. > /** > * Checks whether the given range is a subrange of the presentation's > * default style range. > * > * @param range the range to be checked > * @param start the starting offset > * @param length the StyleRange length > * > * @exception IllegalArgumentException if range is not a subrange of the presentation's default range > */ > private void checkConsistency(StyleRange range, int start, int length) { > > if (range == null || start < 0 || length <= 0) > throw new IllegalArgumentException(); > > if (fDefaultRange != null) { > > if (start < fDefaultRange.start) > >/// Modified to match API specification >/// range.start= fDefaultRange.start; > throw new IllegalArgumentException(); >/// End modification > > int defaultEnd= start + length; > int end= start + length; > if (end > defaultEnd) > >/// Modified to match API specification >/// range.length -= (end - defaultEnd); > throw new IllegalArgumentException(); >/// End modification > > } > } > > /** > * Returns the index of the first range which overlaps with the > * specified window. > * > * @param window the window to be used for searching > * @return the index of the first range overlapping with the window > */ > private int getFirstIndexInWindow(IRegion window) { > if (window != null) { > >/// Modified to use modified version with explicit offset > return getFirstIndexAtOffset(window.getOffset()); >/// End modification > > } > return 0; > } > >/// Modified method which uses explicit offset to find index > /** > * Returns the index of the first range which overlaps with the > * specified offset. > * > * @param start the offset to be used for searching > * @return the index of the first range overlapping with the offset > */ > private int getFirstIndexAtOffset(int start) { > int i= -1, j= fRanges.size(); > while (j - i > 1) { > int k= (i + j) >> 1; > >/// Test using explicit offset and lengths, not style range > if (fRangeOffsets[k] + fRangeLengths[k] > start) > j= k; > else > i= k; > } > return j; > } > > /** > * Returns the index of the first range which comes after the specified window and does > * not overlap with this window. > * > * @param window the window to be used for searching > * @return the index of the first range behind the window and not overlapping with the window > */ > private int getFirstIndexAfterWindow(IRegion window) { > if (window != null) { > >/// Modified to use modified version with explicit offset > return getFirstIndexAfterOffset(window.getOffset() > + window.getLength()); >/// End modification > > } > return fRanges.size(); > } > >/// Modified version which uses explicit offset to find ending index > /** > * Returns the index of the first range which comes after the specified offset. > * > * @param end the offset to be used for searching > * @return the index of the first range following the ending offset > */ > private int getFirstIndexAfterOffset(int end) { > int i= -1, j= fRanges.size(); > while (j - i > 1) { > int k= (i + j) >> 1; > > /// Test from explicit offset array, not style range > if (fRangeOffsets[k] < end) > i= k; > else > j= k; > } > return j; > } > > /** > * Returns a style range which is relative to the specified window and > * appropriately clipped if necessary. The original style range is not > * modified. > * > * @param window the reference window > * @param range the absolute range > * @return the window relative range based on the absolute range > */ > private StyleRange createWindowRelativeRange(IRegion window, StyleRange range) { > >/// Modified to use modified version with explicit offset and length > if (range == null) > return range; > > return createWindowRelativeRange(window, range, range.start, range.length); >/// End modification > > } > >/// Modified version which uses explicit offset and length > /** > * Returns a style range which is relative to the specified window and > * appropriately clipped if necessary. The original style range is not > * modified. > * > * @param window the reference window > * @param range the absolute range > * @param offset the offset the range > * @param length the length the range > * @return the window relative range based on the absolute range > */ > private StyleRange createWindowRelativeRange(IRegion window, StyleRange range, int offset, int length) { >/// Modified to handle model (zero length) StyleRanges > if (range == null) > return range; > > int start = offset; > int end = offset + length; > > if (window != null) { > start = offset - window.getOffset(); > if (start < 0) > start= 0; > > int rangeEnd = offset + length; > int windowEnd= window.getOffset() + window.getLength(); > end= (rangeEnd > windowEnd ? windowEnd : rangeEnd); > end -= window.getOffset(); > } > > if (start == range.start && end - start == range.length) return range; >/// End modification > > StyleRange newRange= (StyleRange) range.clone(); > newRange.start= start; > newRange.length= end - start; > return newRange; > } > > /** > * Returns the region which is relative to the specified window and > * appropriately clipped if necessary. > * > * @param coverage the absolute coverage > * @return the window relative region based on the absolute coverage > * @since 3.0 > */ > private IRegion createWindowRelativeRegion(IRegion coverage) { > if (fResultWindow == null || coverage == null) > return coverage; > > int start= coverage.getOffset() - fResultWindow.getOffset(); > if (start < 0) > start= 0; > > int rangeEnd= coverage.getOffset() + coverage.getLength(); > int windowEnd= fResultWindow.getOffset() + fResultWindow.getLength(); > int end= (rangeEnd > windowEnd ? windowEnd : rangeEnd); > end -= fResultWindow.getOffset(); > >/// Modified to avoid creating an unnecessary Region > if (start == coverage.getOffset() && end - start == coverage.getLength()) > return coverage; >/// End modification > > return new Region(start, end - start); > } > > /** > * Returns an iterator which enumerates all style ranged which define a style > * different from the presentation's default style range. The default style range > * is not enumerated. > * > * @return a style range iterator > */ > public Iterator getNonDefaultStyleRangeIterator() { > return new FilterIterator(fDefaultRange != null); > } > > /** > * Returns an iterator which enumerates all style ranges of this presentation > * except the default style range. The returned <code>StyleRange</code>s > * are relative to the start of the presentation's result window. > * > * @return a style range iterator > */ > public Iterator getAllStyleRangeIterator() { > return new FilterIterator(false); > } > > /** > * Returns whether this collection contains any style range including > * the default style range. > * > * @return <code>true</code> if there is no style range in this presentation > */ > public boolean isEmpty() { > return (fDefaultRange == null && getDenumerableRanges() == 0); > } > > /** > * Returns the number of style ranges in the presentation not counting the default > * style range. > * > * @return the number of style ranges in the presentation excluding the default style range > */ > public int getDenumerableRanges() { > int size= getFirstIndexAfterWindow(fResultWindow) - getFirstIndexInWindow(fResultWindow); > return (size < 0 ? 0 : size); > } > > /** > * Returns the style range with the smallest offset ignoring the default style range or null > * if the presentation is empty. > * > * @return the style range with the smallest offset different from the default style range > */ > public StyleRange getFirstStyleRange() { > try { > >/// Modified to use modified version of createWindowRelativeRange with explicit values > int index = getFirstIndexInWindow(fResultWindow); > StyleRange range= (StyleRange) fRanges.get(index); > return createWindowRelativeRange(fResultWindow, range, fRangeOffsets[index], fRangeLengths[index]); >/// End modification > > } catch (NoSuchElementException x) { > } catch (IndexOutOfBoundsException x) { > } > > return null; > } > > /** > * Returns the style range with the highest offset ignoring the default style range. > * > * @return the style range with the highest offset different from the default style range > */ > public StyleRange getLastStyleRange() { > try { > >/// Modified to use modified version of createWindowRelativeRange > int index = getFirstIndexAfterWindow(fResultWindow) - 1; > StyleRange range = (StyleRange) fRanges.get(index); > return createWindowRelativeRange(fResultWindow, range,fRangeOffsets[index], fRangeLengths[index]); >/// End modification > > } catch (NoSuchElementException x) { > return null; > } catch (IndexOutOfBoundsException x) { > return null; > } > } > > /** > * Returns the coverage of this presentation as clipped by the presentation's > * result window. > * > * @return the coverage of this presentation > */ > public IRegion getCoverage() { > > if (fDefaultRange != null) { > StyleRange range= getDefaultStyleRange(); > return new Region(range.start, range.length); > } > > StyleRange first= getFirstStyleRange(); > StyleRange last= getLastStyleRange(); > > if (first == null || last == null) > return null; > > return new Region(first.start, last.start - first. start + last.length); > } > > /** > * Returns the extent of this presentation clipped by the > * presentation's result window. > * > * @return the clipped extent > * @since 3.0 > */ > public IRegion getExtent() { > if (fExtent != null) > return createWindowRelativeRegion(fExtent); > return getCoverage(); > } > > /** > * Clears this presentation by resetting all applied changes. > * @since 2.0 > */ > public void clear() { > fDefaultRange= null; > fResultWindow= null; > fRanges.clear(); > } > >//////////////////// NEW CODE ////////////////////////////////////////////// > >/// Separate integer arrays containing the offset and length for each >/// StyleRange are maintained. This allows model StyleRanges >/// (with zero offset and length) to be within the fRanges ArrayList. > > /** The StyleRange offsets */ > private int[] fRangeOffsets; > > /** The StyleRange lengths */ > private int[] fRangeLengths; > >////////////////// New API begins here ////////////////////////////////////// > > /** > * Adds a model range to the presentation. > * > * The model range must have a starting offset and length of zero. > * > * If part or all of the range currently exists in the presentation > * it is replaced. > * > * @param range the model style range to be added > * @param start the starting range offset > * @param length the range length > */ > public void addStyleRange(StyleRange range, int start, int length ) { > if (range.start != 0 || range.length != 0) > throw new IllegalArgumentException(); > > applyStyleRange(range, start, length, false); > } > >/// Note that there is no difference between add and replace. This is >/// provided for consistency with existing API, probably unnecessary. > /** > * Replaces a range in the presentation with a model range. > * > * The model range must have a starting offset and length of zero. > * > * If part or all of the range does not currently exist in the > * presentation it is added. > * > * @param range the model style range > * @param start the range start offset > * @param length the range length > */ > public void replaceStyleRange(StyleRange range, int start, int length) { > if (range.start != 0 || range.length != 0) > throw new IllegalArgumentException(); > > applyStyleRange(range, start, length, false); > } > > /** > * Merges a model range into this presentation. > * > * The model range must have a starting offset and length of zero. > * > * If part or all of the range does not currently exist in the > * presentation it is added. > * > * @param range the model style range > * @param start the range start offset > * @param length the range length > */ > public void mergeStyleRange(StyleRange range, int start, int length) { > if (range.start != 0 || range.length != 0) > throw new IllegalArgumentException(); > > applyStyleRange(range, start, length, true); > } > > /** > * Returns an iterator which enumerates all style ranges > * as clipped by the result window. > * > * <p> The style ranges may or may not be models, with a zero starting > * offset and length. > * > * @return an iterator which enumerates all style ranges > * as clipped by the result window. > */ > public Iterator getStyleRangeModelIterator() { > return new StyleIterator(); > } > > /** > * Returns an iterator which enumerates all style range offsets > * as clipped by the result window. > * > * @return an iterator which enumerates all style range offsets > * as clipped by the result window. > */ > public OffsetIterator getStyleRangeOffsetIterator() { > return new OffsetIterator(); > } > > /** > * Returns an iterator which enumerates all style range lengths > * as clipped by the result window. > * > * @return an iterator which enumerates all style range lengths > * as clipped by the result window. > */ > public LengthIterator getStyleRangeLengthIterator() { > return new LengthIterator(); > } > >/////////////////// End of new API ///////////////////////////////////////// > > >/// Modified applyStyleRange method which uses an explicit offset and length > >/// Note that the result window is not used when building or modifying the >/// list - it is only used (or needed) when results are retrieved. > /** > * Applies the given range to this presentation. The range must be a > * subrange of the presentation's default range. > * > * @param range the range to be added > * @param rangeStart the range start > * @param rangeLength the range length > * @param merge <code>true</code> if the style should be merged instead of replaced > * > * @throws IllegalArgumentException if the model range is null > * or has a nonzero starting offset or length, or if the > * specified starting offset is less than zero, or if the > * specified length is not greater than zero. > */ > private void applyStyleRange(StyleRange range, int start, int length, boolean merge) { > StyleRange newRange = range; > int newStart = start; > int newLength = length; > int newEnd = start + length; > > StyleRange mergeRange = null; > > int deleteStart = 0; > int deleteLength = 0; > > int index = fRanges.size(); > > checkConsistency(newRange, newStart, newLength); > > // Search the list unless adding at the end > if (index > 0) { > int last = fRangeOffsets[index -1] + fRangeLengths[index -1]; > if (newStart < last) > index = 0; > } > > for (;; index += 1) { > > // Handle insert at end > if (index == fRanges.size()) { > insert(index); > set(index, newRange, newStart, newLength, merge, mergeRange); > break; > } > > int nextStart = fRangeOffsets[index]; > int nextEnd = nextStart + fRangeLengths[index]; > > // Continue if just searching > if (newStart >= nextEnd) > continue; > > // Split the current range if necessary > if (nextStart < newStart) { > StyleRange r = makeModel(index); > fRangeOffsets[index] = newStart; > fRangeLengths[index] = nextEnd - newStart; > > insert(index); > set(index, r, nextStart, newStart - nextStart, false, mergeRange); > continue; > } > > // Remember the merge style unless an addition > if (merge && nextStart < newEnd) > mergeRange = (StyleRange) fRanges.get(index); > > // Make space for a new range if necessary, set delete length > if (nextEnd > newEnd) { > insert(index); > > if (nextStart < newEnd) { > deleteStart = nextStart; > deleteLength = newEnd - nextStart; > } > } > > // If no residual or merge, replace/merge the range, set delete length > if (! merge || newEnd <= nextEnd) { > set(index, newRange, newStart, newLength, merge, mergeRange); > deleteStart = nextEnd; > deleteLength = newEnd - nextEnd; > break; > } > > // Do the merge and continue with the residual > set(index, newRange, newStart, newLength - nextEnd, merge, mergeRange); > newLength -= newEnd - nextEnd; > newStart = nextEnd; > } > > // Delete any overlapped ranges which follow > index += 1; > while (deleteLength > 0 && index < fRanges.size()) { > int nextStart = fRangeOffsets[index]; > int nextLength = fRangeLengths[index]; > > // Update if space before next range > if (deleteStart < nextStart) { > deleteLength -= nextStart - deleteStart; > deleteStart += nextStart - deleteStart; > if (deleteLength <= 0) break; > } > > // Delete the first part of the next range > if (deleteLength < nextLength) { > makeModel(index); > fRangeOffsets[index] += deleteLength; > fRangeLengths[index] -= deleteLength; > break; > } > > // Delete the next range if necessary and continue > if (deleteLength >= nextLength ) { > delete(index); > deleteStart += nextLength; > deleteLength -= nextLength; > } > } > } > > /** > * Helper method which converts a specified range to a model > * > * @param index the index of the specified StyleRange > * @return the model range > */ > private StyleRange makeModel(int index) { > StyleRange range = (StyleRange) fRanges.get(index); > StyleRange r = makeModel(range); > > if (range != r) > fRanges.set(index, r); > return r; > } > > /** > * Helper method which converts a range to a model and returns it > * > * @param range the StyleRange to be converted to a model > * @return the model range > */ > private StyleRange makeModel(StyleRange range) { > StyleRange r = range; > > if (r.length > 0) { > r = (StyleRange) range.clone(); > r.start = 0; > r.length = 0; > } > return r; > } > > /** > * Helper method to insert space for a range. This includes expanding the > * offset and length arrays (by 50% plus 50) as necessary. > * > * @param index the position to insert the new dummy range > */ > private void insert(int index) { > int size = fRanges.size(); > > if (size >= fRangeOffsets.length) { > int newSize = 50 + size + size /2; > > int[] temp = new int[newSize]; > System.arraycopy(fRangeOffsets, 0, temp, 0, size); > fRangeOffsets = temp; > > temp = new int[newSize]; > System.arraycopy(fRangeLengths, 0, temp, 0, size); > fRangeLengths = temp; > } > > int length = size - index; > if (length > 0) { > System.arraycopy(fRangeOffsets, index, fRangeOffsets, index +1, length); > System.arraycopy(fRangeLengths, index, fRangeLengths, index +1, length); > } > > fRanges.add(index, null); > } > > /** > * Helper method to delete a range > * > * @param index the index of the range to be deleted > */ > private void delete(int index) { > fRanges.remove(index); > > int length = fRanges.size() - index; > if (length > 0) { > System.arraycopy(fRangeOffsets, index + 1, fRangeOffsets, index, length); > System.arraycopy(fRangeLengths, index + 1, fRangeLengths, index, length); > } > } > > /** > * Helper method to set or merge a range > * > * @param index the index of the range > * @param range the new StyleRange > * @param start the starting offset > * @param length the range length > * @param merge <code>true</code> if a merge is to be performed > * @param mergeRange the template range for the merge, if any > */ > private void set(int index, StyleRange range, int start, int length > , boolean merge, StyleRange mergeRange) { > > StyleRange newRange = range; > > // If doing a merge, the target must be a new model > if (merge) { > if (mergeRange != null) > newRange = (StyleRange)mergeRange.clone(); > else { > newRange = getDefaultStyleRange(); > if (newRange == null) > newRange = (StyleRange) range.clone(); > } > > newRange.start = 0; > newRange.length = 0; > applyStyle(range, newRange, true); > } > > fRanges.set(index, newRange); > fRangeOffsets[index] = start; > fRangeLengths[index] = length; > } > > /** > * Enumerates all the model <code>StyleRange</code>s included > * in the presentation as clipped by the result window. > */ > class StyleIterator implements Iterator { > > /** The index of the next text style to be enumerated */ > protected int fIndex; > /** The upper bound of the indices of style ranges to be enumerated */ > protected int fLastIndex; > > /** @see Iterator */ > protected StyleIterator() { > fIndex= getFirstIndexInWindow(fResultWindow); > fLastIndex= getFirstIndexAfterWindow(fResultWindow); > } > > /** @see Iterator#next() */ > public Object next() { > try { > return fRanges.get(fIndex++); > } catch (ArrayIndexOutOfBoundsException x) { > throw new NoSuchElementException(); > } > } > > /** @see Iterator#hasNext() */ > public boolean hasNext() { > return fIndex < fLastIndex; > } > > /** @see Iterator#remove() */ > public void remove() { > throw new UnsupportedOperationException(); > } > } > > /** > * Enumerates all the <code>StyleRange</code> offsets included > * in the presentation as clipped by the result window. > */ > class OffsetIterator implements Iterator { > > /** The index of the next style range to be enumerated */ > protected int fIndex; > /** The upper bound of the indices of style ranges to be enumerated */ > protected int fLastIndex; > > /** @see Iterator */ > protected OffsetIterator() { > fIndex= getFirstIndexInWindow(fResultWindow); > fLastIndex= getFirstIndexAfterWindow(fResultWindow); > } > > /** @see Iterator#next() */ > public Integer next() { > try { > return new Integer(fRangeOffsets[fIndex++]); > } catch (ArrayIndexOutOfBoundsException x) { > throw new NoSuchElementException(); > } > } > > /** > * Returns the next integer value as an int > * > * <p> Used to prevent the unnecessary creation of Integer objects > * > * @return the next int value > */ > public int nextInt() { > try { > return fRangeOffsets[fIndex++]; > } catch (ArrayIndexOutOfBoundsException x) { > throw new NoSuchElementException(); > } > } > > /** @see Iterator#hasNext() */ > public boolean hasNext() { > return fIndex < fLastIndex; > } > > /** @see Iterator#remove() */ > public void remove() { > throw new UnsupportedOperationException(); > } > } > > /** > * Enumerates all the <code>StyleRange</code> lengths included > * in the presentation as clipped by the result window. > */ > class LengthIterator implements Iterator { > > /** The index of the next style range to be enumerated */ > protected int fIndex; > /** The upper bound of the indices of style ranges to be enumerated */ > protected int fLastIndex; > > /** @see Iterator#next() */ > protected LengthIterator() { > fIndex= getFirstIndexInWindow(fResultWindow); > fLastIndex= getFirstIndexAfterWindow(fResultWindow); > } > > /** @see Iterator#next() */ > public Integer next() { > try { > return new Integer(fRangeLengths[fIndex++]); > } catch (ArrayIndexOutOfBoundsException x) { > throw new NoSuchElementException(); > } > } > > /** > * Returns the next integer value as an int > * > * <p> Used to prevent the unnecessary creation of Integer objects > * > * @return the next int value > */ > public int nextInt() { > try { > return fRangeLengths[fIndex++]; > } catch (ArrayIndexOutOfBoundsException x) { > throw new NoSuchElementException(); > } > } > > /** @see Iterator#hasNext() */ > public boolean hasNext() { > return fIndex < fLastIndex; > } > > /** @see Iterator#remove() */ > public void remove() { > throw new UnsupportedOperationException(); > } > } > > >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 119384
:
175181
|
175676
|
175677