Multiple text ranges can be active and work cooperatively on the same story and evolve with the story. For example, if one text range deletes specified text before another text range, the latter tracks the change. In this sense, text ranges are similar to Microsoft Word bookmarks, which also track editing changes. However, bookmarks cannot edit text, while text ranges can. In addition, ranges let you manipulate text without changing the selection or Clipboard, both of which are valuable to end users. The ITextSelection interface inherits from ITextRange and adds some UI-oriented methods and properties as described in the section on ITextSelection.
You can look at a text range using methods based on character positions. Specifically, a text range is characterized by:
- The first character position, cpFirst, which points at an insertion point immediately preceding the first character (relative to the beginning of the story) in the range.
- The limit position, cpLim, which points at an insertion point immediately following the last character in the range.
The first character in a story has cpFirst = zero. If a cp argument has a value greater than the number of characters in the story, the number of characters in the story is used instead. If a cp argument is negative, zero is used instead. For those familiar with Microsoft Visual Basic for Applications, call the cpFirst property Start and the cpLim property End (even though the starting position of a range is also an end).
In the following figure, character positions are represented by the lines separating the letters. The corresponding character position values are given beneath the lines. The range starting at cpFirst = 5 and ending at cpLim = 7 contains the two-letter word is. If this figure depicts the complete text in a story, the story length is 30.
.gif)
The length of a range is given by cpLim - cpFirst or equivalently by End - Start. A range with zero length is called a degenerate or empty range and has equal cp* values, that is, cpFirst = cpLim. An example of a degenerate range is the current insertion point. A non-null selection is an example of a nondegenerate range.
Suppose that the range from 5 to 7 indicated by shaded cells in the preceding figure is told to delete its text (see ITextRange::Delete), thereby turning itself into an insertion point. The range from 25 to 29 would automatically track its contents, namely the word text. The following figure would result.
.gif)
In this figure, the range for text now has been automatically adjusted to have cpFirst = 23 and cpLim = 27. The owner of the range does not have to worry about updating the range character position values in the face of editing.
The names of the move methods indicate which end to move, but note that if any method attempts to move one range end past the other, both ends get moved to the target position. As a result, the insertion point is at the target position. The concept is that cpFirst and cpLim always have to obey the fundamental condition
0 <= cpFirst <= cpLim <= # characters in story
or equivalently for a range r, 0 <= r.Start <= r.End <= r.StoryLength, which is what you would expect from the names of these quantities.
Another important feature is that all stories contain an undeletable final CR (0xD) character at the end. So even an empty story has a single character, namely the final CR. A range can select this character, but cannot become an insertion point beyond it. To see how this works, try selecting the final CR in a Word document and then press the RIGHT ARROW key to collapse it. The directory tree will collapse before the final CR, but the CR cannot be deleted. The Text Object Model (TOM) functions the same way. So, if r.Start <= r.End, then r.End <= (r.StoryLength – 1). For a discussion about deleting a CR, see ITextRange::Delete.
Some methods depend on a Unit argument, which can take on the predefined values listed in the following table.
| Unit | Value | Meaning |
|---|
| tomCharacter | 1 | Character. |
| tomWord | 2 | Word. |
| tomSentence | 3 | Sentence. |
| tomParagraph | 4 | Paragraph. |
| tomLine | 5 | Line (on display). |
| tomStory | 6 | Story. |
| tomScreen | 7 | Screen (as for PAGE UP/PAGE DOWN). |
| tomSection | 8 | Section. |
| tomColumn | 9 | Table column. |
| tomRow | 10 | Table row. |
| tomWindow | 11 | Upper-left or lower-right of the window. |
| tomCell | 12 | Table cell. |
| tomCharFormat | 13 | Run of constant character formatting. |
| tomParaFormat | 14 | Run of constant paragraph formatting. |
| tomTable | 15 | Table. |
| tomObject | 16 | Embedded object. |
Most of the Unit values are self-explanatory. However the following descriptions are provided for additional clarity.
tomWord
The tomWord constant is an end of paragraph or a span of alphanumerics or punctuation including any blanks that follow. To get an on-screen feel for tomWord, watch how the caret moves when you press CTRL+RIGHT ARROW (—>) or CTRL+LEFT ARROW (<—) in a Word document.
tomSentence
The tomSentence constant describes a string of text that ends with a period, question mark, or exclamation mark and is followed either by one or more ASCII white space characters (9 through 0xd and 0x20), or the Unicode paragraph separator (0x2029). The trailing white space is part of the sentence. The last sentence in a story does not need to have a period, question mark, or exclamation mark. The start of a story qualifies as the start of a tomSentence, even if the string there does not qualify as a sentence grammatically. Other sentences must follow a sentence end and cannot begin with a period, question mark, or exclamation mark.
tomParagraph
The tomParagraph constant is a string of text terminated by an end-of-paragraph mark (CRLF, CR, VT (for SHIFT+ENTER), LF, FF, or 0x2029). TOM engines always have an undeletable end-of-paragraph mark at the end of a story. Thus, all TOM stories automatically have at least one tomWord, one tomSentence, and one tomParagraph.
tomLine
The tomLine constant corresponds to one line of text on a display, provided that a display is associated with the range. If no display is associated with a range, tomLine is treated as tomParagraph. A selection automatically has a display and a range that is a duplicate (see ITextRange::GetDuplicate). Other ranges may not have a display, depending on the TOM engine and context.
Methods that move one or both ends in terms of Unit, such as ITextRange::Move, ITextRange::MoveEnd, and ITextRange::MoveStart, depend on the signed Count argument. Except for the ITextSelection geometrical movement commands, if Count is greater than zero, the ends to be moved are moved forward (towards the end of the story), and if Count is less than zero, the ends are moved backward (towards the beginning). The default value of Count for these Move methods is 1. These methods attempt to move Count Units, but movement is never beyond the ends of the story.
Methods that move one or both ends by matching character strings or string patterns, such as ITextRange::MoveWhile, ITextRange::MoveEndWhile, and ITextRange::MoveStartWhile, can move up to a maximum number of characters given by the signed Count argument. If Count is greater than zero, the ends to be moved are moved forward, and if Count is less than zero, the ends are moved backward. Two special Count values, tomForward and tomBackward, are defined. These values are guaranteed to reach the end and the start of the story, respectively. The default value of Count is tomForward.
In Move* methods that turn a nondegenerate range into a degenerate one, such as ITextRange::Move, ITextRange::MoveWhile, and ITextRange::MoveUntil, cpFirst is changed if Count is negative and cpLim is changed if Count is positive. After this movement, the other end of the range is also moved to the new location. See the individual methods for more specific Count information. For nondegenerate ranges, the methods ITextRange::MoveStart, ITextRange::MoveEnd, ITextRange::MoveStartWhile, ITextRange::MoveEndWhile, ITextRange::MoveStartUntil and ITextRange::MoveEndUntil move either the starting position (Start) or the ending position (End).
To select a unit that corresponds to a contiguous range, such as a tomWord, tomSentence, and tomParagraph, use the ITextRange::MoveEnd method. To select a unit that corresponds to a noncontiguous range, such as tomObject, use the ITextRange::EndOf method, since the next object may occur after substantial intermediate text, if at all. To select a tomCell unit, the range must be inside a table.
Examples and further explanation of the Count and Unit arguments follow. Note that TOM engines may not support all of the units in the table above. For example, rich edit controls do not offer the concepts of sections, but rather return E_NOTIMPL when given tomSection. However if a TOM engine does support a unit, it has the index value given in the table.
Applications typically do not implement the ITextRange interface. Microsoft text solutions, such as rich edit controls, implement ITextRange as part of their TOM implementation.
Applications can retrieve an ITextRange pointer by calling the ITextDocument::Range method.