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; }
public AbstractNumberingDefinition(s.BulletStyle style, int level, string text) { _id = _nextId++; _level = level; _style = style; _text = text; }
/// <summary> /// Get the abstract Word numbering definition that maps to the given design style. /// </summary> public int GetNumbering(s.BulletStyle style, int level) { Dictionary <int, AbstractNumberingDefinition> inner = null; AbstractNumberingDefinition def = null; bool found = _abstractDefinitions.TryGetValue(style, out inner); if (found) { found = inner.TryGetValue(level, out def); if (found) { return(def.Id); } } throw new Exception($"Numbering style {style}@{level} not found."); }
public int AddNumberingStyle(s.BulletStyle style, int level, string bulletText) { // I can't find any clear statement in // ECMA-376 that 9 is the maximum level, but section 17.9.12 // "multiLevelType" hints at it with this: "a list with multiple // levels marked as singleLevel shall not be prevented from using // levels 2 through 9", and a quick test in Word shows that you // can't go deeper than 9. // We create a Word abstract numbering definition for every numbering // style found in the laid-out report. If the design specifies two // styles with the same properties then we create them as two abstract // numbering definitions, so that the user can restyle one of them // without affecting the other. If the designer wanted them to be // a single style then he wouldn't have defined them separately in // the design file. return(_numberings.AddAbstractDefinition(style, level, bulletText)); }
/// <summary> /// Create and add a new Word numbering style to represent the given design /// bullet style at the given level. If the bullet style already has a /// representation at this level then return that representation's id. /// </summary> public int AddAbstractDefinition(s.BulletStyle style, int level, string bulletText) { Dictionary <int, AbstractNumberingDefinition> inner = null; AbstractNumberingDefinition def = null; bool found = _abstractDefinitions.TryGetValue(style, out inner); if (found) { found = inner.TryGetValue(level, out def); if (found) { return(def.Id); } } if (inner == null) { inner = new Dictionary <int, AbstractNumberingDefinition>(); _abstractDefinitions.Add(style, inner); } def = new AbstractNumberingDefinition(style, level, bulletText); inner.Add(level, def); return(def.Id); }
int GetNumbering(s.BulletStyle style) { throw new NotImplementedException(); //TODO: refactor so we don't have to do this }
public int AddNumberingStyle(s.BulletStyle style, int level, string bulletText) { throw new NotImplementedException(); //TODO: refactor so we don't have to do this }
public int GetNumbering(s.BulletStyle style, int level) { return(_numberings.GetNumbering(style, level)); }