Parcourir la source

Merge pull request #98 from VictorLoktev/master

Bug fix and new features
master
PrzemyslawKlys il y a 9 ans
Parent
révision
a9f8f8a324

+ 14
- 2
DocX/DocX.cs Voir le fichier

{ {
using (FileStream fs = new FileStream(filename, FileMode.Create)) using (FileStream fs = new FileStream(filename, FileMode.Create))
{ {
CopyStream(memoryStream, fs);
}
// Original code
// fs.Write( memoryStream.ToArray(), 0, (int)memoryStream.Length );
// was replaced by save using small buffer
// CopyStream( memoryStream, fs);
// Corection is to make position equal to 0
if(memoryStream.CanSeek)
{
// Write to the beginning of the stream
memoryStream.Position = 0;
CopyStream(memoryStream, fs);
}
else
fs.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
}
} }
else else
{ {

+ 7
- 3
DocX/DocX.csproj Voir le fichier

<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DocumentationFile>bin\Release\DocX.XML</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SignAssembly>false</SignAssembly>
<SignAssembly>true</SignAssembly>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<AssemblyOriginatorKeyFile>KeyWithoutPassword.snk</AssemblyOriginatorKeyFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<EmbeddedResource Include="Resources\numbering.default_bullet_abstract.xml.gz" /> <EmbeddedResource Include="Resources\numbering.default_bullet_abstract.xml.gz" />
<EmbeddedResource Include="Resources\numbering.default_decimal_abstract.xml.gz" /> <EmbeddedResource Include="Resources\numbering.default_decimal_abstract.xml.gz" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="KeyWithoutPassword.snk" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

BIN
DocX/KeyWithoutPassword.snk Voir le fichier


+ 98
- 95
DocX/Paragraph.cs Voir le fichier

/// </code> /// </code>
/// </example> /// </example>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/> /// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, int, bool, bool)"/>
/// <param name="value">The System.String to insert.</param> /// <param name="value">The System.String to insert.</param>
/// <param name="trackChanges">Flag this insert as a change.</param> /// <param name="trackChanges">Flag this insert as a change.</param>
/// <param name="formatting">The text formatting.</param> /// <param name="formatting">The text formatting.</param>
/// </code> /// </code>
/// </example> /// </example>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/> /// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, int, bool, bool)"/>
/// <param name="index">The index position of the insertion.</param> /// <param name="index">The index position of the insertion.</param>
/// <param name="value">The System.String to insert.</param> /// <param name="value">The System.String to insert.</param>
/// <param name="trackChanges">Flag this insert as a change.</param> /// <param name="trackChanges">Flag this insert as a change.</param>
return new DocProperty(Document, xml); return new DocProperty(Document, xml);
} }
/// <summary>
/// Removes characters from a Novacode.DocX.Paragraph.
/// </summary>
/// <example>
/// <code>
/// // Create a document using a relative filename.
/// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
/// {
/// // Iterate through the paragraphs
/// foreach (Paragraph p in document.Paragraphs)
/// {
/// // Remove the first two characters from every paragraph
/// p.RemoveText(0, 2, false);
/// }
///
/// // Save all changes made to this document.
/// document.Save();
/// }// Release this document from memory.
/// </code>
/// </example>
/// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
/// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
/// <param name="index">The position to begin deleting characters.</param>
/// <param name="count">The number of characters to delete</param>
/// <param name="trackChanges">Track changes</param>
public void RemoveText(int index, int count, bool trackChanges = false)
/// <summary>
/// Removes characters from a Novacode.DocX.Paragraph.
/// </summary>
/// <example>
/// <code>
/// // Create a document using a relative filename.
/// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
/// {
/// // Iterate through the paragraphs
/// foreach (Paragraph p in document.Paragraphs)
/// {
/// // Remove the first two characters from every paragraph
/// p.RemoveText(0, 2, false);
/// }
///
/// // Save all changes made to this document.
/// document.Save();
/// }// Release this document from memory.
/// </code>
/// </example>
/// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
/// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
/// <param name="index">The position to begin deleting characters.</param>
/// <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)
{ {
// 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 after this remove the parent element is empty, remove it.
if (GetElementTextLength(parentElement) == 0)
if (removeEmptyParagraph && GetElementTextLength(parentElement) == 0)
{ {
if (parentElement.Parent != null && parentElement.Parent.Name.LocalName != "tc") if (parentElement.Parent != null && parentElement.Parent.Name.LocalName != "tc")
{ {
RemoveText(index, Text.Length - index, trackChanges); RemoveText(index, Text.Length - index, trackChanges);
} }
/// <summary>
/// Replaces all occurrences of a specified System.String in this instance, with another specified System.String.
/// </summary>
/// <example>
/// <code>
/// // Load a document using a relative filename.
/// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
/// {
/// // The formatting to match.
/// Formatting matchFormatting = new Formatting();
/// matchFormatting.Size = 10;
/// matchFormatting.Italic = true;
/// matchFormatting.FontFamily = new FontFamily("Times New Roman");
///
/// // The formatting to apply to the inserted text.
/// Formatting newFormatting = new Formatting();
/// newFormatting.Size = 22;
/// newFormatting.UnderlineStyle = UnderlineStyle.dotted;
/// newFormatting.Bold = true;
///
/// // Iterate through the paragraphs in this document.
/// foreach (Paragraph p in document.Paragraphs)
/// {
/// /*
/// * Replace all instances of the string "wrong" with the string "right" and ignore case.
/// * Each inserted instance of "wrong" should use the Formatting newFormatting.
/// * Only replace an instance of "wrong" if it is Size 10, Italic and Times New Roman.
/// * SubsetMatch means that the formatting must contain all elements of the match formatting,
/// * but it can also contain additional formatting for example Color, UnderlineStyle, etc.
/// * ExactMatch means it must not contain additional formatting.
/// */
/// p.ReplaceText("wrong", "right", false, RegexOptions.IgnoreCase, newFormatting, matchFormatting, MatchFormattingOptions.SubsetMatch);
/// }
///
/// // Save all changes made to this document.
/// document.Save();
/// }// Release this document from memory.
/// </code>
/// </example>
/// <seealso cref="Paragraph.RemoveText(int, int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
/// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
/// <param name="newValue">A System.String to replace all occurrences of oldValue.</param>
/// <param name="oldValue">A System.String to be replaced.</param>
/// <param name="options">A bitwise OR combination of RegexOption enumeration options.</param>
/// <param name="trackChanges">Track changes</param>
/// <param name="newFormatting">The formatting to apply to the text being inserted.</param>
/// <param name="matchFormatting">The formatting that the text must match in order to be replaced.</param>
/// <param name="fo">How should formatting be matched?</param>
/// <param name="escapeRegEx">True if the oldValue needs to be escaped, otherwise false. If it represents a valid RegEx pattern this should be false.</param>
/// <param name="useRegExSubstitutions">True if RegEx-like replace should be performed, i.e. if newValue contains RegEx substitutions. Does not perform named-group substitutions (only numbered groups).</param>
public void ReplaceText(string oldValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch, bool escapeRegEx = true, bool useRegExSubstitutions = false)
/// <summary>
/// Replaces all occurrences of a specified System.String in this instance, with another specified System.String.
/// </summary>
/// <example>
/// <code>
/// // Load a document using a relative filename.
/// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
/// {
/// // The formatting to match.
/// Formatting matchFormatting = new Formatting();
/// matchFormatting.Size = 10;
/// matchFormatting.Italic = true;
/// matchFormatting.FontFamily = new FontFamily("Times New Roman");
///
/// // The formatting to apply to the inserted text.
/// Formatting newFormatting = new Formatting();
/// newFormatting.Size = 22;
/// newFormatting.UnderlineStyle = UnderlineStyle.dotted;
/// newFormatting.Bold = true;
///
/// // Iterate through the paragraphs in this document.
/// foreach (Paragraph p in document.Paragraphs)
/// {
/// /*
/// * Replace all instances of the string "wrong" with the string "right" and ignore case.
/// * Each inserted instance of "wrong" should use the Formatting newFormatting.
/// * Only replace an instance of "wrong" if it is Size 10, Italic and Times New Roman.
/// * SubsetMatch means that the formatting must contain all elements of the match formatting,
/// * but it can also contain additional formatting for example Color, UnderlineStyle, etc.
/// * ExactMatch means it must not contain additional formatting.
/// */
/// p.ReplaceText("wrong", "right", false, RegexOptions.IgnoreCase, newFormatting, matchFormatting, MatchFormattingOptions.SubsetMatch);
/// }
///
/// // Save all changes made to this document.
/// document.Save();
/// }// Release this document from memory.
/// </code>
/// </example>
/// <seealso cref="Paragraph.RemoveText(int, int, bool, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
/// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
/// <param name="newValue">A System.String to replace all occurrences of oldValue.</param>
/// <param name="oldValue">A System.String to be replaced.</param>
/// <param name="options">A bitwise OR combination of RegexOption enumeration options.</param>
/// <param name="trackChanges">Track changes</param>
/// <param name="newFormatting">The formatting to apply to the text being inserted.</param>
/// <param name="matchFormatting">The formatting that the text must match in order to be replaced.</param>
/// <param name="fo">How should formatting be matched?</param>
/// <param name="escapeRegEx">True if the oldValue needs to be escaped, otherwise false. If it represents a valid RegEx pattern this should be false.</param>
/// <param name="useRegExSubstitutions">True if RegEx-like replace should be performed, i.e. if newValue contains RegEx substitutions. Does not perform named-group substitutions (only numbered groups).</param>
/// <param name="removeEmptyParagraph">Remove empty paragraph</param>
public void ReplaceText(string oldValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch, bool escapeRegEx = true, bool useRegExSubstitutions = false, bool removeEmptyParagraph = true)
{ {
string tText = Text; string tText = Text;
MatchCollection mc = Regex.Matches(tText, escapeRegEx ? Regex.Escape(oldValue) : oldValue, options); MatchCollection mc = Regex.Matches(tText, escapeRegEx ? Regex.Escape(oldValue) : oldValue, options);
if (!String.IsNullOrEmpty(repl)) if (!String.IsNullOrEmpty(repl))
InsertText(m.Index + m.Length, repl, trackChanges, newFormatting); InsertText(m.Index + m.Length, repl, trackChanges, newFormatting);
if (m.Length > 0) if (m.Length > 0)
RemoveText(m.Index, m.Length, trackChanges);
RemoveText(m.Index, m.Length, trackChanges, removeEmptyParagraph);
} }
} }
} }
/// <summary>
/// Find pattern regex must return a group match.
/// </summary>
/// <param name="findPattern">Regex pattern that must include one group match. ie (.*)</param>
/// <param name="regexMatchHandler">A func that accepts the matching find grouping text and returns a replacement value</param>
/// <param name="trackChanges"></param>
/// <param name="options"></param>
/// <param name="newFormatting"></param>
/// <param name="matchFormatting"></param>
/// <param name="fo"></param>
public void ReplaceText(string findPattern, Func<string, string> regexMatchHandler, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch)
/// <summary>
/// Find pattern regex must return a group match.
/// </summary>
/// <param name="findPattern">Regex pattern that must include one group match. ie (.*)</param>
/// <param name="regexMatchHandler">A func that accepts the matching find grouping text and returns a replacement value</param>
/// <param name="trackChanges"></param>
/// <param name="options"></param>
/// <param name="newFormatting"></param>
/// <param name="matchFormatting"></param>
/// <param name="fo"></param>
/// <param name="removeEmptyParagraph">Remove empty paragraph</param>
public void ReplaceText(string findPattern, Func<string, string> regexMatchHandler, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch, bool removeEmptyParagraph = true)
{ {
var matchCollection = Regex.Matches(Text, findPattern, options); var matchCollection = Regex.Matches(Text, findPattern, options);
{ {
var newValue = regexMatchHandler.Invoke(match.Groups[1].Value); var newValue = regexMatchHandler.Invoke(match.Groups[1].Value);
InsertText(match.Index + match.Value.Length, newValue, trackChanges, newFormatting); InsertText(match.Index + match.Value.Length, newValue, trackChanges, newFormatting);
RemoveText(match.Index, match.Value.Length, trackChanges);
RemoveText(match.Index, match.Value.Length, trackChanges, removeEmptyParagraph);
} }
} }
} }

