Bugfix in Row.Height, removing empty paragraphs in cells, Row.InsertRow keeps formattingmaster
| return uniqueResults.Keys.ToList(); // return the unique list of results | return uniqueResults.Keys.ToList(); // return the unique list of results | ||||
| } | } | ||||
| public virtual void ReplaceText(string searchValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch, bool escapeRegEx = true, bool useRegExSubstitutions = false) | |||||
| public virtual void ReplaceText(string searchValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch, bool escapeRegEx = true, bool useRegExSubstitutions = false, bool removeEmptyParagraph = true) | |||||
| { | { | ||||
| if (string.IsNullOrEmpty(searchValue)) | if (string.IsNullOrEmpty(searchValue)) | ||||
| throw new ArgumentException("oldValue cannot be null or empty", "searchValue"); | throw new ArgumentException("oldValue cannot be null or empty", "searchValue"); | ||||
| foreach (var header in headerList) | foreach (var header in headerList) | ||||
| if (header != null) | if (header != null) | ||||
| foreach (var paragraph in header.Paragraphs) | foreach (var paragraph in header.Paragraphs) | ||||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions); | |||||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions, removeEmptyParagraph); | |||||
| // ReplaceText int main body of document. | // ReplaceText int main body of document. | ||||
| foreach (var paragraph in Paragraphs) | foreach (var paragraph in Paragraphs) | ||||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions); | |||||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions, removeEmptyParagraph); | |||||
| // ReplaceText in Footers of the document. | // ReplaceText in Footers of the document. | ||||
| var footerList = new List<Footer> { Document.Footers.first, Document.Footers.even, Document.Footers.odd }; | var footerList = new List<Footer> { Document.Footers.first, Document.Footers.even, Document.Footers.odd }; | ||||
| foreach (var footer in footerList) | foreach (var footer in footerList) | ||||
| if (footer != null) | if (footer != null) | ||||
| foreach (var paragraph in footer.Paragraphs) | foreach (var paragraph in footer.Paragraphs) | ||||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions); | |||||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions, removeEmptyParagraph); | |||||
| } | } | ||||
| /// <summary> | |||||
| /// | |||||
| /// </summary> | |||||
| /// <param name="searchValue">Value to find</param> | |||||
| /// <param name="regexMatchHandler">A Func that accepts the matching regex search group value and passes it to this to return the replacement string</param> | |||||
| /// <param name="trackChanges">Enable trackchanges</param> | |||||
| /// <param name="options">Regex options</param> | |||||
| /// <param name="newFormatting"></param> | |||||
| /// <param name="matchFormatting"></param> | |||||
| /// <param name="formattingOptions"></param> | |||||
| public virtual void ReplaceText(string searchValue, Func<string, string> regexMatchHandler, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch) | |||||
| /// <summary> | |||||
| /// | |||||
| /// </summary> | |||||
| /// <param name="searchValue">Value to find</param> | |||||
| /// <param name="regexMatchHandler">A Func that accepts the matching regex search group value and passes it to this to return the replacement string</param> | |||||
| /// <param name="trackChanges">Enable trackchanges</param> | |||||
| /// <param name="options">Regex options</param> | |||||
| /// <param name="newFormatting"></param> | |||||
| /// <param name="matchFormatting"></param> | |||||
| /// <param name="formattingOptions"></param> | |||||
| /// <param name="removeEmptyParagraph">Remove empty paragraph</param> | |||||
| public virtual void ReplaceText(string searchValue, Func<string, string> regexMatchHandler, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch, bool removeEmptyParagraph = true) | |||||
| { | { | ||||
| if (string.IsNullOrEmpty(searchValue)) | if (string.IsNullOrEmpty(searchValue)) | ||||
| throw new ArgumentException("oldValue cannot be null or empty", "searchValue"); | throw new ArgumentException("oldValue cannot be null or empty", "searchValue"); | ||||
| foreach (var container in containerList) | foreach (var container in containerList) | ||||
| if (container != null) | if (container != null) | ||||
| foreach (var paragraph in container.Paragraphs) | foreach (var paragraph in container.Paragraphs) | ||||
| paragraph.ReplaceText(searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, formattingOptions); | |||||
| paragraph.ReplaceText(searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, formattingOptions, removeEmptyParagraph); | |||||
| // ReplaceText int main body of document. | // ReplaceText int main body of document. | ||||
| foreach (var paragraph in Paragraphs) | foreach (var paragraph in Paragraphs) | ||||
| paragraph.ReplaceText(searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, formattingOptions); | |||||
| paragraph.ReplaceText(searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, formattingOptions, removeEmptyParagraph); | |||||
| } | } | ||||
| /// <summary> | /// <summary> |
| /// <param name="count">The number of characters to delete</param> | /// <param name="count">The number of characters to delete</param> | ||||
| /// <param name="trackChanges">Track changes</param> | /// <param name="trackChanges">Track changes</param> | ||||
| /// <param name="removeEmptyParagraph">Remove empty paragraph</param> | /// <param name="removeEmptyParagraph">Remove empty paragraph</param> | ||||
| public void RemoveText(int index, int count, bool trackChanges = false, bool removeEmptyParagraph=true) | |||||
| public void RemoveText(int index, int count, bool trackChanges = false, bool removeEmptyParagraph = true) | |||||
| { | { | ||||
| // Timestamp to mark the start of insert | // Timestamp to mark the start of insert | ||||
| DateTime now = DateTime.Now; | DateTime now = DateTime.Now; | ||||
| } | } | ||||
| } | } | ||||
| // If after this remove the parent element is empty, remove it. | |||||
| if (removeEmptyParagraph && GetElementTextLength(parentElement) == 0) | |||||
| { | |||||
| if (parentElement.Parent != null && parentElement.Parent.Name.LocalName != "tc") | |||||
| { | |||||
| // Need to make sure there is no drawing element within the parent element. | |||||
| // Picture elements contain no text length but they are still content. | |||||
| if (parentElement.Descendants(XName.Get("drawing", DocX.w.NamespaceName)).Count() == 0) | |||||
| parentElement.Remove(); | |||||
| } | |||||
| } | |||||
| // Removing of empty paragraph is allowed if text is empty and removeEmptyParagraph=true | |||||
| bool removeEmpty = removeEmptyParagraph && GetElementTextLength( parentElement ) == 0; | |||||
| if( parentElement.Parent != null ) | |||||
| { | |||||
| // Need to make sure there is another paragraph in parent cell | |||||
| removeEmpty &= parentElement.Parent.Name.LocalName == "tc" && | |||||
| parentElement.Parent.Elements( XName.Get( "p", DocX.w.NamespaceName ) ).Count() > 1; | |||||
| // Need to make sure there is no drawing element within the parent element. | |||||
| // Picture elements contain no text length but they are still content. | |||||
| removeEmpty &= parentElement.Descendants( XName.Get( "drawing", DocX.w.NamespaceName ) ).Count() == 0; | |||||
| } | |||||
| if( removeEmpty ) | |||||
| parentElement.Remove(); | |||||
| } | } | ||||
| while (processed < count); | while (processed < count); | ||||
| return InsertRow(RowCount); | return InsertRow(RowCount); | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Insert a copy of a row at the end of this table. | |||||
| /// </summary> | |||||
| /// <returns>A new row.</returns> | |||||
| public Row InsertRow(Row row) | |||||
| /// <summary> | |||||
| /// Insert a copy of a row at the end of this table. | |||||
| /// </summary> | |||||
| /// <returns>A new row.</returns> | |||||
| /// <param name="row">The row to insert</param> | |||||
| /// <param name="keepFormatting">True to clone everithing, False to clone cell structure only.</param> | |||||
| /// <returns></returns> | |||||
| public Row InsertRow(Row row, bool keepFormatting = false) | |||||
| { | { | ||||
| return InsertRow(row, RowCount); | |||||
| return InsertRow(row, RowCount, keepFormatting); | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| return InsertRow(content, index); | return InsertRow(content, index); | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Insert a copy of a row into this table. | |||||
| /// </summary> | |||||
| /// <param name="row">Row to copy and insert.</param> | |||||
| /// <param name="index">Index to insert row at.</param> | |||||
| /// <returns>A new Row</returns> | |||||
| public Row InsertRow(Row row, int index) | |||||
| /// <summary> | |||||
| /// Insert a copy of a row into this table. | |||||
| /// </summary> | |||||
| /// <param name="row">Row to copy and insert.</param> | |||||
| /// <param name="index">Index to insert row at.</param> | |||||
| /// <param name="keepFormatting">True to clone everithing, False to clone cell structure only.</param> | |||||
| /// <returns>A new Row</returns> | |||||
| public Row InsertRow(Row row, int index, bool keepFormatting = false) | |||||
| { | { | ||||
| if (row == null) | if (row == null) | ||||
| throw new ArgumentNullException(nameof(row)); | throw new ArgumentNullException(nameof(row)); | ||||
| if (index < 0 || index > RowCount) | if (index < 0 || index > RowCount) | ||||
| throw new IndexOutOfRangeException(); | throw new IndexOutOfRangeException(); | ||||
| List<XElement> content = row.Xml.Elements(XName.Get("tc", DocX.w.NamespaceName)).Select(element => HelperFunctions.CloneElement(element)).ToList(); | |||||
| return InsertRow(content, index); | |||||
| List<XElement> content; | |||||
| if( keepFormatting ) | |||||
| content = row.Xml.Elements().Select(element => HelperFunctions.CloneElement(element)).ToList(); | |||||
| else | |||||
| content = row.Xml.Elements(XName.Get("tc", DocX.w.NamespaceName)).Select(element => HelperFunctions.CloneElement(element)).ToList(); | |||||
| return InsertRow(content, index); | |||||
| } | } | ||||
| private Row InsertRow(List<XElement> content, Int32 index) | private Row InsertRow(List<XElement> content, Int32 index) | ||||
| XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | ||||
| if (trPr == null) | if (trPr == null) | ||||
| { | { | ||||
| Xml.SetElementValue(XName.Get("trPr", DocX.w.NamespaceName), string.Empty); | |||||
| trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||||
| } | |||||
| Xml.SetElementValue(XName.Get("trPr", DocX.w.NamespaceName), string.Empty); | |||||
| trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); | |||||
| /* | |||||
| // Swapping trPr and tc elements - making trPr the first | |||||
| XElement tc = Xml.Element( XName.Get( "tc", DocX.w.NamespaceName ) ); | |||||
| if( tc != null ) | |||||
| { | |||||
| trPr.Remove(); | |||||
| tc.AddBeforeSelf( trPr ); | |||||
| } | |||||
| } | |||||
| /* | |||||
| * Get the trHeight element for this Row, | * Get the trHeight element for this Row, | ||||
| * null will be return if no such element exists. | * null will be return if no such element exists. | ||||
| */ | */ | ||||
| XElement trHeight = trPr.Element(XName.Get("trHeight", DocX.w.NamespaceName)); | |||||
| XElement trHeight = trPr.Element(XName.Get("trHeight", DocX.w.NamespaceName)); | |||||
| if (trHeight == null) | if (trHeight == null) | ||||
| { | { | ||||
| trPr.SetElementValue(XName.Get("trHeight", DocX.w.NamespaceName), string.Empty); | trPr.SetElementValue(XName.Get("trHeight", DocX.w.NamespaceName), string.Empty); | ||||
| trHeight.SetAttributeValue(XName.Get("hRule", DocX.w.NamespaceName), exact ? _hRule_Exact : _hRule_AtLeast); | trHeight.SetAttributeValue(XName.Get("hRule", DocX.w.NamespaceName), exact ? _hRule_Exact : _hRule_AtLeast); | ||||
| // 15 "word units" is equal to one pixel. | // 15 "word units" is equal to one pixel. | ||||
| trHeight.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), (height * 15).ToString()); | |||||
| trHeight.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), | |||||
| ((int)(Math.Round(height * 15,0))).ToString( CultureInfo.InvariantCulture )); // national separators anf fraction should be avoided | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| /// Min-Height in pixels. // Added by Nick Kusters. | /// Min-Height in pixels. // Added by Nick Kusters. |
| <param name="options"></param> | <param name="options"></param> | ||||
| <returns></returns> | <returns></returns> | ||||
| </member> | </member> | ||||
| <member name="M:Novacode.Container.ReplaceText(System.String,System.Func{System.String,System.String},System.Boolean,System.Text.RegularExpressions.RegexOptions,Novacode.Formatting,Novacode.Formatting,Novacode.MatchFormattingOptions)"> | |||||
| <member name="M:Novacode.Container.ReplaceText(System.String,System.Func{System.String,System.String},System.Boolean,System.Text.RegularExpressions.RegexOptions,Novacode.Formatting,Novacode.Formatting,Novacode.MatchFormattingOptions,System.Boolean)"> | |||||
| <summary> | <summary> | ||||
| </summary> | </summary> | ||||
| <param name="newFormatting"></param> | <param name="newFormatting"></param> | ||||
| <param name="matchFormatting"></param> | <param name="matchFormatting"></param> | ||||
| <param name="formattingOptions"></param> | <param name="formattingOptions"></param> | ||||
| <param name="removeEmptyParagraph">Remove empty paragraph</param> | |||||
| </member> | </member> | ||||
| <member name="M:Novacode.Container.RemoveTextInGivenFormat(Novacode.Formatting,Novacode.MatchFormattingOptions)"> | <member name="M:Novacode.Container.RemoveTextInGivenFormat(Novacode.Formatting,Novacode.MatchFormattingOptions)"> | ||||
| <summary> | <summary> | ||||
| </example> | </example> | ||||
| <returns>A new row.</returns> | <returns>A new row.</returns> | ||||
| </member> | </member> | ||||
| <member name="M:Novacode.Table.InsertRow(Novacode.Row)"> | |||||
| <member name="M:Novacode.Table.InsertRow(Novacode.Row,System.Boolean)"> | |||||
| <summary> | <summary> | ||||
| Insert a copy of a row at the end of this table. | Insert a copy of a row at the end of this table. | ||||
| </summary> | </summary> | ||||
| <returns>A new row.</returns> | <returns>A new row.</returns> | ||||
| <param name="row">The row to insert</param> | |||||
| <param name="keepFormatting">True to clone everithing, False to clone cell structure only.</param> | |||||
| <returns></returns> | |||||
| </member> | </member> | ||||
| <member name="M:Novacode.Table.InsertColumn"> | <member name="M:Novacode.Table.InsertColumn"> | ||||
| <summary> | <summary> | ||||
| <param name="index">Index to insert row at.</param> | <param name="index">Index to insert row at.</param> | ||||
| <returns>A new Row</returns> | <returns>A new Row</returns> | ||||
| </member> | </member> | ||||
| <member name="M:Novacode.Table.InsertRow(Novacode.Row,System.Int32)"> | |||||
| <member name="M:Novacode.Table.InsertRow(Novacode.Row,System.Int32,System.Boolean)"> | |||||
| <summary> | <summary> | ||||
| Insert a copy of a row into this table. | Insert a copy of a row into this table. | ||||
| </summary> | </summary> | ||||
| <param name="row">Row to copy and insert.</param> | <param name="row">Row to copy and insert.</param> | ||||
| <param name="index">Index to insert row at.</param> | <param name="index">Index to insert row at.</param> | ||||
| <param name="keepFormatting">True to clone everithing, False to clone cell structure only.</param> | |||||
| <returns>A new Row</returns> | <returns>A new Row</returns> | ||||
| </member> | </member> | ||||
| <member name="M:Novacode.Table.InsertColumn(System.Int32,System.Boolean)"> | <member name="M:Novacode.Table.InsertColumn(System.Int32,System.Boolean)"> |
| } | } | ||||
| } | } | ||||
| public string ReplaceFunc(string findStr) | |||||
| /// <summary> | |||||
| /// TextRemove should not remove empty paragraphs in case the paragraph is alone in the cell. | |||||
| /// In the rest cases empty paragraph may be removed. | |||||
| /// </summary> | |||||
| [Test] | |||||
| public void Test_Table_Paragraph_RemoveText() | |||||
| { | |||||
| using( var input = File.Open( Path.Combine( _directoryWithFiles, "TableSpecifiedHeights.docx" ), FileMode.Open ) ) | |||||
| { | |||||
| using( var doc = DocX.Load( input ) ) | |||||
| { | |||||
| // Make sure content of the file is ok for test | |||||
| Assert.IsTrue( doc.Tables.Count == 1 ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].RowCount == 3 ); | |||||
| string text = "paragraph"; | |||||
| // == Paragraph in the cell is not alone == | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].InsertParagraph( text ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs.Count == 2 ); | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].ReplaceText( text, "", removeEmptyParagraph: true ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs.Count == 1 ); | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].InsertParagraph( text ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs.Count == 2 ); | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].ReplaceText( text, "", removeEmptyParagraph: false ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs.Count == 2 ); | |||||
| // == Paragraph in the cell is alone == | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].InsertParagraph( text ); | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs[ 0 ].Remove( false ); | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs[ 0 ].Remove( false ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs.Count == 1 ); | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].ReplaceText( text, "", removeEmptyParagraph: true ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs.Count == 1 ); | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].InsertParagraph( text ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs.Count == 2 ); | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].ReplaceText( text, "", removeEmptyParagraph: false ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs.Count == 2 ); | |||||
| } | |||||
| } | |||||
| } | |||||
| [Test] | |||||
| public void Test_Table_MinHeight() | |||||
| { | |||||
| using( var input = File.Open( Path.Combine( _directoryWithFiles, "TableSpecifiedHeights.docx" ), FileMode.Open ) ) | |||||
| { | |||||
| using( var doc = DocX.Load( input ) ) | |||||
| { | |||||
| // Make sure content of the file is ok for test | |||||
| Assert.IsTrue( doc.Tables.Count == 1 ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].RowCount == 3 ); | |||||
| // Check heights load is ok | |||||
| Assert.IsTrue( double.IsNaN( doc.Tables[ 0 ].Rows[ 0 ].Height ) ); | |||||
| Assert.IsTrue( double.IsNaN( doc.Tables[ 0 ].Rows[ 0 ].MinHeight ) ); | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 1 ].Height - 37.8f ) < 0.0001f ); | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 1 ].MinHeight - 37.8f ) < 0.0001f ); | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 2 ].Height - 37.8f ) < 0.0001f ); | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 2 ].MinHeight - 37.8f ) < 0.0001f ); | |||||
| // Set MinHeight | |||||
| doc.Tables[ 0 ].Rows[ 0 ].MinHeight = 37.8f; | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 0 ].Height - 37.8f ) < 0.0001f ); | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 0 ].MinHeight - 37.8f ) < 0.0001f ); | |||||
| } | |||||
| } | |||||
| } | |||||
| [Test] | |||||
| public void Test_Table_InsertRow_Keeps_Formatting() | |||||
| { | |||||
| using( var input = File.Open( Path.Combine( _directoryWithFiles, "TableSpecifiedHeights.docx" ), FileMode.Open ) ) | |||||
| { | |||||
| using( var doc = DocX.Load( input ) ) | |||||
| { | |||||
| // Make sure content of the file is ok for test | |||||
| Assert.IsTrue( doc.Tables.Count == 1 ); | |||||
| Assert.IsTrue( doc.Tables[ 0 ].RowCount == 3 ); | |||||
| // Check heights load is ok | |||||
| Assert.IsTrue( double.IsNaN( doc.Tables[ 0 ].Rows[ 0 ].Height ) ); | |||||
| Assert.IsTrue( double.IsNaN( doc.Tables[ 0 ].Rows[ 0 ].MinHeight ) ); | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 1 ].Height - 37.8f ) < 0.0001f ); | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 1 ].MinHeight - 37.8f ) < 0.0001f ); | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 2 ].Height - 37.8f ) < 0.0001f ); | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ 2 ].MinHeight - 37.8f ) < 0.0001f ); | |||||
| // Clone all rows and check heights | |||||
| int n = doc.Tables[ 0 ].RowCount; | |||||
| for( int index = 0; index < n; index++ ) | |||||
| { | |||||
| doc.Tables[ 0 ].InsertRow( doc.Tables[ 0 ].Rows[ index ], true ); | |||||
| } | |||||
| Assert.IsTrue( doc.Tables[ 0 ].RowCount == 2 * n ); | |||||
| for( int index = 0; index < n; index++ ) | |||||
| { | |||||
| // Compare height of original row and cloned | |||||
| Assert.IsTrue( double.IsNaN( doc.Tables[ 0 ].Rows[ n + index ].Height ) == double.IsNaN( doc.Tables[ 0 ].Rows[ index ].Height ) ); | |||||
| if( !double.IsNaN( doc.Tables[ 0 ].Rows[ n + index ].Height ) && !double.IsNaN( doc.Tables[ 0 ].Rows[ index ].Height ) ) | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ n + index ].Height - doc.Tables[ 0 ].Rows[ index ].Height ) < 0.0001f ); | |||||
| Assert.IsTrue( double.IsNaN( doc.Tables[ 0 ].Rows[ n + index ].MinHeight ) == double.IsNaN( doc.Tables[ 0 ].Rows[ index ].MinHeight ) ); | |||||
| if( !double.IsNaN( doc.Tables[ 0 ].Rows[ n + index ].MinHeight ) && !double.IsNaN( doc.Tables[ 0 ].Rows[ index ].MinHeight ) ) | |||||
| Assert.IsTrue( Math.Abs( doc.Tables[ 0 ].Rows[ n + index ].MinHeight - doc.Tables[ 0 ].Rows[ index ].MinHeight ) < 0.0001f ); | |||||
| } | |||||
| // Remove original rows | |||||
| for( int index = 0; index < n; index++ ) | |||||
| { | |||||
| doc.Tables[ 0 ].Rows[ 0 ].Remove(); | |||||
| } | |||||
| // At this point we shuold have document visually equal to original | |||||
| doc.SaveAs( Path.Combine( _directoryWithFiles, "TableSpecifiedHeights_out.docx" ) ); | |||||
| } | |||||
| } | |||||
| } | |||||
| public string ReplaceFunc(string findStr) | |||||
| { | { | ||||
| var testPatterns = new Dictionary<string, string> | var testPatterns = new Dictionary<string, string> | ||||
| { | { |
| <None Include="documents\Tables.docx"> | <None Include="documents\Tables.docx"> | ||||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||
| </None> | </None> | ||||
| <None Include="documents\TableSpecifiedHeights.docx"> | |||||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | |||||
| </None> | |||||
| <None Include="documents\TableSpecifiedWidths.docx"> | <None Include="documents\TableSpecifiedWidths.docx"> | ||||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||
| </None> | </None> |