Example #1
0
        // Attach non-breaking elements to the text or object on
        // their left.
        internal static bool MoveNaviBackward(TextNavigator nav)
        {
            TextSymbolType type;
            bool           continueLoop = true;
            TextPosition   position     = nav.CreatePosition();

            type = nav.GetSymbolType(LogicalDirection.Backward);
            while (continueLoop)
            {
                if (nav.CompareTo(nav.TextContainer.Start) == 0)
                {
                    return(false);
                }

                switch (type)
                {
                case TextSymbolType.Character:
                case TextSymbolType.EmbeddedObject:
                    continueLoop = false;
                    break;

                case TextSymbolType.ElementStart:
                case TextSymbolType.ElementEnd:
                    if (IsBreakingSymbol(nav, LogicalDirection.Backward))
                    {
                        continueLoop = false;
                    }
                    break;
                }
                nav.MoveByDistance(-1);
                type = nav.GetSymbolType(LogicalDirection.Backward);
            }
            return(nav.CompareTo(position) < 0);
        }
Example #2
0
        /// <summary>
        /// Tries to find a selection boundary LogicalDirection.Forward of
        /// the current position.
        /// </summary>
        public bool MoveToNextWordBreak(TextNavigator navigator)
        {
            int index;

            // If the array of break positions hasn't been created and
            // populated yet, do that work now.
            if (null == breakPositions)
            {
                if (!BreakText(navigator, false, out breakPositions))
                {
                    return(false);
                }
            }

            index = breakPositions.BinarySearch(navigator);
            if (index < 0)
            {
                index = (~index);
            }
            else
            {
                index += 1;
            }

            if ((index > breakPositions.Count - 1) &&
                (0 != navigator.TextContainer.End.CompareTo((TextPosition)breakPositions[breakPositions.Count - 1])))
            {
                breakPositions = null;
                if (!BreakText(navigator, false, out breakPositions))
                {
                    return(false);
                }
                index = breakPositions.BinarySearch(navigator);
                if (index < 0)
                {
                    index = (~index);
                }
                else
                {
                    index += 1;
                }
            }

            if ((index < 0) || (index > breakPositions.Count - 1))
            {
                return(false);
            }

            navigator.MoveToPosition((TextPosition)breakPositions[index]);
            return(true);
        }
Example #3
0
        internal bool BreakText(TextPosition start, TextPosition end, bool isSpelling, out ArrayList positionList)
        {
            string        breakingString;
            ArrayList     indexList;
            int           currentIndex = 0;
            int           lastIndex    = 0;
            int           i;
            TextNavigator nav = start.CreateNavigator();

            positionList = null;

            // Convert input and execute main work.
            if (nav.CompareTo(nav.TextContainer.Start) != 0)
            {
                MoveNaviBackward(nav);
                MoveNaviForward(nav);
            }

            breakingString = GenerateText(nav, end);
            if (!BreakText(breakingString, isSpelling, out indexList))
            {
                return(false);
            }

            // Convert from indices to TextPositions and return.
            positionList = new ArrayList();
            if (0 == start.CompareTo(start.TextContainer.Start))
            {
                positionList.Add(start);
            }

            foreach (Object item in indexList)
            {
                currentIndex = (int)item;
                for (i = 0; i < (currentIndex - lastIndex); ++i)
                {
                    MoveNaviForward(nav);
                }
                positionList.Add(nav.CreatePosition());
                lastIndex = currentIndex;
            }

            if (0 == end.CompareTo(end.TextContainer.End))
            {
                // Add the end of the container as the last break.
                positionList.Add(end);
            }
            return(true);
        }
Example #4
0
        private static bool IsBreakingSymbol(TextNavigator navigator, LogicalDirection direction)
        {
            TextSymbolType type = navigator.GetSymbolType(direction);

            // (JCS) - This will need to be reworked after the Avalon team has
            // an API that can be called to determine if an Element should be
            // "breaking" or not.
            return((type == TextSymbolType.None) ||
                   (type == TextSymbolType.EmbeddedObject) ||
                   (((type == TextSymbolType.ElementStart) ||
                     (type == TextSymbolType.ElementEnd)
                     ) &&
                    (navigator.GetElementType(direction).IsAssignableFrom(typeof(InlineElement)))
                   )
                   );
        }
Example #5
0
        internal static string GenerateText(TextPosition begin, TextPosition end)
        {
            StringBuilder  output    = new StringBuilder();
            TextNavigator  navigator = begin.CreateNavigator();
            TextSymbolType type;

            char[] buffer = new char[1];
            char   ch;

            if (begin.TextContainer != end.TextContainer)
            {
                throw new ArgumentException(SR.Get(SRID.BeginEndTextContainerMismatch));
            }

            navigator.MoveToPosition(begin);
            type = navigator.GetSymbolType(LogicalDirection.Forward);
            while (navigator < end)
            {
                switch (type)
                {
                case TextSymbolType.Character:
                    navigator.GetText(LogicalDirection.Forward, 1, navigator.TextContainer.End, buffer, 0);
                    ch = buffer[0];
                    output.Append(ch);
                    break;

                case TextSymbolType.EmbeddedObject:
                    ch = '\xF8FF';          // Private use Unicode.
                    output.Append(ch);
                    break;

                case TextSymbolType.ElementStart:
                case TextSymbolType.ElementEnd:
                    if (IsBreakingSymbol(navigator, LogicalDirection.Forward))
                    {
                        output.Append(" ");
                    }
                    break;
                }

                navigator.MoveByDistance(1);
                type = navigator.GetSymbolType(LogicalDirection.Forward);
            }

            return(output.ToString());
        }
