コード例 #1
0
        private bool SplitParagraph(MultiLineInsertData input, out Action makeSelection)
        {
            int index = ItemIndex(input.Selection as InsertionPoint);

            MakeListItem(index + 1, false);
            var newItem = List[index + 1];
            var sel     = input.Selection as InsertionPoint;

            if (input.TsStrAppendToFirstPara == null || input.TsStrPrependToLastPara == null)
            {
                MoveMaterialAfterIpToStart(sel, input.StringAppendToFirstPara, input.StringPrependToLastPara, newItem);
            }
            else
            {
                MoveMaterialAfterIpToStart(sel, input.TsStrAppendToFirstPara, input.TsStrPrependToLastPara, newItem);
            }
            if (input.ParaStyles != null)
            {
                if (input.ParaStyles.First() != null)
                {
                    ApplyParagraphStyle(index, 1, input.ParaStyles.First().Name);
                }
                if (input.ParaStyles.Last() != null)
                {
                    ApplyParagraphStyle(index + 1, 1, input.ParaStyles.Last().Name);
                }
            }

            makeSelection = () => SelectionBuilder.In(Hookup)[index].Offset(0).Install();
            return(true);
        }
コード例 #2
0
        /// <summary>
        /// Insert a new paragraph, after the user types Enter, where the previous selection
        /// is an insertion point at the end of the paragraph.
        /// </summary>
        public virtual bool InsertFollowingParagraph(InsertionPoint ip, out Action makeSelection)
        {
            int index = ItemIndex(ip) + 1;

            MakeListItem(index, false);
            makeSelection = () => SelectionBuilder.In(Hookup)[index].Offset(0).Install();
            return(true);
        }
コード例 #3
0
        public virtual bool InsertFollowingParagraph(RangeSelection range, out Action makeSelection)
        {
            int index = ItemIndex(range.Start) + 1;

            DeleteItems(range.Start.StringPosition, range.End.StringPosition);
            MakeListItem(index, false);
            makeSelection = () => SelectionBuilder.In(Hookup)[index].Offset(0).Install();
            return(true);
        }
コード例 #4
0
        public bool SplitParagraph(InsertionPoint ip, out Action makeSelection)
        {
            int index = ItemIndex(ip);

            MakeListItem(index + 1, false);
            var newItem = List[index + 1];

            MoveMaterialAfterIpToStart(ip, "", "", newItem);
            makeSelection = () => SelectionBuilder.In(Hookup)[index + 1].Offset(0).Install();
            return(true);
        }
コード例 #5
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="SelectSetup{TSource,TDestination}" /> class.
        /// </summary>
        /// <param name="selectionBuilder">
        ///     The selection builder.
        /// </param>
        /// <param name="data">
        ///     The <see cref="QueryHelperData" /> instance.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="selectionBuilder" /> is null.
        /// </exception>
        public SelectSetup(SelectionBuilder <TSource, TDestination> selectionBuilder, QueryHelperData data)
        {
            if (selectionBuilder == null)
            {
                throw new ArgumentNullException("selectionBuilder");
            }

            Data = data;

            Mappings = new Dictionary <string, IProjection>();

            ProjectionList = Projections.ProjectionList();

            SelectionBuilder = selectionBuilder;
        }
コード例 #6
0
        public void MlsDelete()
        {
            var styles = new AssembledStyles();
            var root   = new RootBoxFdo(styles.WithWs(23));
            var mock1  = new MockData1(23, 23);

            mock1.MlSimpleOne = new MultiAccessor(23, 23);
            mock1.MlSimpleOne.set_String(23, TsStrFactoryClass.Create().MakeString("This is it", 23));
            var engine = new FakeRenderEngine()
            {
                Ws = 23, SegmentHeight = 13
            };
            var factory = new FakeRendererFactory();

            factory.SetRenderer(23, engine);
            root.Builder.Show(Display.Of(() => mock1.MlSimpleOne, 23));
            var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);

            root.Layout(layoutArgs);
            PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
            MockSite       site   = new MockSite();

            site.m_transform  = ptrans;
            site.m_vwGraphics = m_gm.VwGraphics;
            root.Site         = site;

            SelectionBuilder.In(root).Offset("This ".Length).To.Offset("This is ".Length).Install();
            var sel = root.Selection as RangeSelection;

            // This is currently the main test for SelectionBuilder.In(RootBox) and SelectionBuilder.To in TsStrings
            // This verifies that it makes roughly the right range selection.
            Assert.That(sel.Anchor.LogicalParaPosition, Is.EqualTo("This ".Length));
            Assert.That(sel.DragEnd.LogicalParaPosition, Is.EqualTo("This is ".Length));

            Assert.That(sel.CanDelete(), Is.True);
            root.OnDelete();
            ITsString i = mock1.MlSimpleOne.get_String(23);

            Assert.That(mock1.MlSimpleOne.get_String(23).Text, Is.EqualTo("This it"));
            var ip = root.Selection as InsertionPoint;

            Assert.That(ip.LogicalParaPosition, Is.EqualTo("This ".Length));
            // Enhance JohnT: if there is any reason to prefer associatePrevious to be true or false,
            // clamp that and make it so.
            // A fairly rudimentary check on invalidate, since we elsewhere check general string-edit ops.
            Assert.That(site.RectsInvalidatedInRoot, Is.Not.Empty);
        }
