예제 #1
0
        private void RenderList(ListLayout layout, IContentContainer container)
        {
            ++_numberingLevel;
            s.ListStyle listStyle = (s.ListStyle)layout.Style;

            //	Translate the bullet text from design syntax to Word syntax. The
            //	design specification can include formatting of its own, unrelated
            //	to the list style. The easiest way to interpret such formatting
            //	is to create a text layout from the bullet text, which will
            //	separate the formatting from the text. If the bullet includes
            //	formatting then the new text layout will start with a paragraph
            //	verse, which we'll ignore. And it could contain any
            //	number of other verses, but a numbering definition in Word supports
            //	only a single run, so we just concatenate the text from all the
            //	verses, and apply the first verse format we find. Note that our
            //	report design language doesn't support including lower level numbers
            //	in the number, such as 3x in 1, 2, 3a, 3b, 3c, 4, 5 etc.
            s.BulletStyle bulletStyle = listStyle.BulletStyle;
            string        bulletText  = bulletStyle.BulletText
                                        .Replace("%", "%%")
                                        .Replace(ListItemLayout.BulletNumberProperty, $"%{_numberingLevel+1}");
            TextFormat bulletFormat = new TextFormat(bulletStyle.Font, bulletStyle.Color);
            TextBlock  block        = new TextBlock(bulletText, bulletFormat, _generator);

            bulletText   = block.Verses.Select(v => v.Text).Aggregate((c, n) => c + n);
            bulletFormat = block.Verses.Select(v => v.Format).Where(f => f != null).FirstOrDefault();
            int numberingStyleId = _document.AddNumberingStyle(bulletStyle, _numberingLevel, bulletText);

            //	Create a numbering instance based on the numbering style, and add it
            //	to the paragraph. As far as I can make out, in a sequence of numbered
            //	paragraphs every paragraph refers to the one numbering instance.
            //	Any number of such sequences can get their numbering from the one
            //	underlying abstract definition, but each sequence would have its own
            //	instance. Instances are stored in the numbering part along with the
            //	abstract definitions.
            //
            //	We have to store abstract definitions in a dictionary in the document
            //	because we need random access to them so that different layouts in the
            //	design can share a single definition. But we can store instances in a
            //	simple stack in this class because each one is needed only for the
            //	current list.
            int numberingInstanceId = _document.AddNumberingInstance(numberingStyleId);

            _numberingInstances.Push(numberingInstanceId);



            //	Lists in the design can be nested - that's how we do indented list
            //	levels. But in Word each item must be its own paragraph, and the
            //	items together form the list by being contiguous paragraphs with
            //	a common numbering style. That is, Word doesn't have lists, but
            //	rather just has numbered paragraphs.
            foreach (Layout sublayout in layout.SubLayouts)
            {
                Render(sublayout, container);
            }

            _numberingInstances.Pop();
            --_numberingLevel;
        }
예제 #2
0
        private void RenderListItem(ListItemLayout layout, IContentContainer container)
        {
            //	A list item, which is based on a single design layout, can
            //	include any number of design paragraphs introduced by embedded
            //	HTML <p> tags. To render these as a single item in the Word
            //	list, they must all be rendered as a single Word paragraph.
            //	We achieve this by concatenating all the design paragraphs
            //	together, with double line break separators. The first line
            //	break starts a new line, and the second inserts some whitespace.
            //
            //	A nested list is introduced by a group layout, which is a single
            //	item in the current list and which contains its own list.
            //
            //	We only support text content in list items - no photos.
            //
            //	So the list item layout's content sublayout is always either
            //	a text layout or a group layout. And the list item is always
            //	a single Word paragraph.

            //	The item style is to be found in the item's list's style
            s.ListStyle listStyle           = (s.ListStyle)layout.Style;
            s.TextStyle itemStyle           = listStyle.ItemStyle;
            IParagraph  paragraph           = container.AddParagraph(itemStyle, layout.TrackingInfo);
            int         numberingInstanceId = _numberingInstances.Peek();     // stack guaranteed not to be empty

            paragraph.SetNumbering(numberingInstanceId, _numberingLevel);

            switch (layout.ContentLayout.LayoutType)
            {
            case LayoutType.Text:
            {
                TextLayout   contentLayout = (TextLayout)layout.ContentLayout;
                List <Verse> verses        = contentLayout.GetFormattedText();
                if (verses == null)
                {
                    break;
                }
                if (verses.Count == 0)
                {
                    break;
                }
                foreach (Verse verse in verses)
                {
                    if (verse is ParagraphVerse)
                    {
                        //	Two line breaks to look like a new paragraph without actually
                        //	being a new Word paragraph. But don't do this if it's the first
                        //	verse.
                        if (verse == verses[0])
                        {
                            continue;
                        }
                        paragraph.AddLineBreak();
                        paragraph.AddLineBreak();
                    }
                    else if (verse is LineBreakVerse)
                    {
                        paragraph.AddLineBreak();
                    }
                    else
                    {
                        paragraph.AddRun(verse.Text, verse.Format.Font, verse.Format.Color);
                    }
                }
                break;
            }

            case LayoutType.Group:
            {
                foreach (Layout sublayout in layout.ContentLayout.SubLayouts)
                {
                    Render(sublayout, container);
                }
                break;
            }

            default:
            {
                break;
            }
            }
        }