MadBoy_cp 12 роки тому
джерело
коміт
d3342db329

+ 217
- 0
DocX/List.cs Переглянути файл

@@ -0,0 +1,217 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Novacode
{
/// <summary>
/// Represents a List in a document.
/// </summary>
public class List : InsertBeforeOrAfter
{
/// <summary>
/// This is a list of paragraphs that will be added to the document
/// when the list is inserted into the document.
/// The paragraph needs a numPr defined to be in this items collection.
/// </summary>
public List<Paragraph> Items { get; private set; }
/// <summary>
/// The numId used to reference the list settings in the numbering.xml
/// </summary>
public int NumId { get; private set; }
/// <summary>
/// The ListItemType (bullet or numbered) of the list.
/// </summary>
public ListItemType? ListType { get; private set; }

internal List(DocX document, XElement xml)
: base(document, xml)
{
Items = new List<Paragraph>();
ListType = null;
}

/// <summary>
/// Adds an item to the list.
/// </summary>
/// <param name="paragraph"></param>
/// <exception cref="InvalidOperationException">
/// Throws an InvalidOperationException if the item cannot be added to the list.
/// </exception>
public void AddItem(Paragraph paragraph)
{
if (paragraph.IsListItem)
{
var numIdNode = paragraph.Xml.Descendants().First(s => s.Name.LocalName == "numId");
var numId = Int32.Parse(numIdNode.Attribute(DocX.w + "val").Value);

if (CanAddListItem(paragraph))
{
NumId = numId;
Items.Add(paragraph);
}
else
throw new InvalidOperationException("New list items can only be added to this list if they are have the same numId.");
}
}

public void AddItemWithStartValue(Paragraph paragraph, int start)
{
//TODO: Update the numbering
UpdateNumberingForLevelStartNumber(int.Parse(paragraph.IndentLevel.ToString()), start);
if (ContainsLevel(start))
throw new InvalidOperationException("Cannot add a paragraph with a start value if another element already exists in this list with that level.");
AddItem(paragraph);
}

private void UpdateNumberingForLevelStartNumber(int iLevel, int start)
{
var abstractNum = GetAbstractNum(NumId);
var level = abstractNum.Descendants().First(el => el.Name.LocalName == "lvl" && el.GetAttribute(DocX.w + "ilvl") == iLevel.ToString());
level.Descendants().First(el => el.Name.LocalName == "start").SetAttributeValue(DocX.w + "val", start);
}

/// <summary>
/// Determine if it is able to add the item to the list
/// </summary>
/// <param name="paragraph"></param>
/// <returns>
/// Return true if AddItem(...) will succeed with the given paragraph.
/// </returns>
public bool CanAddListItem(Paragraph paragraph)
{
if (paragraph.IsListItem)
{
//var lvlNode = paragraph.Xml.Descendants().First(s => s.Name.LocalName == "ilvl");
var numIdNode = paragraph.Xml.Descendants().First(s => s.Name.LocalName == "numId");
var numId = Int32.Parse(numIdNode.Attribute(DocX.w + "val").Value);

//Level = Int32.Parse(lvlNode.Attribute(DocX.w + "val").Value);
if (NumId == 0 || (numId == NumId && numId > 0))
{
return true;
}
}
return false;
}

public bool ContainsLevel(int ilvl)
{
return Items.Any(i => i.ParagraphNumberProperties.Descendants().First(el => el.Name.LocalName == "ilvl").Value == ilvl.ToString());
}

internal void CreateNewNumberingNumId(int level = 0, ListItemType listType = ListItemType.Numbered)
{
ValidateDocXNumberingPartExists();
if (Document.numbering.Root == null)
{
throw new InvalidOperationException("Numbering section did not instantiate properly.");
}

ListType = listType;

var numId = GetMaxNumId() + 1;
var abstractNumId = GetMaxAbstractNumId() + 1;

XDocument listTemplate;
switch (listType)
{
case ListItemType.Bulleted:
listTemplate = HelperFunctions.DecompressXMLResource("Novacode.Resources.numbering.default_bullet_abstract.xml.gz");
break;
case ListItemType.Numbered:
listTemplate = HelperFunctions.DecompressXMLResource("Novacode.Resources.numbering.default_decimal_abstract.xml.gz");
break;
default:
throw new InvalidOperationException(string.Format("Unable to deal with ListItemType: {0}.", listType.ToString()));
}
var abstractNumTemplate = listTemplate.Descendants().Single(d => d.Name.LocalName == "abstractNum");
abstractNumTemplate.SetAttributeValue(DocX.w + "abstractNumId", abstractNumId);
var abstractNumXml = new XElement(XName.Get("num", DocX.w.NamespaceName), new XAttribute(DocX.w + "numId", numId), new XElement(XName.Get("abstractNumId", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", abstractNumId)));

var abstractNumNode = Document.numbering.Root.Descendants().LastOrDefault(xElement => xElement.Name.LocalName == "abstractNum");
var numXml = Document.numbering.Root.Descendants().LastOrDefault(xElement => xElement.Name.LocalName == "num");

if (abstractNumNode == null || numXml == null)
{
Document.numbering.Root.Add(abstractNumTemplate);
Document.numbering.Root.Add(abstractNumXml);
}
else
{
abstractNumNode.AddAfterSelf(abstractNumTemplate);
numXml.AddAfterSelf(
abstractNumXml
);
}

NumId = numId;
}

/// <summary>
/// Method to determine the last numId for a list element.
/// Also useful for determining the next numId to use for inserting a new list element into the document.
/// </summary>
/// <returns>
/// 0 if there are no elements in the list already.
/// Increment the return for the next valid value of a new list element.
/// </returns>
private int GetMaxNumId()
{
const int defaultValue = 0;
if (Document.numbering == null)
return defaultValue;

var numlist = Document.numbering.Descendants().Where(d => d.Name.LocalName == "num").ToList();
if (numlist.Any())
return numlist.Attributes(DocX.w + "numId").Max(e => int.Parse(e.Value));
return defaultValue;
}

/// <summary>
/// Method to determine the last abstractNumId for a list element.
/// Also useful for determining the next abstractNumId to use for inserting a new list element into the document.
/// </summary>
/// <returns>
/// -1 if there are no elements in the list already.
/// Increment the return for the next valid value of a new list element.
/// </returns>
private int GetMaxAbstractNumId()
{
const int defaultValue = -1;

if (Document.numbering == null)
return defaultValue;

var numlist = Document.numbering.Descendants().Where(d => d.Name.LocalName == "abstractNum").ToList();
if (numlist.Any())
{
var maxAbstractNumId = numlist.Attributes(DocX.w + "abstractNumId").Max(e => int.Parse(e.Value));
return maxAbstractNumId;
}
return defaultValue;
}

/// <summary>
/// Get the abstractNum definition for the given numId
/// </summary>
/// <param name="numId">The numId on the pPr element</param>
/// <returns>XElement representing the requested abstractNum</returns>
internal XElement GetAbstractNum(int numId)
{
var num = Document.numbering.Descendants().First(d => d.Name.LocalName == "num" && d.GetAttribute(DocX.w + "numId").Equals(numId.ToString()));
var abstractNumId = num.Descendants().First(d => d.Name.LocalName == "abstractNumId");
return Document.numbering.Descendants().First(d => d.Name.LocalName == "abstractNum" && d.GetAttribute("abstractNumId").Equals(abstractNumId.Value));
}

private void ValidateDocXNumberingPartExists()
{
var numberingUri = new Uri("/word/numbering.xml", UriKind.Relative);

// If the internal document contains no /word/numbering.xml create one.
if (!Document.package.PartExists(numberingUri))
Document.numbering = HelperFunctions.AddDefaultNumberingXml(Document.package);
}
}
}

BIN
DocX/Resources/numbering.default_bullet_abstract.xml.gz Переглянути файл


BIN
DocX/Resources/numbering.default_decimal_abstract.xml.gz Переглянути файл


BIN
DocX/Resources/numbering.xml.gz Переглянути файл


+ 18
- 0
DocX/Section.cs Переглянути файл

@@ -0,0 +1,18 @@
using System.Collections.Generic;
using System.IO.Packaging;
using System.Xml.Linq;

namespace Novacode
{
public class Section : Container
{

public SectionBreakType SectionBreakType;

internal Section(DocX document, XElement xml) : base(document, xml)
{
}

public List<Paragraph> SectionParagraphs { get; set; }
}
}

Завантаження…
Відмінити
Зберегти