com.adobe.xfa.text.TextRange Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
package com.adobe.xfa.text;
import java.util.List;
import com.adobe.xfa.ut.Rect;
import com.adobe.xfa.text.markup.MarkupIn;
import com.adobe.xfa.text.markup.MarkupOut;
/**
*
* @exclude from published api -- Mike Tardif, May 2006.
*/
public class TextRange {
public final static int POSN_ANCHOR = 0;
public final static int POSN_LOOSE = 1;
public final static int POSN_START = 2;
public final static int POSN_END = 3;
// the "real data
private final TextPosn moAnchor;
private final TextPosn moLoose;
// filled by SortPositions()
private TextPosn moStart;
private TextPosn moEnd;
/**
* Default constructor.
*
* The range is not initially associated with any stream.
*/
public TextRange () {
moAnchor = new TextPosn();
moLoose = new TextPosn();
}
/**
* Copy constructor.
*
* Copy all contents of the source range, including stream
* association, and start/end indexes.
* @param oSource Source position object to copy.
*/
public TextRange (TextRange oSource) {
moAnchor = new TextPosn (oSource.moAnchor);
moLoose = new TextPosn (oSource.moLoose);
}
/**
* Constructor with stream.
*
* Construct a range object associated with the given stream. The range
* initially covers the entire content of the stream.
* @param poStream Stream to associate with. NULL creates a range
* object with no initial association.
*/
public TextRange (TextStream poStream) {
moAnchor = new TextPosn (poStream);
moLoose = new TextPosn (poStream, Integer.MAX_VALUE);
reconcile();
}
/**
* Constructor with stream and indexes.
*
* Construct a range object associated with the given stream and
* covering the range of items indicated by the index values.
* @param poStream Stream to associate with. NULL creates a
* range object with no initial association.
* @param nNewAnchor Anchor index for the range. Will be truncated if
* too large.
* @param nNewLoose (optional) Loose end index for the range. Default
* is to include up to the end of the stream. Note that the loose index
* may be less than, equal to, or greater than the anchor index.
*/
public TextRange (TextStream poStream, int nNewAnchor, int nNewLoose) {
moAnchor = new TextPosn (poStream, nNewAnchor);
moLoose = new TextPosn (poStream, nNewLoose);
reconcile();
}
/**
* Overridden: Associate range with a new stream.
*
* This method associates the range object with the specified stream,
* automatically including all stream content in the range. The range
* object will be tracked by the new stream (if not NULL) and will no
* longer be tracked by its old stream.
* @param poStream Stream to associate with. NULL leaves the range
* object unassociated (and untracked).
*/
public void associate (TextStream poStream) {
moAnchor.associate (poStream, 0);
moLoose.associate (poStream, Integer.MAX_VALUE);
reconcile();
}
/**
* Overridden: Associate range with a new stream, specifying range
* indexes.
*
* This method associates the range object with the specified stream,
* including the portion indicated by index numbers passed as
* parameters. The range object will be tracked by the new stream (if
* not NULL) and will no longer be tracked by its old stream.
* @param poStream Stream to associate with. NULL leaves the range
* object unassociated (and untracked).
* @param nNewAnchor Anchor index for the range. Will be truncated if
* too large.
* @param nNewLoose (optional) Loose end index for the range. Default
* is to include up to the end of the stream. Note that the loose index
* may be less than, equal to, or greater than the anchor index.
*/
public void associate (TextStream poStream, int nNewAnchor, int nNewLoose) {
moAnchor.associate (poStream, nNewAnchor);
moLoose.associate (poStream, nNewLoose);
reconcile();
}
/**
* Optain a pointer to the associated stream.
* @return Pointer to the associated text stream; NULL if the range
* currently has no stream association.
*/
public TextStream stream () {
return moAnchor.stream();
}
/**
* Count the number of items in the range.
* @return Number of items included in the range.
*/
public int count () {
sortPositions();
return moEnd.index() - moStart.index();
}
/**
* Count the number of characters in the range.
* @return Number of characters included in the range.
*/
public int countText () {
return countByType (TextItem.CHAR);
}
/**
* Count the number of embedded fields in the range.
* @return Number of embedded fields included in the range.
*/
public int countField () {
return countByType (TextItem.FIELD);
}
/**
* Count the number of embedded objects in the range.
* @return Number of embedded objects included in the range.
*/
public int countEmbed () {
return countByType (TextItem.OBJECT);
}
/**
* Is the range empty?
* @return TRUE if the range contains no items; FALSE if it contains at
* least one item.
*/
public boolean isEmpty () {
return moAnchor.index() == moLoose.index();
}
/**
* Obtain one of the range endpoints as a text position.
* @param ePosition A member of the local PosnCode enumeration
* indicating which range endpoint is desired. Value must be one of
* POSN_ANCHOR, POSN_LOOSE, POSN_START or POSN_END.
* @return A text position corresponding to the requested endpoint.
* Will not be associated with any stream if the range has no stream
* association.
*/
public TextPosn position (int ePosition) {
switch (ePosition) {
case POSN_ANCHOR:
return moAnchor;
case POSN_LOOSE:
return moLoose;
case POSN_START:
sortPositions();
return moStart;
case POSN_END:
sortPositions();
return moEnd;
default:
return moAnchor;
}
}
/**
* Change a range endpoint by index number.
*
* Given an endpoint position code and an index number, this method sets
* that endpoint of the range to the new index. Whether setting by
* anchor/loose or start/end, it is OK to set the endpoint to occur
* before the start point; the range will simply reorient itself. The
* call is ignored if the range currently has no stream association.
* @param ePosition A member of the local PosnCode enumeration
* indicating which range endpoint is desired. Value must be one of
* POSN_ANCHOR, POSN_LOOSE, POSN_START or POSN_END.
* @param nNewPosition Index number to move the endpoint to. Will be
* truncated if too large.
*/
public void position (int ePosition, int nNewPosition) {
switch (ePosition) {
case POSN_ANCHOR:
moAnchor.index (nNewPosition);
break;
case POSN_LOOSE:
moLoose.index (nNewPosition);
break;
case POSN_START:
sortPositions();
moStart.index (nNewPosition);
break;
case POSN_END:
sortPositions();
moEnd.index (nNewPosition);
break;
}
reconcile();
}
/**
* Change a range endpoint by text position.
*
* Given an endpoint position code and text position object, this method
* sets that endpoint of the range to the new new position. Whether
* setting by anchor/loose or start/end, it is OK to set the endpoint to
* occur before the start point; the range will simply reorient itself.
* The call is ignored if the range currently has no stream association.
* @param ePosition A member of the local PosnCode enumeration
* indicating which range endpoint is desired. Value must be one of
* POSN_ANCHOR, POSN_LOOSE, POSN_START or POSN_END.
* @param oNewPosn New position to set for specified range endpoint.
* If this position is associated with a different stream, only its
* index number is used.
*/
public void position (int ePosition, TextPosn oNewPosn) {
switch (ePosition) {
case POSN_ANCHOR:
moAnchor.copyData (oNewPosn);
break;
case POSN_LOOSE:
moLoose.copyData (oNewPosn);
break;
case POSN_START:
sortPositions();
moStart.copyData (oNewPosn);
break;
case POSN_END:
sortPositions();
moEnd.copyData (oNewPosn);
break;
}
reconcile();
}
/**
* Query the anchor position.
* @return Anchor position.
*/
public TextPosn anchor () {
return position (POSN_ANCHOR);
}
/**
* Set the anchor position by index.
* @param nNewIndex New index for the anchor position. Will be
* truncated if too large.
*/
public void anchor (int nNewIndex) {
position (POSN_ANCHOR, nNewIndex);
}
/**
* Set the anchor position by text position object.
* @param oNewPosn New position for the anchor. If associated with a
* different stream, only its index is used.
*/
public void anchor (TextPosn oNewPosn) {
position (POSN_ANCHOR, oNewPosn);
}
/**
* Query the loose position.
* @return Loose position.
*/
public TextPosn loose () {
return position (POSN_LOOSE);
}
/**
* Set the loose position by index.
* @param nNewIndex New index for the loose position. Will be
* truncated if too large.
*/
public void loose (int nNewIndex) {
position (POSN_LOOSE, nNewIndex);
}
/**
* Set the loose position by text position object.
* @param oNewPosn New position for the loose. If associated with a
* different stream, only its index is used.
*/
public void loose (TextPosn oNewPosn) {
position (POSN_LOOSE, oNewPosn);
}
/**
* Query the start position.
* @return Start position.
*/
public TextPosn start () {
return position (POSN_START);
}
/**
* Set the start position by index.
* @param nNewIndex New index for the start position. Will be
* truncated if too large.
*/
public void start (int nNewIndex) {
position (POSN_START, nNewIndex);
}
/**
* Set the start position by text position object.
* @param oNewPosn New position for the start. If associated with a
* different stream, only its index is used.
*/
public void start (TextPosn oNewPosn) {
position (POSN_START, oNewPosn);
}
/**
* Query the end position.
* @return End position.
*/
public TextPosn end () {
return position (POSN_END);
}
/**
* Set the end position by index.
* @param nNewIndex New index for the end position. Will be
* truncated if too large.
*/
public void end (int nNewIndex) {
position (POSN_END, nNewIndex);
}
/**
* Set the end position by text position object.
* @param oNewPosn New position for the end. If associated with a
* different stream, only its index is used.
*/
public void end (TextPosn oNewPosn) {
position (POSN_END, oNewPosn);
}
/**
* Return the union of two text ranges.
*
* The union of two ranges is defined as including all items in both
* ranges, as well as all items between if the ranges do not overlap.
* Given a second range, this method performs the union operation and
* populates a third range with the resulf.
* @param oAdd Range to union with this one.
* @param oResult Range resulting from the union.
* @return TRUE if the two ranges overlapped; FALSE if not or the ranges
* refer to different streams. Contiguous ranges are considered as
* overlapping.
*/
public boolean union (TextRange oAdd, TextRange oResult) {
if ((stream() != oAdd.stream()) || (stream() == null)) {
return false;
}
int nStart = start().index();
int nEnd = end().index();
int nAddStart = oAdd.start().index();
int nAddEnd = oAdd.end().index();
boolean bOverlap;
if (nStart < nAddStart) {
bOverlap = nEnd >= nAddStart;
} else {
bOverlap = nAddEnd >= nStart;
nStart = nAddStart;
}
if (nEnd < nAddEnd) {
nEnd = nAddEnd;
}
oResult.associate (stream(), nStart, nEnd);
return bOverlap;
}
/**
* Obtain the range content as plain text.
* @param bIncludeFields (optional) If TRUE, the operation recursively
* descends through embedded fields within the range to include their
* text as well. If FALSE (default) only text from the associated
* stream is returned.
*/
public String text (boolean bIncludeFields) {
TextStream poStream = stream();
if (poStream == null) {
return "";
}
sortPositions();
return poStream.rangeText (moStart, moEnd, bIncludeFields);
}
public String text () {
return text (false);
}
/**
* Obtain the range content as rich text.
*
* Copy the content of the range to another stream, replacing its
* previous content. The destination stream retains its graphic source,
* which may be different from that of the associated stream. All
* graphics objects copied are reconciled in the destination stream's
* graphic source. Because this is a copy, the destination stream will
* get clones of any embedded objects or fields.
* @param oText Destination text stream. Not modified if this range
* has no stream association.
*/
public void text (TextStream oText) {
TextStream poStream = stream();
if (poStream == null) {
return;
}
sortPositions();
// Note: no need to check for self-assignment on the stream. Text stream
// object can cleanly extract a self sub-stream.
poStream.rangeText (moStart, moEnd, oText);
}
/**
* Enumerate markers contained within this range.
* @param oMarkers - Array to contain pointers to the enumerated
* markers. Any previous contents are removed by the call. Even though
* the returned array contains non-const pointers to markers, those
* markers are owned by AXTE and must not be deleted by the client,
* though the client can cache pointers to these markers provide that it
* participates in the marker reference counting mechanism.
* @param bPositionMarkers - True if all position markers at this
* position are to be included in the array. False (default) if
* position markers are to be excluded. A position marker is considered
* to be in the text range if it occurs at or after the start of the
* range, and before or at the end of the range.
* @param bRangeMarkers - True (default) if all range markers that span
* this position are to be included in the array. False if range
* markers are to be excluded.
* @param bSubsetOnly - Applies to range markers only. True to limit
* included range markers to those that span a (possibly complete)
* subset of this range; false (default) if any range marker that
* overlaps the this range is to be included.
*/
public void enumerateMarkers (List oMarkers, boolean bPositionMarkers, boolean bRangeMarkers, boolean bSubsetOnly) {
TextStream poStream = stream();
if (poStream == null) {
return;
}
sortPositions();
poStream.rangeEnumMarker (moStart, moEnd, oMarkers, bPositionMarkers, bRangeMarkers, bSubsetOnly);
}
public void enumerateMarkers (List oMarkers) {
enumerateMarkers (oMarkers, false, true, false);
}
/**
* Delete the contents of the range.
*
* Delete all items in the associated stream that fall within this
* range. Normally, there may be fix-up required after such a
* deletion. If there are any attribute changes in the deleted items,
* the last one must be preserved for text that follows the deletion.
* Also, if the deletion spans paragraphs, the result may be a paragraph
* with conflicting paragraph attributes. These are reconciled in
* favour of the first paragraph (if it still has text left after the
* delete). Alternatively, one can invoke a raw delete that doesn't do
* the fix-ups (not recommended, except for very special cases). This
* is referred to as a raw delete.
* @param bRaw (optional) TRUE for raw delete (see above); FALSE
* (default) for normal delete.
*/
public void delete (boolean bRaw) {
// Watson 1325333: Don't dork with positions if empty range; could
// interfere with temporary redundant attribute change.
if ((stream() == null) || isEmpty()) {
return;
}
sortPositions();
moStart.deleteAhead (moEnd.index() - moStart.index(), bRaw);
}
public void delete () {
delete (false);
}
/**
* Replace the range contents with a single character.
*
* This method deletes the content of the range and then inserts a
* single character. When it returns, the range will contain only the
* inserted character.
* @param cReplace Character to insert.
* @param bRaw (optional) TRUE for raw delete; FALSE (default) for
* normal delete. Please see the description of raw deletion with the
* Delete() method.
*/
public void replace (char cReplace, boolean bRaw) {
if (stream() == null) {
return;
}
String sReplace = "";
sReplace += cReplace;
replace (sReplace, bRaw);
}
public void replace (char cReplace) {
replace (cReplace, false);
}
/**
* Replace the range contents with string of text.
*
* This method deletes the content of the range and then inserts a text
* string When it returns, the range will contain only the inserted
* text.
* @param sReplace Text to insert.
* @param bRaw (optional) TRUE for raw delete; FALSE (default) for
* normal delete. Please see the description of raw deletion with the
* Delete() method.
*/
public void replace (String sReplace, boolean bRaw) {
if (stream() == null) {
return;
}
sortPositions();
stream().rangeReplace (moStart, moEnd.index() - moStart.index(), sReplace, bRaw);
}
public final void replace (String sReplace) {
replace (sReplace, false);
}
/**
* Replace the range contents with rich text.
*
* This method deletes the content of the range and then inserts rich
* text. When it returns, the range will contain only the inserted
* character.
* @param oReplace Rich text to insert. May have a different graphic
* source from the associated stream. All stream content is copied. In
* other words, the associated stream gets clones of embedded objects
* and fields in the source stream.
* @param bRaw (optional) TRUE for raw delete; FALSE (default) for
* normal delete. Please see the description of raw deletion with the
* Delete() method.
*/
public void replace (TextStream oReplace, boolean bRaw) {
if (stream() == null) {
return;
}
sortPositions();
stream().rangeReplace (moStart, moEnd.index() - moStart.index(), oReplace, bRaw);
}
public final void replace (TextStream oReplace) {
replace (oReplace, false);
}
/**
* Insert a range marker at the position represented by this position
* object.
*
* If this range is not associated with any text stream, the call is
* ignored.
*
* @param poMarker - Pointer to marker to insert. Note that markers are
* always cloned on insertion, so a copy actually gets inserted. The
* caller continues to retain ownership of the instance referred to by
* this parameter, and can delete it any time after the call.
* @return Pointer to the cloned copy actually inserted in the text
* stream. While this is a non-const pointer, it is owned by AXTE and
* must not be deleted by the client, though the client can cache a
* pointers to this marker provide that it participates in the marker
* reference counting mechanism.
*/
public TextMarker insert (TextMarker poMarker) {
if (stream() == null) {
return null;
}
sortPositions();
return stream().rangeMarker (moStart, moEnd, poMarker);
}
/**
* Obtain the attributes in effect over the range.
*
* Returns a text attribute structure describing the attributes over the
* range. Any attribute that remains constant over the range will have
* an enabled value in the result. Any attribute that changes over the
* range will be disabled in the result.
* @return Text attribute object describing the attributes in effect
* over the range.
*/
public TextAttr attribute () {
TextStream poStream = stream();
if (poStream == null) {
return TextAttr.defaultAttr (false);
}
sortPositions();
return poStream.rangeGetAttr (moStart, moEnd);
}
/**
* Change text attributes over the range.
*
* Given a text attribute object, this method applies enabled attributes
* over the entire range. Disabled attributes in the given object are
* not changed.
* @param oNewAttr Attribute object with enabled attributes to apply.
* @param bRaw (optional) TRUE for raw change; FALSE (default) for
* normal change Please see the description of raw deletion with the
* Delete() method.
*/
public void attribute (TextAttr oNewAttr, boolean bRaw) {
TextStream poStream = stream();
if (poStream == null) {
return;
}
sortPositions();
poStream.rangeSetAttr (moStart, moEnd, oNewAttr, bRaw);
}
public final void attribute (TextAttr oNewAttr) {
attribute (oNewAttr, false);
}
/**
* Convert the range contents to markup.
*
* Convert the range contents to text output in a markup language. The
* particular language is determined by which derived class of
* TextMkOut is passed. The caller may request that fields are
* flattened into stream content in the markup, or retained as
* references.
* @param oMarkup Output markup engine to generate the markup
* language.
* @param poInitAttr (optional) Ambient/initial attributes. This
* parameter, if not NULL, works in concert with the bDefaultInitAttr
* parameter. If that parameter indicates ambient attributes, this
* represents default attributes that need not be written to the markup
* if they apply to the stream. If it indicates initial attributes, all
* enabled values are written to the markup. If NULL (default value) it
* is ignored.
* @param bDefaultInitAttr (optional) If FALSE (default), parameter
* poInitAttr represents initial attributes to write. If TRUE,
* poInitAttr represents ambient attributes as described above.
* @param bFlattenFields Optional. If TRUE, embedded field content is
* written to the markup as if it was part of the range's content. If
* FALSE (default) field references are written to the markup.
*/
public void markup (MarkupOut oMarkup, TextAttr poInitAttr, boolean bDefaultInitAttr, boolean bFlattenFields) {
TextStream poStream = stream();
if (poStream == null) {
return;
}
sortPositions();
poStream.rangeMarkup (moStart, moEnd, oMarkup, poInitAttr, bDefaultInitAttr, bFlattenFields);
}
/**
* Apply markup to the range.
*
* Replace the range's current contents with rich text derived from a
* markup language.
* @param oMarkup Markup engine that processes the markup language.
* This must be pre-initialized with the markup source.
*/
public void markup (MarkupIn oMarkup) {
TextStream poStream = stream();
if (poStream == null) {
return;
}
delete();
poStream.rangeMarkup (end(), oMarkup);
}
/**
* Extend the range to include complete words.
*
* The start of the range moves back to the start of the word containing
* it. The end of the range moves forward to the end of the word that
* contains it. If either position is not within a word or adjacent to
* one, it does not move.
* @return TRUE if the resulting range contains any items; FALSE if it
* is empty (typically occurs when you call this on an empty range that
* is not positioned at a word.
*/
public boolean grabWord (int eWordMode) {
sortPositions();
moStart.wordStart (eWordMode);
moEnd.nextWord (false, eWordMode);
tighten();
reconcile();
return (moStart.index() != moEnd.index());
}
public boolean grabWord () {
return grabWord (TextPosn.WORD_MODE_LEGACY);
}
/**
* Extend the range to include complete lines.
*
* Note: the associated stream must have a text display for line
* operations to succeed. The start of the range moves back to the
* start of the line containing it. The end of the range moves forward
* to the end of the line that contains it.
* @return FALSE if no display; TRUE otherwise.
*/
public boolean grabLine () {
sortPositions();
if (! moStart.start()) {
return false;
}
moEnd.nextLine();
reconcile();
return true;
}
/**
* Extend the range to include complete paragraphs.
*
* Note: a paragraph starts after a paragraph mark and runs until just
* after the next paragraph mark. If our end position is already just
* beyond a paragraph mark, we normally won't want to move it. The
* exception is when our start is also just after the same mark (empty
* range once tightened). In this case, we maintain the start and move
* the end after the next mark.
* @return Always returns TRUE;
*/
public boolean grabPara () {
// Note: a paragraph starts after a paragraph mark and runs until just
// after the next paragraph mark. If our end position is already just
// beyond a paragraph mark, we normally won't want to move it. The
// exception is when our start is also just after the same mark (empty
// range once tightened). In this case, we maintain the start and move
// the end after the nect mark.
tighten();
boolean bEmpty = isEmpty();
sortPositions();
moStart.paraStart();
boolean bSuppressEnd = false;
if (!bEmpty) {
TextPosnBase oTemp = new TextPosnBase (moEnd);
if (oTemp.prevUserPosnType (false) == TextItem.PARA) {
bSuppressEnd = true;
}
}
if (!bSuppressEnd) {
moEnd.nextPara();
}
reconcile();
return true;
}
/**
* Try to exclude spurious attr changes from range.
*
*
* This method "tightens" the range around text and other objects so
* that attribute changes at the extremities don't distort what gets
* returned by an Attribute() call.
*
*
* If the range is empty, we do the following special handling: If the
* range is between attribute changes, we leave it alone (they were
* probably just inserted). Otherwise, we test to see if we're at the
* start of the line. If so, move both positions over any leading
* attribute changes so that we show the attributes in effect at the
* start of the line. Otherwise, we move both positions back over all
* attribute changes, to be consistent with position user item handling.
*
*/
public void tighten () {
sortPositions();
if (moStart.index() == moEnd.index()) {
int ePrev = moStart.prev (TextNullFrame.MODE_STOP, true);
int eNext = moStart.next (TextNullFrame.MODE_STOP, true);
if ((ePrev != TextItem.ATTR) || ((eNext != TextItem.ATTR) && (eNext != TextItem.UNKNOWN))) {
moStart.tighten (false);
if (moStart.isAtStart()) {
moStart.tighten (true);
moEnd.tighten (true);
} else {
moEnd.tighten (false);
}
}
}
else {
moStart.tighten (true);
if (moEnd.next (TextNullFrame.MODE_STOP, true) != TextItem.UNKNOWN) {
moEnd.tighten (false); // keep trailing attr in range if at end of stream
}
if (moStart.index() > moEnd.index()) {
if (moEnd.isAtStart()) {
moEnd.tighten (true);
} else {
moStart.tighten (false);
}
}
}
}
/**
* Create a position with the associated stream, given a character
* index.
*
* Return text position object that is associated with the same stream
* as this object, but is positioned immediately after the Nth
* character, where N is passed as a parameter.
* @param lIndex Character position to search for.
* @return Resulting position object.
*/
public TextPosnBase charPosition (int lIndex) {
return start().charPosition (lIndex);
}
/**
* Create a range with the associated stream, given a character index
* and length.
*
* Return text range object that is associated with the same stream
* as this object. The range will start after the Nth character and
* include M characters, where N and M are passed as parameters.
* @param lStart Character position to search for.
* @param lLength Number of characters to include in the range.
* @return Resulting range object.
*/
public TextRange charRange (int lStart, int lLength) {
return start().charRange (lStart, lLength);
}
/**
* Invalidate the area occupied by the text range in an interactive
* environment.
*
* In conjunction with a graphic environment, this method invalidates
* the (visible) graphic area occupied by the range's underlying text.
* This will lead to a future paint event through the graphic framework.
* @param oGfxEnv Graphic environment to perform the invalidation in.
* @param bEraseBkgnd TRUE if the background is to be erased as well;
* FALSE (default) if not.
*/
// public void Invalidate (jfGfxEnv poGfxEnv, boolean bEraseBkgnd) {
// TextStream poStream = Stream();
// if (poStream == null) {
// return;
// }
//
// TextDisplay poDisplay = poStream.Display();
// if (poDisplay == null) {
// return;
// }
//
// TextRange oDummy;
// poDisplay.UpdateSelected (oGfxEnv, this, oDummy, bEraseBkgnd);
// }
/**
* Obtain the rectangle(s) in the laid-out text corresponding to this
* range.
*
* A single range might yield multiple rectangles if it spans multiple
* lines or there is bidirectional text. Note: This call makes sense
* only for single frame displays. In a multi-frame environment it
* makes more sense to call TextFrame::GetSelectionRectangles() on
* each frame, in order to get rectangles that are positioned relative
* to their frame.
*
* @param oRectangles - Array to receive the rectangles.
* @return True if any rectangles were found; false otherwise. This
* method could return false if the range has no stream associated, the
* stream has no display, or the range is degenerate.
*/
public boolean getSelectionRectangles (List oRectangles) {
TextStream poStream = stream();
if (poStream == null) {
return false;
}
TextDisplay poDisplay = poStream.display();
if (poDisplay == null) {
return false;
}
// return poDisplay.GetSelectionRectangles (this, oRectangles);
return false; // TODO:
}
/**
* Assignment operator.
*
* Copy the entire content of the source range object including stream
* association and indexes.
* @param oSource Source range object to copy.
*/
public void copyFrom (TextRange oSource) {
moAnchor.copyFrom (oSource.moAnchor);
moLoose.copyFrom (oSource.moLoose);
}
/**
* Equality comparison.
*
* Two text ranges are considered equal if they are associated with the
* same stream and have the same pair of index numbers. Note that the
* current implementation is rather crude in that it still compares
* indexes even when both streams are NULL.
* @param object Range to compare against.
* @return TRUE if the ranges are equal; FALSE if not.
*/
public boolean equals (Object object) {
if (this == object)
return true;
// This overrides Object.equals(boolean) directly, so...
if (object == null)
return false;
if (object.getClass() != getClass())
return false;
TextRange test = (TextRange) object;
return moAnchor.equals (test.moAnchor) && moLoose.equals (test.moLoose);
}
public int hashCode() {
int hash = 59;
hash = (hash * 31) ^ moAnchor.hashCode();
hash = (hash * 31) ^ moLoose.hashCode();
return hash;
}
/**
* Inequality comparison.
*
* Two text ranges are considered unequal if they are associated with
* different stream and have different index numbers. Note that the
* current implementation is rather crude in that it still compares
* indexes even when both streams are NULL.
* @param oCompare Range to compare against.
* @return TRUE if the ranges are not equal; FALSE if they are equal.
*/
public boolean notEqual (TextRange oCompare) {
return ! equals (oCompare);
}
private int countByType (int eType) {
sortPositions();
TextPosnBase oCurrent = new TextPosn (moStart);
int nCount = 0;
int eCurrent = oCurrent.next();
while ((oCurrent.index() <= moEnd.index()) && (eCurrent != TextItem.UNKNOWN)) {
if (eCurrent == eType) {
nCount++;
}
eCurrent = oCurrent.next();
}
return nCount;
}
private void reconcile () {
tighten();
sortPositions();
moStart.position (TextPosn.POSN_BEFORE);
moEnd.position (TextPosn.POSN_AFTER);
}
private final void sortPositions () {
if (moAnchor.index() <= moLoose.index()) {
moStart = moAnchor;
moEnd = moLoose;
} else {
moStart = moLoose;
moEnd = moAnchor;
}
}
}