+ 6
- 1
DocX/Properties/AssemblyInfo.cs Voir le fichier

[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
// Allow the UnitTests to get at internal stuff. // Allow the UnitTests to get at internal stuff.
[assembly: InternalsVisibleTo("UnitTests")]
[assembly: InternalsVisibleTo( "UnitTests, PublicKey=" +
"0024000004800000940000000602000000240000525341310004000001000100b739555cdacfd1" +
"f59b61e7fb189ed886849ae10d0f8a876cd700d36286addf1d4a6854bb23b12fad5700b64787e9" +
"9b0b9f0ed0d64d86d591a32e58080470bdc9a61845301edf6cbb447c3578718763d3f93694a2ac" +
"fdac1c2d096343f3d7085ea1c20fcfeb1d8bac4153204c9faa40c29be2dc38056116e756ff7bbf" +
"9d82e3ab" )]
// Setting ComVisible to false makes the types in this assembly not visible // Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from // to COM components. If you need to access a type in this assembly from

+ 2
- 0
DocX/Table.cs Voir le fichier

return tblPr; return tblPr;
} }
#pragma warning disable CS1584 // XML comment has syntactically incorrect cref attribute
/// <summary> /// <summary>
/// Set the specified cell margin for the table-level. /// Set the specified cell margin for the table-level.
/// </summary> /// </summary>
/// <param name="margin">The value for the specified cell margin.</param> /// <param name="margin">The value for the specified cell margin.</param>
/// <remarks>More information can be found <see cref="http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.tablecellmargindefault.aspx">here</see></remarks> /// <remarks>More information can be found <see cref="http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.tablecellmargindefault.aspx">here</see></remarks>
public void SetTableCellMargin(TableCellMarginType type, double margin) public void SetTableCellMargin(TableCellMarginType type, double margin)
#pragma warning restore CS1584 // XML comment has syntactically incorrect cref attribute
{ {
XElement tblPr = GetOrCreate_tblPr(); XElement tblPr = GetOrCreate_tblPr();

+ 5578
- 0
DocX/bin/Release/DocX.XML
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


BIN
DocX/bin/Release/DocX.dll Voir le fichier


+ 5
- 0
Examples/packages.config Voir le fichier

<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="3.6.0" targetFramework="net40" />
<package id="NUnitTestAdapter" version="2.0.0" targetFramework="net40" />
</packages>

+ 42
- 3
UnitTests/DocXUnitTests.cs Voir le fichier

} }
} }
[Test]
[Test]
public void Test_DocX_SaveAs()
{
string temporaryFilePath = Path.Combine( _directoryDocuments, "temp.docx" );
// Load the document 'Paragraphs.docx'
using( DocX document = DocX.Load( Path.Combine( _directoryWithFiles, "Paragraphs.docx" ) ) )
{
document.InsertParagraph( "text" );
// Test the saving of the document.
document.SaveAs( temporaryFilePath );
// Check file size
FileInfo f = new FileInfo( temporaryFilePath );
Assert.IsTrue( f.Length == 9659 );
}
// Delete the tempory file.
File.Delete( temporaryFilePath );
}
[Test]
public void TableWithSpecifiedWidths() public void TableWithSpecifiedWidths()
{ {
using (var output = File.Open(Path.Combine(_directoryWithFiles, "TableSpecifiedWidths.docx"), FileMode.Create)) using (var output = File.Open(Path.Combine(_directoryWithFiles, "TableSpecifiedWidths.docx"), FileMode.Create))
p4.RemoveText(1, 1); Assert.IsTrue(p4.Text == "AB"); p4.RemoveText(1, 1); Assert.IsTrue(p4.Text == "AB");
p4.RemoveText(p4.Text.Length - 1, 1); Assert.IsTrue(p4.Text == "A"); p4.RemoveText(p4.Text.Length - 1, 1); Assert.IsTrue(p4.Text == "A");
p4.RemoveText(p4.Text.Length - 1, 1); Assert.IsTrue(p4.Text == ""); p4.RemoveText(p4.Text.Length - 1, 1); Assert.IsTrue(p4.Text == "");
}
}
// Checks for parameter removeEmptyParagraph
int originalParagraphCount = document.Paragraphs.Count;
string paraToDelText = "text to delete";
Paragraph paraToDel = document.InsertParagraph( paraToDelText );
Assert.IsTrue( document.Paragraphs.Count == originalParagraphCount + 1 );
// Remove text with paragraph
paraToDel.RemoveText( 0, paraToDelText.Length, false, true );
Assert.IsTrue( document.Paragraphs.Count == originalParagraphCount );
originalParagraphCount = document.Paragraphs.Count;
paraToDel = document.InsertParagraph( paraToDelText );
Assert.IsTrue( document.Paragraphs.Count == originalParagraphCount + 1 );
// Remove text and keep paragraph
paraToDel.RemoveText( 0, paraToDelText.Length, false, false );
Assert.IsTrue( document.Paragraphs.Count == originalParagraphCount + 1 );
}
}
[Test] [Test]
public void Test_Document_RemoveTextInGivenFormat() public void Test_Document_RemoveTextInGivenFormat()