コード例 #7
0
        /// <summary>
        /// Replace the text in the range, presumed to extend across more than one paragraph,
        /// with the supplied text.
        /// This one serves also for backspace at start of paragraph and delete at end, since
        /// these can readily be transformed into deleting a range from the end of one para
        /// to the start of the next. The given range is replace by a simple string.
        /// Enhance JohnT: it would probably make sense to break this up, more like SplitParagraph,
        /// into further virtual methods that subclasses could override. But I haven't figured out how yet.
        /// </summary>
        public bool InsertString(RangeSelection range, string insert, out Action makeSelection)
        {
            makeSelection = () => DoNothing();             // a default.
            var firstIp        = range.Start;
            var lastIp         = range.End;
            int firstItemIndex = ItemIndex(firstIp);
            int lastItemIndex  = ItemIndex(lastIp);

            if (firstItemIndex == lastItemIndex)
            {
                throw new ArgumentException("Should not need to use ParagraphOps.InsertString for range in same item");
            }
            int startPosition = firstIp.StringPosition;

            if (!MergeTextAfterSecondIntoFirst(firstIp, lastIp, insert))
            {
                return(false);
            }
            DeleteItems(firstItemIndex + 1, lastItemIndex);
            makeSelection = () => SelectionBuilder.In(Hookup)[firstItemIndex].Offset(startPosition + insert.Length).Install();
            return(true);
        }
コード例 #8
0
        public void DragCopyRtf()
        {
            var stylesheet  = new MockStylesheet();
            var styleFirst  = stylesheet.AddStyle("first", false);
            var styleSecond = stylesheet.AddStyle("second", false);
            var propsTrue   = new MockStyleProp <bool>()
            {
                Value = true, ValueIsSet = true
            };
            var charInfo = new MockCharStyleInfo();

            styleFirst.DefaultCharacterStyleInfo = charInfo;
            charInfo.Bold = propsTrue;
            // Todo: make styleSecond have pretty much everything else.
            var charInfo2 = new MockCharStyleInfo();

            styleSecond.DefaultCharacterStyleInfo = charInfo2;
            charInfo2.FontColor      = MakeColorProp(Color.Red);
            charInfo2.BackColor      = MakeColorProp(Color.Yellow);
            charInfo2.UnderlineColor = MakeColorProp(Color.Green);
            charInfo2.Italic         = propsTrue;
            charInfo2.FontName       = new MockStyleProp <string>()
            {
                Value = "Arial", ValueIsSet = true
            };

            var styles = new AssembledStyles(stylesheet);
            var root   = new RootBoxFdo(styles);
            var mock1  = new MockData1(23, 23);

            mock1.SimpleThree = "This is";
            var mock2 = new MockData1(23, 23);

            mock2.SimpleThree = " the day";
            var mock3 = new MockData1(23, 23);

            mock3.SimpleThree = " that the";
            var engine = new FakeRenderEngine()
            {
                Ws = 23, SegmentHeight = 13
            };
            var factory = new FakeRendererFactory();
            var wsf     = new MockWsf();

            engine.WritingSystemFactory = wsf;
            var wsEngine = wsf.MakeMockEngine(23, "en", engine);

            factory.SetRenderer(23, engine);
            root.Builder.Show(
                Paragraph.Containing(
                    Display.Of(() => mock1.SimpleThree, 23).Style("first"),
                    Display.Of(() => mock2.SimpleThree, 23).Style("second"),
                    Display.Of(() => mock3.SimpleThree, 23).Style("first")
                    ));
            var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);

            root.Layout(layoutArgs);
            PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
            MockSite       site   = new MockSite();

            site.m_transform  = ptrans;
            site.m_vwGraphics = m_gm.VwGraphics;
            root.Site         = site;

            SelectionBuilder.In(root).Offset("This ".Length).To.Offset("This is the day that".Length).Install();
            int indent = FakeRenderEngine.SimulatedWidth("This ");

            root.OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, indent + 5, 4, 0), Keys.None, m_gm.VwGraphics, ptrans);
            root.OnMouseMove(new MouseEventArgs(MouseButtons.Left, 1, indent + 5, 4, 0), Keys.None, m_gm.VwGraphics, ptrans);
            Assert.That(GetStringDropData(site), Is.EqualTo("is the day that"));
            // The order of the font and colors in the color table is arbitrary. This happens to be what the code does now. For some reason
            // Color.Green has green only 128.
            // The order of items in the definition of a style is arbitrary.
            // We're not doing anything yet for background color. \highlightN can specify background color for a character run,
            // but it can't be part of a style definition.
            Assert.That(GetRtfDropData(site), Is.EqualTo(
                            RangeSelection.RtfPrefix
                            + @"{\fonttbl{\f0 MockFont;}{\f1 Arial;}}"
                            + @"{\colortbl ;\red0\green0\blue0;\red255\green255\blue255;\red255\green0\blue0;\red255\green255\blue0;\red0\green128\blue0;}"
                            + @"{\stylesheet{\*\cs1\b\additive first;\*\cs2\i\f1\cf3\ulc5\additive second;}}"
                            + RangeSelection.RtfDataPrefix
                            + @"{\*\cs1\b is}{\*\cs2\i\f1\cf3\ulc5\highlight4  the day}{\*\cs1\b  that\par}"
                            + @"}"));

            // Todo: handle styles that depend on WS
            // Todo: handle more than two runs
            // Todo: handle runs where actual formatting differs from style-specified formatting
            // Todo: handle multiple paragraphs
            // Todo: handle paragraph styles
        }
