- MergeCellsInRow - allow for merging the rows where the columns don't match (for instance, merge the last column of a row with 6 elements and a row with 3 elements will merge the last column of the row with too few elements) - this is a specific case that I needed... others may need it as well, but I've got a separate branch with this change so it's up to you Container.cs (and baseclasses) - Moved PackagePart to the base class - found an issue where images in a table contained in the header or footer wouldn't display, this keeps track of what part of the doc and passes it to child things, (like inserting a table to a paragraph in the footer will have the correct part) - Add a deep search for paragraphs.. This is to find a bookmark within a textbox or other art.. since a paragraph will wind up with a child paragraph.. (if you are searching for a bookmark like that the second one is the "right" one)master
| @@ -79,6 +79,28 @@ namespace Novacode | |||
| return paragraphs.AsReadOnly(); | |||
| } | |||
| } | |||
| public virtual ReadOnlyCollection<Paragraph> ParagraphsDeepSearch | |||
| { | |||
| get | |||
| { | |||
| List<Paragraph> paragraphs = GetParagraphs(true); | |||
| foreach (var p in paragraphs) | |||
| { | |||
| if ((p.Xml.ElementsAfterSelf().FirstOrDefault() != null) && (p.Xml.ElementsAfterSelf().First().Name.Equals(DocX.w + "tbl"))) | |||
| p.FollowingTable = new Table(this.Document, p.Xml.ElementsAfterSelf().First()); | |||
| p.ParentContainer = GetParentFromXmlName(p.Xml.Ancestors().First().Name.LocalName); | |||
| if (p.IsListItem) | |||
| { | |||
| GetListItemType(p); | |||
| } | |||
| } | |||
| return paragraphs.AsReadOnly(); | |||
| } | |||
| } | |||
| // <summary> | |||
| /// Removes paragraph at specified position | |||
| /// </summary> | |||
| @@ -95,9 +117,9 @@ namespace Novacode | |||
| return true; | |||
| } | |||
| ++i; | |||
| } | |||
| return false; | |||
| } | |||
| @@ -170,32 +192,32 @@ namespace Novacode | |||
| //find num node in numbering | |||
| var numNodes = Document.numbering.Descendants().Where(n => n.Name.LocalName == "num"); | |||
| XElement numNode = numNodes.FirstOrDefault(node => node.Attribute(DocX.w + "numId").Value.Equals(numIdValue)); | |||
| if (numNode != null) | |||
| { | |||
| //Get abstractNumId node and its value from numNode | |||
| var abstractNumIdNode = numNode.Descendants().First(n => n.Name.LocalName == "abstractNumId"); | |||
| var abstractNumNodeValue = abstractNumIdNode.Attribute(DocX.w + "val").Value; | |||
| var abstractNumNodes = Document.numbering.Descendants().Where(n => n.Name.LocalName == "abstractNum"); | |||
| XElement abstractNumNode = | |||
| abstractNumNodes.FirstOrDefault(node => node.Attribute(DocX.w + "abstractNumId").Value.Equals(abstractNumNodeValue)); | |||
| //Find lvl node | |||
| var lvlNodes = abstractNumNode.Descendants().Where(n => n.Name.LocalName == "lvl"); | |||
| XElement lvlNode = null; | |||
| foreach (XElement node in lvlNodes) | |||
| { | |||
| if (node.Attribute(DocX.w + "ilvl").Value.Equals(ilvlValue)) | |||
| { | |||
| lvlNode = node; | |||
| break; | |||
| } | |||
| } | |||
| var numFmtNode = lvlNode.Descendants().First(n => n.Name.LocalName == "numFmt"); | |||
| p.ListItemType = GetListItemType(numFmtNode.Attribute(DocX.w + "val").Value); | |||
| } | |||
| if (numNode != null) | |||
| { | |||
| //Get abstractNumId node and its value from numNode | |||
| var abstractNumIdNode = numNode.Descendants().First(n => n.Name.LocalName == "abstractNumId"); | |||
| var abstractNumNodeValue = abstractNumIdNode.Attribute(DocX.w + "val").Value; | |||
| var abstractNumNodes = Document.numbering.Descendants().Where(n => n.Name.LocalName == "abstractNum"); | |||
| XElement abstractNumNode = | |||
| abstractNumNodes.FirstOrDefault(node => node.Attribute(DocX.w + "abstractNumId").Value.Equals(abstractNumNodeValue)); | |||
| //Find lvl node | |||
| var lvlNodes = abstractNumNode.Descendants().Where(n => n.Name.LocalName == "lvl"); | |||
| XElement lvlNode = null; | |||
| foreach (XElement node in lvlNodes) | |||
| { | |||
| if (node.Attribute(DocX.w + "ilvl").Value.Equals(ilvlValue)) | |||
| { | |||
| lvlNode = node; | |||
| break; | |||
| } | |||
| } | |||
| var numFmtNode = lvlNode.Descendants().First(n => n.Name.LocalName == "numFmt"); | |||
| p.ListItemType = GetListItemType(numFmtNode.Attribute(DocX.w + "val").Value); | |||
| } | |||
| } | |||
| @@ -203,38 +225,36 @@ namespace Novacode | |||
| public ContainerType ParentContainer; | |||
| internal List<Paragraph> GetParagraphs() | |||
| internal List<Paragraph> GetParagraphs(bool deepSearch=false) | |||
| { | |||
| // Need some memory that can be updated by the recursive search. | |||
| int index = 0; | |||
| List<Paragraph> paragraphs = new List<Paragraph>(); | |||
| GetParagraphsRecursive(Xml, ref index, ref paragraphs); | |||
| GetParagraphsRecursive(Xml, ref index, ref paragraphs, deepSearch); | |||
| return paragraphs; | |||
| } | |||
| internal void GetParagraphsRecursive(XElement Xml, ref int index, ref List<Paragraph> paragraphs) | |||
| internal void GetParagraphsRecursive(XElement Xml, ref int index, ref List<Paragraph> paragraphs, bool deepSearch=false) | |||
| { | |||
| // sdtContent are for PageNumbers inside Headers or Footers, don't go any deeper. | |||
| //if (Xml.Name.LocalName == "sdtContent") | |||
| // return; | |||
| var keepSearching = true; | |||
| if (Xml.Name.LocalName == "p") | |||
| { | |||
| paragraphs.Add(new Paragraph(Document, Xml, index)); | |||
| index += HelperFunctions.GetText(Xml).Length; | |||
| if (!deepSearch) | |||
| keepSearching = false; | |||
| } | |||
| else | |||
| if (keepSearching && Xml.HasElements) | |||
| { | |||
| if (Xml.HasElements) | |||
| foreach (XElement e in Xml.Elements()) | |||
| { | |||
| foreach (XElement e in Xml.Elements()) | |||
| { | |||
| GetParagraphsRecursive(e, ref index, ref paragraphs); | |||
| } | |||
| GetParagraphsRecursive(e, ref index, ref paragraphs, deepSearch); | |||
| } | |||
| } | |||
| } | |||
| @@ -499,7 +519,7 @@ namespace Novacode | |||
| if (Paragraphs.Any(p => p.ValidateBookmark(bookmarkName))) return new string[0]; | |||
| nonMatching.Add(bookmarkName); | |||
| } | |||
| return nonMatching.ToArray(); | |||
| } | |||
| @@ -823,7 +843,7 @@ namespace Novacode | |||
| XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount); | |||
| Xml.Add(newTable); | |||
| return new Table(Document, newTable); | |||
| return new Table(Document, newTable) { mainPart = mainPart}; | |||
| } | |||
| public Table InsertTable(int index, int rowCount, int columnCount) | |||
| @@ -848,7 +868,7 @@ namespace Novacode | |||
| } | |||
| return new Table(Document, newTable); | |||
| return new Table(Document, newTable) { mainPart = mainPart }; | |||
| } | |||
| public Table InsertTable(Table t) | |||
| @@ -856,8 +876,11 @@ namespace Novacode | |||
| XElement newXElement = new XElement(t.Xml); | |||
| Xml.Add(newXElement); | |||
| Table newTable = new Table(Document, newXElement); | |||
| newTable.Design = t.Design; | |||
| Table newTable = new Table(Document, newXElement) | |||
| { | |||
| mainPart = mainPart, | |||
| Design = t.Design | |||
| }; | |||
| return newTable; | |||
| } | |||
| @@ -875,8 +898,11 @@ namespace Novacode | |||
| split[1] | |||
| ); | |||
| Table newTable = new Table(Document, newXElement); | |||
| newTable.Design = t.Design; | |||
| Table newTable = new Table(Document, newXElement) | |||
| { | |||
| mainPart = mainPart, | |||
| Design = t.Design | |||
| }; | |||
| return newTable; | |||
| } | |||
| @@ -890,7 +916,7 @@ namespace Novacode | |||
| { | |||
| foreach (var item in list.Items) | |||
| { | |||
| // item.Font(System.Drawing.FontFamily fontFamily) | |||
| // item.Font(System.Drawing.FontFamily fontFamily) | |||
| Xml.Add(item.Xml); | |||
| } | |||
| @@ -663,8 +663,6 @@ namespace Novacode | |||
| return sections; | |||
| } | |||
| // Get the word\document.xml part | |||
| internal PackagePart mainPart; | |||
| // Get the word\settings.xml part | |||
| internal PackagePart settingsPart; | |||
| @@ -882,13 +880,13 @@ namespace Novacode | |||
| return HelperFunctions.GetText(Xml); | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// Get the text of each footnote from this document | |||
| /// </summary> | |||
| public IEnumerable<string> FootnotesText | |||
| { | |||
| get | |||
| { | |||
| /// <summary> | |||
| /// Get the text of each footnote from this document | |||
| /// </summary> | |||
| public IEnumerable<string> FootnotesText | |||
| { | |||
| get | |||
| { | |||
| foreach (XElement footnote in footnotes.Root.Elements(w + "footnote")) | |||
| { | |||
| yield return HelperFunctions.GetText(footnote); | |||
| @@ -1043,7 +1041,7 @@ namespace Novacode | |||
| merge_footnotes(remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes); | |||
| remote_footnotes = footnotes; | |||
| break; | |||
| case "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": | |||
| merge_endnotes(remote_pp, local_pp, remote_mainDoc, remote_document, remote_endnotes); | |||
| remote_endnotes = endnotes; | |||
| @@ -1201,9 +1199,9 @@ namespace Novacode | |||
| // In my testing I have found cases of Images inside documents that are not referenced | |||
| var remote_rel = remote_document.mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(remote_pp.Uri.OriginalString.Replace("/word/", ""))).FirstOrDefault(); | |||
| if (remote_rel == null) { | |||
| remote_rel = remote_document.mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(remote_pp.Uri.OriginalString)).FirstOrDefault(); | |||
| if (remote_rel == null) | |||
| return; | |||
| remote_rel = remote_document.mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(remote_pp.Uri.OriginalString)).FirstOrDefault(); | |||
| if (remote_rel == null) | |||
| return; | |||
| } | |||
| String remote_Id = remote_rel.Id; | |||
| @@ -1299,30 +1297,30 @@ namespace Novacode | |||
| } | |||
| if (!defRelId.Success) | |||
| { | |||
| // Replace all instances of remote_Id in the local document with local_Id | |||
| var elems_local = mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName)); | |||
| foreach (var elem in elems_local) | |||
| { | |||
| XAttribute embed = elem.Attribute(XName.Get("embed", DocX.r.NamespaceName)); | |||
| if (embed != null && embed.Value == remote_Id) | |||
| { | |||
| embed.SetValue(new_Id); | |||
| } | |||
| } | |||
| // Replace all instances of remote_Id in the local document with local_Id | |||
| var v_elems_local = mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName)); | |||
| foreach (var elem in v_elems_local) | |||
| { | |||
| XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName)); | |||
| if (id != null && id.Value == remote_Id) | |||
| { | |||
| id.SetValue(new_Id); | |||
| } | |||
| } | |||
| } | |||
| { | |||
| // Replace all instances of remote_Id in the local document with local_Id | |||
| var elems_local = mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName)); | |||
| foreach (var elem in elems_local) | |||
| { | |||
| XAttribute embed = elem.Attribute(XName.Get("embed", DocX.r.NamespaceName)); | |||
| if (embed != null && embed.Value == remote_Id) | |||
| { | |||
| embed.SetValue(new_Id); | |||
| } | |||
| } | |||
| // Replace all instances of remote_Id in the local document with local_Id | |||
| var v_elems_local = mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName)); | |||
| foreach (var elem in v_elems_local) | |||
| { | |||
| XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName)); | |||
| if (id != null && id.Value == remote_Id) | |||
| { | |||
| id.SetValue(new_Id); | |||
| } | |||
| } | |||
| } | |||
| // Replace all instances of remote_Id in the local document with local_Id (for shapes as well) | |||
| @@ -1547,10 +1545,10 @@ namespace Novacode | |||
| // Checking whether there were more than 0 elements, helped me get rid of exceptions thrown while using InsertDocument | |||
| if (numbering.Root.Elements(XName.Get("abstractNum", DocX.w.NamespaceName)).Count() > 0) | |||
| numbering.Root.Elements(XName.Get("abstractNum", DocX.w.NamespaceName)).Last().AddAfterSelf(remote_abstractNums); | |||
| numbering.Root.Elements(XName.Get("abstractNum", DocX.w.NamespaceName)).Last().AddAfterSelf(remote_abstractNums); | |||
| if (numbering.Root.Elements(XName.Get("num", DocX.w.NamespaceName)).Count() > 0) | |||
| numbering.Root.Elements(XName.Get("num", DocX.w.NamespaceName)).Last().AddAfterSelf(remote_nums); | |||
| numbering.Root.Elements(XName.Get("num", DocX.w.NamespaceName)).Last().AddAfterSelf(remote_nums); | |||
| } | |||
| private void merge_fonts(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote) | |||
| @@ -1723,7 +1721,7 @@ namespace Novacode | |||
| } | |||
| } | |||
| // Replace all instances of remote_Id in the local document with local_Id (for shapes as well) | |||
| // Replace all instances of remote_Id in the local document with local_Id (for shapes as well) | |||
| var v_elems = remote_mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName)); | |||
| foreach (var elem in v_elems) | |||
| { | |||
| @@ -2276,7 +2274,7 @@ namespace Novacode | |||
| if (!document.paragraphLookup.ContainsKey(paragraph.endIndex)) | |||
| document.paragraphLookup.Add(paragraph.endIndex, paragraph); | |||
| } | |||
| return document; | |||
| } | |||
| @@ -3216,7 +3214,7 @@ namespace Novacode | |||
| public void Save() | |||
| { | |||
| Headers headers = Headers; | |||
| // Save the main document | |||
| using (TextWriter tw = new StreamWriter(mainPart.GetStream(FileMode.Create, FileAccess.Write))) | |||
| mainDoc.Save(tw, SaveOptions.None); | |||
| @@ -3819,7 +3817,7 @@ namespace Novacode | |||
| customPropDoc.Save(tw, SaveOptions.None); | |||
| // Refresh all fields in this document which display this custom property. | |||
| UpdateCustomPropertyValue(this, cp.Name, (cp.Value ?? "").ToString()); | |||
| UpdateCustomPropertyValue(this, cp.Name, (cp.Value ?? "").ToString()); | |||
| } | |||
| /// <summary> | |||
| @@ -4108,7 +4106,7 @@ namespace Novacode | |||
| { | |||
| return InsertTableOfContents("Table of contents", TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | TableOfContentsSwitches.U); | |||
| } | |||
| /// <summary> | |||
| /// Inserts a TOC into the current document. | |||
| /// </summary> | |||
| @@ -49,7 +49,6 @@ namespace Novacode | |||
| } | |||
| } | |||
| internal PackagePart mainPart; | |||
| internal Footer(DocX document, XElement xml, PackagePart mainPart): base(document, xml) | |||
| { | |||
| this.mainPart = mainPart; | |||
| @@ -54,7 +54,6 @@ namespace Novacode | |||
| public Paragraph PageNumberParagraph; | |||
| internal PackagePart mainPart; | |||
| internal Header(DocX document, XElement xml, PackagePart mainPart):base(document, xml) | |||
| { | |||
| this.mainPart = mainPart; | |||
| @@ -16,7 +16,6 @@ namespace Novacode | |||
| internal String text; | |||
| internal Dictionary<PackagePart, PackageRelationship> hyperlink_rels; | |||
| public PackagePart mainPart; | |||
| internal int type; | |||
| internal String id; | |||
| internal XElement instrText; | |||
| @@ -18,8 +18,6 @@ namespace Novacode | |||
| /// </summary> | |||
| public class Paragraph : InsertBeforeOrAfter | |||
| { | |||
| internal PackagePart mainPart; | |||
| public PackagePart PackagePart { get { return mainPart; } set { mainPart = value; } } | |||
| // The Append family of functions use this List to apply style. | |||
| internal List<XElement> runs; | |||
| @@ -436,7 +434,22 @@ namespace Novacode | |||
| } | |||
| } | |||
| } | |||
| /// <summary> | |||
| public bool IsKeepWithNext | |||
| { | |||
| get | |||
| { | |||
| var pPr = GetOrCreate_pPr(); | |||
| var keepWithNextE = pPr.Element(XName.Get("keepNext", DocX.w.NamespaceName)); | |||
| if (keepWithNextE == null) | |||
| { | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// This paragraph will be kept on the same page as the next paragraph | |||
| /// </summary> | |||
| /// <example> | |||
| @@ -457,6 +470,7 @@ namespace Novacode | |||
| /// </example> | |||
| /// <param name="keepWithNext"></param> | |||
| /// <returns></returns> | |||
| public Paragraph KeepWithNext(bool keepWithNext = true) | |||
| { | |||
| var pPr = GetOrCreate_pPr(); | |||
| @@ -470,9 +484,9 @@ namespace Novacode | |||
| keepWithNextE.Remove(); | |||
| } | |||
| return this; | |||
| } | |||
| /// <summary> | |||
| /// <summary> | |||
| /// Keep all lines in this paragraph together on a page | |||
| /// </summary> | |||
| /// <example> | |||
| @@ -635,7 +649,7 @@ namespace Novacode | |||
| XAttribute hanging = ind.Attribute(XName.Get("hanging", DocX.w.NamespaceName)); | |||
| if (hanging != null) | |||
| return float.Parse(hanging.Value); | |||
| return float.Parse(hanging.Value) / (57 * 10); | |||
| return 0.0f; | |||
| } | |||
| @@ -694,7 +708,7 @@ namespace Novacode | |||
| XAttribute left = ind.Attribute(XName.Get("left", DocX.w.NamespaceName)); | |||
| if (left != null) | |||
| return float.Parse(left.Value); | |||
| return float.Parse(left.Value) / (57 * 10); | |||
| return 0.0f; | |||
| } | |||
| @@ -2860,7 +2874,7 @@ namespace Novacode | |||
| else | |||
| throw new ArgumentException("Size", "Value must be either a whole or half number, examples: 32, 32.5"); | |||
| ApplyTextFormattingProperty(XName.Get("sz", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), fontSize * 2)); | |||
| ApplyTextFormattingProperty(XName.Get("szCs", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), fontSize * 2)); | |||
| @@ -3358,15 +3372,15 @@ namespace Novacode | |||
| var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); | |||
| if (spacingBefore > 0) | |||
| { | |||
| if (spacing == null) | |||
| { | |||
| if (spacing == null) | |||
| { | |||
| spacing = new XElement(XName.Get("spacing", DocX.w.NamespaceName)); | |||
| pPr.Add(spacing); | |||
| } | |||
| var attr = spacing.Attribute(XName.Get("before", DocX.w.NamespaceName)); | |||
| if (attr == null) | |||
| spacing.SetAttributeValue(XName.Get("before", DocX.w.NamespaceName), spacingBefore); | |||
| else | |||
| } | |||
| var attr = spacing.Attribute(XName.Get("before", DocX.w.NamespaceName)); | |||
| if (attr == null) | |||
| spacing.SetAttributeValue(XName.Get("before", DocX.w.NamespaceName), spacingBefore); | |||
| else | |||
| attr.SetValue(spacingBefore); | |||
| } | |||
| if (Math.Abs(spacingBefore) < 0.1f && spacing != null) | |||
| @@ -3406,6 +3420,7 @@ namespace Novacode | |||
| if (!spacing.HasAttributes) | |||
| spacing.Remove(); | |||
| } | |||
| //ApplyTextFormattingProperty(XName.Get("after", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), spacingAfter)); | |||
| return this; | |||
| } | |||
| @@ -55,7 +55,11 @@ namespace Novacode | |||
| * Get the tcPr (table cell properties) element for the first cell in this merge, | |||
| * null will be returned if no such element exists. | |||
| */ | |||
| XElement start_tcPr = Rows[startRow].Cells[columnIndex].Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); | |||
| XElement start_tcPr = null; | |||
| if(columnIndex > Rows[startRow].Cells.Count) | |||
| start_tcPr = Rows[startRow].Cells[Rows[startRow].Cells.Count - 1].Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); | |||
| else | |||
| start_tcPr = Rows[startRow].Cells[columnIndex].Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); | |||
| if (start_tcPr == null) | |||
| { | |||
| Rows[startRow].Cells[columnIndex].Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); | |||
| @@ -200,7 +204,7 @@ namespace Novacode | |||
| if (r.Cells.Count > c) | |||
| r.Cells[c].Width = widths[c]; | |||
| } | |||
| } | |||
| } | |||
| @@ -327,6 +331,7 @@ namespace Novacode | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// Returns the number of rows in this table. | |||
| /// </summary> | |||
| @@ -373,7 +378,6 @@ namespace Novacode | |||
| private TableDesign design; | |||
| internal PackagePart mainPart; | |||
| internal Table(DocX document, XElement xml) | |||
| : base(document, xml) | |||
| @@ -442,14 +446,14 @@ namespace Novacode | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// String containing the Table Caption value (the table's Alternate Text Title) | |||
| /// </summary> | |||
| private string _tableCaption; | |||
| /// <summary> | |||
| /// Gets or Sets the value of the Table Caption (Alternate Text Title) of this table. | |||
| /// </summary> | |||
| public string TableCaption | |||
| /// <summary> | |||
| /// String containing the Table Caption value (the table's Alternate Text Title) | |||
| /// </summary> | |||
| private string _tableCaption; | |||
| /// <summary> | |||
| /// Gets or Sets the value of the Table Caption (Alternate Text Title) of this table. | |||
| /// </summary> | |||
| public string TableCaption | |||
| { | |||
| set | |||
| { | |||
| @@ -464,7 +468,7 @@ namespace Novacode | |||
| tblCaption = new XElement(XName.Get("tblCaption", DocX.w.NamespaceName), | |||
| new XAttribute(XName.Get("val", DocX.w.NamespaceName), value)); | |||
| tblPr.Add(tblCaption); | |||
| tblPr.Add(tblCaption); | |||
| } | |||
| } | |||
| @@ -1977,80 +1981,80 @@ namespace Novacode | |||
| /// </example> | |||
| /// <param name="borderType">The table border to set</param> | |||
| /// <param name="border">Border object to set the table border</param> | |||
| public void SetBorder(TableBorderType borderType, Border border) | |||
| { | |||
| /* | |||
| * Get the tblPr (table properties) element for this Table, | |||
| * null will be return if no such element exists. | |||
| */ | |||
| XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); | |||
| if (tblPr == null) | |||
| { | |||
| Xml.SetElementValue(XName.Get("tblPr", DocX.w.NamespaceName), string.Empty); | |||
| tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); | |||
| } | |||
| /* | |||
| * Get the tblBorders (table borders) element for this Table, | |||
| * null will be return if no such element exists. | |||
| */ | |||
| XElement tblBorders = tblPr.Element(XName.Get("tblBorders", DocX.w.NamespaceName)); | |||
| if (tblBorders == null) | |||
| { | |||
| tblPr.SetElementValue(XName.Get("tblBorders", DocX.w.NamespaceName), string.Empty); | |||
| tblBorders = tblPr.Element(XName.Get("tblBorders", DocX.w.NamespaceName)); | |||
| } | |||
| /* | |||
| * Get the 'borderType' (table border) element for this Table, | |||
| * null will be return if no such element exists. | |||
| */ | |||
| string tbordertype; | |||
| tbordertype = borderType.ToString(); | |||
| // only lower the first char of string (because of insideH and insideV) | |||
| tbordertype = tbordertype.Substring(0, 1).ToLower() + tbordertype.Substring(1); | |||
| XElement tblBorderType = tblBorders.Element(XName.Get(borderType.ToString(), DocX.w.NamespaceName)); | |||
| if (tblBorderType == null) | |||
| { | |||
| tblBorders.SetElementValue(XName.Get(tbordertype, DocX.w.NamespaceName), string.Empty); | |||
| tblBorderType = tblBorders.Element(XName.Get(tbordertype, DocX.w.NamespaceName)); | |||
| } | |||
| // get string value of border style | |||
| string borderstyle = border.Tcbs.ToString().Substring(5); | |||
| borderstyle = borderstyle.Substring(0, 1).ToLower() + borderstyle.Substring(1); | |||
| // The val attribute is used for the border style | |||
| tblBorderType.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), borderstyle); | |||
| if (border.Tcbs != BorderStyle.Tcbs_nil) | |||
| { | |||
| int size; | |||
| switch (border.Size) | |||
| { | |||
| case BorderSize.one: size = 2; break; | |||
| case BorderSize.two: size = 4; break; | |||
| case BorderSize.three: size = 6; break; | |||
| case BorderSize.four: size = 8; break; | |||
| case BorderSize.five: size = 12; break; | |||
| case BorderSize.six: size = 18; break; | |||
| case BorderSize.seven: size = 24; break; | |||
| case BorderSize.eight: size = 36; break; | |||
| case BorderSize.nine: size = 48; break; | |||
| default: size = 2; break; | |||
| } | |||
| // The sz attribute is used for the border size | |||
| tblBorderType.SetAttributeValue(XName.Get("sz", DocX.w.NamespaceName), (size).ToString()); | |||
| // The space attribute is used for the cell spacing (probably '0') | |||
| tblBorderType.SetAttributeValue(XName.Get("space", DocX.w.NamespaceName), (border.Space).ToString()); | |||
| // The color attribute is used for the border color | |||
| public void SetBorder(TableBorderType borderType, Border border) | |||
| { | |||
| /* | |||
| * Get the tblPr (table properties) element for this Table, | |||
| * null will be return if no such element exists. | |||
| */ | |||
| XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); | |||
| if (tblPr == null) | |||
| { | |||
| Xml.SetElementValue(XName.Get("tblPr", DocX.w.NamespaceName), string.Empty); | |||
| tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); | |||
| } | |||
| /* | |||
| * Get the tblBorders (table borders) element for this Table, | |||
| * null will be return if no such element exists. | |||
| */ | |||
| XElement tblBorders = tblPr.Element(XName.Get("tblBorders", DocX.w.NamespaceName)); | |||
| if (tblBorders == null) | |||
| { | |||
| tblPr.SetElementValue(XName.Get("tblBorders", DocX.w.NamespaceName), string.Empty); | |||
| tblBorders = tblPr.Element(XName.Get("tblBorders", DocX.w.NamespaceName)); | |||
| } | |||
| /* | |||
| * Get the 'borderType' (table border) element for this Table, | |||
| * null will be return if no such element exists. | |||
| */ | |||
| string tbordertype; | |||
| tbordertype = borderType.ToString(); | |||
| // only lower the first char of string (because of insideH and insideV) | |||
| tbordertype = tbordertype.Substring(0, 1).ToLower() + tbordertype.Substring(1); | |||
| XElement tblBorderType = tblBorders.Element(XName.Get(borderType.ToString(), DocX.w.NamespaceName)); | |||
| if (tblBorderType == null) | |||
| { | |||
| tblBorders.SetElementValue(XName.Get(tbordertype, DocX.w.NamespaceName), string.Empty); | |||
| tblBorderType = tblBorders.Element(XName.Get(tbordertype, DocX.w.NamespaceName)); | |||
| } | |||
| // get string value of border style | |||
| string borderstyle = border.Tcbs.ToString().Substring(5); | |||
| borderstyle = borderstyle.Substring(0, 1).ToLower() + borderstyle.Substring(1); | |||
| // The val attribute is used for the border style | |||
| tblBorderType.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), borderstyle); | |||
| if (border.Tcbs != BorderStyle.Tcbs_nil) | |||
| { | |||
| int size; | |||
| switch (border.Size) | |||
| { | |||
| case BorderSize.one: size = 2; break; | |||
| case BorderSize.two: size = 4; break; | |||
| case BorderSize.three: size = 6; break; | |||
| case BorderSize.four: size = 8; break; | |||
| case BorderSize.five: size = 12; break; | |||
| case BorderSize.six: size = 18; break; | |||
| case BorderSize.seven: size = 24; break; | |||
| case BorderSize.eight: size = 36; break; | |||
| case BorderSize.nine: size = 48; break; | |||
| default: size = 2; break; | |||
| } | |||
| // The sz attribute is used for the border size | |||
| tblBorderType.SetAttributeValue(XName.Get("sz", DocX.w.NamespaceName), (size).ToString()); | |||
| // The space attribute is used for the cell spacing (probably '0') | |||
| tblBorderType.SetAttributeValue(XName.Get("space", DocX.w.NamespaceName), (border.Space).ToString()); | |||
| // The color attribute is used for the border color | |||
| tblBorderType.SetAttributeValue(XName.Get("color", DocX.w.NamespaceName), border.Color.ToHex()); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// Get a table border | |||
| @@ -2192,7 +2196,7 @@ namespace Novacode | |||
| } | |||
| return b; | |||
| } | |||
| } | |||
| /// <summary> | |||
| @@ -2277,7 +2281,6 @@ namespace Novacode | |||
| } | |||
| internal Table table; | |||
| internal PackagePart mainPart; | |||
| internal Row(Table table, DocX document, XElement xml) | |||
| : base(document, xml) | |||
| { | |||
| @@ -2406,44 +2409,44 @@ namespace Novacode | |||
| /// <summary> | |||
| /// Set to true to make this row the table header row that will be repeated on each page | |||
| /// </summary> | |||
| public bool TableHeader | |||
| { | |||
| get | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| XElement tblHeader = trPr.Element(XName.Get("tblHeader", DocX.w.NamespaceName)); | |||
| if (tblHeader == null) | |||
| { | |||
| return false; | |||
| } | |||
| else | |||
| { | |||
| return true; | |||
| } | |||
| } | |||
| set | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| if (trPr == null) | |||
| { | |||
| Xml.SetElementValue(XName.Get("trPr", DocX.w.NamespaceName), string.Empty); | |||
| trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| } | |||
| XElement tblHeader = trPr.Element(XName.Get("tblHeader", DocX.w.NamespaceName)); | |||
| if (tblHeader == null && value) | |||
| { | |||
| trPr.SetElementValue(XName.Get("tblHeader", DocX.w.NamespaceName), string.Empty); | |||
| } | |||
| if (tblHeader != null && !value) | |||
| { | |||
| tblHeader.Remove(); | |||
| } | |||
| } | |||
| } | |||
| /// Set to true to make this row the table header row that will be repeated on each page | |||
| /// </summary> | |||
| public bool TableHeader | |||
| { | |||
| get | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| XElement tblHeader = trPr.Element(XName.Get("tblHeader", DocX.w.NamespaceName)); | |||
| if (tblHeader == null) | |||
| { | |||
| return false; | |||
| } | |||
| else | |||
| { | |||
| return true; | |||
| } | |||
| } | |||
| set | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| if (trPr == null) | |||
| { | |||
| Xml.SetElementValue(XName.Get("trPr", DocX.w.NamespaceName), string.Empty); | |||
| trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| } | |||
| XElement tblHeader = trPr.Element(XName.Get("tblHeader", DocX.w.NamespaceName)); | |||
| if (tblHeader == null && value) | |||
| { | |||
| trPr.SetElementValue(XName.Get("tblHeader", DocX.w.NamespaceName), string.Empty); | |||
| } | |||
| if (tblHeader != null && !value) | |||
| { | |||
| tblHeader.Remove(); | |||
| } | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// Allow row to break across pages. | |||
| /// The default value is true: Word will break the contents of the row across pages. | |||
| @@ -2451,48 +2454,48 @@ namespace Novacode | |||
| /// </summary> | |||
| public bool BreakAcrossPages | |||
| { | |||
| get | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| if (trPr == null) | |||
| return true; | |||
| XElement trCantSplit = trPr.Element(XName.Get("cantSplit", DocX.w.NamespaceName)); | |||
| if (trCantSplit == null) | |||
| return true; | |||
| return false; | |||
| } | |||
| set | |||
| { | |||
| if (value == false) | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| if (trPr == null) | |||
| { | |||
| Xml.SetElementValue(XName.Get("trPr", DocX.w.NamespaceName), string.Empty); | |||
| trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| } | |||
| XElement trCantSplit = trPr.Element(XName.Get("cantSplit", DocX.w.NamespaceName)); | |||
| if (trCantSplit == null) | |||
| trPr.SetElementValue(XName.Get("cantSplit", DocX.w.NamespaceName), string.Empty); | |||
| } | |||
| if (value == true) | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| if (trPr != null) | |||
| { | |||
| XElement trCantSplit = trPr.Element(XName.Get("cantSplit", DocX.w.NamespaceName)); | |||
| if (trCantSplit != null) | |||
| trCantSplit.Remove(); | |||
| } | |||
| } | |||
| } | |||
| get | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| if (trPr == null) | |||
| return true; | |||
| XElement trCantSplit = trPr.Element(XName.Get("cantSplit", DocX.w.NamespaceName)); | |||
| if (trCantSplit == null) | |||
| return true; | |||
| return false; | |||
| } | |||
| set | |||
| { | |||
| if (value == false) | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| if (trPr == null) | |||
| { | |||
| Xml.SetElementValue(XName.Get("trPr", DocX.w.NamespaceName), string.Empty); | |||
| trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| } | |||
| XElement trCantSplit = trPr.Element(XName.Get("cantSplit", DocX.w.NamespaceName)); | |||
| if (trCantSplit == null) | |||
| trPr.SetElementValue(XName.Get("cantSplit", DocX.w.NamespaceName), string.Empty); | |||
| } | |||
| if (value == true) | |||
| { | |||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||
| if (trPr != null) | |||
| { | |||
| XElement trCantSplit = trPr.Element(XName.Get("cantSplit", DocX.w.NamespaceName)); | |||
| if (trCantSplit != null) | |||
| trCantSplit.Remove(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /// <summary> | |||
| @@ -2573,7 +2576,6 @@ namespace Novacode | |||
| public class Cell : Container | |||
| { | |||
| internal Row row; | |||
| internal PackagePart mainPart; | |||
| internal Cell(Row row, DocX document, XElement xml) | |||
| : base(document, xml) | |||
| { | |||
| @@ -2854,7 +2856,7 @@ namespace Novacode | |||
| //tcW.SetAttributeValue(XName.Get("type", DocX.w.NamespaceName), "auto"); | |||
| //return; | |||
| } | |||
| } | |||
| // The type attribute needs to be set to dxa which represents "twips" or twentieths of a point. In other words, 1/1440th of an inch. | |||
| tcW.SetAttributeValue(XName.Get("type", DocX.w.NamespaceName), "dxa"); | |||
| @@ -3696,6 +3698,7 @@ namespace Novacode | |||
| public override Table InsertTable(int rowCount, int columnCount) | |||
| { | |||
| Table table = base.InsertTable(rowCount, columnCount); | |||
| table.mainPart = mainPart; | |||
| InsertParagraph(); //Dmitchern, It is necessary to put paragraph in the end of the cell, without it MS-Word will say that the document is corrupted | |||
| //IMPORTANT: It will be better to check all methods that work with adding anything to cells | |||
| return table; | |||
| @@ -3770,5 +3773,5 @@ namespace Novacode | |||
| public bool NoHorizontalBanding { get; set; } | |||
| public bool NoVerticalBanding { get; set; } | |||
| } | |||
| } | |||
| @@ -1,4 +1,5 @@ | |||
| using System; | |||
| using System.IO.Packaging; | |||
| using System.Linq; | |||
| using System.Xml.Linq; | |||
| @@ -10,6 +11,9 @@ namespace Novacode | |||
| /// </summary> | |||
| public abstract class DocXElement | |||
| { | |||
| internal PackagePart mainPart; | |||
| public PackagePart PackagePart { get { return mainPart; } set { mainPart = value; } } | |||
| /// <summary> | |||
| /// This is the actual Xml that gives this element substance. | |||
| /// For example, a Paragraphs Xml might look something like the following | |||
| @@ -19,6 +23,7 @@ namespace Novacode | |||
| /// </r> | |||
| /// </p> | |||
| /// </summary> | |||
| public XElement Xml { get; set; } | |||
| /// <summary> | |||
| /// This is a reference to the DocX object that this element belongs to. | |||
| @@ -172,7 +177,7 @@ namespace Novacode | |||
| Xml.AddAfterSelf(newTable); | |||
| XElement newlyInserted = Xml.ElementsAfterSelf().First(); | |||
| return new Table(Document, newlyInserted); | |||
| return new Table(Document, newlyInserted) { mainPart = mainPart }; | |||
| } | |||
| public virtual Table InsertTableAfterSelf(Table t) | |||
| @@ -180,7 +185,7 @@ namespace Novacode | |||
| Xml.AddAfterSelf(t.Xml); | |||
| XElement newlyInserted = Xml.ElementsAfterSelf().First(); | |||
| //Dmitchern | |||
| return new Table(Document, newlyInserted); //return new table, dont affect parameter table | |||
| return new Table(Document, newlyInserted) { mainPart = mainPart }; //return new table, dont affect parameter table | |||
| //t.Xml = newlyInserted; | |||
| //return t; | |||
| @@ -192,7 +197,7 @@ namespace Novacode | |||
| Xml.AddBeforeSelf(newTable); | |||
| XElement newlyInserted = Xml.ElementsBeforeSelf().Last(); | |||
| return new Table(Document, newlyInserted); | |||
| return new Table(Document, newlyInserted) { mainPart = mainPart }; | |||
| } | |||
| public virtual Table InsertTableBeforeSelf(Table t) | |||
| @@ -201,7 +206,7 @@ namespace Novacode | |||
| XElement newlyInserted = Xml.ElementsBeforeSelf().Last(); | |||
| //Dmitchern | |||
| return new Table(Document, newlyInserted); //return new table, dont affect parameter table | |||
| return new Table(Document, newlyInserted) { mainPart=mainPart}; //return new table, dont affect parameter table | |||
| //t.Xml = newlyInserted; | |||
| //return t; | |||