BIN
UnitTests/KeyWithoutPassword.snk Voir le fichier


+ 5
- 5
UnitTests/UnitTests.csproj Voir le fichier

<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SignAssembly>false</SignAssembly>
<SignAssembly>true</SignAssembly>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<AssemblyOriginatorKeyFile>KeyWithoutPassword.snk</AssemblyOriginatorKeyFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="nunit.framework, Version=2.6.3.13283, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<HintPath>..\packages\nunit.framework.2.63.0\lib\nunit.framework.dll</HintPath>
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<None Include="documents\VariousTextFormatting.docx"> <None Include="documents\VariousTextFormatting.docx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Include="KeyWithoutPassword.snk" />
<None Include="packages.config"> <None Include="packages.config">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</None> </None>

+ 1
- 1
UnitTests/packages.config Voir le fichier

<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="NUnit" version="3.4.1" targetFramework="net40" />
<package id="NUnit" version="3.6.0" targetFramework="net40" />
<package id="NUnit.Console" version="3.4.1" targetFramework="net40" /> <package id="NUnit.Console" version="3.4.1" targetFramework="net40" />
<package id="NUnit.ConsoleRunner" version="3.4.1" targetFramework="net40" /> <package id="NUnit.ConsoleRunner" version="3.4.1" targetFramework="net40" />
<package id="NUnit.Extension.NUnitProjectLoader" version="3.4.1" targetFramework="net40" /> <package id="NUnit.Extension.NUnitProjectLoader" version="3.4.1" targetFramework="net40" />

Chargement…
Annuler
Enregistrer