コード例 #9
0
        public void BasicDragMove()
        {
            var styles = new AssembledStyles();
            var root   = new RootBoxFdo(styles);
            var mock1  = new MockData1(23, 23);

            mock1.SimpleThree = "This is the day";
            var engine = new FakeRenderEngine()
            {
                Ws = 23, SegmentHeight = 13
            };
            var factory = new FakeRendererFactory();

            factory.SetRenderer(23, engine);
            root.Builder.Show(Display.Of(() => mock1.SimpleThree, 23));
            var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);

            root.Layout(layoutArgs);
            PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
            MockSite       site   = new MockSite();

            site.m_transform  = ptrans;
            site.m_vwGraphics = m_gm.VwGraphics;
            root.Site         = site;

            SelectionBuilder.In(root).Offset("This ".Length).To.Offset("This is ".Length).Install();

            var dataObj  = new DataObject(DataFormats.StringFormat, "is ");
            int x        = FakeRenderEngine.SimulatedWidth("This is the ") + 2;
            var location = new Point(x, 8);

            // A drag to where we can drop, allowing both copy and move, no keys held
            var dragArgs = new DragEventArgs(dataObj, (int)DragDropKeyStates.None, 200, 300,
                                             DragDropEffects.Copy | DragDropEffects.Move,
                                             DragDropEffects.None);

            root.OnDragEnter(dragArgs, location, m_gm.VwGraphics, ptrans);
            Assert.That(dragArgs.Effect, Is.EqualTo(DragDropEffects.Move));
            Assert.That(root.DragState, Is.EqualTo(WindowDragState.DraggingHere));

            var qcdArgs = new QueryContinueDragEventArgs((int)DragDropKeyStates.None, false, DragAction.Drop);

            root.OnQueryContinueDrag(qcdArgs);
            Assert.That(root.DragState, Is.EqualTo(WindowDragState.InternalMove));
            root.OnDragLeave();
            Assert.That(root.DragState, Is.EqualTo(WindowDragState.InternalMove), "DragLeave should not clear InternalMove");

            root.OnDragDrop(dragArgs, location, m_gm.VwGraphics, ptrans);
            Assert.That(mock1.SimpleThree, Is.EqualTo("This the is day"));
            Assert.That(root.DragState, Is.EqualTo(WindowDragState.None));

            // Now let's drag the 'is' out to another window.
            SelectionBuilder.In(root).Offset("This the ".Length).To.Offset("This the is ".Length).Install();
            qcdArgs = new QueryContinueDragEventArgs((int)DragDropKeyStates.None, false, DragAction.Drop);
            root.OnQueryContinueDrag(qcdArgs);
            Assert.That(root.DragState, Is.EqualTo(WindowDragState.None),
                        "We should only set InternalMove if this window is the destination");
            Assert.That(mock1.SimpleThree, Is.EqualTo("This the day"));

            // Check that we can't drag inside our own selection.
            SelectionBuilder.In(root).Offset("This ".Length).To.Offset("This the".Length).Install();
            x        = FakeRenderEngine.SimulatedWidth("This t") + 2;
            location = new Point(x, 8);
            dragArgs = new DragEventArgs(dataObj, (int)DragDropKeyStates.None, 200, 300,
                                         DragDropEffects.Copy | DragDropEffects.Move,
                                         DragDropEffects.None);
            root.DragState = WindowDragState.InternalMove;
            root.OnDragDrop(dragArgs, location, m_gm.VwGraphics, ptrans);
            Assert.That(dragArgs.Effect, Is.EqualTo(DragDropEffects.None));
            Assert.That(mock1.SimpleThree, Is.EqualTo("This the day"));
        }
