void ITextRangeProvider.ExpandToEnclosingUnit(TextUnit unit) { Misc.SetFocus(_provider._hwnd); switch (unit) { case TextUnit.Character: // if it is a degenerate range then expand it to be one character. // otherwise, leave it as it is. if (Start == End) { int moved; End = MoveEndpointForward(End, TextUnit.Character, 1, out moved); } break; case TextUnit.Word: { // this works same as paragraph except we look for word boundaries instead of paragraph boundaries. // get the text so we can figure out where the boundaries are string text = _provider.GetText(); ValidateEndpoints(); #if WCP_NLS_ENABLED // use the same word breaker that Avalon Text uses. WordBreaker breaker = new WordBreaker(); TextContainer container = new TextContainer(text); // if the starting point of the range is not already at a word break // then move it backwards to the nearest word break. TextNavigator startNavigator = new TextNavigator(Start, container); if (!breaker.IsAtWordBreak(startNavigator)) { breaker.MoveToPreviousWordBreak(startNavigator); Start = startNavigator.Position; } // if the range is degenerate or the ending point of the range is not already at a word break // then move it forwards to the nearest word break. TextNavigator endNavigator = new TextNavigator(End, container); if (Start == End || !breaker.IsAtWordBreak(endNavigator)) { breaker.MoveToNextWordBreak(endNavigator); End = endNavigator.Position; } #else // move start left until we reach a word boundary. for (; !AtWordBoundary(text, Start); Start--) { ; } // move end right until we reach word boundary (different from Start). End = Math.Min(Math.Max(End, Start + 1), text.Length); for (; !AtWordBoundary(text, End); End++) { ; } #endif } break; case TextUnit.Line: { if (_provider.GetLineCount() != 1) { int startLine = _provider.LineFromChar(Start); int endLine = _provider.LineFromChar(End); MoveTo(_provider.LineIndex(startLine), _provider.LineIndex(endLine + 1)); } else { MoveTo(0, _provider.GetTextLength()); } } break; case TextUnit.Paragraph: { // this works same as paragraph except we look for word boundaries instead of paragraph boundaries. // get the text so we can figure out where the boundaries are string text = _provider.GetText(); ValidateEndpoints(); // move start left until we reach a paragraph boundary. for (; !AtParagraphBoundary(text, Start); Start--) { ; } // move end right until we reach a paragraph boundary (different from Start). End = Math.Min(Math.Max(End, Start + 1), text.Length); for (; !AtParagraphBoundary(text, End); End++) { ; } } break; case TextUnit.Format: case TextUnit.Page: case TextUnit.Document: MoveTo(0, _provider.GetTextLength()); break; //break; default: throw new System.ComponentModel.InvalidEnumArgumentException("unit", (int)unit, typeof(TextUnit)); } }
// moves an endpoint forward a certain number of units. // the endpoint is just an index into the text so it could represent either // the endpoint. private int MoveEndpointForward(int index, TextUnit unit, int count, out int moved) { switch (unit) { case TextUnit.Character: { int limit = _provider.GetTextLength(); ValidateEndpoints(); moved = Math.Min(count, limit - index); index = index + moved; index = index > limit ? limit : index; } break; case TextUnit.Word: { string text = _provider.GetText(); ValidateEndpoints(); #if WCP_NLS_ENABLED // use the same word breaker as Avalon Text. WordBreaker breaker = new WordBreaker(); TextContainer container = new TextContainer(text); TextNavigator navigator = new TextNavigator(index, container); // move forward one word break for each count for (moved = 0; moved < count && index < text.Length; moved++) { if (!breaker.MoveToNextWordBreak(navigator)) { break; } } index = navigator.Position; #else for (moved = 0; moved < count && index < text.Length; moved++) { for (index++; !AtWordBoundary(text, index); index++) { ; } } #endif } break; case TextUnit.Line: { // figure out what line we are on. if we are in the middle of a line and // are moving left then we'll round up to the next line so that we move // to the beginning of the current line. int line = _provider.LineFromChar(index); // limit the number of lines moved to the number of lines available to move // Note lineMax is always >= 1. int lineMax = _provider.GetLineCount(); moved = Math.Min(count, lineMax - line - 1); if (moved > 0) { // move the endpoint to the beginning of the destination line. index = _provider.LineIndex(line + moved); } else if (moved == 0 && lineMax == 1) { // There is only one line so get the text length as endpoint index = _provider.GetTextLength(); moved = 1; } } break; case TextUnit.Paragraph: { // just like moving words but we look for paragraph boundaries instead of // word boundaries. string text = _provider.GetText(); ValidateEndpoints(); for (moved = 0; moved < count && index < text.Length; moved++) { for (index++; !AtParagraphBoundary(text, index); index++) { ; } } } break; case TextUnit.Format: case TextUnit.Page: case TextUnit.Document: { // since edit controls are plain text moving one uniform format unit will // take us all the way to the end of the document, just like // "pages" and document. int limit = _provider.GetTextLength(); ValidateEndpoints(); // we'll move 1 format unit if we aren't already at the end of the // document. Otherwise, we won't move at all. moved = index < limit ? 1 : 0; index = limit; } break; default: throw new System.ComponentModel.InvalidEnumArgumentException("unit", (int)unit, typeof(TextUnit)); } return(index); }