Skip to content

Commit

Permalink
Merge pull request #99 from VictorLoktev/master
Browse files Browse the repository at this point in the history
Bugfix in Row.Height, removing empty paragraphs in cells, Row.InsertRow keeps formatting
  • Loading branch information
PrzemyslawKlys committed Feb 22, 2017
2 parents a9f8f8a + d6c6757 commit b536b5e
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 54 deletions.
35 changes: 18 additions & 17 deletions DocX/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ public virtual List<string> FindUniqueByPattern(string pattern, RegexOptions opt
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))
throw new ArgumentException("oldValue cannot be null or empty", "searchValue");
Expand All @@ -486,31 +486,32 @@ public virtual void ReplaceText(string searchValue, string newValue, bool trackC
foreach (var header in headerList)
if (header != null)
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.
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.
var footerList = new List<Footer> { Document.Footers.first, Document.Footers.even, Document.Footers.odd };
foreach (var footer in footerList)
if (footer != null)
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))
throw new ArgumentException("oldValue cannot be null or empty", "searchValue");
Expand All @@ -525,11 +526,11 @@ public virtual void ReplaceText(string searchValue, Func<string, string> regexMa
foreach (var container in containerList)
if (container != null)
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.
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>
Expand Down
27 changes: 15 additions & 12 deletions DocX/Paragraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3679,7 +3679,7 @@ public DocProperty InsertDocProperty(CustomProperty cp, bool trackChanges = fals
/// <param name="count">The number of characters to delete</param>
/// <param name="trackChanges">Track changes</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
DateTime now = DateTime.Now;
Expand Down Expand Up @@ -3759,17 +3759,20 @@ public void RemoveText(int index, int count, bool trackChanges = false, bool rem
}
}

// 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);

Expand Down
60 changes: 39 additions & 21 deletions DocX/Table.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1239,13 +1239,16 @@ public Row InsertRow()
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>
Expand Down Expand Up @@ -1482,22 +1485,28 @@ public Row InsertRow(int 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)
throw new ArgumentNullException(nameof(row));

if (index < 0 || index > RowCount)
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)
Expand Down Expand Up @@ -2545,15 +2554,23 @@ void SetHeight(double height, bool exact)
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));
}
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,
* 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)
{
trPr.SetElementValue(XName.Get("trHeight", DocX.w.NamespaceName), string.Empty);
Expand All @@ -2564,7 +2581,8 @@ void SetHeight(double height, bool exact)
trHeight.SetAttributeValue(XName.Get("hRule", DocX.w.NamespaceName), exact ? _hRule_Exact : _hRule_AtLeast);

// 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>
/// Min-Height in pixels. // Added by Nick Kusters.
Expand Down
11 changes: 8 additions & 3 deletions DocX/bin/Release/DocX.XML

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified DocX/bin/Release/DocX.dll
Binary file not shown.
Loading

0 comments on commit b536b5e

Please sign in to comment.