コード例 #10
0
        public void CombinedParaOperations()
        {
            // Set up a simple multi-para layout using the ObjSeq2 and SimpleThree properties of MockData1
            AssembledStyles styles = new AssembledStyles();
            RootBox         root   = new RootBoxFdo(styles);
            var             owner  = new MockData1();
            var             p1     = new MockData1(10, 11);
            var             p2     = new MockData1(10, 11);

            p1.SimpleThree = "Hello World";
            p2.SimpleThree = "This is a test";
            owner.ObjSeq2.Add(p1);
            owner.ObjSeq2.Add(p2);
            var po = new MockReceiveParagraphOperations();

            root.Builder.Show(Display.Of(() => owner.ObjSeq2)
                              .Using((builder, para) => builder.AddString(() => para.SimpleThree, 10))
                              .EditParagraphsUsing(po));
            SetupFakeRootSite(root);
            var layoutInfo = HookupTests.MakeLayoutInfo(int.MaxValue / 2, m_gm.VwGraphics, 55);

            root.Layout(layoutInfo);
            var ip = root.FirstBox.SelectAtEnd();

            // Insert at end of paragraph.
            ip.InsertLineBreak();
            Assert.That(owner.ObjSeq2.Count, Is.EqualTo(3));
            Assert.That(owner.ObjSeq2[0], Is.EqualTo(p1));
            Assert.That(owner.ObjSeq2[2], Is.EqualTo(p2));
            var p3 = owner.ObjSeq2[1];             // empty inserted paragraph.

            ((MockSite)root.Site).DoPendingAfterNotificationTasks();
            ip = (InsertionPoint)root.Selection;
            Assert.That(root.FirstBox.Next.Next, Is.Not.Null);
            Assert.That(ip.StringPosition, Is.EqualTo(0));
            Assert.That(ip.Para, Is.EqualTo(root.FirstBox.Next));

            // Insert at start of paragraph. To make it unambiguously the start, give p3 some data,
            // and since that might eventually destroy the selection, reset it.
            var rootHookup = ip.Hookup.ParentHookup.ParentHookup;             // StringHookup, ItemHookup, Sequence

            p3.SimpleThree = "First insert";
            ip             = (InsertionPoint)SelectionBuilder.In(rootHookup)[1].Offset(0).Install();
            ip.InsertLineBreak();
            Assert.That(owner.ObjSeq2.Count, Is.EqualTo(4));
            Assert.That(owner.ObjSeq2[0], Is.EqualTo(p1));
            Assert.That(owner.ObjSeq2[2], Is.EqualTo(p3));
            Assert.That(owner.ObjSeq2[3], Is.EqualTo(p2));
            var p4 = owner.ObjSeq2[1];             // empty inserted paragraph (before p3).

            Assert.That(root.FirstBox.Next.Next.Next, Is.Not.Null);
            ((MockSite)root.Site).DoPendingAfterNotificationTasks();
            ip = (InsertionPoint)root.Selection;
            Assert.That(ip.StringPosition, Is.EqualTo(0));
            Assert.That(ip.Para, Is.EqualTo(root.FirstBox.Next.Next));

            // Split a paragraph.
            var oldObjects = owner.ObjSeq2.ToArray();

            ip = (InsertionPoint)SelectionBuilder.In(rootHookup)[2].Offset("First ".Length).Install();
            ip.InsertLineBreak();
            Assert.That(owner.ObjSeq2.Count, Is.EqualTo(5));
            Assert.That(owner.ObjSeq2[1], Is.EqualTo(oldObjects[1]));
            Assert.That(owner.ObjSeq2[2], Is.EqualTo(oldObjects[2]));
            Assert.That(owner.ObjSeq2[4], Is.EqualTo(oldObjects[3])); // insert between 2 and 3
            var p5 = owner.ObjSeq2[3];                                // inserted paragraph.

            ((MockSite)root.Site).DoPendingAfterNotificationTasks();
            ip = (InsertionPoint)root.Selection;
            Assert.That(ip.StringPosition, Is.EqualTo(0));
            Assert.That(ip.Para, Is.EqualTo(root.FirstBox.Next.Next.Next));
            Assert.That(owner.ObjSeq2[2].SimpleThree, Is.EqualTo("First "));
            Assert.That(owner.ObjSeq2[3].SimpleThree, Is.EqualTo("insert"));

            // Combine two paragraphs by backspace at start of line.
            oldObjects = owner.ObjSeq2.ToArray();
            ip.Backspace();
            Assert.That(owner.ObjSeq2.Count, Is.EqualTo(4));
            Assert.That(owner.ObjSeq2[1], Is.EqualTo(oldObjects[1]));
            Assert.That(owner.ObjSeq2[2], Is.EqualTo(oldObjects[2]));
            Assert.That(owner.ObjSeq2[3], Is.EqualTo(oldObjects[4]));             // delete item 3
            ((MockSite)root.Site).DoPendingAfterNotificationTasks();
            ip = (InsertionPoint)root.Selection;
            Assert.That(ip.StringPosition, Is.EqualTo("First ".Length));
            Assert.That(ip.Para, Is.EqualTo(root.FirstBox.Next.Next));
            Assert.That(owner.ObjSeq2[2].SimpleThree, Is.EqualTo("First insert"));
        }