Example #6
0
        internal bool BreakText(TextPosition position, bool isSpelling, out ArrayList positionList)
        {
            TextNavigator start      = position.CreateNavigator();
            TextNavigator end        = position.CreateNavigator();
            TextNavigator checkLeft  = position.CreateNavigator();
            TextNavigator checkRight = position.CreateNavigator();
            bool          leftEdge   = false;
            bool          rightEdge  = false;
            int           distance   = 32;
            int           index;
            bool          foundBreaks = false;

            positionList = null;

            while (!(leftEdge && rightEdge))
            {
                if (!leftEdge)
                {
                    if (start.TextContainer.Start.GetDistanceTo(start) > distance)
                    {
                        start.MoveByDistance(-(distance));
                    }
                    else
                    {
                        start.MoveToPosition(start.TextContainer.Start);
                        leftEdge = true;
                    }

                    MoveNaviForward(start);
                    MoveNaviBackward(start);
                }

                if (!rightEdge)
                {
                    if (end.GetDistanceTo(end.TextContainer.End) > distance)
                    {
                        end.MoveByDistance(distance);
                    }
                    else
                    {
                        end.MoveToPosition(end.TextContainer.End);
                        rightEdge = true;
                    }

                    MoveNaviBackward(end);
                    MoveNaviForward(end);
                }

                if (BreakText(start, end, isSpelling, out positionList))
                {
                    foundBreaks = true;
                }
                else
                {
                    continue;
                }

                if (!leftEdge)
                {
                    index = positionList.BinarySearch(checkLeft);
                    if (index < 0)
                    {
                        index = (~index);
                    }
                    index -= 1;

                    leftEdge = (index >= 0);
                }

                if (!rightEdge)
                {
                    index = positionList.BinarySearch(checkRight);
                    if (index < 0)
                    {
                        index = (~index);
                    }
                    else
                    {
                        index += 1;
                    }

                    rightEdge = (index < positionList.Count);
                }
            }
            return(foundBreaks);
        }
        // moves an endpoint backward a certain number of units.
        // the endpoint is just an index into the text so it could represent either
        // the endpoint.
        private int MoveEndpointBackward(int index, TextUnit unit, int count, out int moved)
        {
            switch (unit)
            {
            case TextUnit.Character:
            {
                int limit = _provider.GetTextLength();
                ValidateEndpoints();

                int oneBasedIndex = index + 1;

                moved = Math.Max(count, -oneBasedIndex);
                index = index + moved;

                index = index < 0 ? 0 : 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 backward one word break for each count
                for (moved = 0; moved > count && index > 0; moved--)
                {
                    if (!breaker.MoveToPreviousWordBreak(navigator))
                    {
                        break;
                    }
                }

                index = navigator.Position;
#else
                for (moved = 0; moved > count && index > 0; moved--)
                {
                    for (index--; !AtWordBoundary(text, index); index--)
                    {
                        ;
                    }
                }
#endif
            }
            break;

            case TextUnit.Line:
            {
                // Note count < 0.

                // Get 1-based line.
                int line = _provider.LineFromChar(index) + 1;

                int lineMax = _provider.GetLineCount();

                // Truncate the count to the number of available lines.
                int actualCount = Math.Max(count, -line);

                moved = actualCount;

                if (actualCount == -line)
                {
                    // We are moving by the maximum number of possible lines,
                    // so we know the resulting index will be 0.
                    index = 0;

                    // If a line other than the first consists of only "\r\n",
                    // you can move backwards past this line and the position changes,
                    // hence this is counted.  The first line is special, though:
                    // if it is empty, and you move say from the second line back up
                    // to the first, you cannot move further; however if the first line
                    // is nonempty, you can move from the end of the first line to its
                    // beginning!  This latter move is counted, but if the first line
                    // is empty, it is not counted.

                    // Recalculate the value of "moved".
                    // The first line is empty if it consists only of
                    // a line separator sequence.
                    bool firstLineEmpty =
                        ((lineMax > 1 && _provider.LineIndex(1) == _lineSeparator.Length) ||
                         lineMax == 0);

                    if (moved < 0 && firstLineEmpty)
                    {
                        ++moved;
                    }
                }
                else         // actualCount > -line
                {
                    // Move the endpoint to the beginning of the following line,
                    // then back by the line separator length to get to the end
                    // of the previous line, since the Edit control has
                    // no method to get the character index of the end
                    // of a line directly.
                    index = _provider.LineIndex(line + actualCount) - _lineSeparator.Length;
                }
            }
            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 > 0; 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 beginning of the document, just like
                // "pages" and document.

                // we'll move 1 format unit if we aren't already at the beginning of the
                // document.  Otherwise, we won't move at all.
                moved = index > 0 ? -1 : 0;
                index = 0;
            }
            break;

            default:
                throw new System.ComponentModel.InvalidEnumArgumentException("unit", (int)unit, typeof(TextUnit));
            }

            return(index);
        }
        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);
        }