コード例 #11
0
ファイル: StTextTests.cs プロジェクト: vkarthim/FieldWorks
        public void CombinedParaOperationsFdo()
        {
            // Set up a simple multi-para layout using the ObjSeq2 and SimpleThree properties of MockData1
            AssembledStyles styles = new AssembledStyles();
            var             root   = new RootBoxFdo(styles);
            var             text   = Cache.ServiceLocator.GetInstance <ITextFactory>().Create();
            //Cache.LangProject.TextsOC.Add(text);
            var owner = Cache.ServiceLocator.GetInstance <IStTextFactory>().Create();

            text.ContentsOA = owner;
            IStTxtPara p1 = MakePara(owner, "Hello World");
            var        p2 = MakePara(owner, "This is a test");

            m_actionHandler.EndUndoTask();             // Finish settin up data, we want to control from now on.

            var po = new StTextParagraphOperations(owner);

            root.Builder.Show(Display.Of(() => owner.ParagraphsOS).Using((builder, para) => builder.AddString(()
                                                                                                              => ((IStTxtPara)para).Contents)).EditParagraphsUsing(po));
            SetupFakeRootSite(root);
            var layoutInfo = HookupTests.MakeLayoutInfo(int.MaxValue / 2, m_gm.VwGraphics, 55);

            root.Layout(layoutInfo);
            var ip = root.FirstBox.SelectAtEnd();

            // Insert at end of paragraph.
            m_actionHandler.BeginUndoTask("undo insert line break", "redo insert");
            ip.InsertLineBreak();
            m_actionHandler.EndUndoTask();
            Assert.That(owner.ParagraphsOS.Count, Is.EqualTo(3));
            Assert.That(owner.ParagraphsOS[0], Is.EqualTo(p1));
            Assert.That(owner.ParagraphsOS[2], Is.EqualTo(p2));
            var p3 = (IStTxtPara)owner.ParagraphsOS[1];             // empty inserted paragraph.

            Assert.That(p3.Contents.Length, Is.EqualTo(0));
            Assert.That(p3.Contents.get_WritingSystem(0), Is.EqualTo(Cache.DefaultVernWs));
            ((MockSite)root.Site).DoPendingAfterNotificationTasks();
            ip = (InsertionPoint)root.Selection;
            Assert.That(root.FirstBox.Next.Next, Is.Not.Null);
            Assert.That(ip.StringPosition, Is.EqualTo(0));
            Assert.That(ip.Para, Is.EqualTo(root.FirstBox.Next));

            // Insert at start of paragraph. To make it unambiguously the start, give p3 some data,
            // and since that might eventually destroy the selection, reset it.
            var rootHookup = ip.Hookup.ParentHookup.ParentHookup;             // StringHookup, ItemHookup, Sequence

            UndoableUnitOfWorkHelper.Do("adjust contents", "redo", m_actionHandler,
                                        () => p3.Contents = Cache.TsStrFactory.MakeString("First insert", Cache.DefaultVernWs));
            ip = (InsertionPoint)SelectionBuilder.In(rootHookup)[1].Offset(0).Install();
            m_actionHandler.BeginUndoTask("undo insert line break", "redo insert");
            ip.InsertLineBreak();
            m_actionHandler.EndUndoTask();
            Assert.That(owner.ParagraphsOS.Count, Is.EqualTo(4));
            Assert.That(owner.ParagraphsOS[0], Is.EqualTo(p1));
            Assert.That(owner.ParagraphsOS[2], Is.EqualTo(p3));
            Assert.That(owner.ParagraphsOS[3], Is.EqualTo(p2));
            var p4 = (IStTxtPara)owner.ParagraphsOS[1];             // empty inserted paragraph (before p3).

            Assert.That(root.FirstBox.Next.Next.Next, Is.Not.Null);
            Assert.That(p4.Contents.get_WritingSystem(0), Is.EqualTo(Cache.DefaultVernWs));
            ((MockSite)root.Site).DoPendingAfterNotificationTasks();
            ip = (InsertionPoint)root.Selection;
            Assert.That(ip.StringPosition, Is.EqualTo(0));
            Assert.That(ip.Para, Is.EqualTo(root.FirstBox.Next.Next));

            // Split a paragraph.
            var oldObjects = owner.ParagraphsOS.ToArray();

            ip = (InsertionPoint)SelectionBuilder.In(rootHookup)[2].Offset("First ".Length).Install();
            m_actionHandler.BeginUndoTask("undo insert line break", "redo insert");
            ip.InsertLineBreak();
            m_actionHandler.EndUndoTask();
            Assert.That(owner.ParagraphsOS.Count, Is.EqualTo(5));
            Assert.That(owner.ParagraphsOS[1], Is.EqualTo(oldObjects[1]));
            Assert.That(owner.ParagraphsOS[2], Is.EqualTo(oldObjects[2]));
            Assert.That(owner.ParagraphsOS[4], Is.EqualTo(oldObjects[3])); // insert between 2 and 3
            var p5 = (IStTxtPara)owner.ParagraphsOS[3];                    // inserted paragraph.

            ((MockSite)root.Site).DoPendingAfterNotificationTasks();
            ip = (InsertionPoint)root.Selection;
            Assert.That(ip.StringPosition, Is.EqualTo(0));
            Assert.That(ip.Para, Is.EqualTo(root.FirstBox.Next.Next.Next));
            Assert.That(((IStTxtPara)owner.ParagraphsOS[2]).Contents.Text, Is.EqualTo("First "));
            Assert.That(((IStTxtPara)owner.ParagraphsOS[3]).Contents.Text, Is.EqualTo("insert"));

            // Combine two paragraphs by backspace at start of line.
            oldObjects = owner.ParagraphsOS.ToArray();
            m_actionHandler.BeginUndoTask("undo backspace", "redo backspace");
            ip.Backspace();
            m_actionHandler.EndUndoTask();
            Assert.That(owner.ParagraphsOS.Count, Is.EqualTo(4));
            Assert.That(owner.ParagraphsOS[1], Is.EqualTo(oldObjects[1]));
            Assert.That(owner.ParagraphsOS[2], Is.EqualTo(oldObjects[2]));
            Assert.That(owner.ParagraphsOS[3], Is.EqualTo(oldObjects[4]));             // delete item 3
            ((MockSite)root.Site).DoPendingAfterNotificationTasks();
            ip = (InsertionPoint)root.Selection;
            Assert.That(ip.StringPosition, Is.EqualTo("First ".Length));
            Assert.That(ip.Para, Is.EqualTo(root.FirstBox.Next.Next));
            Assert.That(((IStTxtPara)owner.ParagraphsOS[2]).Contents.Text, Is.EqualTo("First insert"));
        }