diff --git a/.gitignore b/.gitignore deleted file mode 100644 index e935e2df..00000000 --- a/.gitignore +++ /dev/null @@ -1,239 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ -Documentation/Help/Documentation.chw -DocX/bin/Debug/DocX.dll diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 81d8a721..00000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: csharp -solution: DocX.sln -install: - - nuget restore DocX.sln - - nuget install NUnit.Console -Version 3.4.1 -OutputDirectory testrunner -script: - - xbuild /p:Configuration=Debug DocX.sln - - mono --debug ./testrunner/NUnit.ConsoleRunner.3.4.1/tools/nunit3-console.exe ./UnitTests/bin/Debug/UnitTests.dll \ No newline at end of file diff --git a/BuildProcessTemplates/DefaultTemplate.11.1.xaml b/BuildProcessTemplates/DefaultTemplate.11.1.xaml deleted file mode 100644 index 60eac4b8..00000000 --- a/BuildProcessTemplates/DefaultTemplate.11.1.xaml +++ /dev/null @@ -1,543 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - [New Microsoft.TeamFoundation.Build.Workflow.Activities.BuildSettings()] - [False] - [New Microsoft.TeamFoundation.Build.Workflow.Activities.TestSpecList(New Microsoft.TeamFoundation.Build.Workflow.Activities.AgileTestPlatformSpec("**\*test*.dll"))] - ["$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r)"] - [False] - [True] - [True] - [Microsoft.TeamFoundation.Build.Workflow.Activities.CleanWorkspaceOption.All] - - - - [Microsoft.TeamFoundation.Build.Workflow.Activities.CodeAnalysisOption.AsConfigured] - [True] - [Microsoft.TeamFoundation.Build.Workflow.Activities.ToolPlatform.Auto] - [True] - [New Microsoft.TeamFoundation.Build.Workflow.Activities.SourceAndSymbolServerSettings(True, Nothing)] - [True] - - - - [New Microsoft.TeamFoundation.Build.Workflow.Activities.AgentSettings() With {.MaxWaitTime = New System.TimeSpan(4, 0, 0), .MaxExecutionTime = New System.TimeSpan(0, 0, 0), .TagComparison = Microsoft.TeamFoundation.Build.Workflow.Activities.TagComparison.MatchExactly }] - [Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity.Normal] - - - - - - - All - 11.0 - Assembly references and imported namespaces serialized as XML namespaces - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/BuildProcessTemplates/DefaultTemplate.xaml b/BuildProcessTemplates/DefaultTemplate.xaml deleted file mode 100644 index eae035b2..00000000 --- a/BuildProcessTemplates/DefaultTemplate.xaml +++ /dev/null @@ -1,602 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Assembly references and imported namespaces serialized as XML namespaces - - - True - - - - - - - - - True - - - - - - - True - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - True - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - - - - True - - - - - - - - - True - - - - - - - - - - - - - - - True - - - - - - True - - - - - - - - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - False - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - - - False - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - - - - - - - - False - - - - - - - - - - - - - - - - - - - - - - - - - - False - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/BuildProcessTemplates/LabDefaultTemplate.11.xaml b/BuildProcessTemplates/LabDefaultTemplate.11.xaml deleted file mode 100644 index 542717f2..00000000 --- a/BuildProcessTemplates/LabDefaultTemplate.11.xaml +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - - - - - - - - 11.0 - - - - - - 920,3702 - Assembly references and imported namespaces serialized as XML namespaces - - - - - - - - - - - - - - - - - - - - - True - - - - - - - [LabWorkflowParameters.BuildDetails.BuildUri] - - - [ChildBuildDetail.Uri] - - - - - - - - - - - - [BuildLocation] - - - [If(LabWorkflowParameters.BuildDetails.Configuration Is Nothing, BuildLocation, If(LabWorkflowParameters.BuildDetails.Configuration.IsEmpty Or (SelectedBuildDetail.Information.GetNodesByType(Microsoft.TeamFoundation.Build.Common.InformationTypes.ConfigurationSummary, True)).Count = 1, BuildLocation, If(LabWorkflowParameters.BuildDetails.Configuration.IsPlatformEmptyOrAnyCpu, BuildLocation + "\" + LabWorkflowParameters.BuildDetails.Configuration.Configuration, BuildLocation + "\" + LabWorkflowParameters.BuildDetails.Configuration.Platform + "\" + LabWorkflowParameters.BuildDetails.Configuration.Configuration)))] - - - - - - - - - - - - [LabEnvironmentUri] - - - [LabWorkflowParameters.EnvironmentDetails.LabEnvironmentUri.ToString()] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [PostDeploymentSnapshotName] - - - [If(LabWorkflowParameters.BuildDetails.IsTeamSystemBuild = True,String.Format("{0}_{1}_{2}", LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildNumber,BuildDetail.BuildNumber),String.Format("{0}_{1}", LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildDetail.BuildNumber))] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [BuildStatus] - - - [Microsoft.TeamFoundation.Build.Client.BuildStatus.PartiallySucceeded] - - - - - - - [BuildStatus] - - - [Microsoft.TeamFoundation.Build.Client.BuildStatus.Failed] - - - - - - - - - - - - \ No newline at end of file diff --git a/BuildProcessTemplates/UpgradeTemplate.xaml b/BuildProcessTemplates/UpgradeTemplate.xaml deleted file mode 100644 index 4877aa35..00000000 --- a/BuildProcessTemplates/UpgradeTemplate.xaml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - [New Microsoft.TeamFoundation.Build.Workflow.Activities.AgentSettings() With {.MaxWaitTime = New System.TimeSpan(4, 0, 0), .MaxExecutionTime = New System.TimeSpan(0, 0, 0), .TagComparison = Microsoft.TeamFoundation.Build.Workflow.Activities.TagComparison.MatchExactly }] - - - - [Microsoft.TeamFoundation.Build.Workflow.Activities.ToolPlatform.Auto] - [False] - [False] - - - - - - - - - - [Microsoft.TeamFoundation.VersionControl.Client.RecursionType.OneLevel] - [Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity.Normal] - - - - All - Assembly references and imported namespaces serialized as XML namespaces - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DocX.Xamarin.sln b/DocX.Xamarin.sln deleted file mode 100644 index 0c0879c7..00000000 --- a/DocX.Xamarin.sln +++ /dev/null @@ -1,33 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocX.iOS.Test", "DocX.iOS.Test\DocX.iOS.Test.csproj", "{E504B3DA-ED72-4A45-ADCC-F573908A84EB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocX.iOS", "DocX.iOS\DocX.iOS.csproj", "{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|iPhoneSimulator = Debug|iPhoneSimulator - Release|iPhone = Release|iPhone - Release|iPhoneSimulator = Release|iPhoneSimulator - Debug|iPhone = Debug|iPhone - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Debug|iPhone.Build.0 = Debug|Any CPU - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Release|iPhone.ActiveCfg = Release|Any CPU - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Release|iPhone.Build.0 = Release|Any CPU - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Debug|iPhone.ActiveCfg = Debug|iPhone - {E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Debug|iPhone.Build.0 = Debug|iPhone - {E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator - {E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator - {E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Release|iPhone.ActiveCfg = Release|iPhone - {E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Release|iPhone.Build.0 = Release|iPhone - {E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator - {E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator - EndGlobalSection -EndGlobal diff --git a/DocX.cs b/DocX.cs deleted file mode 100644 index 2618be57..00000000 --- a/DocX.cs +++ /dev/null @@ -1,4459 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Packaging; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml; -using System.Xml.Linq; -using System.Collections.ObjectModel; - -namespace Novacode -{ - /// - /// Represents a document. - /// - public class DocX : Container, IDisposable - { - #region Namespaces - static internal XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; - static internal XNamespace rel = "http://schemas.openxmlformats.org/package/2006/relationships"; - - static internal XNamespace r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; - static internal XNamespace m = "http://schemas.openxmlformats.org/officeDocument/2006/math"; - static internal XNamespace customPropertiesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"; - static internal XNamespace customVTypesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"; - - static internal XNamespace wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"; - static internal XNamespace a = "http://schemas.openxmlformats.org/drawingml/2006/main"; - static internal XNamespace c = "http://schemas.openxmlformats.org/drawingml/2006/chart"; - - static internal XNamespace v = "urn:schemas-microsoft-com:vml"; - - internal static XNamespace n = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"; - #endregion - - internal float getMarginAttribute(XName name) - { - XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - if (sectPr != null) - { - XElement pgMar = sectPr.Element(XName.Get("pgMar", DocX.w.NamespaceName)); - if (pgMar != null) - { - XAttribute top = pgMar.Attribute(name); - if (top != null) - { - float f; - if (float.TryParse(top.Value, out f)) - return (int)(f / 20.0f); - } - } - } - - return 0; - } - - internal void setMarginAttribute(XName xName, float value) - { - XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - if (sectPr != null) - { - XElement pgMar = sectPr.Element(XName.Get("pgMar", DocX.w.NamespaceName)); - if (pgMar != null) - { - XAttribute top = pgMar.Attribute(xName); - if (top != null) - { - top.SetValue(value * 20); - } - } - } - } - - public BookmarkCollection Bookmarks - { - get - { - BookmarkCollection bookmarks = new BookmarkCollection(); - foreach (Paragraph paragraph in Paragraphs) - bookmarks.AddRange(paragraph.GetBookmarks()); - return bookmarks; - } - } - - /// - /// Top margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginTop - { - get - { - return getMarginAttribute(XName.Get("top", DocX.w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("top", DocX.w.NamespaceName), value); - } - } - - /// - /// Bottom margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginBottom - { - get - { - return getMarginAttribute(XName.Get("bottom", DocX.w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("bottom", DocX.w.NamespaceName), value); - } - } - - /// - /// Left margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginLeft - { - get - { - return getMarginAttribute(XName.Get("left", DocX.w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("left", DocX.w.NamespaceName), value); - } - } - - /// - /// Right margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginRight - { - get - { - return getMarginAttribute(XName.Get("right", DocX.w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("right", DocX.w.NamespaceName), value); - } - } - - /// - /// Header margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginHeader - { - get - { - return getMarginAttribute(XName.Get("header", DocX.w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("header", DocX.w.NamespaceName), value); - } - } - - /// - /// Footer margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginFooter - { - get - { - return getMarginAttribute(XName.Get("footer", DocX.w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("footer", DocX.w.NamespaceName), value); - } - } - - /// - /// Page width value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float PageWidth - { - get - { - XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - if (sectPr != null) - { - XElement pgSz = sectPr.Element(XName.Get("pgSz", DocX.w.NamespaceName)); - - if (pgSz != null) - { - XAttribute w = pgSz.Attribute(XName.Get("w", DocX.w.NamespaceName)); - if (w != null) - { - float f; - if (float.TryParse(w.Value, out f)) - return (int)(f / 20.0f); - } - } - } - - return (12240.0f / 20.0f); - } - - set - { - XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - - if (body != null) - { - XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - - if (sectPr != null) - { - XElement pgSz = sectPr.Element(XName.Get("pgSz", DocX.w.NamespaceName)); - - if (pgSz != null) - { - pgSz.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), value * 20); - } - } - } - } - } - - /// - /// Page height value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float PageHeight - { - get - { - XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - if (sectPr != null) - { - XElement pgSz = sectPr.Element(XName.Get("pgSz", DocX.w.NamespaceName)); - - if (pgSz != null) - { - XAttribute w = pgSz.Attribute(XName.Get("h", DocX.w.NamespaceName)); - if (w != null) - { - float f; - if (float.TryParse(w.Value, out f)) - return (int)(f / 20.0f); - } - } - } - - return (15840.0f / 20.0f); - } - - set - { - XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - - if (body != null) - { - XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - - if (sectPr != null) - { - XElement pgSz = sectPr.Element(XName.Get("pgSz", DocX.w.NamespaceName)); - - if (pgSz != null) - { - pgSz.SetAttributeValue(XName.Get("h", DocX.w.NamespaceName), value * 20); - } - } - } - } - } - /// - /// Returns true if any editing restrictions are imposed on this document. - /// - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// if(document.isProtected) - /// Console.WriteLine("Protected"); - /// else - /// Console.WriteLine("Not protected"); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public bool isProtected - { - get - { - return settings.Descendants(XName.Get("documentProtection", DocX.w.NamespaceName)).Count() > 0; - } - } - - /// - /// Returns the type of editing protection imposed on this document. - /// - /// The type of editing protection imposed on this document. - /// - /// - /// Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Make sure the document is protected before checking the protection type. - /// if (document.isProtected) - /// { - /// EditRestrictions protection = document.GetProtectionType(); - /// Console.WriteLine("Document is protected using " + protection.ToString()); - /// } - /// - /// else - /// Console.WriteLine("Document is not protected."); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public EditRestrictions GetProtectionType() - { - if (isProtected) - { - XElement documentProtection = settings.Descendants(XName.Get("documentProtection", DocX.w.NamespaceName)).FirstOrDefault(); - string edit_type = documentProtection.Attribute(XName.Get("edit", DocX.w.NamespaceName)).Value; - return (EditRestrictions)Enum.Parse(typeof(EditRestrictions), edit_type); - } - - return EditRestrictions.none; - } - - /// - /// Add editing protection to this document. - /// - /// The type of protection to add to this document. - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Allow no editing, only the adding of comment. - /// document.AddProtection(EditRestrictions.comments); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public void AddProtection(EditRestrictions er) - { - // Call remove protection before adding a new protection element. - RemoveProtection(); - - if (er == EditRestrictions.none) - return; - - XElement documentProtection = new XElement(XName.Get("documentProtection", DocX.w.NamespaceName)); - documentProtection.Add(new XAttribute(XName.Get("edit", DocX.w.NamespaceName), er.ToString())); - documentProtection.Add(new XAttribute(XName.Get("enforcement", DocX.w.NamespaceName), "1")); - - settings.Root.AddFirst(documentProtection); - } - - public void AddProtection(EditRestrictions er, string strPassword) - { - // http://blogs.msdn.com/b/vsod/archive/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0.aspx - // Call remove protection before adding a new protection element. - RemoveProtection(); - - if (er == EditRestrictions.none) - return; - - XElement documentProtection = new XElement(XName.Get("documentProtection", DocX.w.NamespaceName)); - documentProtection.Add(new XAttribute(XName.Get("edit", DocX.w.NamespaceName), er.ToString())); - documentProtection.Add(new XAttribute(XName.Get("enforcement", DocX.w.NamespaceName), "1")); - - int[] InitialCodeArray = { 0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3 }; - int[,] EncryptionMatrix = new int[15, 7] - { - - /* char 1 */ {0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09}, - /* char 2 */ {0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF}, - /* char 3 */ {0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0}, - /* char 4 */ {0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40}, - /* char 5 */ {0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5}, - /* char 6 */ {0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A}, - /* char 7 */ {0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9}, - /* char 8 */ {0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0}, - /* char 9 */ {0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC}, - /* char 10 */ {0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10}, - /* char 11 */ {0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168}, - /* char 12 */ {0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C}, - /* char 13 */ {0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD}, - /* char 14 */ {0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC}, - /* char 15 */ {0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4} - }; - - // Generate the Salt - byte[] arrSalt = new byte[16]; - RandomNumberGenerator rand = new RNGCryptoServiceProvider(); - rand.GetNonZeroBytes(arrSalt); - - //Array to hold Key Values - byte[] generatedKey = new byte[4]; - - //Maximum length of the password is 15 chars. - int intMaxPasswordLength = 15; - - if (!String.IsNullOrEmpty(strPassword)) - { - strPassword = strPassword.Substring(0, Math.Min(strPassword.Length, intMaxPasswordLength)); - - byte[] arrByteChars = new byte[strPassword.Length]; - - for (int intLoop = 0; intLoop < strPassword.Length; intLoop++) - { - int intTemp = Convert.ToInt32(strPassword[intLoop]); - arrByteChars[intLoop] = Convert.ToByte(intTemp & 0x00FF); - if (arrByteChars[intLoop] == 0) - arrByteChars[intLoop] = Convert.ToByte((intTemp & 0xFF00) >> 8); - } - - int intHighOrderWord = InitialCodeArray[arrByteChars.Length - 1]; - - for (int intLoop = 0; intLoop < arrByteChars.Length; intLoop++) - { - int tmp = intMaxPasswordLength - arrByteChars.Length + intLoop; - for (int intBit = 0; intBit < 7; intBit++) - { - if ((arrByteChars[intLoop] & (0x0001 << intBit)) != 0) - { - intHighOrderWord ^= EncryptionMatrix[tmp, intBit]; - } - } - } - - int intLowOrderWord = 0; - - // For each character in the strPassword, going backwards - for (int intLoopChar = arrByteChars.Length - 1; intLoopChar >= 0; intLoopChar--) - { - intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars[intLoopChar]; - } - - intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars.Length ^ 0xCE4B; - - // Combine the Low and High Order Word - int intCombinedkey = (intHighOrderWord << 16) + intLowOrderWord; - - // The byte order of the result shall be reversed [Example: 0x64CEED7E becomes 7EEDCE64. end example], - // and that value shall be hashed as defined by the attribute values. - - for (int intTemp = 0; intTemp < 4; intTemp++) - { - generatedKey[intTemp] = Convert.ToByte(((uint)(intCombinedkey & (0x000000FF << (intTemp * 8)))) >> (intTemp * 8)); - } - } - - StringBuilder sb = new StringBuilder(); - for (int intTemp = 0; intTemp < 4; intTemp++) - { - sb.Append(Convert.ToString(generatedKey[intTemp], 16)); - } - generatedKey = Encoding.Unicode.GetBytes(sb.ToString().ToUpper()); - - byte[] tmpArray1 = generatedKey; - byte[] tmpArray2 = arrSalt; - byte[] tempKey = new byte[tmpArray1.Length + tmpArray2.Length]; - Buffer.BlockCopy(tmpArray2, 0, tempKey, 0, tmpArray2.Length); - Buffer.BlockCopy(tmpArray1, 0, tempKey, tmpArray2.Length, tmpArray1.Length); - generatedKey = tempKey; - - - int iterations = 100000; - - HashAlgorithm sha1 = new SHA1Managed(); - generatedKey = sha1.ComputeHash(generatedKey); - byte[] iterator = new byte[4]; - for (int intTmp = 0; intTmp < iterations; intTmp++) - { - - iterator[0] = Convert.ToByte((intTmp & 0x000000FF) >> 0); - iterator[1] = Convert.ToByte((intTmp & 0x0000FF00) >> 8); - iterator[2] = Convert.ToByte((intTmp & 0x00FF0000) >> 16); - iterator[3] = Convert.ToByte((intTmp & 0xFF000000) >> 24); - - generatedKey = concatByteArrays(iterator, generatedKey); - generatedKey = sha1.ComputeHash(generatedKey); - } - - documentProtection.Add(new XAttribute(XName.Get("cryptProviderType", DocX.w.NamespaceName), "rsaFull")); - documentProtection.Add(new XAttribute(XName.Get("cryptAlgorithmClass", DocX.w.NamespaceName), "hash")); - documentProtection.Add(new XAttribute(XName.Get("cryptAlgorithmType", DocX.w.NamespaceName), "typeAny")); - documentProtection.Add(new XAttribute(XName.Get("cryptAlgorithmSid", DocX.w.NamespaceName), "4")); // SHA1 - documentProtection.Add(new XAttribute(XName.Get("cryptSpinCount", DocX.w.NamespaceName), iterations.ToString())); - documentProtection.Add(new XAttribute(XName.Get("hash", DocX.w.NamespaceName), Convert.ToBase64String(generatedKey))); - documentProtection.Add(new XAttribute(XName.Get("salt", DocX.w.NamespaceName), Convert.ToBase64String(arrSalt))); - - settings.Root.AddFirst(documentProtection); - } - - private byte[] concatByteArrays(byte[] array1, byte[] array2) - { - byte[] result = new byte[array1.Length + array2.Length]; - Buffer.BlockCopy(array2, 0, result, 0, array2.Length); - Buffer.BlockCopy(array1, 0, result, array2.Length, array1.Length); - return result; - } - - /// - /// Remove editing protection from this document. - /// - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Remove any editing restrictions that are imposed on this document. - /// document.RemoveProtection(); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public void RemoveProtection() - { - // Remove every node of type documentProtection. - settings.Descendants(XName.Get("documentProtection", DocX.w.NamespaceName)).Remove(); - } - - public PageLayout PageLayout - { - get - { - XElement sectPr = Xml.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - if (sectPr == null) - { - Xml.SetElementValue(XName.Get("sectPr", DocX.w.NamespaceName), string.Empty); - sectPr = Xml.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - } - - return new PageLayout(this, sectPr); - } - } - - /// - /// Returns a collection of Headers in this Document. - /// A document typically contains three Headers. - /// A default one (odd), one for the first page and one for even pages. - /// - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add header support to this document. - /// document.AddHeaders(); - /// - /// // Get a collection of all headers in this document. - /// Headers headers = document.Headers; - /// - /// // The header used for the first page of this document. - /// Header first = headers.first; - /// - /// // The header used for odd pages of this document. - /// Header odd = headers.odd; - /// - /// // The header used for even pages of this document. - /// Header even = headers.even; - /// } - /// - /// - public Headers Headers - { - get - { - return headers; - } - } - private Headers headers; - - /// - /// Returns a collection of Footers in this Document. - /// A document typically contains three Footers. - /// A default one (odd), one for the first page and one for even pages. - /// - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add footer support to this document. - /// document.AddFooters(); - /// - /// // Get a collection of all footers in this document. - /// Footers footers = document.Footers; - /// - /// // The footer used for the first page of this document. - /// Footer first = footers.first; - /// - /// // The footer used for odd pages of this document. - /// Footer odd = footers.odd; - /// - /// // The footer used for even pages of this document. - /// Footer even = footers.even; - /// } - /// - /// - public Footers Footers - { - get - { - return footers; - } - } - - private Footers footers; - - /// - /// Should the Document use different Headers and Footers for odd and even pages? - /// - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add header support to this document. - /// document.AddHeaders(); - /// - /// // Get a collection of all headers in this document. - /// Headers headers = document.Headers; - /// - /// // The header used for odd pages of this document. - /// Header odd = headers.odd; - /// - /// // The header used for even pages of this document. - /// Header even = headers.even; - /// - /// // Force the document to use a different header for odd and even pages. - /// document.DifferentOddAndEvenPages = true; - /// - /// // Content can be added to the Headers in the same manor that it would be added to the main document. - /// Paragraph p1 = odd.InsertParagraph(); - /// p1.Append("This is the odd pages header."); - /// - /// Paragraph p2 = even.InsertParagraph(); - /// p2.Append("This is the even pages header."); - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public bool DifferentOddAndEvenPages - { - get - { - XDocument settings; - using (TextReader tr = new StreamReader(settingsPart.GetStream())) - settings = XDocument.Load(tr); - - XElement evenAndOddHeaders = settings.Root.Element(w + "evenAndOddHeaders"); - - return evenAndOddHeaders != null; - } - - set - { - XDocument settings; - using (TextReader tr = new StreamReader(settingsPart.GetStream())) - settings = XDocument.Load(tr); - - XElement evenAndOddHeaders = settings.Root.Element(w + "evenAndOddHeaders"); - if (evenAndOddHeaders == null) - { - if (value) - settings.Root.AddFirst(new XElement(w + "evenAndOddHeaders")); - } - else - { - if (!value) - evenAndOddHeaders.Remove(); - } - - using (TextWriter tw = new StreamWriter(new PackagePartStream(settingsPart.GetStream()))) - settings.Save(tw); - } - } - - /// - /// Should the Document use an independent Header and Footer for the first page? - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add header support to this document. - /// document.AddHeaders(); - /// - /// // The header used for the first page of this document. - /// Header first = document.Headers.first; - /// - /// // Force the document to use a different header for first page. - /// document.DifferentFirstPage = true; - /// - /// // Content can be added to the Headers in the same manor that it would be added to the main document. - /// Paragraph p = first.InsertParagraph(); - /// p.Append("This is the first pages header."); - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - public bool DifferentFirstPage - { - get - { - XElement body = mainDoc.Root.Element(w + "body"); - XElement sectPr = body.Element(w + "sectPr"); - - if (sectPr != null) - { - XElement titlePg = sectPr.Element(w + "titlePg"); - if (titlePg != null) - return true; - } - - return false; - } - - set - { - XElement body = mainDoc.Root.Element(w + "body"); - XElement sectPr = null; - XElement titlePg = null; - - if (sectPr == null) - body.Add(new XElement(w + "sectPr", string.Empty)); - - sectPr = body.Element(w + "sectPr"); - - titlePg = sectPr.Element(w + "titlePg"); - if (titlePg == null) - { - if (value) - sectPr.Add(new XElement(w + "titlePg", string.Empty)); - } - else - { - if (!value) - titlePg.Remove(); - } - } - } - - private Header GetHeaderByType(string type) - { - return (Header)GetHeaderOrFooterByType(type, true); - } - - private Footer GetFooterByType(string type) - { - return (Footer)GetHeaderOrFooterByType(type, false); - } - - private object GetHeaderOrFooterByType(string type, bool isHeader) - { - // Switch which handles either case Header\Footer, this just cuts down on code duplication. - string reference = "footerReference"; - if (isHeader) - reference = "headerReference"; - - // Get the Id of the [default, even or first] [Header or Footer] - - string Id = - ( - from e in mainDoc.Descendants(XName.Get("body", DocX.w.NamespaceName)).Descendants() - where (e.Name.LocalName == reference) && (e.Attribute(w + "type").Value == type) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (Id != null) - { - // Get the Xml file for this Header or Footer. - Uri partUri = mainPart.GetRelationship(Id).TargetUri; - - // Weird problem with PackaePart API. - if (!partUri.OriginalString.StartsWith("/word/")) - partUri = new Uri("/word/" + partUri.OriginalString, UriKind.Relative); - - // Get the Part and open a stream to get the Xml file. - PackagePart part = package.GetPart(partUri); - - XDocument doc; - using (TextReader tr = new StreamReader(part.GetStream())) - { - doc = XDocument.Load(tr); - - // Header and Footer extend Container. - Container c; - if (isHeader) - c = new Header(this, doc.Element(w + "hdr"), part); - else - c = new Footer(this, doc.Element(w + "ftr"), part); - - return c; - } - } - - // If we got this far something went wrong. - return null; - } - - - - public List
GetSections() - { - - var allParas = Paragraphs; - - var parasInASection = new List(); - var sections = new List
(); - - foreach (var para in allParas) - { - - var sectionInPara = para.Xml.Descendants().FirstOrDefault(s => s.Name.LocalName == "sectPr"); - - if (sectionInPara == null) - { - parasInASection.Add(para); - } - else - { - parasInASection.Add(para); - var section = new Section(Document, sectionInPara) { SectionParagraphs = parasInASection }; - sections.Add(section); - parasInASection = new List(); - } - - } - - XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - XElement baseSectionXml = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - var baseSection = new Section(Document, baseSectionXml) { SectionParagraphs = parasInASection }; - sections.Add(baseSection); - - return sections; - } - - - // Get the word\settings.xml part - internal PackagePart settingsPart; - internal PackagePart endnotesPart; - internal PackagePart footnotesPart; - internal PackagePart stylesPart; - internal PackagePart stylesWithEffectsPart; - internal PackagePart numberingPart; - internal PackagePart fontTablePart; - - #region Internal variables defined foreach DocX object - // Object representation of the .docx - internal Package package; - - // The mainDocument is loaded into a XDocument object for easy querying and editing - internal XDocument mainDoc; - internal XDocument settings; - internal XDocument endnotes; - internal XDocument footnotes; - internal XDocument styles; - internal XDocument stylesWithEffects; - internal XDocument numbering; - internal XDocument fontTable; - internal XDocument header1; - internal XDocument header2; - internal XDocument header3; - - // A lookup for the Paragraphs in this document. - internal Dictionary paragraphLookup = new Dictionary(); - // Every document is stored in a MemoryStream, all edits made to a document are done in memory. - internal MemoryStream memoryStream; - // The filename that this document was loaded from - internal string filename; - // The stream that this document was loaded from - internal Stream stream; - #endregion - - internal DocX(DocX document, XElement xml) - : base(document, xml) - { - - } - - /// - /// Returns a list of Images in this document. - /// - /// - /// Get the unique Id of every Image in this document. - /// - /// // Load a document. - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// // Loop through each Image in this document. - /// foreach (Novacode.Image i in document.Images) - /// { - /// // Get the unique Id which identifies this Image. - /// string uniqueId = i.Id; - /// } - /// - /// - /// - /// - /// - /// - /// - public List Images - { - get - { - PackageRelationshipCollection imageRelationships = mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"); - if (imageRelationships.Count() > 0) - { - return - ( - from i in imageRelationships - select new Image(this, i) - ).ToList(); - } - - return new List(); - } - } - - /// - /// Returns a list of custom properties in this document. - /// - /// - /// Method 1: Get the name, type and value of each CustomProperty in this document. - /// - /// // Load Example.docx - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// /* - /// * No two custom properties can have the same name, - /// * so a Dictionary is the perfect data structure to store them in. - /// * Each custom property can be accessed using its name. - /// */ - /// foreach (string name in document.CustomProperties.Keys) - /// { - /// // Grab a custom property using its name. - /// CustomProperty cp = document.CustomProperties[name]; - /// - /// // Write this custom properties details to Console. - /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value)); - /// } - /// - /// Console.WriteLine("Press any key..."); - /// - /// // Wait for the user to press a key before closing the Console. - /// Console.ReadKey(); - /// - /// - /// - /// Method 2: Get the name, type and value of each CustomProperty in this document. - /// - /// // Load Example.docx - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// /* - /// * No two custom properties can have the same name, - /// * so a Dictionary is the perfect data structure to store them in. - /// * The values of this Dictionary are CustomProperties. - /// */ - /// foreach (CustomProperty cp in document.CustomProperties.Values) - /// { - /// // Write this custom properties details to Console. - /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value)); - /// } - /// - /// Console.WriteLine("Press any key..."); - /// - /// // Wait for the user to press a key before closing the Console. - /// Console.ReadKey(); - /// - /// - /// - public Dictionary CustomProperties - { - get - { - if (package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative))) - { - PackagePart docProps_custom = package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative)); - XDocument customPropDoc; - using (TextReader tr = new StreamReader(docProps_custom.GetStream(FileMode.Open, FileAccess.Read))) - customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace); - - // Get all of the custom properties in this document - return - ( - from p in customPropDoc.Descendants(XName.Get("property", customPropertiesSchema.NamespaceName)) - let Name = p.Attribute(XName.Get("name")).Value - let Type = p.Descendants().Single().Name.LocalName - let Value = p.Descendants().Single().Value - select new CustomProperty(Name, Type, Value) - ).ToDictionary(p => p.Name, StringComparer.CurrentCultureIgnoreCase); - } - - return new Dictionary(); - } - } - - /// - /// Returns the list of document core properties with corresponding values. - /// - public Dictionary CoreProperties - { - get - { - if (package.PartExists(new Uri("/docProps/core.xml", UriKind.Relative))) - { - PackagePart docProps_Core = package.GetPart(new Uri("/docProps/core.xml", UriKind.Relative)); - XDocument corePropDoc; - using (TextReader tr = new StreamReader(docProps_Core.GetStream(FileMode.Open, FileAccess.Read))) - corePropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace); - - // Get all of the core properties in this document - return (from docProperty in corePropDoc.Root.Elements() - select - new KeyValuePair( - string.Format( - "{0}:{1}", - corePropDoc.Root.GetPrefixOfNamespace(docProperty.Name.Namespace), - docProperty.Name.LocalName), - docProperty.Value)).ToDictionary(p => p.Key, v => v.Value); - } - - return new Dictionary(); - } - } - - /// - /// Get the Text of this document. - /// - /// - /// Write to Console the Text from this document. - /// - /// // Load a document - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// // Get the text of this document. - /// string text = document.Text; - /// - /// // Write the text of this document to Console. - /// Console.Write(text); - /// - /// // Wait for the user to press a key before closing the console window. - /// Console.ReadKey(); - /// - /// - public string Text - { - get - { - return HelperFunctions.GetText(Xml); - } - } - /// - /// Get the text of each footnote from this document - /// - public IEnumerable FootnotesText - { - get - { - foreach (XElement footnote in footnotes.Root.Elements(w + "footnote")) - { - yield return HelperFunctions.GetText(footnote); - } - } - } - - /// - /// Get the text of each endnote from this document - /// - public IEnumerable EndnotesText - { - get - { - foreach (XElement endnote in endnotes.Root.Elements(w + "endnote")) - { - yield return HelperFunctions.GetText(endnote); - } - } - } - - - - internal string GetCollectiveText(List list) - { - string text = string.Empty; - - foreach (var hp in list) - { - using (TextReader tr = new StreamReader(hp.GetStream())) - { - XDocument d = XDocument.Load(tr); - - StringBuilder sb = new StringBuilder(); - - // Loop through each text item in this run - foreach (XElement descendant in d.Descendants()) - { - switch (descendant.Name.LocalName) - { - case "tab": - sb.Append("\t"); - break; - case "br": - sb.Append("\n"); - break; - case "t": - goto case "delText"; - case "delText": - sb.Append(descendant.Value); - break; - default: break; - } - } - - text += "\n" + sb.ToString(); - } - } - - return text; - } - - /// - /// Insert the contents of another document at the end of this document. - /// - /// The document to insert at the end of this document. - /// If true, document is inserted at the end, otherwise document is inserted at the beginning. - /// - /// Create a new document and insert an old document into it. - /// - /// // Create a new document. - /// using (DocX newDocument = DocX.Create(@"NewDocument.docx")) - /// { - /// // Load an old document. - /// using (DocX oldDocument = DocX.Load(@"OldDocument.docx")) - /// { - /// // Insert the old document into the new document. - /// newDocument.InsertDocument(oldDocument); - /// - /// // Save the new document. - /// newDocument.Save(); - /// }// Release the old document from memory. - /// }// Release the new document from memory. - /// - /// - /// If the document being inserted contains Images, CustomProperties and or custom styles, these will be correctly inserted into the new document. In the case of Images, new ID's are generated for the Images being inserted to avoid ID conflicts. CustomProperties with the same name will be ignored not replaced. - /// - /// - public void InsertDocument(DocX remote_document, bool append = true) - { - // We don't want to effect the origional XDocument, so create a new one from the old one. - XDocument remote_mainDoc = new XDocument(remote_document.mainDoc); - - XDocument remote_footnotes = null; - if (remote_document.footnotes != null) - remote_footnotes = new XDocument(remote_document.footnotes); - - XDocument remote_endnotes = null; - if (remote_document.endnotes != null) - remote_endnotes = new XDocument(remote_document.endnotes); - - // Remove all header and footer references. - remote_mainDoc.Descendants(XName.Get("headerReference", DocX.w.NamespaceName)).Remove(); - remote_mainDoc.Descendants(XName.Get("footerReference", DocX.w.NamespaceName)).Remove(); - - // Get the body of the remote document. - XElement remote_body = remote_mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - - // Every file that is missing from the local document will have to be copied, every file that already exists will have to be merged. - PackagePartCollection ppc = remote_document.package.GetParts(); - - List ignoreContentTypes = new List - { - "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", - "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", - "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", - "application/vnd.openxmlformats-package.core-properties+xml", - "application/vnd.openxmlformats-officedocument.extended-properties+xml", - "application/vnd.openxmlformats-package.relationships+xml", - }; - - List imageContentTypes = new List - { - "image/jpeg", - "image/jpg", - "image/png", - "image/bmp", - "image/gif", - "image/tiff", - "image/icon", - "image/pcx", - "image/emf", - "image/wmf" - }; - // Check if each PackagePart pp exists in this document. - foreach (PackagePart remote_pp in ppc) - { - if (ignoreContentTypes.Contains(remote_pp.ContentType) || imageContentTypes.Contains(remote_pp.ContentType)) - continue; - - // If this external PackagePart already exits then we must merge them. - if (package.PartExists(remote_pp.Uri)) - { - PackagePart local_pp = package.GetPart(remote_pp.Uri); - switch (remote_pp.ContentType) - { - case "application/vnd.openxmlformats-officedocument.custom-properties+xml": - merge_customs(remote_pp, local_pp, remote_mainDoc); - break; - - // Merge footnotes (and endnotes) before merging styles, then set the remote_footnotes to the just updated footnotes - case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": - 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; - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": - merge_styles(remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes); - break; - - // Merge styles after merging the footnotes, so the changes will be applied to the correct document/footnotes - case "application/vnd.ms-word.stylesWithEffects+xml": - merge_styles(remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes); - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml": - merge_fonts(remote_pp, local_pp, remote_mainDoc, remote_document); - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": - merge_numbering(remote_pp, local_pp, remote_mainDoc, remote_document); - break; - - default: - break; - } - } - - // If this external PackagePart does not exits in the internal document then we can simply copy it. - else - { - var packagePart = clonePackagePart(remote_pp); - switch (remote_pp.ContentType) - { - case "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": - endnotesPart = packagePart; - endnotes = remote_endnotes; - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": - footnotesPart = packagePart; - footnotes = remote_footnotes; - break; - - case "application/vnd.openxmlformats-officedocument.custom-properties+xml": - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": - stylesPart = packagePart; - using (TextReader tr = new StreamReader(stylesPart.GetStream())) - styles = XDocument.Load(tr); - break; - - case "application/vnd.ms-word.stylesWithEffects+xml": - stylesWithEffectsPart = packagePart; - using (TextReader tr = new StreamReader(stylesWithEffectsPart.GetStream())) - stylesWithEffects = XDocument.Load(tr); - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml": - fontTablePart = packagePart; - using (TextReader tr = new StreamReader(fontTablePart.GetStream())) - fontTable = XDocument.Load(tr); - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": - numberingPart = packagePart; - using (TextReader tr = new StreamReader(numberingPart.GetStream())) - numbering = XDocument.Load(tr); - break; - - } - - clonePackageRelationship(remote_document, remote_pp, remote_mainDoc); - } - } - - foreach (var hyperlink_rel in remote_document.mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")) - { - var old_rel_Id = hyperlink_rel.Id; - var new_rel_Id = mainPart.CreateRelationship(hyperlink_rel.TargetUri, hyperlink_rel.TargetMode, hyperlink_rel.RelationshipType).Id; - var hyperlink_refs = remote_mainDoc.Descendants(XName.Get("hyperlink", DocX.w.NamespaceName)); - foreach (var hyperlink_ref in hyperlink_refs) - { - XAttribute a0 = hyperlink_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)); - if (a0 != null && a0.Value == old_rel_Id) - { - a0.SetValue(new_rel_Id); - } - } - } - - ////ole object links - foreach (var oleObject_rel in remote_document.mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject")) - { - var old_rel_Id = oleObject_rel.Id; - var new_rel_Id = mainPart.CreateRelationship(oleObject_rel.TargetUri, oleObject_rel.TargetMode, oleObject_rel.RelationshipType).Id; - var oleObject_refs = remote_mainDoc.Descendants(XName.Get("OLEObject", "urn:schemas-microsoft-com:office:office")); - foreach (var oleObject_ref in oleObject_refs) - { - XAttribute a0 = oleObject_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)); - if (a0 != null && a0.Value == old_rel_Id) - { - a0.SetValue(new_rel_Id); - } - } - } - - - foreach (PackagePart remote_pp in ppc) - { - if (imageContentTypes.Contains(remote_pp.ContentType)) - { - merge_images(remote_pp, remote_document, remote_mainDoc, remote_pp.ContentType); - } - } - - int id = 0; - var local_docPrs = mainDoc.Root.Descendants(XName.Get("docPr", DocX.wp.NamespaceName)); - foreach (var local_docPr in local_docPrs) - { - XAttribute a_id = local_docPr.Attribute(XName.Get("id")); - int a_id_value; - if (a_id != null && int.TryParse(a_id.Value, out a_id_value)) - if (a_id_value > id) - id = a_id_value; - } - id++; - - // docPr must be sequential - var docPrs = remote_body.Descendants(XName.Get("docPr", DocX.wp.NamespaceName)); - foreach (var docPr in docPrs) - { - docPr.SetAttributeValue(XName.Get("id"), id); - id++; - } - - // Add the remote documents contents to this document. - XElement local_body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - if (append) - local_body.Add(remote_body.Elements()); - else - local_body.AddFirst(remote_body.Elements()); - - // Copy any missing root attributes to the local document. - foreach (XAttribute a in remote_mainDoc.Root.Attributes()) - { - if (mainDoc.Root.Attribute(a.Name) == null) - { - mainDoc.Root.SetAttributeValue(a.Name, a.Value); - } - } - - } - - private void merge_images(PackagePart remote_pp, DocX remote_document, XDocument remote_mainDoc, String contentType) - { - // Before doing any other work, check to see if this image is actually referenced in the document. - // 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; - } - String remote_Id = remote_rel.Id; - - String remote_hash = ComputeMD5HashString(remote_pp.GetStream()); - var image_parts = package.GetParts().Where(pp => pp.ContentType.Equals(contentType)); - - bool found = false; - foreach (var part in image_parts) - { - String local_hash = ComputeMD5HashString(part.GetStream()); - if (local_hash.Equals(remote_hash)) - { - // This image already exists in this document. - found = true; - - var local_rel = mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(part.Uri.OriginalString.Replace("/word/", ""))).FirstOrDefault(); - if (local_rel == null) - { - local_rel = mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(part.Uri.OriginalString)).FirstOrDefault(); - } - if (local_rel != null) - { - String new_Id = local_rel.Id; - - // Replace all instances of remote_Id in the local document with local_Id - var elems = remote_mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName)); - foreach (var elem in elems) - { - 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 (for shapes as well) - var v_elems = remote_mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName)); - foreach (var elem in v_elems) - { - XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName)); - if (id != null && id.Value == remote_Id) - { - id.SetValue(new_Id); - } - } - } - - break; - } - } - - // This image does not exist in this document. - if (!found) - { - String new_uri = remote_pp.Uri.OriginalString; - new_uri = new_uri.Remove(new_uri.LastIndexOf("/")); - //new_uri = new_uri.Replace("word/", ""); - new_uri += "/" + Guid.NewGuid().ToString() + contentType.Replace("image/", "."); - if (!new_uri.StartsWith("/")) - new_uri = "/" + new_uri; - - PackagePart new_pp = package.CreatePart(new Uri(new_uri, UriKind.Relative), remote_pp.ContentType, CompressionOption.Normal); - - using (Stream s_read = remote_pp.GetStream()) - { - using (Stream s_write = new PackagePartStream(new_pp.GetStream(FileMode.Create))) - { - byte[] buffer = new byte[32768]; - int read; - while ((read = s_read.Read(buffer, 0, buffer.Length)) > 0) - { - s_write.Write(buffer, 0, read); - } - } - } - - PackageRelationship pr = mainPart.CreateRelationship(new Uri(new_uri, UriKind.Relative), TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"); - - String new_Id = pr.Id; - - //Check if the remote relationship id is a default rId from Word - Match defRelId = Regex.Match(remote_Id, @"rId\d+", RegexOptions.IgnoreCase); - - // Replace all instances of remote_Id in the local document with local_Id - var elems = remote_mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName)); - foreach (var elem in elems) - { - XAttribute embed = elem.Attribute(XName.Get("embed", DocX.r.NamespaceName)); - if (embed != null && embed.Value == remote_Id) - { - embed.SetValue(new_Id); - } - } - - 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 (for shapes as well) - var v_elems = remote_mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName)); - foreach (var elem in v_elems) - { - XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName)); - if (id != null && id.Value == remote_Id) - { - id.SetValue(new_Id); - } - } - } - } - - private string ComputeMD5HashString(Stream stream) - { - MD5 md5 = MD5.Create(); - byte[] hash = md5.ComputeHash(stream); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < hash.Length; i++) - sb.Append(hash[i].ToString("X2")); - return sb.ToString(); - } - - private void merge_endnotes(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_endnotes) - { - IEnumerable ids = - ( - from d in endnotes.Root.Descendants() - where d.Name.LocalName == "endnote" - select int.Parse(d.Attribute(XName.Get("id", DocX.w.NamespaceName)).Value) - ); - - int max_id = ids.Max() + 1; - var endnoteReferences = remote_mainDoc.Descendants(XName.Get("endnoteReference", DocX.w.NamespaceName)); - - foreach (var endnote in remote_endnotes.Root.Elements().OrderBy(fr => fr.Attribute(XName.Get("id", DocX.r.NamespaceName))).Reverse()) - { - XAttribute id = endnote.Attribute(XName.Get("id", DocX.w.NamespaceName)); - int i; - if (id != null && int.TryParse(id.Value, out i)) - { - if (i > 0) - { - foreach (var endnoteRef in endnoteReferences) - { - XAttribute a = endnoteRef.Attribute(XName.Get("id", DocX.w.NamespaceName)); - if (a != null && int.Parse(a.Value).Equals(i)) - { - a.SetValue(max_id); - } - } - - // We care about copying this footnote. - endnote.SetAttributeValue(XName.Get("id", DocX.w.NamespaceName), max_id); - endnotes.Root.Add(endnote); - max_id++; - } - } - } - } - - private void merge_footnotes(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes) - { - IEnumerable ids = - ( - from d in footnotes.Root.Descendants() - where d.Name.LocalName == "footnote" - select int.Parse(d.Attribute(XName.Get("id", DocX.w.NamespaceName)).Value) - ); - - int max_id = ids.Max() + 1; - var footnoteReferences = remote_mainDoc.Descendants(XName.Get("footnoteReference", DocX.w.NamespaceName)); - - foreach (var footnote in remote_footnotes.Root.Elements().OrderBy(fr => fr.Attribute(XName.Get("id", DocX.r.NamespaceName))).Reverse()) - { - XAttribute id = footnote.Attribute(XName.Get("id", DocX.w.NamespaceName)); - int i; - if (id != null && int.TryParse(id.Value, out i)) - { - if (i > 0) - { - foreach (var footnoteRef in footnoteReferences) - { - XAttribute a = footnoteRef.Attribute(XName.Get("id", DocX.w.NamespaceName)); - if (a != null && int.Parse(a.Value).Equals(i)) - { - a.SetValue(max_id); - } - } - - // We care about copying this footnote. - footnote.SetAttributeValue(XName.Get("id", DocX.w.NamespaceName), max_id); - footnotes.Root.Add(footnote); - max_id++; - } - } - } - } - - private void merge_customs(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc) - { - // Get the remote documents custom.xml file. - XDocument remote_custom_document; - using (TextReader tr = new StreamReader(remote_pp.GetStream())) - remote_custom_document = XDocument.Load(tr); - - // Get the local documents custom.xml file. - XDocument local_custom_document; - using (TextReader tr = new StreamReader(local_pp.GetStream())) - local_custom_document = XDocument.Load(tr); - - IEnumerable pids = - ( - from d in remote_custom_document.Root.Descendants() - where d.Name.LocalName == "property" - select int.Parse(d.Attribute(XName.Get("pid")).Value) - ); - - int pid = pids.Max() + 1; - - foreach (XElement remote_property in remote_custom_document.Root.Elements()) - { - bool found = false; - foreach (XElement local_property in local_custom_document.Root.Elements()) - { - XAttribute remote_property_name = remote_property.Attribute(XName.Get("name")); - XAttribute local_property_name = local_property.Attribute(XName.Get("name")); - - if (remote_property != null && local_property_name != null && remote_property_name.Value.Equals(local_property_name.Value)) - found = true; - } - - if (!found) - { - remote_property.SetAttributeValue(XName.Get("pid"), pid); - local_custom_document.Root.Add(remote_property); - - pid++; - } - } - - // Save the modified local custom styles.xml file. - using (TextWriter tw = new StreamWriter(new PackagePartStream(local_pp.GetStream(FileMode.Create, FileAccess.Write)))) - local_custom_document.Save(tw, SaveOptions.None); - } - - private void merge_numbering(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote) - { - // Add each remote numbering to this document. - IEnumerable remote_abstractNums = remote.numbering.Root.Elements(XName.Get("abstractNum", DocX.w.NamespaceName)); - int guidd = 0; - foreach (var an in remote_abstractNums) - { - XAttribute a = an.Attribute(XName.Get("abstractNumId", DocX.w.NamespaceName)); - if (a != null) - { - int i; - if (int.TryParse(a.Value, out i)) - { - if (i > guidd) - guidd = i; - } - } - } - guidd++; - - IEnumerable remote_nums = remote.numbering.Root.Elements(XName.Get("num", DocX.w.NamespaceName)); - int guidd2 = 0; - foreach (var an in remote_nums) - { - XAttribute a = an.Attribute(XName.Get("numId", DocX.w.NamespaceName)); - if (a != null) - { - int i; - if (int.TryParse(a.Value, out i)) - { - if (i > guidd2) - guidd2 = i; - } - } - } - guidd2++; - - foreach (XElement remote_abstractNum in remote_abstractNums) - { - XAttribute abstractNumId = remote_abstractNum.Attribute(XName.Get("abstractNumId", DocX.w.NamespaceName)); - if (abstractNumId != null) - { - String abstractNumIdValue = abstractNumId.Value; - abstractNumId.SetValue(guidd); - - foreach (XElement remote_num in remote_nums) - { - var numIds = remote_mainDoc.Descendants(XName.Get("numId", DocX.w.NamespaceName)); - foreach (var numId in numIds) - { - XAttribute attr = numId.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (attr != null && attr.Value.Equals(remote_num.Attribute(XName.Get("numId", DocX.w.NamespaceName)).Value)) - { - attr.SetValue(guidd2); - } - - } - remote_num.SetAttributeValue(XName.Get("numId", DocX.w.NamespaceName), guidd2); - - XElement e = remote_num.Element(XName.Get("abstractNumId", DocX.w.NamespaceName)); - if (e != null) - { - XAttribute a2 = e.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (a2 != null && a2.Value.Equals(abstractNumIdValue)) - a2.SetValue(guidd); - } - - guidd2++; - } - } - - guidd++; - } - - // 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); - - 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); - } - - private void merge_fonts(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote) - { - // Add each remote font to this document. - IEnumerable remote_fonts = remote.fontTable.Root.Elements(XName.Get("font", DocX.w.NamespaceName)); - IEnumerable local_fonts = fontTable.Root.Elements(XName.Get("font", DocX.w.NamespaceName)); - - foreach (XElement remote_font in remote_fonts) - { - bool flag_addFont = true; - foreach (XElement local_font in local_fonts) - { - if (local_font.Attribute(XName.Get("name", DocX.w.NamespaceName)).Value == remote_font.Attribute(XName.Get("name", DocX.w.NamespaceName)).Value) - { - flag_addFont = false; - break; - } - } - - if (flag_addFont) - { - fontTable.Root.Add(remote_font); - } - } - } - - private void merge_styles(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes, XDocument remote_endnotes) - { - Dictionary local_styles = new Dictionary(); - foreach (XElement local_style in styles.Root.Elements(XName.Get("style", DocX.w.NamespaceName))) - { - XElement temp = new XElement(local_style); - XAttribute styleId = temp.Attribute(XName.Get("styleId", DocX.w.NamespaceName)); - String value = styleId.Value; - styleId.Remove(); - String key = Regex.Replace(temp.ToString(), @"\s+", ""); - if (!local_styles.ContainsKey(key)) local_styles.Add(key, value); - } - - // Add each remote style to this document. - IEnumerable remote_styles = remote.styles.Root.Elements(XName.Get("style", DocX.w.NamespaceName)); - foreach (XElement remote_style in remote_styles) - { - XElement temp = new XElement(remote_style); - XAttribute styleId = temp.Attribute(XName.Get("styleId", DocX.w.NamespaceName)); - String value = styleId.Value; - styleId.Remove(); - String key = Regex.Replace(temp.ToString(), @"\s+", ""); - String guuid; - - // Check to see if the local document already contains the remote style. - if (local_styles.ContainsKey(key)) - { - String local_value; - local_styles.TryGetValue(key, out local_value); - - // If the styleIds are the same then nothing needs to be done. - if (local_value == value) - continue; - - // All we need to do is update the styleId. - else - { - guuid = local_value; - } - } - else - { - guuid = Guid.NewGuid().ToString(); - // Set the styleId in the remote_style to this new Guid - // [Fixed the issue that my document referred to a new Guid while my styles still had the old value ("Titel")] - remote_style.SetAttributeValue(XName.Get("styleId", DocX.w.NamespaceName), guuid); - } - - foreach (XElement e in remote_mainDoc.Root.Descendants(XName.Get("pStyle", DocX.w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - foreach (XElement e in remote_mainDoc.Root.Descendants(XName.Get("rStyle", DocX.w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - foreach (XElement e in remote_mainDoc.Root.Descendants(XName.Get("tblStyle", DocX.w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - if (remote_endnotes != null) - { - foreach (XElement e in remote_endnotes.Root.Descendants(XName.Get("rStyle", DocX.w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - foreach (XElement e in remote_endnotes.Root.Descendants(XName.Get("pStyle", DocX.w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - } - - if (remote_footnotes != null) - { - foreach (XElement e in remote_footnotes.Root.Descendants(XName.Get("rStyle", DocX.w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - foreach (XElement e in remote_footnotes.Root.Descendants(XName.Get("pStyle", DocX.w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - } - - // Make sure they don't clash by using a uuid. - styleId.SetValue(guuid); - styles.Root.Add(remote_style); - } - } - - protected void clonePackageRelationship(DocX remote_document, PackagePart pp, XDocument remote_mainDoc) - { - string url = pp.Uri.OriginalString.Replace("/", ""); - var remote_rels = remote_document.mainPart.GetRelationships(); - foreach (var remote_rel in remote_rels) - { - if (url.Equals("word" + remote_rel.TargetUri.OriginalString.Replace("/", ""))) - { - String remote_Id = remote_rel.Id; - String local_Id = mainPart.CreateRelationship(remote_rel.TargetUri, remote_rel.TargetMode, remote_rel.RelationshipType).Id; - - // Replace all instances of remote_Id in the local document with local_Id - var elems = remote_mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName)); - foreach (var elem in elems) - { - XAttribute embed = elem.Attribute(XName.Get("embed", DocX.r.NamespaceName)); - if (embed != null && embed.Value == remote_Id) - { - embed.SetValue(local_Id); - } - } - - // 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) - { - XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName)); - if (id != null && id.Value == remote_Id) - { - id.SetValue(local_Id); - } - } - break; - } - } - } - - protected PackagePart clonePackagePart(PackagePart pp) - { - PackagePart new_pp = package.CreatePart(pp.Uri, pp.ContentType, CompressionOption.Normal); - - using (Stream s_read = pp.GetStream()) - { - using (Stream s_write = new PackagePartStream(new_pp.GetStream(FileMode.Create))) - { - byte[] buffer = new byte[32768]; - int read; - while ((read = s_read.Read(buffer, 0, buffer.Length)) > 0) - { - s_write.Write(buffer, 0, read); - } - } - } - - return new_pp; - } - - protected string GetMD5HashFromStream(Stream stream) - { - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] retVal = md5.ComputeHash(stream); - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < retVal.Length; i++) - { - sb.Append(retVal[i].ToString("x2")); - } - return sb.ToString(); - } - - /// - /// Insert a new Table at the end of this document. - /// - /// The number of columns to create. - /// The number of rows to create. - /// A new Table. - /// - /// Insert a new Table with 2 columns and 3 rows, at the end of a document. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"C:\Example\Test.docx")) - /// { - /// // Create a new Table with 2 columns and 3 rows. - /// Table newTable = document.InsertTable(2, 3); - /// - /// // Set the design of this Table. - /// newTable.Design = TableDesign.LightShadingAccent2; - /// - /// // Set the column names. - /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false); - /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false); - /// - /// // Fill row 1 - /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false); - /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false); - /// - /// // Fill row 2 - /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false); - /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false); - /// - /// // Save all changes made to document b. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public new Table InsertTable(int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = base.InsertTable(rowCount, columnCount); - t.mainPart = mainPart; - return t; - } - - public Table AddTable(int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = new Table(this, HelperFunctions.CreateTable(rowCount, columnCount)); - t.mainPart = mainPart; - return t; - } - - /// - /// Create a new list with a list item. - /// - /// The text of the first element in the created list. - /// The indentation level of the element in the list. - /// The type of list to be created: Bulleted or Numbered. - /// The number start number for the list. - /// Enable change tracking - /// Set to true if you want to continue numbering from the previous numbered list - /// - /// The created List. Call AddListItem(...) to add more elements to the list. - /// Write the list to the Document with InsertList(...) once the list has all the desired - /// elements, otherwise the list will not be included in the working Document. - /// - public List AddList(string listText = null, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false) - { - return AddListItem(new List(this, null), listText, level, listType, startNumber, trackChanges, continueNumbering); - } - - /// - /// Add a list item to an already existing list. - /// - /// The list to add the new list item to. - /// The run text that should be in the new list item. - /// The indentation level of the new list element. - /// The number start number for the list. - /// Enable change tracking - /// Numbered or Bulleted list type. - /// /// Set to true if you want to continue numbering from the previous numbered list - /// - /// The created List. Call AddListItem(...) to add more elements to the list. - /// Write the list to the Document with InsertList(...) once the list has all the desired - /// elements, otherwise the list will not be included in the working Document. - /// - public List AddListItem(List list, string listText, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false) - { - if (startNumber.HasValue && continueNumbering) throw new InvalidOperationException("Cannot specify a start number and at the same time continue numbering from another list"); - var listToReturn = HelperFunctions.CreateItemInList(list, listText, level, listType, startNumber, trackChanges, continueNumbering); - var lastItem = listToReturn.Items.LastOrDefault(); - if (lastItem != null) - { - lastItem.PackagePart = mainPart; - } - return listToReturn; - - } - - /// - /// Insert list into the document. - /// - /// The list to insert into the document. - /// The list that was inserted into the document. - public new List InsertList(List list) - { - base.InsertList(list); - return list; - } - public new List InsertList(List list, Font fontFamily, double fontSize) - { - base.InsertList(list, fontFamily, fontSize); - return list; - } - public new List InsertList(List list, double fontSize) - { - base.InsertList(list, fontSize); - return list; - } - - /// - /// Insert a list at an index location in the document. - /// - /// Index in document to insert the list. - /// The list that was inserted into the document. - /// - public new List InsertList(int index, List list) - { - base.InsertList(index, list); - return list; - } - - internal XDocument AddStylesForList() - { - var wordStylesUri = new Uri("/word/styles.xml", UriKind.Relative); - - // If the internal document contains no /word/styles.xml create one. - if (!package.PartExists(wordStylesUri)) - HelperFunctions.AddDefaultStylesXml(package); - - // Load the styles.xml into memory. - XDocument wordStyles; - using (TextReader tr = new StreamReader(package.GetPart(wordStylesUri).GetStream())) - wordStyles = XDocument.Load(tr); - - bool listStyleExists = - ( - from s in wordStyles.Element(w + "styles").Elements() - let styleId = s.Attribute(XName.Get("styleId", w.NamespaceName)) - where (styleId != null && styleId.Value == "ListParagraph") - select s - ).Any(); - - if (!listStyleExists) - { - var style = new XElement - ( - w + "style", - new XAttribute(w + "type", "paragraph"), - new XAttribute(w + "styleId", "ListParagraph"), - new XElement(w + "name", new XAttribute(w + "val", "List Paragraph")), - new XElement(w + "basedOn", new XAttribute(w + "val", "Normal")), - new XElement(w + "uiPriority", new XAttribute(w + "val", "34")), - new XElement(w + "qformat"), - new XElement(w + "rsid", new XAttribute(w + "val", "00832EE1")), - new XElement - ( - w + "rPr", - new XElement(w + "ind", new XAttribute(w + "left", "720")), - new XElement - ( - w + "contextualSpacing" - ) - ) - ); - wordStyles.Element(w + "styles").Add(style); - - // Save the styles document. - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(wordStylesUri).GetStream()))) - wordStyles.Save(tw); - } - - return wordStyles; - } - - /// - /// Insert a Table into this document. The Table's source can be a completely different document. - /// - /// The Table to insert. - /// The index to insert this Table at. - /// The Table now associated with this document. - /// - /// Extract a Table from document a and insert it into document b, at index 10. - /// - /// // Place holder for a Table. - /// Table t; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx")) - /// { - /// // Get the first Table from this document. - /// t = documentA.Tables[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx")) - /// { - /// /* - /// * Insert the Table that was extracted from document a, into document b. - /// * This creates a new Table that is now associated with document b. - /// */ - /// Table newTable = documentB.InsertTable(10, t); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public new Table InsertTable(int index, Table t) - { - Table t2 = base.InsertTable(index, t); - t2.mainPart = mainPart; - return t2; - } - - /// - /// Insert a Table into this document. The Table's source can be a completely different document. - /// - /// The Table to insert. - /// The Table now associated with this document. - /// - /// Extract a Table from document a and insert it at the end of document b. - /// - /// // Place holder for a Table. - /// Table t; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx")) - /// { - /// // Get the first Table from this document. - /// t = documentA.Tables[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx")) - /// { - /// /* - /// * Insert the Table that was extracted from document a, into document b. - /// * This creates a new Table that is now associated with document b. - /// */ - /// Table newTable = documentB.InsertTable(t); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public new Table InsertTable(Table t) - { - t = base.InsertTable(t); - t.mainPart = mainPart; - return t; - } - - /// - /// Insert a new Table at the end of this document. - /// - /// The number of columns to create. - /// The number of rows to create. - /// The index to insert this Table at. - /// A new Table. - /// - /// Insert a new Table with 2 columns and 3 rows, at index 37 in this document. - /// - /// // Create a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Create a new Table with 3 rows and 2 columns. Insert this Table at index 37. - /// Table newTable = document.InsertTable(37, 3, 2); - /// - /// // Set the design of this Table. - /// newTable.Design = TableDesign.LightShadingAccent3; - /// - /// // Set the column names. - /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false); - /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false); - /// - /// // Fill row 1 - /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false); - /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false); - /// - /// // Fill row 2 - /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false); - /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false); - /// - /// // Save all changes made to document b. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public new Table InsertTable(int index, int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = base.InsertTable(index, rowCount, columnCount); - t.mainPart = mainPart; - return t; - } - - /// - /// Creates a document using a Stream. - /// - /// The Stream to create the document from. - /// - /// Returns a DocX object which represents the document. - /// - /// Creating a document from a FileStream. - /// - /// // Use a FileStream fs to create a new document. - /// using(FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Create)) - /// { - /// // Load the document using fs - /// using (DocX document = DocX.Create(fs)) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// } - /// - /// - /// - /// Creating a document in a SharePoint site. - /// - /// using(SPSite mySite = new SPSite("http://server/sites/site")) - /// { - /// // Open a connection to the SharePoint site - /// using(SPWeb myWeb = mySite.OpenWeb()) - /// { - /// // Create a MemoryStream ms. - /// using (MemoryStream ms = new MemoryStream()) - /// { - /// // Create a document using ms. - /// using (DocX document = DocX.Create(ms)) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory - /// - /// // Add the document to the SharePoint site - /// web.Files.Add("filename", ms.ToArray(), true); - /// } - /// } - /// } - /// - /// - /// - /// - /// - public static DocX Create(Stream stream, DocumentTypes documentType = DocumentTypes.Document) - { - // Store this document in memory - MemoryStream ms = new MemoryStream(); - - // Create the docx package - Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); - - PostCreation(package, documentType); - DocX document = DocX.Load(ms); - document.stream = stream; - return document; - } - - /// - /// Creates a document using a fully qualified or relative filename. - /// - /// The fully qualified or relative filename. - /// - /// Returns a DocX object which represents the document. - /// - /// - /// // Create a document using a relative filename. - /// using (DocX document = DocX.Create(@"..\Test.docx")) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory - /// - /// - /// // Create a document using a relative filename. - /// using (DocX document = DocX.Create(@"..\Test.docx")) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory - /// - /// - /// - /// - /// - public static DocX Create(string filename, DocumentTypes documentType = DocumentTypes.Document) - { - // Store this document in memory - MemoryStream ms = new MemoryStream(); - - // Create the docx package - //WordprocessingDocument wdDoc = WordprocessingDocument.Create(ms, DocumentFormat.OpenXml.WordprocessingDocumentType.Document); - Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); - - PostCreation(package, documentType); - DocX document = DocX.Load(ms); - document.filename = filename; - return document; - } - - internal static void PostCreation(Package package, DocumentTypes documentType = DocumentTypes.Document) - { - XDocument mainDoc, stylesDoc, numberingDoc; - - #region MainDocumentPart - // Create the main document part for this package - PackagePart mainDocumentPart; - if (documentType == DocumentTypes.Document) - { - mainDocumentPart = package.CreatePart(new Uri("/word/document.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", CompressionOption.Normal); - } - else - { - mainDocumentPart = package.CreatePart(new Uri("/word/document.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml", CompressionOption.Normal); - } - package.CreateRelationship(mainDocumentPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"); - - // Load the document part into a XDocument object - using (TextReader tr = new StreamReader(mainDocumentPart.GetStream(FileMode.Create, FileAccess.ReadWrite))) - { - mainDoc = XDocument.Parse - (@" - - - - - - - - - - " - ); - } - - // Save the main document - using (TextWriter tw = new StreamWriter(new PackagePartStream(mainDocumentPart.GetStream(FileMode.Create, FileAccess.Write)))) - mainDoc.Save(tw, SaveOptions.None); - #endregion - - #region StylePart - stylesDoc = HelperFunctions.AddDefaultStylesXml(package); - #endregion - - #region NumberingPart - numberingDoc = HelperFunctions.AddDefaultNumberingXml(package); - #endregion - - package.Close(); - } - - internal static DocX PostLoad(ref Package package) - { - DocX document = new DocX(null, null); - document.package = package; - document.Document = document; - - #region MainDocumentPart - document.mainPart = package.GetParts().Where - ( - p => p.ContentType.Equals(HelperFunctions.DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase) || - p.ContentType.Equals(HelperFunctions.TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase) - ).Single(); - - using (TextReader tr = new StreamReader(document.mainPart.GetStream(FileMode.Open, FileAccess.Read))) - document.mainDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace); - #endregion - - PopulateDocument(document, package); - - using (TextReader tr = new StreamReader(document.settingsPart.GetStream())) - document.settings = XDocument.Load(tr); - - document.paragraphLookup.Clear(); - foreach (var paragraph in document.Paragraphs) - { - if (!document.paragraphLookup.ContainsKey(paragraph.endIndex)) - document.paragraphLookup.Add(paragraph.endIndex, paragraph); - } - - return document; - } - - private static void PopulateDocument(DocX document, Package package) - { - Headers headers = new Headers(); - headers.odd = document.GetHeaderByType("default"); - headers.even = document.GetHeaderByType("even"); - headers.first = document.GetHeaderByType("first"); - - Footers footers = new Footers(); - footers.odd = document.GetFooterByType("default"); - footers.even = document.GetFooterByType("even"); - footers.first = document.GetFooterByType("first"); - - //// Get the sectPr for this document. - //XElement sect = document.mainDoc.Descendants(XName.Get("sectPr", DocX.w.NamespaceName)).Single(); - - //if (sectPr != null) - //{ - // // Extract the even header reference - // var header_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even"); - // string id = header_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res = document.mainPart.GetRelationship(id); - // string ans = res.SourceUri.OriginalString; - // headers.even.xml_filename = ans; - - // // Extract the odd header reference - // var header_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default"); - // string id2 = header_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res2 = document.mainPart.GetRelationship(id2); - // string ans2 = res2.SourceUri.OriginalString; - // headers.odd.xml_filename = ans2; - - // // Extract the first header reference - // var header_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "h - //eaderReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first"); - // string id3 = header_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res3 = document.mainPart.GetRelationship(id3); - // string ans3 = res3.SourceUri.OriginalString; - // headers.first.xml_filename = ans3; - - // // Extract the even footer reference - // var footer_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even"); - // string id4 = footer_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res4 = document.mainPart.GetRelationship(id4); - // string ans4 = res4.SourceUri.OriginalString; - // footers.even.xml_filename = ans4; - - // // Extract the odd footer reference - // var footer_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default"); - // string id5 = footer_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res5 = document.mainPart.GetRelationship(id5); - // string ans5 = res5.SourceUri.OriginalString; - // footers.odd.xml_filename = ans5; - - // // Extract the first footer reference - // var footer_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first"); - // string id6 = footer_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res6 = document.mainPart.GetRelationship(id6); - // string ans6 = res6.SourceUri.OriginalString; - // footers.first.xml_filename = ans6; - - //} - - document.Xml = document.mainDoc.Root.Element(w + "body"); - document.headers = headers; - document.footers = footers; - document.settingsPart = HelperFunctions.CreateOrGetSettingsPart(package); - - var ps = package.GetParts(); - - //document.endnotesPart = HelperFunctions.GetPart(); - - foreach (var rel in document.mainPart.GetRelationships()) - { - string url = "/word/" + rel.TargetUri.OriginalString.Replace("/word/", "").Replace("file://", ""); - - switch (rel.RelationshipType) - { - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes": - document.endnotesPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.endnotesPart.GetStream())) - document.endnotes = XDocument.Load(tr); - break; - - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes": - document.footnotesPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.footnotesPart.GetStream())) - document.footnotes = XDocument.Load(tr); - break; - - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles": - document.stylesPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.stylesPart.GetStream())) - document.styles = XDocument.Load(tr); - break; - - case "http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects": - document.stylesWithEffectsPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.stylesWithEffectsPart.GetStream())) - document.stylesWithEffects = XDocument.Load(tr); - break; - - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable": - document.fontTablePart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.fontTablePart.GetStream())) - document.fontTable = XDocument.Load(tr); - break; - - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering": - document.numberingPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.numberingPart.GetStream())) - document.numbering = XDocument.Load(tr); - break; - - default: - break; - } - } - } - - /// - /// Saves and copies the document into a new DocX object - /// - /// - /// Returns a new DocX object with an identical document - /// - /// - /// - /// - /// - public DocX Copy() - { - MemoryStream ms = new MemoryStream(); - SaveAs(ms); - ms.Seek(0, SeekOrigin.Begin); - - return DocX.Load(ms); - } - - /// - /// Loads a document into a DocX object using a Stream. - /// - /// The Stream to load the document from. - /// - /// Returns a DocX object which represents the document. - /// - /// - /// Loading a document from a FileStream. - /// - /// // Open a FileStream fs to a document. - /// using (FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Open)) - /// { - /// // Load the document using fs. - /// using (DocX document = DocX.Load(fs)) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to the document. - /// document.Save(); - /// }// Release this document from memory. - /// } - /// - /// - /// - /// Loading a document from a SharePoint site. - /// - /// // Get the SharePoint site that you want to access. - /// using (SPSite mySite = new SPSite("http://server/sites/site")) - /// { - /// // Open a connection to the SharePoint site - /// using (SPWeb myWeb = mySite.OpenWeb()) - /// { - /// // Grab a document stored on this site. - /// SPFile file = web.GetFile("Source_Folder_Name/Source_File"); - /// - /// // DocX.Load requires a Stream, so open a Stream to this document. - /// Stream str = new MemoryStream(file.OpenBinary()); - /// - /// // Load the file using the Stream str. - /// using (DocX document = DocX.Load(str)) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to the document. - /// document.Save(); - /// }// Release this document from memory. - /// } - /// } - /// - /// - /// - /// - public static DocX Load(Stream stream) - { - MemoryStream ms = new MemoryStream(); - - stream.Position = 0; - byte[] data = new byte[stream.Length]; - stream.Read(data, 0, (int)stream.Length); - ms.Write(data, 0, (int)stream.Length); - - // Open the docx package - Package package = Package.Open(ms, FileMode.Open, FileAccess.ReadWrite); - - DocX document = PostLoad(ref package); - document.package = package; - document.memoryStream = ms; - document.stream = stream; - return document; - } - - /// - /// Loads a document into a DocX object using a fully qualified or relative filename. - /// - /// The fully qualified or relative filename. - /// - /// Returns a DocX object which represents the document. - /// - /// - /// - /// // Load a document using its fully qualified filename - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Do something with the document here - /// - /// // Save all changes made to document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// // Load a document using its relative filename. - /// using(DocX document = DocX.Load(@"..\..\Test.docx")) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// - public static DocX Load(string filename) - { - if (!File.Exists(filename)) - throw new FileNotFoundException(string.Format("File could not be found {0}", filename)); - - MemoryStream ms = new MemoryStream(); - - using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - byte[] data = new byte[fs.Length]; - fs.Read(data, 0, (int)fs.Length); - ms.Write(data, 0, (int)fs.Length); - } - - // Open the docx package - Package package = Package.Open(ms, FileMode.Open, FileAccess.ReadWrite); - - DocX document = PostLoad(ref package); - document.package = package; - document.filename = filename; - document.memoryStream = ms; - - return document; - } - - /// - /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. - /// - ///The path to the document template file. - ///The document template file not found. - public void ApplyTemplate(string templateFilePath) - { - ApplyTemplate(templateFilePath, true); - } - - /// - /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. - /// - ///The path to the document template file. - ///Whether to copy the document template text content to document. - ///The document template file not found. - public void ApplyTemplate(string templateFilePath, bool includeContent) - { - if (!File.Exists(templateFilePath)) - { - throw new FileNotFoundException(string.Format("File could not be found {0}", templateFilePath)); - } - using (FileStream packageStream = new FileStream(templateFilePath, FileMode.Open, FileAccess.Read)) - { - ApplyTemplate(packageStream, includeContent); - } - } - - /// - /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. - /// - ///The stream of the document template file. - public void ApplyTemplate(Stream templateStream) - { - ApplyTemplate(templateStream, true); - } - - /// - /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. - /// - ///The stream of the document template file. - ///Whether to copy the document template text content to document. - public void ApplyTemplate(Stream templateStream, bool includeContent) - { - Package templatePackage = Package.Open(templateStream); - try - { - PackagePart documentPart = null; - XDocument documentDoc = null; - foreach (PackagePart packagePart in templatePackage.GetParts()) - { - switch (packagePart.Uri.ToString()) - { - case "/word/document.xml": - documentPart = packagePart; - using (XmlReader xr = XmlReader.Create(packagePart.GetStream(FileMode.Open, FileAccess.Read))) - { - documentDoc = XDocument.Load(xr); - } - break; - case "/_rels/.rels": - if (!this.package.PartExists(packagePart.Uri)) - { - this.package.CreatePart(packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption); - } - PackagePart globalRelsPart = this.package.GetPart(packagePart.Uri); - using ( - StreamReader tr = new StreamReader( - packagePart.GetStream(FileMode.Open, FileAccess.Read), Encoding.UTF8)) - { - using ( - StreamWriter tw = new StreamWriter( - new PackagePartStream(globalRelsPart.GetStream(FileMode.Create, FileAccess.Write)), Encoding.UTF8)) - { - tw.Write(tr.ReadToEnd()); - } - } - break; - case "/word/_rels/document.xml.rels": - break; - default: - if (!this.package.PartExists(packagePart.Uri)) - { - this.package.CreatePart(packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption); - } - Encoding packagePartEncoding = Encoding.Default; - if (packagePart.Uri.ToString().EndsWith(".xml") || packagePart.Uri.ToString().EndsWith(".rels")) - { - packagePartEncoding = Encoding.UTF8; - } - PackagePart nativePart = this.package.GetPart(packagePart.Uri); - using ( - StreamReader tr = new StreamReader( - packagePart.GetStream(FileMode.Open, FileAccess.Read), packagePartEncoding)) - { - using ( - StreamWriter tw = new StreamWriter( - new PackagePartStream(nativePart.GetStream(FileMode.Create, FileAccess.Write)), tr.CurrentEncoding)) - { - tw.Write(tr.ReadToEnd()); - } - } - break; - } - } - if (documentPart != null) - { - string mainContentType = documentPart.ContentType.Replace("template.main", "document.main"); - if (this.package.PartExists(documentPart.Uri)) - { - this.package.DeletePart(documentPart.Uri); - } - PackagePart documentNewPart = this.package.CreatePart( - documentPart.Uri, mainContentType, documentPart.CompressionOption); - using (XmlWriter xw = XmlWriter.Create(new PackagePartStream(documentNewPart.GetStream(FileMode.Create, FileAccess.Write)))) - { - documentDoc.WriteTo(xw); - } - foreach (PackageRelationship documentPartRel in documentPart.GetRelationships()) - { - documentNewPart.CreateRelationship( - documentPartRel.TargetUri, - documentPartRel.TargetMode, - documentPartRel.RelationshipType, - documentPartRel.Id); - } - this.mainPart = documentNewPart; - this.mainDoc = documentDoc; - PopulateDocument(this, templatePackage); - - // DragonFire: I added next line and recovered ApplyTemplate method. - // I do it, becouse PopulateDocument(...) writes into field "settingsPart" the part of Template's package - // and after line "templatePackage.Close();" in finally, field "settingsPart" becomes not available and method "Save" throw an exception... - // That's why I recreated settingsParts and unlinked it from Template's package =) - settingsPart = HelperFunctions.CreateOrGetSettingsPart(package); - } - if (!includeContent) - { - foreach (Paragraph paragraph in this.Paragraphs) - { - paragraph.Remove(false); - } - } - } - finally - { - this.package.Flush(); - var documentRelsPart = this.package.GetPart(new Uri("/word/_rels/document.xml.rels", UriKind.Relative)); - using (TextReader tr = new StreamReader(documentRelsPart.GetStream(FileMode.Open, FileAccess.Read))) - { - tr.Read(); - } - templatePackage.Close(); - PopulateDocument(Document, package); - } - } - - /// - /// Add an Image into this document from a fully qualified or relative filename. - /// - /// The fully qualified or relative filename. - /// An Image file. - /// - /// Add an Image into this document from a fully qualified filename. - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Add an Image from a file. - /// document.AddImage(@"C:\Example\Image.png"); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// - public Image AddImage(string filename) - { - string contentType = ""; - - // The extension this file has will be taken to be its format. - switch (Path.GetExtension(filename)) - { - case ".tiff": contentType = "image/tif"; break; - case ".tif": contentType = "image/tif"; break; - case ".png": contentType = "image/png"; break; - case ".bmp": contentType = "image/png"; break; - case ".gif": contentType = "image/gif"; break; - case ".jpg": contentType = "image/jpg"; break; - case ".jpeg": contentType = "image/jpeg"; break; - default: contentType = "image/jpg"; break; - } - - return AddImage(filename as object, contentType); - } - - /// - /// Add an Image into this document from a Stream. - /// - /// A Stream stream. - /// An Image file. - /// - /// Add an Image into a document using a Stream. - /// - /// // Open a FileStream fs to an Image. - /// using (FileStream fs = new FileStream(@"C:\Example\Image.jpg", FileMode.Open)) - /// { - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Add an Image from a filestream fs. - /// document.AddImage(fs); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// } - /// - /// - /// - /// - public Image AddImage(Stream stream) - { - return AddImage(stream as object); - } - - /// - /// Adds a hyperlink to a document and creates a Paragraph which uses it. - /// - /// The text as displayed by the hyperlink. - /// The hyperlink itself. - /// Returns a hyperlink that can be inserted into a Paragraph. - /// - /// Adds a hyperlink to a document and creates a Paragraph which uses it. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add a hyperlink to this document. - /// Hyperlink h = document.AddHyperlink("Google", new Uri("http://www.google.com")); - /// - /// // Add a new Paragraph to this document. - /// Paragraph p = document.InsertParagraph(); - /// p.Append("My favourite search engine is "); - /// p.AppendHyperlink(h); - /// p.Append(", I think it's great."); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public Hyperlink AddHyperlink(string text, Uri uri) - { - XElement i = new XElement - ( - XName.Get("hyperlink", DocX.w.NamespaceName), - new XAttribute(r + "id", string.Empty), - new XAttribute(w + "history", "1"), - new XElement(XName.Get("r", DocX.w.NamespaceName), - new XElement(XName.Get("rPr", DocX.w.NamespaceName), - new XElement(XName.Get("rStyle", DocX.w.NamespaceName), - new XAttribute(w + "val", "Hyperlink"))), - new XElement(XName.Get("t", DocX.w.NamespaceName), text)) - ); - - Hyperlink h = new Hyperlink(this, mainPart, i); - - h.text = text; - h.uri = uri; - - AddHyperlinkStyleIfNotPresent(); - - return h; - } - - internal void AddHyperlinkStyleIfNotPresent() - { - Uri word_styles_Uri = new Uri("/word/styles.xml", UriKind.Relative); - - // If the internal document contains no /word/styles.xml create one. - if (!package.PartExists(word_styles_Uri)) - HelperFunctions.AddDefaultStylesXml(package); - - // Load the styles.xml into memory. - XDocument word_styles; - using (TextReader tr = new StreamReader(package.GetPart(word_styles_Uri).GetStream())) - word_styles = XDocument.Load(tr); - - bool hyperlinkStyleExists = - ( - from s in word_styles.Element(w + "styles").Elements() - let styleId = s.Attribute(XName.Get("styleId", w.NamespaceName)) - where (styleId != null && styleId.Value == "Hyperlink") - select s - ).Count() > 0; - - if (!hyperlinkStyleExists) - { - XElement style = new XElement - ( - w + "style", - new XAttribute(w + "type", "character"), - new XAttribute(w + "styleId", "Hyperlink"), - new XElement(w + "name", new XAttribute(w + "val", "Hyperlink")), - new XElement(w + "basedOn", new XAttribute(w + "val", "DefaultParagraphFont")), - new XElement(w + "uiPriority", new XAttribute(w + "val", "99")), - new XElement(w + "unhideWhenUsed"), - new XElement(w + "rsid", new XAttribute(w + "val", "0005416C")), - new XElement - ( - w + "rPr", - new XElement(w + "color", new XAttribute(w + "val", "0000FF"), new XAttribute(w + "themeColor", "hyperlink")), - new XElement - ( - w + "u", - new XAttribute(w + "val", "single") - ) - ) - ); - word_styles.Element(w + "styles").Add(style); - - // Save the styles document. - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(word_styles_Uri).GetStream()))) - word_styles.Save(tw); - } - } - - private string GetNextFreeRelationshipID() - { - int id = ( - from r in mainPart.GetRelationships() - where r.Id.Substring(0, 3).Equals("rId") - select int.Parse(r.Id.Substring(3)) - ).DefaultIfEmpty().Max(); - - // The conventiom for ids is rid01, rid02, etc - string newId = id.ToString(); - int result; - if (int.TryParse(newId, out result)) - return ("rId" + (result + 1)); - else - { - String guid = String.Empty; - do - { - guid = Guid.NewGuid().ToString(); - } while (Char.IsDigit(guid[0])); - return guid; - } - } - - /// - /// Adds three new Headers to this document. One for the first page, one for odd pages and one for even pages. - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add header support to this document. - /// document.AddHeaders(); - /// - /// // Get a collection of all headers in this document. - /// Headers headers = document.Headers; - /// - /// // The header used for the first page of this document. - /// Header first = headers.first; - /// - /// // The header used for odd pages of this document. - /// Header odd = headers.odd; - /// - /// // The header used for even pages of this document. - /// Header even = headers.even; - /// - /// // Force the document to use a different header for first, odd and even pages. - /// document.DifferentFirstPage = true; - /// document.DifferentOddAndEvenPages = true; - /// - /// // Content can be added to the Headers in the same manor that it would be added to the main document. - /// Paragraph p = first.InsertParagraph(); - /// p.Append("This is the first pages header."); - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - public void AddHeaders() - { - AddHeadersOrFooters(true); - - headers.odd = Document.GetHeaderByType("default"); - headers.even = Document.GetHeaderByType("even"); - headers.first = Document.GetHeaderByType("first"); - } - - /// - /// Adds three new Footers to this document. One for the first page, one for odd pages and one for even pages. - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add footer support to this document. - /// document.AddFooters(); - /// - /// // Get a collection of all footers in this document. - /// Footers footers = document.Footers; - /// - /// // The footer used for the first page of this document. - /// Footer first = footers.first; - /// - /// // The footer used for odd pages of this document. - /// Footer odd = footers.odd; - /// - /// // The footer used for even pages of this document. - /// Footer even = footers.even; - /// - /// // Force the document to use a different footer for first, odd and even pages. - /// document.DifferentFirstPage = true; - /// document.DifferentOddAndEvenPages = true; - /// - /// // Content can be added to the Footers in the same manor that it would be added to the main document. - /// Paragraph p = first.InsertParagraph(); - /// p.Append("This is the first pages footer."); - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - public void AddFooters() - { - AddHeadersOrFooters(false); - - footers.odd = Document.GetFooterByType("default"); - footers.even = Document.GetFooterByType("even"); - footers.first = Document.GetFooterByType("first"); - } - - /// - /// Adds a Header to a document. - /// If the document already contains a Header it will be replaced. - /// - /// The Header that was added to the document. - internal void AddHeadersOrFooters(bool b) - { - string element = "ftr"; - string reference = "footer"; - if (b) - { - element = "hdr"; - reference = "header"; - } - - DeleteHeadersOrFooters(b); - - XElement sectPr = mainDoc.Root.Element(w + "body").Element(w + "sectPr"); - - for (int i = 1; i < 4; i++) - { - string header_uri = string.Format("/word/{0}{1}.xml", reference, i); - - PackagePart headerPart = package.CreatePart(new Uri(header_uri, UriKind.Relative), string.Format("application/vnd.openxmlformats-officedocument.wordprocessingml.{0}+xml", reference), CompressionOption.Normal); - PackageRelationship headerRelationship = mainPart.CreateRelationship(headerPart.Uri, TargetMode.Internal, string.Format("http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference)); - - XDocument header; - - // Load the document part into a XDocument object - using (TextReader tr = new StreamReader(headerPart.GetStream(FileMode.Create, FileAccess.ReadWrite))) - { - header = XDocument.Parse - (string.Format(@" - - - - - - - ", element, reference) - ); - } - - // Save the main document - using (TextWriter tw = new StreamWriter(new PackagePartStream(headerPart.GetStream(FileMode.Create, FileAccess.Write)))) - header.Save(tw, SaveOptions.None); - - string type; - switch (i) - { - case 1: type = "default"; break; - case 2: type = "even"; break; - case 3: type = "first"; break; - default: throw new ArgumentOutOfRangeException(); - } - - sectPr.Add - ( - new XElement - ( - w + string.Format("{0}Reference", reference), - new XAttribute(w + "type", type), - new XAttribute(r + "id", headerRelationship.Id) - ) - ); - } - } - - internal void DeleteHeadersOrFooters(bool b) - { - string reference = "footer"; - if (b) - reference = "header"; - - // Get all header Relationships in this document. - var header_relationships = mainPart.GetRelationshipsByType(string.Format("http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference)); - - foreach (PackageRelationship header_relationship in header_relationships) - { - // Get the TargetUri for this Part. - Uri header_uri = header_relationship.TargetUri; - - // Check to see if the document actually contains the Part. - if (!header_uri.OriginalString.StartsWith("/word/")) - header_uri = new Uri("/word/" + header_uri.OriginalString, UriKind.Relative); - - if (package.PartExists(header_uri)) - { - // Delete the Part - package.DeletePart(header_uri); - - // Get all references to this Relationship in the document. - var query = - ( - from e in mainDoc.Descendants(XName.Get("body", DocX.w.NamespaceName)).Descendants() - where (e.Name.LocalName == string.Format("{0}Reference", reference)) && (e.Attribute(r + "id").Value == header_relationship.Id) - select e - ); - - // Remove all references to this Relationship in the document. - for (int i = 0; i < query.Count(); i++) - query.ElementAt(i).Remove(); - - // Delete the Relationship. - package.DeleteRelationship(header_relationship.Id); - } - } - } - - internal Image AddImage(object o, string contentType = "image/jpeg") - { - // Open a Stream to the new image being added. - Stream newImageStream; - if (o is string) - newImageStream = new FileStream(o as string, FileMode.Open, FileAccess.Read); - else - newImageStream = o as Stream; - - // Get all image parts in word\document.xml - - PackageRelationshipCollection relationshipsByImages = mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"); - List imageParts = relationshipsByImages.Select(ir => package.GetParts().FirstOrDefault(p => p.Uri.ToString().EndsWith(ir.TargetUri.ToString()))).Where(e => e != null).ToList(); - - foreach (PackagePart relsPart in package.GetParts().Where(part => part.Uri.ToString().Contains("/word/")).Where(part => part.ContentType.Equals("application/vnd.openxmlformats-package.relationships+xml"))) - { - XDocument relsPartContent; - using (TextReader tr = new StreamReader(relsPart.GetStream(FileMode.Open, FileAccess.Read))) - relsPartContent = XDocument.Load(tr); - - IEnumerable imageRelationships = - relsPartContent.Root.Elements().Where - ( - imageRel => - imageRel.Attribute(XName.Get("Type")).Value.Equals("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image") - ); - - foreach (XElement imageRelationship in imageRelationships) - { - if (imageRelationship.Attribute(XName.Get("Target")) != null) - { - string targetMode = string.Empty; - - XAttribute targetModeAttibute = imageRelationship.Attribute(XName.Get("TargetMode")); - if (targetModeAttibute != null) - { - targetMode = targetModeAttibute.Value; - } - - if (!targetMode.Equals("External")) - { - string imagePartUri = Path.Combine(Path.GetDirectoryName(relsPart.Uri.ToString()), imageRelationship.Attribute(XName.Get("Target")).Value); - imagePartUri = Path.GetFullPath(imagePartUri.Replace("\\_rels", string.Empty)); - imagePartUri = imagePartUri.Replace(Path.GetFullPath("\\"), string.Empty).Replace("\\", "/"); - - if (!imagePartUri.StartsWith("/")) - imagePartUri = "/" + imagePartUri; - - PackagePart imagePart = package.GetPart(new Uri(imagePartUri, UriKind.Relative)); - imageParts.Add(imagePart); - } - } - } - } - - // Loop through each image part in this document. - foreach (PackagePart pp in imageParts) - { - // Open a tempory Stream to this image part. - using (Stream tempStream = pp.GetStream(FileMode.Open, FileAccess.Read)) - { - // Compare this image to the new image being added. - if (HelperFunctions.IsSameFile(tempStream, newImageStream)) - { - // Get the image object for this image part - string id = mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image") - .Where(r => r.TargetUri == pp.Uri) - .Select(r => r.Id).First(); - - // Return the Image object - return Images.Where(i => i.Id == id).First(); - } - } - } - - string imgPartUriPath = string.Empty; - string extension = contentType.Substring(contentType.LastIndexOf("/") + 1); - do - { - // Create a new image part. - imgPartUriPath = string.Format - ( - "/word/media/{0}.{1}", - Guid.NewGuid().ToString(), // The unique part. - extension - ); - - } while (package.PartExists(new Uri(imgPartUriPath, UriKind.Relative))); - - // We are now guareenteed that imgPartUriPath is unique. - PackagePart img = package.CreatePart(new Uri(imgPartUriPath, UriKind.Relative), contentType, CompressionOption.Normal); - - // Create a new image relationship - PackageRelationship rel = mainPart.CreateRelationship(img.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"); - - // Open a Stream to the newly created Image part. - using (Stream stream = new PackagePartStream(img.GetStream(FileMode.Create, FileAccess.Write))) - { - // Using the Stream to the real image, copy this streams data into the newly create Image part. - using (newImageStream) - { - byte[] bytes = new byte[newImageStream.Length]; - newImageStream.Read(bytes, 0, (int)newImageStream.Length); - stream.Write(bytes, 0, (int)newImageStream.Length); - }// Close the Stream to the new image. - }// Close the Stream to the new image part. - - return new Image(this, rel); - } - - /// - /// Save this document back to the location it was loaded from. - /// - /// - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Add an Image from a file. - /// document.AddImage(@"C:\Example\Image.jpg"); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// - /// - /// - public void Save() - { - Headers headers = Headers; - - // Save the main document - using (TextWriter tw = new StreamWriter(new PackagePartStream(mainPart.GetStream(FileMode.Create, FileAccess.Write)))) - mainDoc.Save(tw, SaveOptions.None); - - if (settings == null) - { - using (TextReader tr = new StreamReader(settingsPart.GetStream())) - settings = XDocument.Load(tr); - } - - XElement body = mainDoc.Root.Element(w + "body"); - XElement sectPr = body.Descendants(w + "sectPr").FirstOrDefault(); - - if (sectPr != null) - { - var evenHeaderRef = - ( - from e in mainDoc.Descendants(w + "headerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("even", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (evenHeaderRef != null) - { - XElement even = headers.even.Xml; - - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(evenHeaderRef).TargetUri - ); - - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - even - ).Save(tw, SaveOptions.None); - } - } - - var oddHeaderRef = - ( - from e in mainDoc.Descendants(w + "headerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("default", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (oddHeaderRef != null) - { - XElement odd = headers.odd.Xml; - - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(oddHeaderRef).TargetUri - ); - - // Save header1 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - odd - ).Save(tw, SaveOptions.None); - } - } - - var firstHeaderRef = - ( - from e in mainDoc.Descendants(w + "headerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("first", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (firstHeaderRef != null) - { - XElement first = headers.first.Xml; - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(firstHeaderRef).TargetUri - ); - - // Save header3 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - first - ).Save(tw, SaveOptions.None); - } - } - - var oddFooterRef = - ( - from e in mainDoc.Descendants(w + "footerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("default", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (oddFooterRef != null) - { - XElement odd = footers.odd.Xml; - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(oddFooterRef).TargetUri - ); - - // Save header1 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - odd - ).Save(tw, SaveOptions.None); - } - } - - var evenFooterRef = - ( - from e in mainDoc.Descendants(w + "footerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("even", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (evenFooterRef != null) - { - XElement even = footers.even.Xml; - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(evenFooterRef).TargetUri - ); - - // Save header2 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - even - ).Save(tw, SaveOptions.None); - } - } - - var firstFooterRef = - ( - from e in mainDoc.Descendants(w + "footerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("first", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (firstFooterRef != null) - { - XElement first = footers.first.Xml; - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(firstFooterRef).TargetUri - ); - - // Save header3 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - first - ).Save(tw, SaveOptions.None); - } - } - - // Save the settings document. - using (TextWriter tw = new StreamWriter(new PackagePartStream(settingsPart.GetStream(FileMode.Create, FileAccess.Write)))) - settings.Save(tw, SaveOptions.None); - - if (endnotesPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(endnotesPart.GetStream(FileMode.Create, FileAccess.Write)))) - endnotes.Save(tw, SaveOptions.None); - } - - if (footnotesPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(footnotesPart.GetStream(FileMode.Create, FileAccess.Write)))) - footnotes.Save(tw, SaveOptions.None); - } - - if (stylesPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(stylesPart.GetStream(FileMode.Create, FileAccess.Write)))) - styles.Save(tw, SaveOptions.None); - } - - if (stylesWithEffectsPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(stylesWithEffectsPart.GetStream(FileMode.Create, FileAccess.Write)))) - stylesWithEffects.Save(tw, SaveOptions.None); - } - - if (numberingPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(numberingPart.GetStream(FileMode.Create, FileAccess.Write)))) - numbering.Save(tw, SaveOptions.None); - } - - if (fontTablePart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(fontTablePart.GetStream(FileMode.Create, FileAccess.Write)))) - fontTable.Save(tw, SaveOptions.None); - } - } - - // Close the document so that it can be saved. - package.Flush(); - - #region Save this document back to a file or stream, that was specified by the user at save time. - if (filename != null) - { - using (FileStream fs = new FileStream(filename, FileMode.Create)) - { - fs.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length); - } - } - else - { - if (stream.CanSeek) // 2013-05-25: Check if stream can be seeked to support System.Web.HttpResponseStream - { - // Set the length of this stream to 0 - stream.SetLength(0); - - // Write to the beginning of the stream - stream.Position = 0; - } - - memoryStream.WriteTo(stream); - memoryStream.Flush(); - } - #endregion - } - - /// - /// Save this document to a file. - /// - /// The filename to save this document as. - /// - /// Load a document from one file and save it to another. - /// - /// // Load a document using its fully qualified filename. - /// DocX document = DocX.Load(@"C:\Example\Test1.docx"); - /// - /// // Insert a new Paragraph - /// document.InsertParagraph("Hello world!", false); - /// - /// // Save the document to a new location. - /// document.SaveAs(@"C:\Example\Test2.docx"); - /// - /// - /// - /// Load a document from a Stream and save it to a file. - /// - /// DocX document; - /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open)) - /// { - /// // Load a document using a stream. - /// document = DocX.Load(fs1); - /// - /// // Insert a new Paragraph - /// document.InsertParagraph("Hello world again!", false); - /// } - /// - /// // Save the document to a new location. - /// document.SaveAs(@"C:\Example\Test2.docx"); - /// - /// - /// - /// - /// - public void SaveAs(string filename) - { - this.filename = filename; - this.stream = null; - Save(); - } - - /// - /// Save this document to a Stream. - /// - /// The Stream to save this document to. - /// - /// Load a document from a file and save it to a Stream. - /// - /// // Place holder for a document. - /// DocX document; - /// - /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open)) - /// { - /// // Load a document using a stream. - /// document = DocX.Load(fs1); - /// - /// // Insert a new Paragraph - /// document.InsertParagraph("Hello world again!", false); - /// } - /// - /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create)) - /// { - /// // Save the document to a different stream. - /// document.SaveAs(fs2); - /// } - /// - /// // Release this document from memory. - /// document.Dispose(); - /// - /// - /// - /// Load a document from one Stream and save it to another. - /// - /// DocX document; - /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open)) - /// { - /// // Load a document using a stream. - /// document = DocX.Load(fs1); - /// - /// // Insert a new Paragraph - /// document.InsertParagraph("Hello world again!", false); - /// } - /// - /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create)) - /// { - /// // Save the document to a different stream. - /// document.SaveAs(fs2); - /// } - /// - /// - /// - /// - /// - public void SaveAs(Stream stream) - { - this.filename = null; - this.stream = stream; - Save(); - } - - /// - /// Add a core property to this document. If a core property already exists with the same name it will be replaced. Core property names are case insensitive. - /// - ///The property name. - ///The property value. - /// - /// Add a core properties of each type to a document. - /// - /// // Load Example.docx - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // If this document does not contain a core property called 'forename', create one. - /// if (!document.CoreProperties.ContainsKey("forename")) - /// { - /// // Create a new core property called 'forename' and set its value. - /// document.AddCoreProperty("forename", "Cathal"); - /// } - /// - /// // Get this documents core property called 'forename'. - /// string forenameValue = document.CoreProperties["forename"]; - /// - /// // Print all of the information about this core property to Console. - /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", "forename", forenameValue)); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } // Release this document from memory. - /// - /// // Wait for the user to press a key before exiting. - /// Console.ReadKey(); - /// - /// - /// - /// - /// - public void AddCoreProperty(string propertyName, string propertyValue) - { - string propertyNamespacePrefix = propertyName.Contains(":") ? propertyName.Split(new[] { ':' })[0] : "cp"; - string propertyLocalName = propertyName.Contains(":") ? propertyName.Split(new[] { ':' })[1] : propertyName; - - // If this document does not contain a coreFilePropertyPart create one.) - if (!package.PartExists(new Uri("/docProps/core.xml", UriKind.Relative))) - throw new Exception("Core properties part doesn't exist."); - - XDocument corePropDoc; - PackagePart corePropPart = package.GetPart(new Uri("/docProps/core.xml", UriKind.Relative)); - using (TextReader tr = new StreamReader(corePropPart.GetStream(FileMode.Open, FileAccess.Read))) - { - corePropDoc = XDocument.Load(tr); - } - - XElement corePropElement = - (from propElement in corePropDoc.Root.Elements() - where (propElement.Name.LocalName.Equals(propertyLocalName)) - select propElement).SingleOrDefault(); - if (corePropElement != null) - { - corePropElement.SetValue(propertyValue); - } - else - { - var propertyNamespace = corePropDoc.Root.GetNamespaceOfPrefix(propertyNamespacePrefix); - corePropDoc.Root.Add(new XElement(XName.Get(propertyLocalName, propertyNamespace.NamespaceName), propertyValue)); - } - - using (TextWriter tw = new StreamWriter(new PackagePartStream(corePropPart.GetStream(FileMode.Create, FileAccess.Write)))) - { - corePropDoc.Save(tw); - } - UpdateCorePropertyValue(this, propertyLocalName, propertyValue); - } - - internal static void UpdateCorePropertyValue(DocX document, string corePropertyName, string corePropertyValue) - { - string matchPattern = string.Format(@"(DOCPROPERTY)?{0}\\\*MERGEFORMAT", corePropertyName).ToLower(); - foreach (XElement e in document.mainDoc.Descendants(XName.Get("fldSimple", w.NamespaceName))) - { - string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim().ToLower(); - - if (Regex.IsMatch(attr_value, matchPattern)) - { - XElement firstRun = e.Element(w + "r"); - XElement firstText = firstRun.Element(w + "t"); - XElement rPr = firstText.Element(w + "rPr"); - - // Delete everything and insert updated text value - e.RemoveNodes(); - - XElement t = new XElement(w + "t", rPr, corePropertyValue); - Novacode.Text.PreserveSpace(t); - e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t)); - } - } - - #region Headers - - IEnumerable headerParts = from headerPart in document.package.GetParts() - where (Regex.IsMatch(headerPart.Uri.ToString(), @"/word/header\d?.xml")) - select headerPart; - foreach (PackagePart pp in headerParts) - { - XDocument header = XDocument.Load(new StreamReader(pp.GetStream())); - - foreach (XElement e in header.Descendants(XName.Get("fldSimple", w.NamespaceName))) - { - string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim().ToLower(); - if (Regex.IsMatch(attr_value, matchPattern)) - { - XElement firstRun = e.Element(w + "r"); - - // Delete everything and insert updated text value - e.RemoveNodes(); - - XElement t = new XElement(w + "t", corePropertyValue); - Novacode.Text.PreserveSpace(t); - e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t)); - } - } - - using (TextWriter tw = new StreamWriter(new PackagePartStream(pp.GetStream(FileMode.Create, FileAccess.Write)))) - header.Save(tw); - } - #endregion - - #region Footers - IEnumerable footerParts = from footerPart in document.package.GetParts() - where (Regex.IsMatch(footerPart.Uri.ToString(), @"/word/footer\d?.xml")) - select footerPart; - foreach (PackagePart pp in footerParts) - { - XDocument footer = XDocument.Load(new StreamReader(pp.GetStream())); - - foreach (XElement e in footer.Descendants(XName.Get("fldSimple", w.NamespaceName))) - { - string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim().ToLower(); - if (Regex.IsMatch(attr_value, matchPattern)) - { - XElement firstRun = e.Element(w + "r"); - - // Delete everything and insert updated text value - e.RemoveNodes(); - - XElement t = new XElement(w + "t", corePropertyValue); - Novacode.Text.PreserveSpace(t); - e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t)); - } - } - - using (TextWriter tw = new StreamWriter(new PackagePartStream(pp.GetStream(FileMode.Create, FileAccess.Write)))) - footer.Save(tw); - } - #endregion - PopulateDocument(document, document.package); - } - - /// - /// Add a custom property to this document. If a custom property already exists with the same name it will be replace. CustomProperty names are case insensitive. - /// - /// The CustomProperty to add to this document. - /// - /// Add a custom properties of each type to a document. - /// - /// // Load Example.docx - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // A CustomProperty called forename which stores a string. - /// CustomProperty forename; - /// - /// // If this document does not contain a custom property called 'forename', create one. - /// if (!document.CustomProperties.ContainsKey("forename")) - /// { - /// // Create a new custom property called 'forename' and set its value. - /// document.AddCustomProperty(new CustomProperty("forename", "Cathal")); - /// } - /// - /// // Get this documents custom property called 'forename'. - /// forename = document.CustomProperties["forename"]; - /// - /// // Print all of the information about this CustomProperty to Console. - /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", forename.Name, forename.Value)); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } // Release this document from memory. - /// - /// // Wait for the user to press a key before exiting. - /// Console.ReadKey(); - /// - /// - /// - /// - public void AddCustomProperty(CustomProperty cp) - { - // If this document does not contain a customFilePropertyPart create one. - if (!package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative))) - HelperFunctions.CreateCustomPropertiesPart(this); - - XDocument customPropDoc; - PackagePart customPropPart = package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative)); - using (TextReader tr = new StreamReader(customPropPart.GetStream(FileMode.Open, FileAccess.Read))) - customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace); - - // Each custom property has a PID, get the highest PID in this document. - IEnumerable pids = - ( - from d in customPropDoc.Descendants() - where d.Name.LocalName == "property" - select int.Parse(d.Attribute(XName.Get("pid")).Value) - ); - - int pid = 1; - if (pids.Count() > 0) - pid = pids.Max(); - - // Check if a custom property already exists with this name - // 2013-05-25: IgnoreCase while searching for custom property as it would produce a currupted docx. - var customProperty = - ( - from d in customPropDoc.Descendants() - where (d.Name.LocalName == "property") && (d.Attribute(XName.Get("name")).Value.Equals(cp.Name, StringComparison.InvariantCultureIgnoreCase)) - select d - ).SingleOrDefault(); - - // If a custom property with this name already exists remove it. - if (customProperty != null) - customProperty.Remove(); - - XElement propertiesElement = customPropDoc.Element(XName.Get("Properties", customPropertiesSchema.NamespaceName)); - propertiesElement.Add - ( - new XElement - ( - XName.Get("property", customPropertiesSchema.NamespaceName), - new XAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"), - new XAttribute("pid", pid + 1), - new XAttribute("name", cp.Name), - new XElement(customVTypesSchema + cp.Type, cp.Value ?? "") - ) - ); - - // Save the custom properties - using (TextWriter tw = new StreamWriter(new PackagePartStream(customPropPart.GetStream(FileMode.Create, FileAccess.Write)))) - customPropDoc.Save(tw, SaveOptions.None); - - // Refresh all fields in this document which display this custom property. - UpdateCustomPropertyValue(this, cp.Name, (cp.Value ?? "").ToString()); - } - - /// - /// Update the custom properties inside the document - /// - /// The DocX document - /// The property used inside the document - /// The new value for the property - /// Different version of Word create different Document XML. - internal static void UpdateCustomPropertyValue(DocX document, string customPropertyName, string customPropertyValue) - { - // A list of documents, which will contain, The Main Document and if they exist: header1, header2, header3, footer1, footer2, footer3. - List documents = new List { document.mainDoc.Root }; - - // Check if each header exists and add if if so. - #region Headers - Headers headers = document.Headers; - if (headers.first != null) - documents.Add(headers.first.Xml); - if (headers.odd != null) - documents.Add(headers.odd.Xml); - if (headers.even != null) - documents.Add(headers.even.Xml); - #endregion - - // Check if each footer exists and add if if so. - #region Footers - Footers footers = document.Footers; - if (footers.first != null) - documents.Add(footers.first.Xml); - if (footers.odd != null) - documents.Add(footers.odd.Xml); - if (footers.even != null) - documents.Add(footers.even.Xml); - #endregion - - var matchCustomPropertyName = customPropertyName; - if (customPropertyName.Contains(" ")) matchCustomPropertyName = "\"" + customPropertyName + "\""; - string match_value = string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", matchCustomPropertyName).Replace(" ", string.Empty); - - // Process each document in the list. - foreach (XElement doc in documents) - { - #region Word 2010+ - foreach (XElement e in doc.Descendants(XName.Get("instrText", w.NamespaceName))) - { - - string attr_value = e.Value.Replace(" ", string.Empty).Trim(); - - if (attr_value.Equals(match_value, StringComparison.CurrentCultureIgnoreCase)) - { - XNode node = e.Parent.NextNode; - bool found = false; - while (true) - { - if (node.NodeType == XmlNodeType.Element) - { - var ele = node as XElement; - var match = ele.Descendants(XName.Get("t", w.NamespaceName)); - if (match.Count() > 0) - { - if (!found) - { - match.First().Value = customPropertyValue; - found = true; - } - else - { - ele.RemoveNodes(); - } - } - else - { - match = ele.Descendants(XName.Get("fldChar", w.NamespaceName)); - if (match.Count() > 0) - { - var endMatch = match.First().Attribute(XName.Get("fldCharType", w.NamespaceName)); - if (endMatch != null && endMatch.Value == "end") - { - break; - } - } - } - } - node = node.NextNode; - } - } - } - #endregion - - #region < Word 2010 - foreach (XElement e in doc.Descendants(XName.Get("fldSimple", w.NamespaceName))) - { - string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim(); - - if (attr_value.Equals(match_value, StringComparison.CurrentCultureIgnoreCase)) - { - XElement firstRun = e.Element(w + "r"); - XElement firstText = firstRun.Element(w + "t"); - XElement rPr = firstText.Element(w + "rPr"); - - // Delete everything and insert updated text value - e.RemoveNodes(); - - XElement t = new XElement(w + "t", rPr, customPropertyValue); - Novacode.Text.PreserveSpace(t); - e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t)); - } - } - #endregion - } - } - - public override Paragraph InsertParagraph() - { - Paragraph p = base.InsertParagraph(); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(int index, string text, bool trackChanges) - { - Paragraph p = base.InsertParagraph(index, text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(Paragraph p) - { - p.PackagePart = mainPart; - return base.InsertParagraph(p); - } - - public override Paragraph InsertParagraph(int index, Paragraph p) - { - p.PackagePart = mainPart; - return base.InsertParagraph(index, p); - } - - public override Paragraph InsertParagraph(int index, string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraph(index, text, trackChanges, formatting); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text) - { - Paragraph p = base.InsertParagraph(text); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text, bool trackChanges) - { - Paragraph p = base.InsertParagraph(text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraph(text, trackChanges, formatting); - p.PackagePart = mainPart; - - return p; - } - - public Paragraph[] InsertParagraphs(string text) - { - String[] textArray = text.Split('\n'); - List paragraphs = new List(); - foreach (var textForParagraph in textArray) - { - Paragraph p = base.InsertParagraph(text); - p.PackagePart = mainPart; - paragraphs.Add(p); - } - return paragraphs.ToArray(); - } - - public override ReadOnlyCollection Contents - { - get - { - ReadOnlyCollection l = base.Contents; - foreach (var content in l) - { - content.PackagePart = mainPart; - } - return l; - } - } - - public void SetContent(XElement el) - { - foreach (XElement e in el.Elements()) - { - (from d in Document.Contents - where d.Name == e.Name - select d).First().SetText(e.Value); - } - } - - public void SetContent(Dictionary dict) - { - foreach (KeyValuePair item in dict) - { - (from d in Document.Contents - where d.Name == item.Key - select d).First().SetText(item.Value); - } - } - - public void SetContent(string path) - { - XDocument doc = XDocument.Load(path); - SetContent(doc); - } - - public void SetContent(XDocument xmlDoc) - { - - foreach (XElement e in xmlDoc.ElementsAfterSelf()) - { - (from d in Document.Contents - where d.Name == e.Name - select d).First().SetText(e.Value); - } - } - - public override ReadOnlyCollection Paragraphs - { - get - { - ReadOnlyCollection l = base.Paragraphs; - foreach (var paragraph in l) - { - paragraph.PackagePart = mainPart; - } - return l; - } - } - - public override List Lists - { - get - { - List l = base.Lists; - l.ForEach(x => x.Items.ForEach(i => i.PackagePart = mainPart)); - return l; - } - } - - public override List Tables - { - get - { - List
l = base.Tables; - l.ForEach(x => x.mainPart = mainPart); - return l; - } - } - - - /// - /// Create an equation and insert it in the new paragraph - /// - public override Paragraph InsertEquation(String equation) - { - Paragraph p = base.InsertEquation(equation); - p.PackagePart = mainPart; - return p; - } - - /// - /// Insert a chart in document - /// - public void InsertChart(Chart chart) - { - // Create a new chart part uri. - String chartPartUriPath = String.Empty; - Int32 chartIndex = 1; - do - { - chartPartUriPath = String.Format - ( - "/word/charts/chart{0}.xml", - chartIndex - ); - chartIndex++; - } while (package.PartExists(new Uri(chartPartUriPath, UriKind.Relative))); - - // Create chart part. - PackagePart chartPackagePart = package.CreatePart(new Uri(chartPartUriPath, UriKind.Relative), "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", CompressionOption.Normal); - - // Create a new chart relationship - String relID = GetNextFreeRelationshipID(); - PackageRelationship rel = mainPart.CreateRelationship(chartPackagePart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", relID); - - // Save a chart info the chartPackagePart - using (TextWriter tw = new StreamWriter(new PackagePartStream(chartPackagePart.GetStream(FileMode.Create, FileAccess.Write)))) - chart.Xml.Save(tw); - - // Insert a new chart into a paragraph. - Paragraph p = InsertParagraph(); - XElement chartElement = new XElement( - XName.Get("r", DocX.w.NamespaceName), - new XElement( - XName.Get("drawing", DocX.w.NamespaceName), - new XElement( - XName.Get("inline", DocX.wp.NamespaceName), - new XElement(XName.Get("extent", DocX.wp.NamespaceName), new XAttribute("cx", "5486400"), new XAttribute("cy", "3200400")), - new XElement(XName.Get("effectExtent", DocX.wp.NamespaceName), new XAttribute("l", "0"), new XAttribute("t", "0"), new XAttribute("r", "19050"), new XAttribute("b", "19050")), - new XElement(XName.Get("docPr", DocX.wp.NamespaceName), new XAttribute("id", "1"), new XAttribute("name", "chart")), - new XElement( - XName.Get("graphic", DocX.a.NamespaceName), - new XElement( - XName.Get("graphicData", DocX.a.NamespaceName), - new XAttribute("uri", DocX.c.NamespaceName), - new XElement( - XName.Get("chart", DocX.c.NamespaceName), - new XAttribute(XName.Get("id", DocX.r.NamespaceName), relID) - ) - ) - ) - ) - )); - p.Xml.Add(chartElement); - } - - /// - /// Inserts a default TOC into the current document. - /// Title: Table of contents - /// Swithces will be: TOC \h \o '1-3' \u \z - /// - /// The inserted TableOfContents - public TableOfContents InsertDefaultTableOfContents() - { - return InsertTableOfContents("Table of contents", TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | TableOfContentsSwitches.U); - } - - /// - /// Inserts a TOC into the current document. - /// - /// The title of the TOC - /// Switches to be applied, see: http://officeopenxml.com/WPtableOfContents.php - /// Lets you set the style name of the TOC header - /// Lets you specify how many header levels should be included - default is 1-3 - /// Lets you override the right tab position - this is not common - /// The inserted TableOfContents - public TableOfContents InsertTableOfContents(string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null) - { - var toc = TableOfContents.CreateTableOfContents(this, title, switches, headerStyle, maxIncludeLevel, rightTabPos); - Xml.Add(toc.Xml); - return toc; - } - - /// - /// Inserts at TOC into the current document before the provided - /// - /// The paragraph to use as reference - /// The title of the TOC - /// Switches to be applied, see: http://officeopenxml.com/WPtableOfContents.php - /// Lets you set the style name of the TOC header - /// Lets you specify how many header levels should be included - default is 1-3 - /// Lets you override the right tab position - this is not common - /// The inserted TableOfContents - public TableOfContents InsertTableOfContents(Paragraph reference, string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null) - { - var toc = TableOfContents.CreateTableOfContents(this, title, switches, headerStyle, maxIncludeLevel, rightTabPos); - reference.Xml.AddBeforeSelf(toc.Xml); - return toc; - } - - #region IDisposable Members - - /// - /// Releases all resources used by this document. - /// - /// - /// If you take advantage of the using keyword, Dispose() is automatically called for you. - /// - /// // Load document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // The document is only in memory while in this scope. - /// - /// }// Dispose() is automatically called at this point. - /// - /// - /// - /// This example is equilivant to the one above example. - /// - /// // Load document. - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// // Do something with the document here. - /// - /// // Dispose of the document. - /// document.Dispose(); - /// - /// - public void Dispose() - { - package.Close(); - } - - #endregion - } -} diff --git a/DocX.iOS.Test/DocX.iOS.Test.csproj b/DocX.iOS.Test/DocX.iOS.Test.csproj deleted file mode 100644 index fc022dce..00000000 --- a/DocX.iOS.Test/DocX.iOS.Test.csproj +++ /dev/null @@ -1,107 +0,0 @@ - - - - Debug - iPhoneSimulator - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {E504B3DA-ED72-4A45-ADCC-F573908A84EB} - Exe - DocX.iOS.Test - Resources - DocX.iOS.Test - - - true - full - false - bin\iPhoneSimulator\Debug - DEBUG;ENABLE_TEST_CLOUD; - prompt - 4 - false - i386 - None - true - true - true - true - iPhone Developer - true - west - - - full - true - bin\iPhone\Release - prompt - 4 - false - ARMv7, ARM64 - Entitlements.plist - true - true - iPhone Developer - true - - - full - true - bin\iPhoneSimulator\Release - prompt - 4 - false - i386 - None - true - iPhone Developer - true - - - true - full - false - bin\iPhone\Debug - DEBUG;ENABLE_TEST_CLOUD; - prompt - 4 - false - ARMv7, ARM64 - Entitlements.plist - true - iPhone Developer - true - true - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC} - DocX.iOS - - - - - - \ No newline at end of file diff --git a/DocX.iOS.Test/Entitlements.plist b/DocX.iOS.Test/Entitlements.plist deleted file mode 100644 index 9ae59937..00000000 --- a/DocX.iOS.Test/Entitlements.plist +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/DocX.iOS.Test/Info.plist b/DocX.iOS.Test/Info.plist deleted file mode 100644 index 6fc61a63..00000000 --- a/DocX.iOS.Test/Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CFBundleName - DocX Test - CFBundleIdentifier - com.managingsoftware.docx.docx-ios-test - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1.0 - LSRequiresIPhoneOS - - MinimumOSVersion - 9.3 - UIDeviceFamily - - 1 - 2 - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - XSAppIconAssets - Resources/Images.xcassets/AppIcons.appiconset - - diff --git a/DocX.iOS.Test/Resources/Images.xcassets/AppIcons.appiconset/Contents.json b/DocX.iOS.Test/Resources/Images.xcassets/AppIcons.appiconset/Contents.json deleted file mode 100644 index 6a8e7fe2..00000000 --- a/DocX.iOS.Test/Resources/Images.xcassets/AppIcons.appiconset/Contents.json +++ /dev/null @@ -1,162 +0,0 @@ -{ - "images": [ - { - "idiom": "iphone", - "size": "29x29", - "scale": "1x" - }, - { - "idiom": "iphone", - "size": "29x29", - "scale": "2x" - }, - { - "idiom": "iphone", - "size": "29x29", - "scale": "3x" - }, - { - "idiom": "iphone", - "size": "40x40", - "scale": "2x" - }, - { - "idiom": "iphone", - "size": "40x40", - "scale": "3x" - }, - { - "idiom": "iphone", - "size": "57x57", - "scale": "1x" - }, - { - "idiom": "iphone", - "size": "57x57", - "scale": "2x" - }, - { - "idiom": "iphone", - "size": "60x60", - "scale": "2x" - }, - { - "idiom": "iphone", - "size": "60x60", - "scale": "3x" - }, - { - "idiom": "ipad", - "size": "29x29", - "scale": "1x" - }, - { - "idiom": "ipad", - "size": "29x29", - "scale": "2x" - }, - { - "idiom": "ipad", - "size": "40x40", - "scale": "1x" - }, - { - "idiom": "ipad", - "size": "40x40", - "scale": "2x" - }, - { - "idiom": "ipad", - "size": "50x50", - "scale": "1x" - }, - { - "idiom": "ipad", - "size": "50x50", - "scale": "2x" - }, - { - "idiom": "ipad", - "size": "72x72", - "scale": "1x" - }, - { - "idiom": "ipad", - "size": "72x72", - "scale": "2x" - }, - { - "idiom": "ipad", - "size": "76x76", - "scale": "1x" - }, - { - "idiom": "ipad", - "size": "76x76", - "scale": "2x" - }, - { - "idiom": "car", - "size": "120x120", - "scale": "1x" - }, - { - "size": "24x24", - "idiom": "watch", - "scale": "2x", - "role": "notificationCenter", - "subtype": "38mm" - }, - { - "size": "27.5x27.5", - "idiom": "watch", - "scale": "2x", - "role": "notificationCenter", - "subtype": "42mm" - }, - { - "size": "29x29", - "idiom": "watch", - "role": "companionSettings", - "scale": "2x" - }, - { - "size": "29x29", - "idiom": "watch", - "role": "companionSettings", - "scale": "3x" - }, - { - "size": "40x40", - "idiom": "watch", - "scale": "2x", - "role": "appLauncher", - "subtype": "38mm" - }, - { - "size": "44x44", - "idiom": "watch", - "scale": "2x", - "role": "longLook", - "subtype": "42mm" - }, - { - "size": "86x86", - "idiom": "watch", - "scale": "2x", - "role": "quickLook", - "subtype": "38mm" - }, - { - "size": "98x98", - "idiom": "watch", - "scale": "2x", - "role": "quickLook", - "subtype": "42mm" - } - ], - "info": { - "version": 1, - "author": "xcode" - } -} \ No newline at end of file diff --git a/DocX.iOS.Test/Resources/LaunchScreen.xib b/DocX.iOS.Test/Resources/LaunchScreen.xib deleted file mode 100644 index 5ed72384..00000000 --- a/DocX.iOS.Test/Resources/LaunchScreen.xib +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DocX.iOS.Test/Sources/App.cs b/DocX.iOS.Test/Sources/App.cs deleted file mode 100644 index 69307f10..00000000 --- a/DocX.iOS.Test/Sources/App.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System; -using System.IO; - -using Foundation; -using UIKit; - -namespace DocX.iOS.Test -{ - [Register ("App")] - - public class App : UIApplicationDelegate - { - // Main - - private static void Main (string[] args) - { - UIApplication.Main (args, null, "App"); - } - - // constants - - private const string messageFormat = @" - - - - - -

{0}

-
{1}
- - -"; - - // publics - - public override UIWindow Window { get; set; } - - // FinishedLaunching - - public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions) - { - // create webview + controller - - var controller = new UIViewController (); - - controller.Title = "DocX - Test"; - - var webview = new UIWebView (controller.View.Frame); - - webview.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions; - - webview.ScalesPageToFit = true; - - controller.View.AddSubview (webview); - - // create navigation controller - - var navigation = new UINavigationController (controller); - - // initialize window - - this.Window = new UIWindow (UIScreen.MainScreen.Bounds); - - this.Window.RootViewController = navigation; - - this.Window.MakeKeyAndVisible (); - - // - - try - { - // path to our temp docx file - - string pathDocx = Path.Combine(Path.GetTempPath (), "Document.docx"); - - // inform user of what we are about to do - - webview.LoadHtmlString (string.Format(messageFormat, "Generating .docx file, please wait...", pathDocx), null); - - // generating docx - - using (var document = Novacode.DocX.Create (pathDocx)) - { - Novacode.Paragraph p = document.InsertParagraph(); - - p.Append("This is a Word Document"); - - p = document.InsertParagraph(); - - p.Append(""); - - p = document.InsertParagraph(); - - p.Append("Hello World"); - - document.Save(); - } - - // showing docx in webview, with delay, otherwise we don't see our initial message - - this.Invoke(() => { - - webview.LoadRequest (NSUrlRequest.FromUrl (NSUrl.FromFilename (pathDocx))); - - }, 2.0f); - - // done - } - catch (Exception e) - { - webview.LoadHtmlString (string.Format(messageFormat, "Exception Occurred :", e), null); - } - - // done - - return true; - } - } -} \ No newline at end of file diff --git a/DocX.iOS/DocX.iOS.csproj b/DocX.iOS/DocX.iOS.csproj deleted file mode 100644 index 6a8b224f..00000000 --- a/DocX.iOS/DocX.iOS.csproj +++ /dev/null @@ -1,200 +0,0 @@ - - - - Debug - AnyCPU - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC} - Library - DocX.iOS - Resources - DocX.iOS - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - 219;414;168; - - - true - bin\Release - prompt - 4 - false - 219;414;168; - - - - - - - - - - - - - - - - - - - - - - - Sources\Charts\Axis.cs - - - Sources\Charts\BarChart.cs - - - Sources\Charts\Chart.cs - - - Sources\Charts\LineChart.cs - - - Sources\Charts\PieChart.cs - - - Sources\Charts\XElementHelpers.cs - - - Sources\Bookmark.cs - - - Sources\BookmarkCollection.cs - - - Sources\Border.cs - - - Sources\Container.cs - - - Sources\CustomProperty.cs - - - Sources\DocProperty.cs - - - Sources\DocX.cs - - - Sources\DocumentTypes.cs - - - Sources\ExtensionsHeadings.cs - - - Sources\Footer.cs - - - Sources\Footers.cs - - - Sources\FormattedText.cs - - - Sources\Formatting.cs - - - Sources\Header.cs - - - Sources\Headers.cs - - - Sources\HelperFunctions.cs - - - Sources\Hyperlink.cs - - - Sources\IParagraphContainer.cs - - - Sources\Image.cs - - - Sources\List.cs - - - Sources\PageLayout.cs - - - Sources\Paragraph.cs - - - Sources\Picture.cs - - - Sources\Section.cs - - - Sources\Table.cs - - - Sources\TableOfContents.cs - - - Sources\_BaseClasses.cs - - - Sources\_Enumerations.cs - - - Sources\_Extensions.cs - - - - - - - - - - - - - - - - - - - - - - - - - Resources\default_styles.xml.gz - Novacode.Resources.default_styles.xml.gz - - - Resources\numbering.default_bullet_abstract.xml.gz - Novacode.Resources.default_bullet_abstract.xml.gz - - - Resources\numbering.default_decimal_abstract.xml.gz - Novacode.Resources.default_decimal_abstract.xml.gz - - - Resources\numbering.xml.gz - Novacode.Resources.numbering.xml.gz - - - Resources\styles.xml.gz - Novacode.Resources.styles.xml.gz - - - \ No newline at end of file diff --git a/DocX.iOS/Properties/AssemblyInfo.cs b/DocX.iOS/Properties/AssemblyInfo.cs deleted file mode 100644 index 575ee6d3..00000000 --- a/DocX.iOS/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -[assembly: AssemblyTitle ("DocX.iOS")] -[assembly: AssemblyDescription ("")] -[assembly: AssemblyConfiguration ("")] -[assembly: AssemblyCompany ("Managing Software")] -[assembly: AssemblyProduct ("")] -[assembly: AssemblyCopyright ("Managing Software")] -[assembly: AssemblyTrademark ("")] -[assembly: AssemblyCulture ("")] - -// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". -// The form "{Major}.{Minor}.*" will automatically update the build and revision, -// and "{Major}.{Minor}.{Build}.*" will update just the revision. - -[assembly: AssemblyVersion ("1.0.*")] - -// The following attributes are used to specify the signing key for the assembly, -// if desired. See the Mono documentation for more information about signing. - -//[assembly: AssemblyDelaySign(false)] -//[assembly: AssemblyKeyFile("")] - diff --git a/DocX.iOS/System/Drawing/ColorTranslator.cs b/DocX.iOS/System/Drawing/ColorTranslator.cs deleted file mode 100644 index 8b29012f..00000000 --- a/DocX.iOS/System/Drawing/ColorTranslator.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Drawing; - -using Foundation; -using UIKit; - -namespace System.Drawing -{ - // ColorTranslator - - public static class ColorTranslator - { - // FromHtml - - public static Color FromHtml(string color, float alpha = 1.0f) - { - color = color.Replace ("#", "").Replace (" ", "").Trim (); - - if (alpha > 1.0f) - { - alpha = 1.0f; - } - - if (alpha < 0.0f) - { - alpha = 0.0f; - } - - int A = 0, R = 0, G = 0, B = 0; - - switch (color.Length) - { - case 3 : // #RGB - { - A = (int)(alpha * 255); - - R = Convert.ToInt32(string.Format("{0}{0}", color.Substring(0, 1)), 16); - - G = Convert.ToInt32(string.Format("{0}{0}", color.Substring(1, 1)), 16); - - B = Convert.ToInt32(string.Format("{0}{0}", color.Substring(2, 1)), 16); - - break; - } - - case 4 : // #ARGB - { - A = Convert.ToInt32(string.Format("{0}{0}", color.Substring(0, 1)), 16); - - R = Convert.ToInt32(string.Format("{0}{0}", color.Substring(1, 1)), 16); - - G = Convert.ToInt32(string.Format("{0}{0}", color.Substring(2, 1)), 16); - - B = Convert.ToInt32(string.Format("{0}{0}", color.Substring(3, 1)), 16); - - break; - } - - case 6 : // #RRGGBB - { - A = (int)(alpha * 255); - - R = Convert.ToInt32(color.Substring(0, 2), 16); - - G = Convert.ToInt32(color.Substring(2, 2), 16); - - B = Convert.ToInt32(color.Substring(4, 2), 16); - - break; - } - - case 8 : // #RRGGBB - { - A = Convert.ToInt32(color.Substring(0, 2), 16); - - R = Convert.ToInt32(color.Substring(2, 2), 16); - - G = Convert.ToInt32(color.Substring(4, 2), 16); - - B = Convert.ToInt32(color.Substring(6, 2), 16); - - break; - } - } - - return Color.FromArgb (A, R, G, B); - } - } -} \ No newline at end of file diff --git a/DocX.iOS/System/Drawing/FontFamily.cs b/DocX.iOS/System/Drawing/FontFamily.cs deleted file mode 100644 index 7f8a48b0..00000000 --- a/DocX.iOS/System/Drawing/FontFamily.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace System.Drawing -{ - // FontFamily - - public class FontFamily : MarshalByRefObject - { - // properties - - public string Name { get; private set; } - - // constructor - - public FontFamily (string name) - { - this.Name = name; - } - } -} \ No newline at end of file diff --git a/DocX.iOS/System/Drawing/Image.cs b/DocX.iOS/System/Drawing/Image.cs deleted file mode 100644 index 2b327c36..00000000 --- a/DocX.iOS/System/Drawing/Image.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.IO; - -using Foundation; -using UIKit; - -namespace System.Drawing -{ - // Image - - public class Image : MarshalByRefObject, IDisposable - { - // FromStream - - public static Image FromStream(Stream stream) - { - return new Image (stream); - } - - // properties - - public bool Disposed { get; private set; } - - public int Height { get; private set; } - - public int Width { get; private set; } - - // constructor - - private Image (Stream stream) - { - using (var image = UIImage.LoadFromData (NSData.FromStream (stream))) - { - this.Width = (int)image.Size.Width; - - this.Height = (int)image.Size.Height; - } - } - - // destructor - - ~Image() - { - Dispose(false); - } - - // Dispose - - public void Dispose() - { - this.Dispose(true); - - GC.SuppressFinalize(this); - } - - // Dispose - - protected virtual void Dispose(bool disposing) - { - if (this.Disposed) - { - return; - } - - try - { - try - { - if (disposing) - { - // dispose managed - } - } - finally - { - // dispose unmanaged - } - } - finally - { - this.Disposed = true; - } - } - } -} \ No newline at end of file diff --git a/DocX.iOS/System/IO/Packaging/Check.cs b/DocX.iOS/System/IO/Packaging/Check.cs deleted file mode 100644 index 3da1387b..00000000 --- a/DocX.iOS/System/IO/Packaging/Check.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -//using DocumentFormat.OpenXml.Packaging; - -namespace System.IO.Packaging -{ - internal static class Check - { - static void NotNull(object o, string name) - { - if (o == null) - throw new ArgumentNullException(name); - } - - public static void ContentTypeIsValid(string contentType) - { - if (string.IsNullOrEmpty(contentType)) - return; - - // Must be in form of: type/subtype - int index = contentType.IndexOf('/'); - bool result = (index > 0) && contentType.Length > (index + 1) && contentType.IndexOf('/', index + 1) == -1; - - if (!result) - throw new ArgumentException("contentType", "contentType must be in the form of 'type/subtype'"); - } - - public static void Id(object id) - { - NotNull(id, "id"); - } - - public static void IdIsValid(string id) - { - if (id == null) - return; - - // If the ID is a zero string, need to throw a ArgNullEx - if (id.Length == 0) - throw new ArgumentNullException("id", "Cannot be whitespace or empty"); - - // FIXME: I need to XSD parse this to make sure it's valid - // If it's not, throw an XmlException - } - - private static bool EmptyOrBlank(string s) - { - return (s != null && (s == "" || s.Trim().Length == 0)); - } - - private static void PartUriDoesntEndWithSlash(Uri uri) - { - var s = !uri.IsAbsoluteUri ? uri.OriginalString - : uri.GetComponents(UriComponents.Path, UriFormat.UriEscaped); - - // We allow '/' at uri's beggining. - if ((s.Length > 1) && s.EndsWith("/")) - { - throw new ArgumentException("Part URI cannot end with a forward slash."); - } - } - - public static void Package(object package) - { - if (package == null) - throw new ArgumentNullException(nameof(package)); - } - - - public static void PackageUri(object packageUri) - { - NotNull(packageUri, "packageUri"); - } - - public static void PackageUriIsValid(Uri packageUri) - { - if (!packageUri.IsAbsoluteUri) - throw new ArgumentException(nameof(packageUri), "Uri must be absolute"); - } - - public static void PackUriIsValid(Uri packUri) - { - if (!packUri.IsAbsoluteUri) - throw new ArgumentException(nameof(packUri), "PackUris must be absolute"); - - if (packUri.Scheme != PackUriHelper.UriSchemePack) - throw new ArgumentException(nameof(packUri), "Uri scheme is not a valid PackUri scheme"); - } - - public static void PartUri(object partUri) - { - if (partUri == null) - throw new ArgumentNullException(nameof(partUri)); - } - - public static void PartUriIsValid(Uri partUri) - { - if (!partUri.OriginalString.StartsWith("/")) - throw new ArgumentException("PartUris must start with '/'"); - - if (partUri.IsAbsoluteUri) - throw new ArgumentException("PartUris cannot be absolute"); - } - - public static void RelationshipTypeIsValid(string relationshipType) - { - if (relationshipType == null) - throw new ArgumentNullException(nameof(relationshipType)); - if (EmptyOrBlank(relationshipType)) - throw new ArgumentException("relationshipType", "Cannot be whitespace or empty"); - } - - public static void PartUri(Uri partUri) - { - if (partUri == null) - throw new ArgumentNullException(nameof(partUri)); - if (partUri.IsAbsoluteUri) - throw new ArgumentException(nameof(partUri), "Absolute URIs are not supported"); - if (string.IsNullOrEmpty(partUri.OriginalString)) - throw new ArgumentException(nameof(partUri), "Part uri cannot be an empty string"); - } - - public static void PackUri(Uri packUri) - { - NotNull(packUri, "packUri"); - } - - public static void SourcePartUri(Uri sourcePartUri) - { - NotNull(sourcePartUri, "sourcePartUri"); - PartUriDoesntEndWithSlash(sourcePartUri); - } - - public static void TargetPartUri(Uri targetPartUri) - { - NotNull(targetPartUri, "targetPartUri"); - PartUriDoesntEndWithSlash(targetPartUri); - } - - public static void SourceUri(Uri sourceUri) - { - if (sourceUri == null) - throw new ArgumentNullException(nameof(sourceUri)); - // if (sourceUri.IsAbsoluteUri) - // throw new ArgumentException ("sourceUri", "Absolute URIs are not supported"); - if (string.IsNullOrEmpty(sourceUri.OriginalString)) - throw new ArgumentException(nameof(sourceUri), "Part uri cannot be an empty string"); - } - - public static void TargetUri(Uri targetUri) - { - if (targetUri == null) - throw new ArgumentNullException(nameof(targetUri)); - // if (targetUri.IsAbsoluteUri) - // throw new ArgumentException ("targetUri", "Absolute URIs are not supported"); - if (string.IsNullOrEmpty(targetUri.OriginalString)) - throw new ArgumentException(nameof(targetUri), "Part uri cannot be an empty string"); - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/CompressionOption.cs b/DocX.iOS/System/IO/Packaging/CompressionOption.cs deleted file mode 100644 index 2d656b33..00000000 --- a/DocX.iOS/System/IO/Packaging/CompressionOption.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System.IO.Packaging -{ - public enum CompressionOption - { - NotCompressed = -1, - Normal, - Maximum, - Fast, - SuperFast, - } -} diff --git a/DocX.iOS/System/IO/Packaging/PackUriHelper.cs b/DocX.iOS/System/IO/Packaging/PackUriHelper.cs deleted file mode 100644 index 9ed8e87f..00000000 --- a/DocX.iOS/System/IO/Packaging/PackUriHelper.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System.IO.Packaging -{ - public static class PackUriHelper - { - public static readonly string UriSchemePack = "pack"; - static readonly Uri PackSchemeUri = new Uri("pack://", UriKind.Absolute); - static readonly char[] _escapedChars = new char[] { '%', ',', '?', '@' }; - - - static PackUriHelper() - { - if (!UriParser.IsKnownScheme(UriSchemePack)) - UriParser.Register(new PackUriParser(), UriSchemePack, -1); - } - - public static int ComparePackUri(Uri firstPackUri, Uri secondPackUri) - { - if (firstPackUri == null) - return secondPackUri == null ? 0 : -1; - if (secondPackUri == null) - return 1; - - Check.PackUriIsValid(firstPackUri); - Check.PackUriIsValid(secondPackUri); - - // FIXME: What exactly is compared. Lets assume originalstring - return firstPackUri.OriginalString.CompareTo(secondPackUri.OriginalString); - } - - public static int ComparePartUri(Uri firstPartUri, Uri secondPartUri) - { - if (firstPartUri == null) - return secondPartUri == null ? 0 : -1; - if (secondPartUri == null) - return 1; - - Check.PartUriIsValid(firstPartUri); - Check.PartUriIsValid(secondPartUri); - - return firstPartUri.OriginalString.CompareTo(secondPartUri.OriginalString); - } - - public static Uri Create(Uri packageUri) - { - return Create(packageUri, null, null); - } - - public static Uri Create(Uri packageUri, Uri partUri) - { - return Create(packageUri, partUri, null); - } - - public static Uri Create(Uri packageUri, Uri partUri, string fragment) - { - Check.PackageUri(packageUri); - Check.PackageUriIsValid(packageUri); - - if (partUri != null) - Check.PartUriIsValid(partUri); - - if (fragment != null && (fragment.Length == 0 || fragment[0] != '#')) - throw new ArgumentException("Fragment", "Fragment must not be empty and must start with '#'"); - - // FIXME: Validate that partUri is a valid one? Must be relative, must start with '/' - - // First replace the slashes, then escape the special characters - //string orig = packageUri.GetComponents(UriComponents.AbsoluteUri, UriFormat.UriEscaped); - string orig = packageUri.OriginalString; - - foreach (var ch in _escapedChars) - { - orig = !orig.Contains(ch.ToString()) ? orig : orig.Replace(ch.ToString(), Uri.HexEscape(ch)); - } - - orig = orig.Replace('/', ','); - - if (partUri != null) - orig += partUri.OriginalString; - - if ((fragment == null && partUri == null) && orig[orig.Length - 1] != '/') - orig += '/'; - - if (fragment != null) - orig += fragment; - - return new Uri("pack://" + orig); - } - - public static Uri CreatePartUri(Uri partUri) - { - Check.PartUri(partUri); - - if (partUri.OriginalString[0] != '/') - partUri = new Uri("/" + partUri.ToString(), UriKind.Relative); - return partUri; - } - - public static Uri GetNormalizedPartUri(Uri partUri) - { - Check.PartUri(partUri); - return new Uri(partUri.ToString().ToUpperInvariant(), UriKind.Relative); - } - - public static Uri GetPackageUri(Uri packUri) - { - Check.PackUri(packUri); - Check.PackUriIsValid(packUri); - - string s = packUri.Host.Replace(',', '/'); - return new Uri(Uri.UnescapeDataString(s), UriKind.RelativeOrAbsolute); - } - - public static Uri GetPartUri(Uri packUri) - { - Check.PackUri(packUri); - Check.PackUriIsValid(packUri); - - if (string.IsNullOrEmpty(packUri.AbsolutePath) || packUri.AbsolutePath == "/") - return null; - - return new Uri(packUri.AbsolutePath, UriKind.Relative); - } - - public static Uri GetRelationshipPartUri(Uri partUri) - { - Check.PartUri(partUri); - Check.PartUriIsValid(partUri); - - int index = partUri.OriginalString.LastIndexOf("/"); - string s = partUri.OriginalString.Substring(0, index); - s += "/_rels" + partUri.OriginalString.Substring(index) + ".rels"; - return new Uri(s, UriKind.Relative); - } - - public static Uri GetRelativeUri(Uri sourcePartUri, Uri targetPartUri) - { - Check.SourcePartUri(sourcePartUri); - Check.TargetPartUri(targetPartUri); - - Uri uri = new Uri("http://fake.com"); - Uri a = new Uri(uri, sourcePartUri.OriginalString); - Uri b = new Uri(uri, targetPartUri.OriginalString); - - return a.MakeRelativeUri(b); - } - - public static Uri GetSourcePartUriFromRelationshipPartUri(Uri relationshipPartUri) - { - //Check.RelationshipPartUri (relationshipPartUri); - if (!IsRelationshipPartUri(relationshipPartUri)) - throw new Exception("is not a relationship part!?"); - return null; - } - - public static bool IsRelationshipPartUri(Uri partUri) - { - Check.PartUri(partUri); - return partUri.OriginalString.StartsWith("/_rels") && partUri.OriginalString.EndsWith(".rels"); - } - - public static Uri ResolvePartUri(Uri sourcePartUri, Uri targetUri) - { - Check.SourcePartUri(sourcePartUri); - Check.TargetUri(targetUri); - - Check.PartUriIsValid(sourcePartUri); - // commented out because on Android they are absolute file:/// - // if (targetUri.IsAbsoluteUri) - // throw new ArgumentException("targetUri", "Absolute URIs are not supported"); - - Uri uri = new Uri("http://fake.com"); - uri = new Uri(uri, sourcePartUri); - uri = new Uri(uri, targetUri); - - // Trim out 'http://fake.com' - return new Uri(uri.OriginalString.Substring(15), UriKind.Relative); - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/PackUriParser.cs b/DocX.iOS/System/IO/Packaging/PackUriParser.cs deleted file mode 100644 index f06320a7..00000000 --- a/DocX.iOS/System/IO/Packaging/PackUriParser.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System.IO.Packaging -{ - class PackUriParser : GenericUriParser - { - const string SchemaName = "pack"; - - StringBuilder builder = new StringBuilder(); - - public PackUriParser() - : base(GenericUriParserOptions.Default) - { - } - - protected override string GetComponents(Uri uri, UriComponents components, UriFormat format) - { - string s = uri.OriginalString; - builder.Remove(0, builder.Length); - - if ((components & UriComponents.Scheme) == UriComponents.Scheme) - { - int start = 0; - int end = s.IndexOf(':'); - builder.Append(s, start, end - start); - } - - if ((components & UriComponents.Host) == UriComponents.Host) - { - // Skip past pack:// - int start = 7; - int end = s.IndexOf('/', start); - if (end == -1) - end = s.Length; - - if (builder.Length > 0) - builder.Append("://"); - - builder.Append(s, start, end - start); - } - - // Port is always -1, so i think i can ignore both Port and StrongPort - // Normally they'd get parsed here - - if ((components & UriComponents.Path) == UriComponents.Path) - { - // Skip past pack:// - int start = s.IndexOf('/', 7); - int end = s.IndexOf('?'); - if (end == -1) - end = s.IndexOf('#'); - if (end == -1) - end = s.Length; - - if ((components & UriComponents.KeepDelimiter) != UriComponents.KeepDelimiter && - builder.Length == 0) - start++; - - if (start > 0) builder.Append(s, start, end - start); - } - - if ((components & UriComponents.Query) == UriComponents.Query) - { - int index = s.IndexOf('?'); - - if (index != -1) - { - if ((components & UriComponents.KeepDelimiter) != UriComponents.KeepDelimiter && - builder.Length == 0) - index++; - - int fragIndex = s.IndexOf('#'); - int end = fragIndex == -1 ? s.Length : fragIndex; - builder.Append(s, index, end - index); - } - } - - if ((components & UriComponents.Fragment) == UriComponents.Fragment) - { - int index = s.IndexOf('#'); - - if (index != -1) - { - if ((components & UriComponents.KeepDelimiter) != UriComponents.KeepDelimiter && - builder.Length == 0) - index++; - - builder.Append(s, index, s.Length - index); - } - } - - return builder.ToString(); - } - - protected override void InitializeAndValidate(Uri uri, out UriFormatException parsingError) - { - parsingError = null; - } - - protected override UriParser OnNewUri() - { - return new PackUriParser(); - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/Package.cs b/DocX.iOS/System/IO/Packaging/Package.cs deleted file mode 100644 index 0aee1be5..00000000 --- a/DocX.iOS/System/IO/Packaging/Package.cs +++ /dev/null @@ -1,488 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -//using DocumentFormat.OpenXml.Packaging; - -namespace System.IO.Packaging -{ - public abstract class Package : IDisposable - { - internal const string RelationshipContentType = "application/vnd.openxmlformats-package.relationships+xml"; - internal const string RelationshipNamespace = "http://schemas.openxmlformats.org/package/2006/relationships"; - internal static readonly Uri RelationshipUri = new Uri("/_rels/.rels", UriKind.Relative); - - private PackageProperties packageProperties; - private PackagePartCollection partsCollection; - private Dictionary relationships; - private PackageRelationshipCollection relationshipsCollection = new PackageRelationshipCollection(); - private Uri Uri = new Uri("/", UriKind.Relative); - - private bool Disposed { get; set; } - - public FileAccess FileOpenAccess { get; private set; } - - public PackageProperties PackageProperties - { - get - { - // PackageProperties are loaded when the relationships are loaded. - // Therefore ensure we've already loaded the relationships. - int count = Relationships.Count; - - if (packageProperties == null) - { - packageProperties = new PackagePropertiesPart(); - packageProperties.Package = this; - } - return packageProperties; - } - } - - private PackagePartCollection PartsCollection - { - get - { - if (partsCollection == null) - { - partsCollection = new PackagePartCollection(); - partsCollection.Parts.AddRange(GetPartsCore()); - } - return partsCollection; - } - } - - private int RelationshipId { get; set; } - - private Dictionary Relationships - { - get - { - if (relationships == null) - { - LoadRelationships(); - } - return relationships; - } - } - - private bool Streaming { get; set; } - - - protected Package(FileAccess openFileAccess) - : this(openFileAccess, false) - { - - } - - protected Package(FileAccess openFileAccess, bool streaming) - { - FileOpenAccess = openFileAccess; - Streaming = streaming; - } - - - internal void CheckIsReadOnly() - { - if (FileOpenAccess == FileAccess.Read) - throw new IOException("Operation not valid when package is read-only"); - } - - public void Close() - { - // FIXME: Ensure that Flush is actually called before dispose - ((IDisposable) this).Dispose(); - } - - public PackagePart CreatePart(Uri partUri, string contentType) - { - return CreatePart(partUri, contentType, CompressionOption.NotCompressed); - } - - public PackagePart CreatePart(Uri partUri, string contentType, CompressionOption compressionOption) - { - CheckIsReadOnly(); - Check.PartUri(partUri); - Check.ContentTypeIsValid(contentType); - - if (PartExists(partUri)) - throw new InvalidOperationException("This partUri is already contained in the package"); - - PackagePart part = CreatePartCore(partUri, contentType, compressionOption); - PartsCollection.Parts.Add(part); - return part; - } - - protected abstract PackagePart CreatePartCore(Uri partUri, string contentType, - CompressionOption compressionOption); - - public PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType) - { - return CreateRelationship(targetUri, targetMode, relationshipType, null); - } - - public PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType, - string id) - { - return CreateRelationship(targetUri, targetMode, relationshipType, id, false); - } - - internal PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType, - string id, bool loading) - { - if (!loading) - CheckIsReadOnly(); - - Check.TargetUri(targetUri); - if (targetUri.IsAbsoluteUri && targetMode == TargetMode.Internal) - throw new ArgumentException("TargetUri cannot be absolute for an internal relationship"); - - Check.RelationshipTypeIsValid(relationshipType); - Check.IdIsValid(id); - - if (id == null) - id = NextId(); - - PackageRelationship r = new PackageRelationship(id, this, relationshipType, Uri, targetMode, targetUri); - - if (!PartExists(RelationshipUri)) - CreatePartCore(RelationshipUri, RelationshipContentType, CompressionOption.NotCompressed).IsRelationship - = true; - - Relationships.Add(r.Id, r); - relationshipsCollection.Relationships.Add(r); - - if (!loading) - { - using (Stream s = GetPart(RelationshipUri).GetStream()) - WriteRelationships(relationships, s); - } - - return r; - } - - - public void DeletePart(Uri partUri) - { - CheckIsReadOnly(); - Check.PartUri(partUri); - - PackagePart part = GetPart(partUri); - if (part != null) - { - if (part.Package == null) - throw new InvalidOperationException("This part has already been removed"); - - // FIXME: MS.NET doesn't remove the relationship part - // Instead it throws an exception if you try to use it - if (PartExists(part.RelationshipsPartUri)) - GetPart(part.RelationshipsPartUri).Package = null; - - part.Package = null; - DeletePartCore(partUri); - PartsCollection.Parts.RemoveAll(p => p.Uri == partUri); - } - } - - protected abstract void DeletePartCore(Uri partUri); - - public void DeleteRelationship(string id) - { - Check.Id(id); - CheckIsReadOnly(); - - Relationships.Remove(id); - - relationshipsCollection.Relationships.RemoveAll(r => r.Id == id); - if (Relationships.Count > 0) - using (Stream s = GetPart(RelationshipUri).GetStream()) - WriteRelationships(relationships, s); - else - DeletePart(RelationshipUri); - } - - void IDisposable.Dispose() - { - if (!Disposed) - { - Flush(); - Dispose(true); - Disposed = true; - } - } - - protected virtual void Dispose(bool disposing) - { - // Nothing here needs to be disposed of - } - - private bool flushing = false; - - public void Flush() - { - if (FileOpenAccess == FileAccess.Read || flushing) - return; - - flushing = true; - - // Ensure we've loaded the relationships, parts and properties - int count = Relationships.Count; - - if (packageProperties != null) - packageProperties.Flush(); - - FlushCore(); - - flushing = false; - } - - protected abstract void FlushCore(); - - public PackagePart GetPart(Uri partUri) - { - Check.PartUri(partUri); - return GetPartCore(partUri); - } - - protected abstract PackagePart GetPartCore(Uri partUri); - - public PackagePartCollection GetParts() - { - PartsCollection.Parts.Clear(); - PartsCollection.Parts.AddRange(GetPartsCore()); - return PartsCollection; - } - - protected abstract PackagePart[] GetPartsCore(); - - public PackageRelationship GetRelationship(string id) - { - return Relationships[id]; - } - - public PackageRelationshipCollection GetRelationships() - { - // Ensure the Relationships dict is instantiated first. - ICollection rels = Relationships.Values; - relationshipsCollection.Relationships.Clear(); - relationshipsCollection.Relationships.AddRange(rels); - return relationshipsCollection; - } - - public PackageRelationshipCollection GetRelationshipsByType(string relationshipType) - { - PackageRelationshipCollection collection = new PackageRelationshipCollection(); - foreach (PackageRelationship r in Relationships.Values) - if (r.RelationshipType == relationshipType) - collection.Relationships.Add(r); - - return collection; - } - - private void LoadRelationships() - { - relationships = new Dictionary(); - - if (!PartExists(RelationshipUri)) - return; - - using (Stream stream = GetPart(RelationshipUri).GetStream()) - { - XmlDocument doc = new XmlDocument(); - doc.Load(stream); - XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); - manager.AddNamespace("rel", RelationshipNamespace); - - foreach (XmlNode node in doc.SelectNodes("/rel:Relationships/*", manager)) - { - TargetMode mode = TargetMode.Internal; - if (node.Attributes["TargetMode"] != null) - mode = (TargetMode) Enum.Parse(typeof (TargetMode), node.Attributes["TargetMode"].Value); - - Uri uri; - try - { - uri = new Uri(node.Attributes["Target"].Value.ToString(), UriKind.Relative); - } - catch - { - uri = new Uri(node.Attributes["Target"].Value.ToString(), UriKind.Absolute); - } - CreateRelationship(uri, - mode, - node.Attributes["Type"].Value.ToString(), - node.Attributes["Id"].Value.ToString(), - true); - } - - foreach (PackageRelationship r in relationships.Values) - { - if (r.RelationshipType == PackageProperties.NSPackagePropertiesRelation) - { - PackagePart part = GetPart(PackUriHelper.ResolvePartUri(Uri, r.TargetUri)); - packageProperties = new PackagePropertiesPart(); - packageProperties.Package = this; - packageProperties.Part = part; - packageProperties.LoadFrom(part.GetStream()); - } - } - } - } - - private string NextId() - { - while (true) - { - string s = "Re" + RelationshipId.ToString(); - if (!Relationships.ContainsKey(s)) - return s; - - RelationshipId++; - } - } - - public static Package Open(Stream stream) - { - return Open(stream, FileMode.Open); - } - - public static Package Open(string path) - { - return Open(path, FileMode.OpenOrCreate); - } - - public static Package Open(Stream stream, FileMode packageMode) - { - FileAccess access = packageMode == FileMode.Open ? FileAccess.Read : FileAccess.ReadWrite; - return Open(stream, packageMode, access); - } - - public static Package Open(string path, FileMode packageMode) - { - return Open(path, packageMode, FileAccess.ReadWrite); - } - - public static Package Open(Stream stream, FileMode packageMode, FileAccess packageAccess) - { - return Open(stream, packageMode, packageAccess, false); - } - - private static Package Open(Stream stream, FileMode packageMode, FileAccess packageAccess, bool ownsStream) - { - return OpenCore(stream, packageMode, packageAccess, ownsStream); - } - - public static Package Open(string path, FileMode packageMode, FileAccess packageAccess) - { - return Open(path, packageMode, packageAccess, FileShare.None); - } - - public static Package Open(string path, FileMode packageMode, FileAccess packageAccess, FileShare packageShare) - { - if (packageShare != FileShare.Read && packageShare != FileShare.None) - throw new NotSupportedException("FileShare.Read and FileShare.None are the only supported options"); - - FileInfo info = new FileInfo(path); - - // Bug - MS.NET appears to test for FileAccess.ReadWrite, not FileAccess.Write - if (packageAccess != FileAccess.ReadWrite && !info.Exists) - throw new ArgumentException("packageAccess", "Cannot create stream with FileAccess.Read"); - - - if (info.Exists && packageMode == FileMode.OpenOrCreate && info.Length == 0) - throw new FileFormatException("Stream length cannot be zero with FileMode.Open"); - - Stream s = File.Open(path, packageMode, packageAccess, packageShare); - return Open(s, packageMode, packageAccess, true); - } - - private static Package OpenCore(Stream stream, FileMode packageMode, FileAccess packageAccess, bool ownsStream) - { - if ((packageAccess & FileAccess.Read) == FileAccess.Read && !stream.CanRead) - throw new IOException("Stream does not support reading"); - - if ((packageAccess & FileAccess.Write) == FileAccess.Write && !stream.CanWrite) - throw new IOException("Stream does not support reading"); - - if (!stream.CanSeek) - throw new ArgumentException("stream", "Stream must support seeking"); - - if (packageMode == FileMode.Open && stream.Length == 0) - throw new FileFormatException("Stream length cannot be zero with FileMode.Open"); - - if (packageMode == FileMode.CreateNew && stream.Length > 0) - throw new IOException("Cannot use CreateNew when stream contains data"); - - if (packageMode == FileMode.Append || packageMode == FileMode.Truncate) - { - if (stream.CanWrite) - throw new NotSupportedException(string.Format("PackageMode.{0} is not supported", packageMode)); - else - throw new IOException(string.Format("PackageMode.{0} is not supported", packageMode)); - } - - return new ZipPackage(packageAccess, ownsStream, stream); - } - - public virtual bool PartExists(Uri partUri) - { - return GetPart(partUri) != null; - } - - public bool RelationshipExists(string id) - { - return Relationships.ContainsKey(id); - } - - internal static void WriteRelationships(Dictionary relationships, Stream stream) - { - XmlDocument doc = new XmlDocument(); - XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); - manager.AddNamespace("rel", RelationshipNamespace); - - doc.AppendChild(doc.CreateNode(XmlNodeType.XmlDeclaration, "", "")); - - XmlNode root = doc.CreateNode(XmlNodeType.Element, "Relationships", RelationshipNamespace); - doc.AppendChild(root); - - foreach (PackageRelationship relationship in relationships.Values) - { - XmlNode node = doc.CreateNode(XmlNodeType.Element, "Relationship", RelationshipNamespace); - - XmlAttribute idAtt = doc.CreateAttribute("Id"); - idAtt.Value = relationship.Id; - node.Attributes.Append(idAtt); - - XmlAttribute targetAtt = doc.CreateAttribute("Target"); - targetAtt.Value = relationship.TargetUri.ToString(); - node.Attributes.Append(targetAtt); - - if (relationship.TargetMode != TargetMode.Internal) - { - XmlAttribute modeAtt = doc.CreateAttribute("TargetMode"); - modeAtt.Value = relationship.TargetMode.ToString(); - node.Attributes.Append(modeAtt); - } - XmlAttribute typeAtt = doc.CreateAttribute("Type"); - typeAtt.Value = relationship.RelationshipType; - node.Attributes.Append(typeAtt); - - root.AppendChild(node); - } - - using (XmlTextWriter writer = new XmlTextWriter(stream, System.Text.Encoding.UTF8)) - doc.WriteTo(writer); - } - } - - internal class FileFormatException : Exception - { - public FileFormatException(string message): base(message) - { - - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/PackagePart.cs b/DocX.iOS/System/IO/Packaging/PackagePart.cs deleted file mode 100644 index 0fa11475..00000000 --- a/DocX.iOS/System/IO/Packaging/PackagePart.cs +++ /dev/null @@ -1,257 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -//using DocumentFormat.OpenXml.Packaging; - -namespace System.IO.Packaging -{ - public abstract class PackagePart - { - string contentType; - - internal bool IsRelationship { get; set; } - - int relationshipId; - Dictionary relationships; - PackageRelationshipCollection relationshipsCollection = new PackageRelationshipCollection(); - - Dictionary Relationships - { - get - { - if (relationships == null) - { - relationships = new Dictionary(StringComparer.OrdinalIgnoreCase); - if (Package.PartExists(RelationshipsPartUri)) - using (Stream s = Package.GetPart(RelationshipsPartUri).GetStream()) - LoadRelationships(relationships, s); - } - - return relationships; - } - } - Stream PartStream { get; set; } - - internal Uri RelationshipsPartUri - { - get; - set; - } - - protected PackagePart(Package package, Uri partUri) - : this(package, partUri, null) - { - - } - - protected internal PackagePart(Package package, Uri partUri, string contentType) - : this(package, partUri, contentType, CompressionOption.Normal) - { - - } - - protected internal PackagePart(Package package, Uri partUri, string contentType, CompressionOption compressionOption) - { - Check.Package(package); - Check.PartUri(partUri); - Check.ContentTypeIsValid(contentType); - - Package = package; - Uri = partUri; - ContentType = contentType; - CompressionOption = compressionOption; - RelationshipsPartUri = PackUriHelper.GetRelationshipPartUri(Uri); - } - - public CompressionOption CompressionOption - { - get; - private set; - } - - public string ContentType - { - get - { - if (contentType == null && (contentType = GetContentTypeCore()) == null) - throw new NotSupportedException("If contentType is not supplied in the constructor, GetContentTypeCore must be overridden"); - return contentType; - } - private set - { - contentType = value; - } - } - - public Package Package - { - get; - internal set; - } - - public Uri Uri - { - get; - private set; - } - - private void CheckIsRelationship() - { - if (IsRelationship) - throw new InvalidOperationException("A relationship cannot have relationships to other parts"); - } - - public PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType) - { - return CreateRelationship(targetUri, targetMode, relationshipType, null); - } - - public PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType, string id) - { - return CreateRelationship(targetUri, targetMode, relationshipType, id, false); - } - - private PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType, string id, bool loading) - { - //Package.CheckIsReadOnly(); - Check.TargetUri(targetUri); - Check.RelationshipTypeIsValid(relationshipType); - Check.IdIsValid(id); - - if (id == null) - id = NextId(); - - if (Relationships.ContainsKey(id)) - throw new XmlException("A relationship with this ID already exists"); - - PackageRelationship r = new PackageRelationship(id, Package, relationshipType, Uri, targetMode, targetUri); - Relationships.Add(r.Id, r); - - if (!loading) - WriteRelationships(); - return r; - } - - public void DeleteRelationship(string id) - { - Package.CheckIsReadOnly(); - CheckIsRelationship(); - Relationships.Remove(id); - WriteRelationships(); - } - - void LoadRelationships(Dictionary relationships, Stream stream) - { - XmlDocument doc = new XmlDocument(); - doc.Load(stream); - XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); - manager.AddNamespace("rel", Package.RelationshipNamespace); - - foreach (XmlNode node in doc.SelectNodes("/rel:Relationships/*", manager)) - { - TargetMode mode = TargetMode.Internal; - if (node.Attributes["TargetMode"] != null) - mode = (TargetMode)Enum.Parse(typeof(TargetMode), node.Attributes["TargetMode"].Value); - - CreateRelationship(new Uri(node.Attributes["Target"].Value.ToString(), UriKind.RelativeOrAbsolute), - mode, - node.Attributes["Type"].Value.ToString(), - node.Attributes["Id"].Value.ToString(), - true); - } - } - - public bool RelationshipExists(string id) - { - CheckIsRelationship(); - return Relationships.ContainsKey(id); - } - - public PackageRelationship GetRelationship(string id) - { - CheckIsRelationship(); - return Relationships[id]; - } - - public PackageRelationshipCollection GetRelationships() - { - CheckIsRelationship(); - relationshipsCollection.Relationships.Clear(); - relationshipsCollection.Relationships.AddRange(Relationships.Values); - return relationshipsCollection; - } - - public PackageRelationshipCollection GetRelationshipsByType(string relationshipType) - { - CheckIsRelationship(); - PackageRelationshipCollection collection = new PackageRelationshipCollection(); - foreach (PackageRelationship r in Relationships.Values) - if (r.RelationshipType == relationshipType) - collection.Relationships.Add(r); - - return collection; - } - - public Stream GetStream() - { - return GetStream(Package.FileOpenAccess == FileAccess.Read && !IsRelationship ? FileMode.Open : FileMode.OpenOrCreate); - } - - public Stream GetStream(FileMode mode) - { - return GetStream(mode, IsRelationship ? FileAccess.ReadWrite : Package.FileOpenAccess); - } - - public Stream GetStream(FileMode mode, FileAccess access) - { - bool notAllowed = mode == FileMode.Append || mode == FileMode.CreateNew || mode == FileMode.Truncate; - if (access != FileAccess.Read && notAllowed) - throw new ArgumentException(string.Format(string.Format("FileMode '{0}' not supported", mode))); - - if (access == FileAccess.Read && (notAllowed || mode == FileMode.Create)) - throw new IOException(string.Format("FileMode '{0}' not allowed on a readonly stream", mode)); - - return GetStreamCore(mode, access); - } - - protected abstract Stream GetStreamCore(FileMode mode, FileAccess access); - - protected virtual string GetContentTypeCore() - { - return null; - } - - private string NextId() - { - while (true) - { - string s = "Re" + relationshipId.ToString(); - if (!RelationshipExists(s)) - return s; - relationshipId++; - } - } - - void WriteRelationships() - { - bool exists = Package.PartExists(RelationshipsPartUri); - if (exists && Relationships.Count == 0) - { - Package.DeletePart(RelationshipsPartUri); - return; - } - - if (!exists) - { - PackagePart part = Package.CreatePart(RelationshipsPartUri, Package.RelationshipContentType); - part.IsRelationship = true; - } - using (Stream s = Package.GetPart(RelationshipsPartUri).GetStream()) - Package.WriteRelationships(Relationships, s); - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/PackagePartCollection.cs b/DocX.iOS/System/IO/Packaging/PackagePartCollection.cs deleted file mode 100644 index 6464aad8..00000000 --- a/DocX.iOS/System/IO/Packaging/PackagePartCollection.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System.IO.Packaging -{ - public class PackagePartCollection : IEnumerable, IEnumerable - { - internal List Parts { get; private set; } - - internal PackagePartCollection() - { - Parts = new List(); - } - - public IEnumerator GetEnumerator() - { - return Parts.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return Parts.GetEnumerator(); - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/PackageProperties.cs b/DocX.iOS/System/IO/Packaging/PackageProperties.cs deleted file mode 100644 index 16fba98c..00000000 --- a/DocX.iOS/System/IO/Packaging/PackageProperties.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; - -namespace System.IO.Packaging -{ - public abstract class PackageProperties : IDisposable - { - internal const string NSPackageProperties = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"; - internal const string NSPackagePropertiesRelation = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"; - internal const string PackagePropertiesContentType = "application/vnd.openxmlformats-package.core-properties+xml"; - - - static int uuid; - - protected PackageProperties() - { - - } - - public abstract string Category { get; set; } - public abstract string ContentStatus { get; set; } - public abstract string ContentType { get; set; } - public abstract DateTime? Created { get; set; } - public abstract string Creator { get; set; } - public abstract string Description { get; set; } - public abstract string Identifier { get; set; } - public abstract string Keywords { get; set; } - public abstract string Language { get; set; } - public abstract string LastModifiedBy { get; set; } - public abstract DateTime? LastPrinted { get; set; } - public abstract DateTime? Modified { get; set; } - internal Package Package { get; set; } - internal PackagePart Part { get; set; } - public abstract string Revision { get; set; } - public abstract string Subject { get; set; } - public abstract string Title { get; set; } - public abstract string Version { get; set; } - - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - // Nothing - } - - internal void Flush() - { - using (MemoryStream temp = new MemoryStream()) - { - using (XmlTextWriter writer = new XmlTextWriter(temp, System.Text.Encoding.UTF8)) - { - WriteTo(writer); - writer.Flush(); - if (temp.Length == 0) - return; - } - } - - if (Part == null) - { - int id = System.Threading.Interlocked.Increment(ref uuid); - Uri uri = new Uri(string.Format("/package/services/metadata/core-properties/{0}.psmdcp", id), UriKind.Relative); - Part = Package.CreatePart(uri, PackagePropertiesContentType); - PackageRelationship rel = Package.CreateRelationship(uri, TargetMode.Internal, NSPackagePropertiesRelation); - } - - using (Stream s = Part.GetStream(FileMode.Create)) - using (XmlTextWriter writer = new XmlTextWriter(s, System.Text.Encoding.UTF8)) - WriteTo(writer); - } - - internal virtual void LoadFrom(Stream stream) - { - - } - - internal virtual void WriteTo(XmlTextWriter writer) - { - - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/PackagePropertiesPart.cs b/DocX.iOS/System/IO/Packaging/PackagePropertiesPart.cs deleted file mode 100644 index e9f0dde8..00000000 --- a/DocX.iOS/System/IO/Packaging/PackagePropertiesPart.cs +++ /dev/null @@ -1,355 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; - -namespace System.IO.Packaging -{ - class PackagePropertiesPart : PackageProperties - { - const string NSDc = "http://purl.org/dc/elements/1.1/"; - const string NSDcTerms = "http://purl.org/dc/terms/"; - const string NSXsi = "http://www.w3.org/2001/XMLSchema-instance"; - - string category; - string contentStatus; - string contentType; - DateTime? created; - string creator; - string description; - string identifier; - string keywords; - string language; - string lastModifiedBy; - DateTime? lastPrinted; - DateTime? modified; - string revision; - string subject; - string title; - string version; - - public PackagePropertiesPart() - { - - } - - public override string Category - { - get - { - return category; - } - set - { - Package.CheckIsReadOnly(); - category = value; - } - } - public override string ContentStatus - { - get - { - return contentStatus; - } - set - { - Package.CheckIsReadOnly(); - contentStatus = value; - } - } - public override string ContentType - { - get - { - return contentType; - } - set - { - Package.CheckIsReadOnly(); - contentType = value; - } - } - public override DateTime? Created - { - get - { - return created; - } - set - { - Package.CheckIsReadOnly(); - created = value; - } - } - public override string Creator - { - get - { - return creator; - } - set - { - Package.CheckIsReadOnly(); - creator = value; - } - } - public override string Description - { - get - { - return description; - } - set - { - Package.CheckIsReadOnly(); - description = value; - } - } - public override string Identifier - { - get - { - return identifier; - } - set - { - Package.CheckIsReadOnly(); - identifier = value; - } - } - public override string Keywords - { - get - { - return keywords; - } - set - { - Package.CheckIsReadOnly(); - keywords = value; - } - } - public override string Language - { - get - { - return language; - } - set - { - Package.CheckIsReadOnly(); - language = value; - } - } - public override string LastModifiedBy - { - get - { - return lastModifiedBy; - } - set - { - Package.CheckIsReadOnly(); - lastModifiedBy = value; - } - } - public override DateTime? LastPrinted - { - get - { - return lastPrinted; - } - set - { - Package.CheckIsReadOnly(); - lastPrinted = value; - } - } - public override DateTime? Modified - { - get - { - return modified; - } - set - { - Package.CheckIsReadOnly(); - modified = value; - } - } - public override string Revision - { - get - { - return revision; - } - set - { - Package.CheckIsReadOnly(); - revision = value; - } - } - public override string Subject - { - get - { - return subject; - } - set - { - Package.CheckIsReadOnly(); - subject = value; - } - } - public override string Title - { - get - { - return title; - } - set - { - Package.CheckIsReadOnly(); - title = value; - } - } - public override string Version - { - get - { - return version; - } - set - { - Package.CheckIsReadOnly(); - version = value; - } - } - - internal override void LoadFrom(Stream stream) - { - if (stream.Length == 0) - return; - - XmlDocument doc = new XmlDocument(); - doc.Load(stream); - - XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); - manager.AddNamespace("prop", NSPackageProperties); - manager.AddNamespace("dc", NSDc); - manager.AddNamespace("dcterms", NSDcTerms); - manager.AddNamespace("xsi", NSXsi); - - XmlNode node; - if ((node = doc.SelectSingleNode("prop:coreProperties/prop:category", manager)) != null) - category = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/prop:contentStatus", manager)) != null) - contentStatus = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/prop:contentType", manager)) != null) - contentType = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/dcterms:created", manager)) != null) - created = DateTime.Parse(node.InnerXml); - if ((node = doc.SelectSingleNode("prop:coreProperties/dc:creator", manager)) != null) - creator = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/dc:description", manager)) != null) - description = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/dc:identifier", manager)) != null) - identifier = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/prop:keywords", manager)) != null) - keywords = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/dc:language", manager)) != null) - language = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/prop:lastModifiedBy", manager)) != null) - lastModifiedBy = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/prop:lastPrinted", manager)) != null) - lastPrinted = DateTime.Parse(node.InnerXml); - if ((node = doc.SelectSingleNode("prop:coreProperties/dcterms:modified", manager)) != null) - modified = DateTime.Parse(node.InnerXml); - if ((node = doc.SelectSingleNode("prop:coreProperties/prop:revision", manager)) != null) - revision = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/dc:subject", manager)) != null) - subject = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/dc:title", manager)) != null) - title = node.InnerXml; - if ((node = doc.SelectSingleNode("prop:coreProperties/prop:version", manager)) != null) - version = node.InnerXml; - } - - internal override void WriteTo(XmlTextWriter writer) - { - XmlDocument doc = new XmlDocument(); - XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); - manager.AddNamespace("prop", NSPackageProperties); - manager.AddNamespace("dc", NSDc); - manager.AddNamespace("dcterms", NSDcTerms); - manager.AddNamespace("xsi", NSXsi); - - // Create XML declaration - doc.AppendChild(doc.CreateXmlDeclaration("1.0", "UTF-8", null)); - - // Create root node with required namespace declarations - XmlNode coreProperties = doc.AppendChild(doc.CreateNode(XmlNodeType.Element, "coreProperties", NSPackageProperties)); - coreProperties.Attributes.Append(doc.CreateAttribute("xmlns:dc")).Value = NSDc; - coreProperties.Attributes.Append(doc.CreateAttribute("xmlns:dcterms")).Value = NSDcTerms; - coreProperties.Attributes.Append(doc.CreateAttribute("xmlns:xsi")).Value = NSXsi; - - // Create the children - if (Category != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "category", NSPackageProperties)).InnerXml = Category; - if (ContentStatus != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "contentStatus", NSPackageProperties)).InnerXml = ContentStatus; - if (ContentType != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "contentType", NSPackageProperties)).InnerXml = ContentType; - if (Created.HasValue) - { - XmlAttribute att = doc.CreateAttribute("xsi", "type", NSXsi); - att.Value = "dcterms:W3CDTF"; - - XmlNode created = coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dcterms", "created", NSDcTerms)); - created.Attributes.Append(att); - created.InnerXml = Created.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss") + "Z"; - } - if (Creator != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "creator", NSDc)).InnerXml = Creator; - if (Description != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "description", NSDc)).InnerXml = Description; - if (Identifier != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "identifier", NSDc)).InnerXml = Identifier; - if (Keywords != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "keywords", NSPackageProperties)).InnerXml = Keywords; - if (Language != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "language", NSDc)).InnerXml = Language; - if (LastModifiedBy != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "lastModifiedBy", NSPackageProperties)).InnerXml = LastModifiedBy; - if (LastPrinted.HasValue) - { - XmlNode lastPrinted = coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "lastPrinted", NSPackageProperties)); - - lastPrinted.InnerXml = LastPrinted.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss") + "Z"; - } - if (Revision != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "revision", NSPackageProperties)).InnerXml = Revision; - if (Subject != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "subject", NSDc)).InnerXml = Subject; - if (Title != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "title", NSDc)).InnerXml = Title; - if (Version != null) - coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "version", NSPackageProperties)).InnerXml = Version; - - if (Modified.HasValue) - { - XmlAttribute att = doc.CreateAttribute("xsi", "type", NSXsi); - att.Value = "dcterms:W3CDTF"; - - XmlNode modified = coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dcterms", "modified", NSDcTerms)); - modified.Attributes.Append(att); - modified.InnerXml = Modified.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss") + "Z"; - } - - doc.WriteContentTo(writer); - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/PackageRelationship.cs b/DocX.iOS/System/IO/Packaging/PackageRelationship.cs deleted file mode 100644 index 2d03d4ef..00000000 --- a/DocX.iOS/System/IO/Packaging/PackageRelationship.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System.IO.Packaging -{ - public class PackageRelationship - { - internal PackageRelationship(string id, Package package, string relationshipType, - Uri sourceUri, TargetMode targetMode, Uri targetUri) - { - Check.IdIsValid(id); - Check.Package(package); - Check.RelationshipTypeIsValid(relationshipType); - Check.SourceUri(sourceUri); - Check.TargetUri(targetUri); - - Id = id; - Package = package; - RelationshipType = relationshipType; - SourceUri = sourceUri; - TargetMode = targetMode; - TargetUri = targetUri; - } - - public string Id - { - get; - private set; - } - public Package Package - { - get; - private set; - } - public string RelationshipType - { - get; - private set; - } - public Uri SourceUri - { - get; - private set; - } - public TargetMode TargetMode - { - get; - private set; - } - public Uri TargetUri - { - get; - private set; - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/PackageRelationshipCollection.cs b/DocX.iOS/System/IO/Packaging/PackageRelationshipCollection.cs deleted file mode 100644 index 8dfcd1e1..00000000 --- a/DocX.iOS/System/IO/Packaging/PackageRelationshipCollection.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System.IO.Packaging -{ - public class PackageRelationshipCollection : IEnumerable, IEnumerable - { - internal List Relationships { get; private set; } - - internal PackageRelationshipCollection() - { - Relationships = new List(); - } - - public IEnumerator GetEnumerator() - { - return Relationships.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/TargetMode.cs b/DocX.iOS/System/IO/Packaging/TargetMode.cs deleted file mode 100644 index 46c503ec..00000000 --- a/DocX.iOS/System/IO/Packaging/TargetMode.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System.IO.Packaging -{ - public enum TargetMode - { - Internal, - External - } -} diff --git a/DocX.iOS/System/IO/Packaging/ZipPackage.cs b/DocX.iOS/System/IO/Packaging/ZipPackage.cs deleted file mode 100644 index 75141e1a..00000000 --- a/DocX.iOS/System/IO/Packaging/ZipPackage.cs +++ /dev/null @@ -1,266 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using DocX.iOS.Zip; - -namespace System.IO.Packaging -{ - class UriComparer : IEqualityComparer - { - public int GetHashCode(Uri uri) - { - return 1; - } - - public bool Equals(Uri x, Uri y) - { - return x.OriginalString.Equals(y.OriginalString, StringComparison.OrdinalIgnoreCase); - } - } - - public sealed class ZipPackage : Package - { - public ZipStorer Archive { get; set; } - private const string ContentNamespace = "http://schemas.openxmlformats.org/package/2006/content-types"; - private const string ContentUri = "[Content_Types].xml"; - - bool OwnsStream - { - get; - set; - } - - Dictionary parts; - internal Dictionary PartStreams = new Dictionary(new UriComparer()); - - internal Stream PackageStream { get; set; } - - Dictionary Parts - { - get - { - if (parts == null) - LoadParts(); - return parts; - } - } - - internal ZipPackage(FileAccess access, bool ownsStream, Stream stream) - : base(access) - { - OwnsStream = ownsStream; - PackageStream = stream; - } - - internal ZipPackage(FileAccess access, bool ownsStream, Stream stream, bool streaming) - : base(access, streaming) - { - OwnsStream = ownsStream; - PackageStream = stream; - } - - protected override void Dispose(bool disposing) - { - foreach (Stream s in PartStreams.Values) - s.Close(); - - if (Archive != null) // GZE fixed bug where Archive == null - { - Archive.Close(); - } - - base.Dispose(disposing); - - if (OwnsStream) - PackageStream.Close(); - } - - protected override void FlushCore() - { - // Ensure that all the data has been read out of the package - // stream already. Otherwise we'll lose data when we recreate the zip - - foreach (ZipPackagePart part in Parts.Values) - { - part.GetStream(); - } - if (!PackageStream.CanSeek) - return; - // Empty the package stream - PackageStream.Position = 0; - PackageStream.SetLength(0); - - // Recreate the zip file - using (ZipStorer archive = ZipStorer.Create(PackageStream, "", false)) - { - - // Write all the part streams - foreach (ZipPackagePart part in Parts.Values) - { - Stream partStream = part.GetStream(); - partStream.Seek(0, SeekOrigin.Begin); - - archive.AddStream(ZipStorer.Compression.Deflate, part.Uri.ToString().Substring(1), partStream, - DateTime.UtcNow, ""); - } - - using (var ms = new MemoryStream()) - { - WriteContentType(ms); - ms.Seek(0, SeekOrigin.Begin); - - archive.AddStream(ZipStorer.Compression.Deflate, ContentUri, ms, DateTime.UtcNow, ""); - } - } - } - - - protected override PackagePart CreatePartCore(Uri partUri, string contentType, CompressionOption compressionOption) - { - ZipPackagePart part = new ZipPackagePart(this, partUri, contentType, compressionOption); - Parts.Add(part.Uri, part); - return part; - } - - protected override void DeletePartCore(Uri partUri) - { - Parts.Remove(partUri); - } - - protected override PackagePart GetPartCore(Uri partUri) - { - ZipPackagePart part; - Parts.TryGetValue(partUri, out part); - return part; - } - - protected override PackagePart[] GetPartsCore() - { - ZipPackagePart[] p = new ZipPackagePart[Parts.Count]; - Parts.Values.CopyTo(p, 0); - return p; - } - - void LoadParts() - { - parts = new Dictionary(new UriComparer()); - try - { - PackageStream.Seek(0, SeekOrigin.Begin); - if (Archive == null) - { - Archive = ZipStorer.Open(PackageStream, FileAccess.Read, false); - } - List dir = Archive.ReadCentralDir(); - - // Load the content type map file - XmlDocument doc = new XmlDocument(); - var content = dir.FirstOrDefault(x => x.FilenameInZip == ContentUri); - using (var ms = new MemoryStream()) - { - Archive.ExtractFile(content, ms); - ms.Seek(0, SeekOrigin.Begin); - doc.Load(ms); - } - - XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); - manager.AddNamespace("content", ContentNamespace); - - // The file names in the zip archive are not prepended with '/' - foreach (var file in dir) - { - if (file.FilenameInZip.Equals(ContentUri, StringComparison.Ordinal)) - continue; - - XmlNode node; - - if (file.FilenameInZip == RelationshipUri.ToString().Substring(1)) - { - CreatePartCore(RelationshipUri, RelationshipContentType, CompressionOption.Normal); - continue; - } - - string xPath = string.Format("/content:Types/content:Override[@PartName='/{0}']", file); - node = doc.SelectSingleNode(xPath, manager); - - if (node == null) - { - string ext = Path.GetExtension(file.FilenameInZip); - if (ext.StartsWith(".")) - ext = ext.Substring(1); - xPath = string.Format("/content:Types/content:Default[@Extension='{0}']", ext); - node = doc.SelectSingleNode(xPath, manager); - } - - // What do i do if the node is null? This means some has tampered with the - // package file manually - if (node != null) - CreatePartCore(new Uri("/" + file, UriKind.Relative), node.Attributes["ContentType"].Value, - CompressionOption.Normal); - } - } - catch - { - // The archive is invalid - therefore no parts - } - } - - void WriteContentType(Stream s) - { - XmlDocument doc = new XmlDocument(); - XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); - Dictionary mimes = new Dictionary(); - - manager.AddNamespace("content", ContentNamespace); - - doc.AppendChild(doc.CreateNode(XmlNodeType.XmlDeclaration, "", "")); - - XmlNode root = doc.CreateNode(XmlNodeType.Element, "Types", ContentNamespace); - doc.AppendChild(root); - foreach (ZipPackagePart part in Parts.Values) - { - XmlNode node = null; - string existingMimeType; - - var extension = Path.GetExtension(part.Uri.OriginalString); - if (extension.Length > 0) - extension = extension.Substring(1); - - if (!mimes.TryGetValue(extension, out existingMimeType)) - { - node = doc.CreateNode(XmlNodeType.Element, "Default", ContentNamespace); - - XmlAttribute ext = doc.CreateAttribute("Extension"); - ext.Value = extension; - node.Attributes.Append(ext); - mimes[extension] = part.ContentType; - } - else if (part.ContentType != existingMimeType) - { - node = doc.CreateNode(XmlNodeType.Element, "Override", ContentNamespace); - - XmlAttribute name = doc.CreateAttribute("PartName"); - name.Value = part.Uri.ToString(); - node.Attributes.Append(name); - } - - if (node != null) - { - XmlAttribute contentType = doc.CreateAttribute("ContentType"); - contentType.Value = part.ContentType; - node.Attributes.Prepend(contentType); - - root.AppendChild(node); - } - } - - XmlTextWriter writer = new XmlTextWriter(s, System.Text.Encoding.UTF8); - doc.WriteTo(writer); - writer.Flush(); - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/ZipPackagePart.cs b/DocX.iOS/System/IO/Packaging/ZipPackagePart.cs deleted file mode 100644 index e9aeeed7..00000000 --- a/DocX.iOS/System/IO/Packaging/ZipPackagePart.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using DocX.iOS.Zip; - -namespace System.IO.Packaging -{ - public sealed class ZipPackagePart : PackagePart - { - new ZipPackage Package - { - get { return (ZipPackage)base.Package; } - } - - internal ZipPackagePart(Package package, Uri partUri) - : base(package, partUri) - { - - } - - internal ZipPackagePart(Package package, Uri partUri, string contentType) - : base(package, partUri, contentType) - { - - } - - internal ZipPackagePart(Package package, Uri partUri, string contentType, CompressionOption compressionOption) - : base(package, partUri, contentType, compressionOption) - { - - } - - protected override Stream GetStreamCore(FileMode mode, FileAccess access) - { - ZipPartStream zps; - MemoryStream stream; - if (Package.PartStreams.TryGetValue(Uri, out stream)) - { - //zps = new ZipPartStream(Package, stream, access); - if (mode == FileMode.Create) - stream.SetLength(0); - return new ZipPartStream(Package, stream, access); - } - - stream = new MemoryStream(); - try - { - if (Package.Archive == null) - { - Package.Archive = ZipStorer.Open(Package.PackageStream, access, false); - } - List dir = Package.Archive.ReadCentralDir(); - foreach (ZipStorer.ZipFileEntry entry in dir) - { - if (entry.FilenameInZip != Uri.ToString().Substring(1)) - continue; - - Package.Archive.ExtractFile(entry, stream); - } - } - catch - { - // The zipfile is invalid, so just create the file - // as if it didn't exist - stream.SetLength(0); - } - - Package.PartStreams.Add(Uri, stream); - if (mode == FileMode.Create) - stream.SetLength(0); - return new ZipPartStream(Package, stream, access); - } - } -} diff --git a/DocX.iOS/System/IO/Packaging/ZipPartStream.cs b/DocX.iOS/System/IO/Packaging/ZipPartStream.cs deleted file mode 100644 index 3ab84ea1..00000000 --- a/DocX.iOS/System/IO/Packaging/ZipPartStream.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System.IO.Packaging -{ - internal class ZipPartStream : Stream - { - public MemoryStream BaseStream { get; private set; } - public ZipPackage Package { get; private set; } - - public override bool CanRead - { - get - { - return BaseStream.CanRead; - } - } - - public override bool CanSeek - { - get - { - return BaseStream.CanSeek; - } - } - - public override bool CanTimeout - { - get { return BaseStream.CanTimeout; } - } - - public override bool CanWrite - { - get { return Writeable; } - } - - public override long Length - { - get { return BaseStream.Length; } - } - - public override long Position - { - get; - set; - } - - public bool Writeable - { - get; - set; - } - - public override int WriteTimeout - { - get - { - return BaseStream.WriteTimeout; - } - set - { - BaseStream.WriteTimeout = value; - } - } - - public override int ReadTimeout - { - get - { - return BaseStream.ReadTimeout; - } - set - { - BaseStream.ReadTimeout = value; - } - } - - public ZipPartStream(ZipPackage package, MemoryStream stream, FileAccess access) - { - BaseStream = stream; - Package = package; - Writeable = access != FileAccess.Read; - } - - public override void Flush() - { - // If the user flushes any of the part streams, - // we need to flush the entire package - - // FIXME: Ensure that this actually happens with a testcase - // ...if possible - // Package.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - Seek(Position, SeekOrigin.Begin); - int read = BaseStream.Read(buffer, offset, count); - Position += read; - return read; - } - - public override long Seek(long offset, SeekOrigin origin) - { - Position = BaseStream.Seek(offset, origin); - return Position; - } - - public override void SetLength(long value) - { - if (!CanWrite) - throw new InvalidOperationException("Stream is not writeable"); - - BaseStream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (!CanWrite) - throw new InvalidOperationException("Stream is not writeable"); - - Seek(Position, SeekOrigin.Begin); - BaseStream.Write(buffer, offset, count); - Position += count; - } - } -} diff --git a/DocX.iOS/Zip/ZipStorer.cs b/DocX.iOS/Zip/ZipStorer.cs deleted file mode 100644 index af399cbf..00000000 --- a/DocX.iOS/Zip/ZipStorer.cs +++ /dev/null @@ -1,758 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DocX.iOS.Zip -{ - /// - /// Unique class for compression/decompression file. Represents a Zip file. - /// - public class ZipStorer : IDisposable - { - /// - /// Compression method enumeration - /// - public enum Compression : ushort - { - /// Uncompressed storage - Store = 0, - /// Deflate compression method - Deflate = 8 - } - - /// - /// Represents an entry in Zip file directory - /// - public struct ZipFileEntry - { - /// Compression method - public Compression Method; - /// Full path and filename as stored in Zip - public string FilenameInZip; - /// Original file size - public uint FileSize; - /// Compressed file size - public uint CompressedSize; - /// Offset of header information inside Zip storage - public uint HeaderOffset; - /// Offset of file inside Zip storage - public uint FileOffset; - /// Size of header information - public uint HeaderSize; - /// 32-bit checksum of entire file - public uint Crc32; - /// Last modification time of file - public DateTime ModifyTime; - /// User comment for file - public string Comment; - /// True if UTF8 encoding for filename and comments, false if default (CP 437) - public bool EncodeUTF8; - - /// Overriden method - /// Filename in Zip - public override string ToString() - { - return this.FilenameInZip; - } - } - - #region Public fields - /// True if UTF8 encoding for filename and comments, false if default (CP 437) - public bool EncodeUTF8 = false; - /// Force deflate algotithm even if it inflates the stored file. Off by default. - public bool ForceDeflating = false; - #endregion - - #region Private fields - // List of files to store - private List Files = new List(); - // Filename of storage file - private string FileName; - // Stream object of storage file - private Stream ZipFileStream; - private bool OwnsStream = true; - // General comment - private string Comment = ""; - // Central dir image - private byte[] CentralDirImage = null; - // Existing files in zip - private ushort ExistingFiles = 0; - // File access for Open method - private FileAccess Access; - // Static CRC32 Table - private static UInt32[] CrcTable = null; - // Default filename encoder - private static Encoding DefaultEncoding = Encoding.GetEncoding(437); - #endregion - - #region Public methods - // Static constructor. Just invoked once in order to create the CRC32 lookup table. - static ZipStorer() - { - // Generate CRC32 table - CrcTable = new UInt32[256]; - for (int i = 0; i < CrcTable.Length; i++) - { - UInt32 c = (UInt32)i; - for (int j = 0; j < 8; j++) - { - if ((c & 1) != 0) - c = 3988292384 ^ (c >> 1); - else - c >>= 1; - } - CrcTable[i] = c; - } - } - /// - /// Method to create a new storage file - /// - /// Full path of Zip file to create - /// General comment for Zip file - /// A valid ZipStorer object - public static ZipStorer Create(string _filename, string _comment) - { - Stream stream = new FileStream(_filename, FileMode.Create, FileAccess.ReadWrite); - - ZipStorer zip = Create(stream, _comment, true); - zip.Comment = _comment; - zip.FileName = _filename; - - return zip; - } - /// - /// Method to create a new zip storage in a stream - /// - /// - /// - /// A valid ZipStorer object - public static ZipStorer Create(Stream _stream, string _comment, bool _ownsStream = false) - { - ZipStorer zip = new ZipStorer(); - zip.Comment = _comment; - zip.ZipFileStream = _stream; - zip.OwnsStream = _ownsStream; - zip.Access = FileAccess.Write; - - return zip; - } - /// - /// Method to open an existing storage file - /// - /// Full path of Zip file to open - /// File access mode as used in FileStream constructor - /// A valid ZipStorer object - public static ZipStorer Open(string _filename, FileAccess _access) - { - Stream stream = (Stream)new FileStream(_filename, FileMode.Open, _access == FileAccess.Read ? FileAccess.Read : FileAccess.ReadWrite); - - ZipStorer zip = Open(stream, _access, true); - zip.FileName = _filename; - - return zip; - } - /// - /// Method to open an existing storage from stream - /// - /// Already opened stream with zip contents - /// File access mode for stream operations - /// A valid ZipStorer object - public static ZipStorer Open(Stream _stream, FileAccess _access, bool _ownsStream = false) - { - if (!_stream.CanSeek && _access != FileAccess.Read) - throw new InvalidOperationException("Stream cannot seek"); - - ZipStorer zip = new ZipStorer(); - //zip.FileName = _filename; - zip.ZipFileStream = _stream; - zip.OwnsStream = _ownsStream; - zip.Access = _access; - - if (zip.ReadFileInfo()) - return zip; - - throw new System.IO.InvalidDataException(); - } - /// - /// Add full contents of a file into the Zip storage - /// - /// Compression method - /// Full path of file to add to Zip storage - /// Filename and path as desired in Zip directory - /// Comment for stored file - public void AddFile(Compression _method, string _pathname, string _filenameInZip, string _comment) - { - if (Access == FileAccess.Read) - throw new InvalidOperationException("Writing is not alowed"); - - FileStream stream = new FileStream(_pathname, FileMode.Open, FileAccess.Read); - AddStream(_method, _filenameInZip, stream, File.GetLastWriteTime(_pathname), _comment); - stream.Close(); - } - /// - /// Add full contents of a stream into the Zip storage - /// - /// Compression method - /// Filename and path as desired in Zip directory - /// Stream object containing the data to store in Zip - /// Modification time of the data to store - /// Comment for stored file - public void AddStream(Compression _method, string _filenameInZip, Stream _source, DateTime _modTime, string _comment) - { - if (Access == FileAccess.Read) - throw new InvalidOperationException("Writing is not alowed"); - - long offset; - if (this.Files.Count == 0) - offset = 0; - else - { - ZipFileEntry last = this.Files[this.Files.Count - 1]; - offset = last.HeaderOffset + last.HeaderSize; - } - - // Prepare the fileinfo - ZipFileEntry zfe = new ZipFileEntry(); - zfe.Method = _method; - zfe.EncodeUTF8 = this.EncodeUTF8; - zfe.FilenameInZip = NormalizedFilename(_filenameInZip); - zfe.Comment = (_comment == null ? "" : _comment); - - // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc. - zfe.Crc32 = 0; // to be updated later - zfe.HeaderOffset = (uint)this.ZipFileStream.Position; // offset within file of the start of this local record - zfe.ModifyTime = _modTime; - - // Write local header - WriteLocalHeader(ref zfe); - zfe.FileOffset = (uint)this.ZipFileStream.Position; - - // Write file to zip (store) - Store(ref zfe, _source); - _source.Close(); - - this.UpdateCrcAndSizes(ref zfe); - - Files.Add(zfe); - } - /// - /// Updates central directory (if pertinent) and close the Zip storage - /// - /// This is a required step, unless automatic dispose is used - public void Close() - { - if (this.Access != FileAccess.Read) - { - uint centralOffset = (uint)this.ZipFileStream.Position; - uint centralSize = 0; - - if (this.CentralDirImage != null) - this.ZipFileStream.Write(CentralDirImage, 0, CentralDirImage.Length); - - for (int i = 0; i < Files.Count; i++) - { - long pos = this.ZipFileStream.Position; - this.WriteCentralDirRecord(Files[i]); - centralSize += (uint)(this.ZipFileStream.Position - pos); - } - - if (this.CentralDirImage != null) - this.WriteEndRecord(centralSize + (uint)CentralDirImage.Length, centralOffset); - else - this.WriteEndRecord(centralSize, centralOffset); - } - - if (this.ZipFileStream != null && ZipFileStream.CanSeek) - { - this.ZipFileStream.Flush(); - - // GZE added ownsStream, to prevent premature closure - - if (this.OwnsStream) - { - this.ZipFileStream.Dispose(); - } - - this.ZipFileStream = null; - } - } - /// - /// Read all the file records in the central directory - /// - /// List of all entries in directory - public List ReadCentralDir() - { - if (this.CentralDirImage == null) - throw new InvalidOperationException("Central directory currently does not exist"); - - List result = new List(); - - for (int pointer = 0; pointer < this.CentralDirImage.Length; ) - { - uint signature = BitConverter.ToUInt32(CentralDirImage, pointer); - if (signature != 0x02014b50) - break; - - bool encodeUTF8 = (BitConverter.ToUInt16(CentralDirImage, pointer + 8) & 0x0800) != 0; - ushort method = BitConverter.ToUInt16(CentralDirImage, pointer + 10); - uint modifyTime = BitConverter.ToUInt32(CentralDirImage, pointer + 12); - uint crc32 = BitConverter.ToUInt32(CentralDirImage, pointer + 16); - uint comprSize = BitConverter.ToUInt32(CentralDirImage, pointer + 20); - uint fileSize = BitConverter.ToUInt32(CentralDirImage, pointer + 24); - ushort filenameSize = BitConverter.ToUInt16(CentralDirImage, pointer + 28); - ushort extraSize = BitConverter.ToUInt16(CentralDirImage, pointer + 30); - ushort commentSize = BitConverter.ToUInt16(CentralDirImage, pointer + 32); - uint headerOffset = BitConverter.ToUInt32(CentralDirImage, pointer + 42); - uint headerSize = (uint)(46 + filenameSize + extraSize + commentSize); - - Encoding encoder = encodeUTF8 ? Encoding.UTF8 : DefaultEncoding; - - ZipFileEntry zfe = new ZipFileEntry(); - zfe.Method = (Compression)method; - zfe.FilenameInZip = encoder.GetString(CentralDirImage, pointer + 46, filenameSize); - zfe.FileOffset = GetFileOffset(headerOffset); - zfe.FileSize = fileSize; - zfe.CompressedSize = comprSize; - zfe.HeaderOffset = headerOffset; - zfe.HeaderSize = headerSize; - zfe.Crc32 = crc32; - zfe.ModifyTime = DosTimeToDateTime(modifyTime); - if (commentSize > 0) - zfe.Comment = encoder.GetString(CentralDirImage, pointer + 46 + filenameSize + extraSize, commentSize); - - result.Add(zfe); - pointer += (46 + filenameSize + extraSize + commentSize); - } - - return result; - } - /// - /// Copy the contents of a stored file into a physical file - /// - /// Entry information of file to extract - /// Name of file to store uncompressed data - /// True if success, false if not. - /// Unique compression methods are Store and Deflate - public bool ExtractFile(ZipFileEntry _zfe, string _filename) - { - // Make sure the parent directory exist - string path = System.IO.Path.GetDirectoryName(_filename); - - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - // Check it is directory. If so, do nothing - if (Directory.Exists(_filename)) - return true; - - Stream output = new FileStream(_filename, FileMode.Create, FileAccess.Write); - bool result = ExtractFile(_zfe, output); - if (result) - output.Close(); - - File.SetCreationTime(_filename, _zfe.ModifyTime); - File.SetLastWriteTime(_filename, _zfe.ModifyTime); - - return result; - } - /// - /// Copy the contents of a stored file into an opened stream - /// - /// Entry information of file to extract - /// Stream to store the uncompressed data - /// True if success, false if not. - /// Unique compression methods are Store and Deflate - public bool ExtractFile(ZipFileEntry _zfe, Stream _stream) - { - if (!_stream.CanWrite) - throw new InvalidOperationException("Stream cannot be written"); - - // check signature - byte[] signature = new byte[4]; - this.ZipFileStream.Seek(_zfe.HeaderOffset, SeekOrigin.Begin); - this.ZipFileStream.Read(signature, 0, 4); - if (BitConverter.ToUInt32(signature, 0) != 0x04034b50) - return false; - - // Select input stream for inflating or just reading - Stream inStream; - if (_zfe.Method == Compression.Store) - inStream = this.ZipFileStream; - else if (_zfe.Method == Compression.Deflate) - inStream = new DeflateStream(this.ZipFileStream, CompressionMode.Decompress, true); - else - return false; - - // Buffered copy - byte[] buffer = new byte[16384]; - this.ZipFileStream.Seek(_zfe.FileOffset, SeekOrigin.Begin); - uint bytesPending = _zfe.FileSize; - while (bytesPending > 0) - { - int bytesRead = inStream.Read(buffer, 0, (int)Math.Min(bytesPending, buffer.Length)); - _stream.Write(buffer, 0, bytesRead); - bytesPending -= (uint)bytesRead; - } - _stream.Flush(); - - if (_zfe.Method == Compression.Deflate) - inStream.Dispose(); - return true; - } - /// - /// Removes one of many files in storage. It creates a new Zip file. - /// - /// Reference to the current Zip object - /// List of Entries to remove from storage - /// True if success, false if not - /// This method only works for storage of type FileStream - public static bool RemoveEntries(ref ZipStorer _zip, List _zfes) - { - if (!(_zip.ZipFileStream is FileStream)) - throw new InvalidOperationException("RemoveEntries is allowed just over streams of type FileStream"); - - - //Get full list of entries - List fullList = _zip.ReadCentralDir(); - - //In order to delete we need to create a copy of the zip file excluding the selected items - string tempZipName = Path.GetTempFileName(); - string tempEntryName = Path.GetTempFileName(); - - try - { - ZipStorer tempZip = ZipStorer.Create(tempZipName, string.Empty); - - foreach (ZipFileEntry zfe in fullList) - { - if (!_zfes.Contains(zfe)) - { - if (_zip.ExtractFile(zfe, tempEntryName)) - { - tempZip.AddFile(zfe.Method, tempEntryName, zfe.FilenameInZip, zfe.Comment); - } - } - } - _zip.Close(); - tempZip.Close(); - - File.Delete(_zip.FileName); - File.Move(tempZipName, _zip.FileName); - - _zip = ZipStorer.Open(_zip.FileName, _zip.Access); - } - catch - { - return false; - } - finally - { - if (File.Exists(tempZipName)) - File.Delete(tempZipName); - if (File.Exists(tempEntryName)) - File.Delete(tempEntryName); - } - return true; - } - #endregion - - #region Private methods - // Calculate the file offset by reading the corresponding local header - private uint GetFileOffset(uint _headerOffset) - { - byte[] buffer = new byte[2]; - - this.ZipFileStream.Seek(_headerOffset + 26, SeekOrigin.Begin); - this.ZipFileStream.Read(buffer, 0, 2); - ushort filenameSize = BitConverter.ToUInt16(buffer, 0); - this.ZipFileStream.Read(buffer, 0, 2); - ushort extraSize = BitConverter.ToUInt16(buffer, 0); - - return (uint)(30 + filenameSize + extraSize + _headerOffset); - } - /* Local file header: - local file header signature 4 bytes (0x04034b50) - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - filename length 2 bytes - extra field length 2 bytes - - filename (variable size) - extra field (variable size) - */ - private void WriteLocalHeader(ref ZipFileEntry _zfe) - { - long pos = this.ZipFileStream.Position; - Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding; - byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip); - - this.ZipFileStream.Write(new byte[] { 80, 75, 3, 4, 20, 0 }, 0, 6); // No extra header - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 0x0800 : 0)), 0, 2); // filename and comment encoding - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method - this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); // zipping date and time - this.ZipFileStream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 12); // unused CRC, un/compressed size, updated later - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); // filename length - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // extra length - - this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length); - _zfe.HeaderSize = (uint)(this.ZipFileStream.Position - pos); - } - /* Central directory's File header: - central file header signature 4 bytes (0x02014b50) - version made by 2 bytes - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - filename length 2 bytes - extra field length 2 bytes - file comment length 2 bytes - disk number start 2 bytes - internal file attributes 2 bytes - external file attributes 4 bytes - relative offset of local header 4 bytes - - filename (variable size) - extra field (variable size) - file comment (variable size) - */ - private void WriteCentralDirRecord(ZipFileEntry _zfe) - { - Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding; - byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip); - byte[] encodedComment = encoder.GetBytes(_zfe.Comment); - - this.ZipFileStream.Write(new byte[] { 80, 75, 1, 2, 23, 0xB, 20, 0 }, 0, 8); - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 0x0800 : 0)), 0, 2); // filename and comment encoding - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method - this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); // zipping date and time - this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); // file CRC - this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); // compressed file size - this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); // uncompressed file size - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); // Filename in zip - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // extra length - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedComment.Length), 0, 2); - - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // disk=0 - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // file type: binary - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // Internal file attributes - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0x8100), 0, 2); // External file attributes (normal/readable) - this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.HeaderOffset), 0, 4); // Offset of header - - this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length); - this.ZipFileStream.Write(encodedComment, 0, encodedComment.Length); - } - /* End of central dir record: - end of central dir signature 4 bytes (0x06054b50) - number of this disk 2 bytes - number of the disk with the - start of the central directory 2 bytes - total number of entries in - the central dir on this disk 2 bytes - total number of entries in - the central dir 2 bytes - size of the central directory 4 bytes - offset of start of central - directory with respect to - the starting disk number 4 bytes - zipfile comment length 2 bytes - zipfile comment (variable size) - */ - private void WriteEndRecord(uint _size, uint _offset) - { - Encoding encoder = this.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding; - byte[] encodedComment = encoder.GetBytes(this.Comment); - - this.ZipFileStream.Write(new byte[] { 80, 75, 5, 6, 0, 0, 0, 0 }, 0, 8); - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)Files.Count + ExistingFiles), 0, 2); - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)Files.Count + ExistingFiles), 0, 2); - this.ZipFileStream.Write(BitConverter.GetBytes(_size), 0, 4); - this.ZipFileStream.Write(BitConverter.GetBytes(_offset), 0, 4); - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedComment.Length), 0, 2); - this.ZipFileStream.Write(encodedComment, 0, encodedComment.Length); - } - // Copies all source file into storage file - private void Store(ref ZipFileEntry _zfe, Stream _source) - { - byte[] buffer = new byte[16384]; - int bytesRead; - uint totalRead = 0; - Stream outStream; - - long posStart = this.ZipFileStream.Position; - long sourceStart = _source.Position; - - if (_zfe.Method == Compression.Store) - outStream = this.ZipFileStream; - else - outStream = new DeflateStream(this.ZipFileStream, CompressionMode.Compress, true); - - _zfe.Crc32 = 0 ^ 0xffffffff; - - do - { - bytesRead = _source.Read(buffer, 0, buffer.Length); - totalRead += (uint)bytesRead; - if (bytesRead > 0) - { - outStream.Write(buffer, 0, bytesRead); - - for (uint i = 0; i < bytesRead; i++) - { - _zfe.Crc32 = ZipStorer.CrcTable[(_zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (_zfe.Crc32 >> 8); - } - } - } while (bytesRead == buffer.Length); - outStream.Flush(); - - if (_zfe.Method == Compression.Deflate) - outStream.Dispose(); - - _zfe.Crc32 ^= 0xffffffff; - _zfe.FileSize = totalRead; - _zfe.CompressedSize = (uint)(this.ZipFileStream.Position - posStart); - - // Verify for real compression - if (_zfe.Method == Compression.Deflate && !this.ForceDeflating && _source.CanSeek && _zfe.CompressedSize > _zfe.FileSize) - { - // Start operation again with Store algorithm - _zfe.Method = Compression.Store; - this.ZipFileStream.Position = posStart; - this.ZipFileStream.SetLength(posStart); - _source.Position = sourceStart; - this.Store(ref _zfe, _source); - } - } - /* DOS Date and time: - MS-DOS date. The date is a packed value with the following format. Bits Description - 0-4 Day of the month (1–31) - 5-8 Month (1 = January, 2 = February, and so on) - 9-15 Year offset from 1980 (add 1980 to get actual year) - MS-DOS time. The time is a packed value with the following format. Bits Description - 0-4 Second divided by 2 - 5-10 Minute (0–59) - 11-15 Hour (0–23 on a 24-hour clock) - */ - private uint DateTimeToDosTime(DateTime _dt) - { - return (uint)( - (_dt.Second / 2) | (_dt.Minute << 5) | (_dt.Hour << 11) | - (_dt.Day << 16) | (_dt.Month << 21) | ((_dt.Year - 1980) << 25)); - } - private DateTime DosTimeToDateTime(uint _dt) - { - return new DateTime( - (int)(_dt >> 25) + 1980, - (int)(_dt >> 21) & 15, - (int)(_dt >> 16) & 31, - (int)(_dt >> 11) & 31, - (int)(_dt >> 5) & 63, - (int)(_dt & 31) * 2); - } - - /* CRC32 algorithm - The 'magic number' for the CRC is 0xdebb20e3. - The proper CRC pre and post conditioning - is used, meaning that the CRC register is - pre-conditioned with all ones (a starting value - of 0xffffffff) and the value is post-conditioned by - taking the one's complement of the CRC residual. - If bit 3 of the general purpose flag is set, this - field is set to zero in the local header and the correct - value is put in the data descriptor and in the central - directory. - */ - private void UpdateCrcAndSizes(ref ZipFileEntry _zfe) - { - long lastPos = this.ZipFileStream.Position; // remember position - - this.ZipFileStream.Position = _zfe.HeaderOffset + 8; - this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method - - this.ZipFileStream.Position = _zfe.HeaderOffset + 14; - this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); // Update CRC - this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); // Compressed size - this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); // Uncompressed size - - this.ZipFileStream.Position = lastPos; // restore position - } - // Replaces backslashes with slashes to store in zip header - private string NormalizedFilename(string _filename) - { - string filename = _filename.Replace('\\', '/'); - - int pos = filename.IndexOf(':'); - if (pos >= 0) - filename = filename.Remove(0, pos + 1); - - return filename.Trim('/'); - } - // Reads the end-of-central-directory record - private bool ReadFileInfo() - { - if (this.ZipFileStream.Length < 22) - return false; - - try - { - this.ZipFileStream.Seek(-17, SeekOrigin.End); - BinaryReader br = new BinaryReader(this.ZipFileStream); - do - { - this.ZipFileStream.Seek(-5, SeekOrigin.Current); - UInt32 sig = br.ReadUInt32(); - if (sig == 0x06054b50) - { - this.ZipFileStream.Seek(6, SeekOrigin.Current); - - UInt16 entries = br.ReadUInt16(); - Int32 centralSize = br.ReadInt32(); - UInt32 centralDirOffset = br.ReadUInt32(); - UInt16 commentSize = br.ReadUInt16(); - - // check if comment field is the very last data in file - if (this.ZipFileStream.Position + commentSize != this.ZipFileStream.Length) - return false; - - // Copy entire central directory to a memory buffer - this.ExistingFiles = entries; - this.CentralDirImage = new byte[centralSize]; - this.ZipFileStream.Seek(centralDirOffset, SeekOrigin.Begin); - this.ZipFileStream.Read(this.CentralDirImage, 0, centralSize); - - // Leave the pointer at the begining of central dir, to append new files - this.ZipFileStream.Seek(centralDirOffset, SeekOrigin.Begin); - return true; - } - } while (this.ZipFileStream.Position > 0); - } - catch { } - - return false; - } - #endregion - - #region IDisposable Members - /// - /// Closes the Zip file stream - /// - public void Dispose() - { - this.Close(); - } - #endregion - } -} diff --git a/DocX.sln b/DocX.sln deleted file mode 100644 index fdc30e8c..00000000 --- a/DocX.sln +++ /dev/null @@ -1,53 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DF41F5CE-8BCB-40CC-835F-54A3DB7D802F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocX", "DocX\DocX.csproj", "{E863D072-AA8B-4108-B5F1-785241B37F67}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA}" - ProjectSection(ProjectDependencies) = postProject - {E863D072-AA8B-4108-B5F1-785241B37F67} = {E863D072-AA8B-4108-B5F1-785241B37F67} - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Examples", "Examples\Examples.csproj", "{F3022BB7-0E40-4C80-A495-37FEAF3671AB}" - ProjectSection(ProjectDependencies) = postProject - {E863D072-AA8B-4108-B5F1-785241B37F67} = {E863D072-AA8B-4108-B5F1-785241B37F67} - EndProjectSection -EndProject -Project("{7CF6DF6D-3B04-46F8-A40B-537D21BCA0B4}") = "Documentation", "Documentation\Documentation.shfbproj", "{1EB1EE8F-9978-425B-A742-533DCCEB4811}" - ProjectSection(ProjectDependencies) = postProject - {E863D072-AA8B-4108-B5F1-785241B37F67} = {E863D072-AA8B-4108-B5F1-785241B37F67} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Any CPU.Build.0 = Release|Any CPU - {3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA}.Release|Any CPU.Build.0 = Release|Any CPU - {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Release|Any CPU.Build.0 = Release|Any CPU - {1EB1EE8F-9978-425B-A742-533DCCEB4811}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1EB1EE8F-9978-425B-A742-533DCCEB4811}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1EB1EE8F-9978-425B-A742-533DCCEB4811}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(TestCaseManagementSettings) = postSolution - CategoryFile = DocX.vsmdi - EndGlobalSection -EndGlobal diff --git a/DocX.vssscc b/DocX.vssscc deleted file mode 100644 index 794f014c..00000000 --- a/DocX.vssscc +++ /dev/null @@ -1,10 +0,0 @@ -"" -{ -"FILE_VERSION" = "9237" -"ENLISTMENT_CHOICE" = "NEVER" -"PROJECT_FILE_RELATIVE_PATH" = "" -"NUMBER_OF_EXCLUDED_FILES" = "0" -"ORIGINAL_PROJECT_FILE_PATH" = "" -"NUMBER_OF_NESTED_PROJECTS" = "0" -"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" -} diff --git a/DocX/Bookmark.cs b/DocX/Bookmark.cs deleted file mode 100644 index 273c2878..00000000 --- a/DocX/Bookmark.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Novacode -{ - public class Bookmark - { - public string Name { get; set; } - public Paragraph Paragraph { get; set; } - - public void SetText(string newText) - { - Paragraph.ReplaceAtBookmark(newText, Name); - } - } -} diff --git a/DocX/BookmarkCollection.cs b/DocX/BookmarkCollection.cs deleted file mode 100644 index c1e2358a..00000000 --- a/DocX/BookmarkCollection.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Novacode -{ - public class BookmarkCollection : List - { - public Bookmark this[string name] - { - get - { - return this.FirstOrDefault(bookmark => string.Equals(bookmark.Name, name, StringComparison.CurrentCultureIgnoreCase)); - } - } - } -} diff --git a/DocX/Border.cs b/DocX/Border.cs deleted file mode 100644 index e9aa115f..00000000 --- a/DocX/Border.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Drawing; - -namespace Novacode -{ - /// - /// Represents a border of a table or table cell - /// Added by lckuiper @ 20101117 - /// - public class Border - { - public BorderStyle Tcbs { get; set; } - public BorderSize Size { get; set; } - public int Space { get; set; } - public Color Color { get; set; } - public Border() - { - this.Tcbs = BorderStyle.Tcbs_single; - this.Size = BorderSize.one; - this.Space = 0; - this.Color = Color.Black; - } - - public Border(BorderStyle tcbs, BorderSize size, int space, Color color) - { - this.Tcbs = tcbs; - this.Size = size; - this.Space = space; - this.Color = color; - } - } -} \ No newline at end of file diff --git a/DocX/Charts/Axis.cs b/DocX/Charts/Axis.cs deleted file mode 100644 index b6b9611c..00000000 --- a/DocX/Charts/Axis.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Xml.Linq; - -namespace Novacode -{ - /// - /// Axis base class - /// - public abstract class Axis - { - /// - /// ID of this Axis - /// - public String Id - { - get - { - return Xml.Element(XName.Get("axId", DocX.c.NamespaceName)).Attribute(XName.Get("val")).Value; - } - } - - /// - /// Return true if this axis is visible - /// - public Boolean IsVisible - { - get - { - return Xml.Element(XName.Get("delete", DocX.c.NamespaceName)).Attribute(XName.Get("val")).Value == "0"; - } - set - { - if (value) - Xml.Element(XName.Get("delete", DocX.c.NamespaceName)).Attribute(XName.Get("val")).Value = "0"; - else - Xml.Element(XName.Get("delete", DocX.c.NamespaceName)).Attribute(XName.Get("val")).Value = "1"; - } - } - - /// - /// Axis xml element - /// - internal XElement Xml { get; set; } - - internal Axis(XElement xml) - { - Xml = xml; - } - - public Axis(String id) - { } - } - - /// - /// Represents Category Axes - /// - public class CategoryAxis : Axis - { - internal CategoryAxis(XElement xml) - : base(xml) - { } - - public CategoryAxis(String id) - : base(id) - { - Xml = XElement.Parse(String.Format( - @" - - - - - - - - - - - - - - - - ", id)); - } - } - - /// - /// Represents Values Axes - /// - public class ValueAxis : Axis - { - internal ValueAxis(XElement xml) - : base(xml) - { } - - public ValueAxis(String id) - : base(id) - { - Xml = XElement.Parse(String.Format( - @" - - - - - - - - - - - - - - - ", id)); - } - } -} diff --git a/DocX/Charts/BarChart.cs b/DocX/Charts/BarChart.cs deleted file mode 100644 index ed0daa70..00000000 --- a/DocX/Charts/BarChart.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Xml.Linq; - -namespace Novacode -{ - /// - /// This element contains the 2-D bar or column series on this chart. - /// 21.2.2.16 barChart (Bar Charts) - /// - public class BarChart : Chart - { - /// - /// Specifies the possible directions for a bar chart. - /// - public BarDirection BarDirection - { - get - { - return XElementHelpers.GetValueToEnum( - ChartXml.Element(XName.Get("barDir", DocX.c.NamespaceName))); - } - set - { - XElementHelpers.SetValueFromEnum( - ChartXml.Element(XName.Get("barDir", DocX.c.NamespaceName)), value); - } - } - - /// - /// Specifies the possible groupings for a bar chart. - /// - public BarGrouping BarGrouping - { - get - { - return XElementHelpers.GetValueToEnum( - ChartXml.Element(XName.Get("grouping", DocX.c.NamespaceName))); - } - set - { - XElementHelpers.SetValueFromEnum( - ChartXml.Element(XName.Get("grouping", DocX.c.NamespaceName)), value); - } - } - - /// - /// Specifies that its contents contain a percentage between 0% and 500%. - /// - public Int32 GapWidth - { - get - { - return Convert.ToInt32( - ChartXml.Element(XName.Get("gapWidth", DocX.c.NamespaceName)).Attribute(XName.Get("val")).Value); - } - set - { - if ((value < 1) || (value > 500)) - throw new ArgumentException("GapWidth lay between 0% and 500%!"); - ChartXml.Element(XName.Get("gapWidth", DocX.c.NamespaceName)).Attribute(XName.Get("val")).Value = value.ToString(); - } - } - - protected override XElement CreateChartXml() - { - return XElement.Parse( - @" - - - - "); - } - } - - /// - /// Specifies the possible directions for a bar chart. - /// 21.2.3.3 ST_BarDir (Bar Direction) - /// - public enum BarDirection - { - [XmlName("col")] - Column, - [XmlName("bar")] - Bar - } - - /// - /// Specifies the possible groupings for a bar chart. - /// 21.2.3.4 ST_BarGrouping (Bar Grouping) - /// - public enum BarGrouping - { - [XmlName("clustered")] - Clustered, - [XmlName("percentStacked")] - PercentStacked, - [XmlName("stacked")] - Stacked, - [XmlName("standard")] - Standard - } -} diff --git a/DocX/Charts/Chart.cs b/DocX/Charts/Chart.cs deleted file mode 100644 index b9844012..00000000 --- a/DocX/Charts/Chart.cs +++ /dev/null @@ -1,477 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; -using System.Collections; -using System.Drawing; - -namespace Novacode -{ - /// - /// Represents every Chart in this document. - /// - public abstract class Chart - { - protected XElement ChartXml { get; private set; } - protected XElement ChartRootXml { get; private set; } - - /// - /// The xml representation of this chart - /// - public XDocument Xml { get; private set; } - - #region Series - - /// - /// Chart's series - /// - public List Series - { - get - { - List series = new List(); - int indx = 1; - foreach (XElement element in ChartXml.Elements(XName.Get("ser", DocX.c.NamespaceName))) - { - element.Add(new XElement(XName.Get("idx", DocX.c.NamespaceName)), (indx++).ToString()); - series.Add(new Series(element)); - } - return series; - } - } - - /// - /// Return maximum count of series - /// - public virtual Int16 MaxSeriesCount { get { return Int16.MaxValue; } } - - /// - /// Add a new series to this chart - /// - public void AddSeries(Series series) - { - int serCount = ChartXml.Elements(XName.Get("ser", DocX.c.NamespaceName)).Count(); - if (serCount == MaxSeriesCount) - throw new InvalidOperationException("Maximum series for this chart is" + MaxSeriesCount.ToString() + "and have exceeded!"); - // Sourceman 16.04.2015 - Every Series needs to have an order and index element for being processed by Word 2013 - series.Xml.AddFirst( - new XElement(XName.Get("order", DocX.c.NamespaceName), - new XAttribute(XName.Get("val"), (serCount + 1).ToString()))); - series.Xml.AddFirst( - new XElement(XName.Get("idx", DocX.c.NamespaceName), - new XAttribute(XName.Get("val"), (serCount + 1).ToString()))); - ChartXml.Add(series.Xml); - } - - #endregion - - #region Legend - - /// - /// Chart's legend. - /// If legend doesn't exist property is null. - /// - public ChartLegend Legend { get; private set; } - - /// - /// Add standart legend to the chart. - /// - public void AddLegend() - { - AddLegend(ChartLegendPosition.Right, false); - } - - /// - /// Add a legend with parameters to the chart. - /// - public void AddLegend(ChartLegendPosition position, Boolean overlay) - { - if (Legend != null) - RemoveLegend(); - Legend = new ChartLegend(position, overlay); - //ChartRootXml.Add(Legend.Xml); - // Sourceman: seems to be necessary to keep track of the order of elements as defined in the schema (Word 2013) - ChartRootXml.Element(XName.Get("plotArea", DocX.c.NamespaceName)).AddAfterSelf(Legend.Xml); - } - - /// - /// Remove the legend from the chart. - /// - public void RemoveLegend() - { - Legend.Xml.Remove(); - Legend = null; - } - - #endregion - - #region Axis - - /// - /// Represents the category axis - /// - public CategoryAxis CategoryAxis { get; private set; } - - /// - /// Represents the values axis - /// - public ValueAxis ValueAxis { get; private set; } - - /// - /// Represents existing the axis - /// - public virtual Boolean IsAxisExist { get { return true; } } - - #endregion - - /// - /// Get or set 3D view for this chart - /// - public Boolean View3D - { - get - { - return ChartXml.Name.LocalName.Contains("3D"); - } - set - { - if (value) - { - if (!View3D) - { - String currentName = ChartXml.Name.LocalName; - ChartXml.Name = XName.Get(currentName.Replace("Chart", "3DChart"), DocX.c.NamespaceName); - } - } - else - { - if (View3D) - { - String currentName = ChartXml.Name.LocalName; - ChartXml.Name = XName.Get(currentName.Replace("3DChart", "Chart"), DocX.c.NamespaceName); - } - } - } - } - - /// - /// Specifies how blank cells shall be plotted on a chart - /// - public DisplayBlanksAs DisplayBlanksAs - { - get - { - return XElementHelpers.GetValueToEnum( - ChartRootXml.Element(XName.Get("dispBlanksAs", DocX.c.NamespaceName))); - } - set - { - XElementHelpers.SetValueFromEnum( - ChartRootXml.Element(XName.Get("dispBlanksAs", DocX.c.NamespaceName)), value); - } - } - - /// - /// Create an Chart for this document - /// - public Chart() - { - // Create global xml - Xml = XDocument.Parse - (@" - - - - - - - - - "); - - // Create a real chart xml in an inheritor - ChartXml = CreateChartXml(); - - // Create result plotarea element - XElement plotAreaXml = new XElement( - XName.Get("plotArea", DocX.c.NamespaceName), - new XElement(XName.Get("layout", DocX.c.NamespaceName)), - ChartXml); - - // Set labels - XElement dLblsXml = XElement.Parse( - @" - - - - - - - - "); - ChartXml.Add(dLblsXml); - - // if axes exists, create their - if (IsAxisExist) - { - CategoryAxis = new CategoryAxis("148921728"); - ValueAxis = new ValueAxis("154227840"); - - XElement axIDcatXml = XElement.Parse(String.Format( - @"", CategoryAxis.Id)); - XElement axIDvalXml = XElement.Parse(String.Format( - @"", ValueAxis.Id)); - - // Sourceman: seems to be necessary to keep track of the order of elements as defined in the schema (Word 2013) - var insertPoint = ChartXml.Element(XName.Get("gapWidth", DocX.c.NamespaceName)); - if (insertPoint != null) { - insertPoint.AddAfterSelf(axIDvalXml); - insertPoint.AddAfterSelf(axIDcatXml); - } else { - ChartXml.Add(axIDcatXml); - ChartXml.Add(axIDvalXml); - } - - plotAreaXml.Add(CategoryAxis.Xml); - plotAreaXml.Add(ValueAxis.Xml); - } - - ChartRootXml = Xml.Root.Element(XName.Get("chart", DocX.c.NamespaceName)); - //ChartRootXml.Add(plotAreaXml); - ChartRootXml.Element(XName.Get("autoTitleDeleted", DocX.c.NamespaceName)).AddAfterSelf(plotAreaXml); - } - - /// - /// An abstract method which creates the current chart xml - /// - protected abstract XElement CreateChartXml(); - } - - - - /// - /// Represents a chart series - /// - public class Series - { - private XElement strCache; - private XElement numCache; - - /// - /// Series xml element - /// - internal XElement Xml { get; private set; } - - public Color Color - { - get - { - XElement colorElement = Xml.Element(XName.Get("spPr", DocX.c.NamespaceName)); - if (colorElement == null) - return Color.Transparent; - else - return Color.FromArgb(Int32.Parse( - colorElement.Element(XName.Get("solidFill", DocX.a.NamespaceName)).Element(XName.Get("srgbClr", DocX.a.NamespaceName)).Attribute(XName.Get("val")).Value, - System.Globalization.NumberStyles.HexNumber)); - } - set - { - XElement colorElement = Xml.Element(XName.Get("spPr", DocX.c.NamespaceName)); - if (colorElement != null) - colorElement.Remove(); - colorElement = new XElement( - XName.Get("spPr", DocX.c.NamespaceName), - new XElement( - XName.Get("solidFill", DocX.a.NamespaceName), - new XElement( - XName.Get("srgbClr", DocX.a.NamespaceName), - new XAttribute(XName.Get("val"), value.ToHex())))); - Xml.Element(XName.Get("tx", DocX.c.NamespaceName)).AddAfterSelf(colorElement); - } - } - - internal Series(XElement xml) - { - Xml = xml; - strCache = xml.Element(XName.Get("cat", DocX.c.NamespaceName)).Element(XName.Get("strRef", DocX.c.NamespaceName)).Element(XName.Get("strCache", DocX.c.NamespaceName)); - numCache = xml.Element(XName.Get("val", DocX.c.NamespaceName)).Element(XName.Get("numRef", DocX.c.NamespaceName)).Element(XName.Get("numCache", DocX.c.NamespaceName)); - } - - public Series(String name) - { - strCache = new XElement(XName.Get("strCache", DocX.c.NamespaceName)); - numCache = new XElement(XName.Get("numCache", DocX.c.NamespaceName)); - - Xml = new XElement( - XName.Get("ser", DocX.c.NamespaceName), - new XElement( - XName.Get("tx", DocX.c.NamespaceName), - new XElement( - XName.Get("strRef", DocX.c.NamespaceName), - new XElement(XName.Get("f", DocX.c.NamespaceName), ""), - new XElement( - XName.Get("strCache", DocX.c.NamespaceName), - new XElement( - XName.Get("pt", DocX.c.NamespaceName), - new XAttribute(XName.Get("idx"), "0"), - new XElement(XName.Get("v", DocX.c.NamespaceName), name) - )))), - new XElement(XName.Get("invertIfNegative", DocX.c.NamespaceName), "0"), - new XElement( - XName.Get("cat", DocX.c.NamespaceName), - new XElement(XName.Get("strRef", DocX.c.NamespaceName), - new XElement(XName.Get("f", DocX.c.NamespaceName), ""), - strCache)), - new XElement( - XName.Get("val", DocX.c.NamespaceName), - new XElement(XName.Get("numRef", DocX.c.NamespaceName), - new XElement(XName.Get("f", DocX.c.NamespaceName), ""), - numCache)) - ); - } - - public void Bind(ICollection list, String categoryPropertyName, String valuePropertyName) - { - XElement ptCount = new XElement(XName.Get("ptCount", DocX.c.NamespaceName), new XAttribute(XName.Get("val"), list.Count)); - XElement formatCode = new XElement(XName.Get("formatCode", DocX.c.NamespaceName), "General"); - - strCache.RemoveAll(); - numCache.RemoveAll(); - - strCache.Add(ptCount); - numCache.Add(formatCode); - numCache.Add(ptCount); - - Int32 index = 0; - XElement pt; - foreach (var item in list) - { - pt = new XElement(XName.Get("pt", DocX.c.NamespaceName), new XAttribute(XName.Get("idx"), index), - new XElement(XName.Get("v", DocX.c.NamespaceName), item.GetType().GetProperty(categoryPropertyName).GetValue(item, null))); - strCache.Add(pt); - pt = new XElement(XName.Get("pt", DocX.c.NamespaceName), new XAttribute(XName.Get("idx"), index), - new XElement(XName.Get("v", DocX.c.NamespaceName), item.GetType().GetProperty(valuePropertyName).GetValue(item, null))); - numCache.Add(pt); - index++; - } - } - - public void Bind(IList categories, IList values) - { - if (categories.Count != values.Count) - throw new ArgumentException("Categories count must equal to Values count"); - - XElement ptCount = new XElement(XName.Get("ptCount", DocX.c.NamespaceName), new XAttribute(XName.Get("val"), categories.Count)); - XElement formatCode = new XElement(XName.Get("formatCode", DocX.c.NamespaceName), "General"); - - strCache.RemoveAll(); - numCache.RemoveAll(); - - strCache.Add(ptCount); - numCache.Add(formatCode); - numCache.Add(ptCount); - - XElement pt; - for (int index = 0; index < categories.Count; index++) - { - pt = new XElement(XName.Get("pt", DocX.c.NamespaceName), new XAttribute(XName.Get("idx"), index), - new XElement(XName.Get("v", DocX.c.NamespaceName), categories[index].ToString())); - strCache.Add(pt); - pt = new XElement(XName.Get("pt", DocX.c.NamespaceName), new XAttribute(XName.Get("idx"), index), - new XElement(XName.Get("v", DocX.c.NamespaceName), values[index].ToString())); - numCache.Add(pt); - } - } - } - - /// - /// Represents a chart legend - /// More: http://msdn.microsoft.com/ru-ru/library/cc845123.aspx - /// - public class ChartLegend - { - /// - /// Legend xml element - /// - internal XElement Xml { get; private set; } - - /// - /// Specifies that other chart elements shall be allowed to overlap this chart element - /// - public Boolean Overlay - { - get { return Xml.Element(XName.Get("overlay", DocX.c.NamespaceName)).Attribute("val").Value == "1"; } - set { Xml.Element(XName.Get("overlay", DocX.c.NamespaceName)).Attribute("val").Value = GetOverlayValue(value); } - } - - /// - /// Specifies the possible positions for a legend - /// - public ChartLegendPosition Position - { - get - { - return XElementHelpers.GetValueToEnum( - Xml.Element(XName.Get("legendPos", DocX.c.NamespaceName))); - } - set - { - XElementHelpers.SetValueFromEnum( - Xml.Element(XName.Get("legendPos", DocX.c.NamespaceName)), value); - } - } - - internal ChartLegend(ChartLegendPosition position, Boolean overlay) - { - Xml = new XElement( - XName.Get("legend", DocX.c.NamespaceName), - new XElement(XName.Get("legendPos", DocX.c.NamespaceName), new XAttribute("val", XElementHelpers.GetXmlNameFromEnum(position))), - new XElement(XName.Get("overlay", DocX.c.NamespaceName), new XAttribute("val", GetOverlayValue(overlay))) - ); - } - - /// - /// ECMA-376, page 3840 - /// 21.2.2.132 overlay (Overlay) - /// - private String GetOverlayValue(Boolean overlay) - { - if (overlay) - return "1"; - else - return "0"; - } - } - - /// - /// Specifies the possible positions for a legend. - /// 21.2.3.24 ST_LegendPos (Legend Position) - /// - public enum ChartLegendPosition - { - [XmlName("t")] - Top, - [XmlName("b")] - Bottom, - [XmlName("l")] - Left, - [XmlName("r")] - Right, - [XmlName("tr")] - TopRight - } - - /// - /// Specifies the possible ways to display blanks. - /// 21.2.3.10 ST_DispBlanksAs (Display Blanks As) - /// - public enum DisplayBlanksAs - { - [XmlName("gap")] - Gap, - [XmlName("span")] - Span, - [XmlName("zero")] - Zero - } -} diff --git a/DocX/Charts/LineChart.cs b/DocX/Charts/LineChart.cs deleted file mode 100644 index c335e1c8..00000000 --- a/DocX/Charts/LineChart.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Xml.Linq; - -namespace Novacode -{ - /// - /// This element contains the 2-D line chart series. - /// 21.2.2.97 lineChart (Line Charts) - /// - public class LineChart: Chart - { - /// - /// Specifies the kind of grouping for a column, line, or area chart. - /// - public Grouping Grouping - { - get - { - return XElementHelpers.GetValueToEnum( - ChartXml.Element(XName.Get("grouping", DocX.c.NamespaceName))); - } - set - { - XElementHelpers.SetValueFromEnum( - ChartXml.Element(XName.Get("grouping", DocX.c.NamespaceName)), value); - } - } - - protected override XElement CreateChartXml() - { - return XElement.Parse( - @" - - "); - } - } - - /// - /// Specifies the kind of grouping for a column, line, or area chart. - /// 21.2.2.76 grouping (Grouping) - /// - public enum Grouping - { - [XmlName("percentStacked")] - PercentStacked, - [XmlName("stacked")] - Stacked, - [XmlName("standard")] - Standard - } -} diff --git a/DocX/Charts/PieChart.cs b/DocX/Charts/PieChart.cs deleted file mode 100644 index 179e727d..00000000 --- a/DocX/Charts/PieChart.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Xml.Linq; - -namespace Novacode -{ - /// - /// This element contains the 2-D pie series for this chart. - /// 21.2.2.141 pieChart (Pie Charts) - /// - public class PieChart : Chart - { - public override Boolean IsAxisExist { get { return false; } } - public override Int16 MaxSeriesCount { get { return 1; } } - - protected override XElement CreateChartXml() - { - return XElement.Parse( - @" - "); - } - } -} diff --git a/DocX/Charts/XElementHelpers.cs b/DocX/Charts/XElementHelpers.cs deleted file mode 100644 index 54a25e39..00000000 --- a/DocX/Charts/XElementHelpers.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Xml.Linq; - -namespace Novacode -{ - internal static class XElementHelpers - { - /// - /// Get value from XElement and convert it to enum - /// - /// Enum type - internal static T GetValueToEnum(XElement element) - { - if (element == null) - throw new ArgumentNullException(nameof(element)); - - String value = element.Attribute(XName.Get("val")).Value; - foreach (T e in Enum.GetValues(typeof(T))) - { - FieldInfo fi = typeof(T).GetField(e.ToString()); - if (fi.GetCustomAttributes(typeof(XmlNameAttribute), false).Count() == 0) - throw new Exception(String.Format("Attribute 'XmlNameAttribute' is not assigned to {0} fields!", typeof(T).Name)); - XmlNameAttribute a = (XmlNameAttribute)fi.GetCustomAttributes(typeof(XmlNameAttribute), false).First(); - if (a.XmlName == value) - return e; - } - throw new ArgumentException("Invalid element value!"); - } - - /// - /// Convert value to xml string and set it into XElement - /// - /// Enum type - internal static void SetValueFromEnum(XElement element, T value) - { - if (element == null) - throw new ArgumentNullException(nameof(element)); - element.Attribute(XName.Get("val")).Value = GetXmlNameFromEnum(value); - } - - /// - /// Return xml string for this value - /// - /// Enum type - internal static String GetXmlNameFromEnum(T value) - { - if (value == null) - throw new ArgumentNullException(nameof(value)); - - FieldInfo fi = typeof(T).GetField(value.ToString()); - if (fi.GetCustomAttributes(typeof(XmlNameAttribute), false).Count() == 0) - throw new Exception(String.Format("Attribute 'XmlNameAttribute' is not assigned to {0} fields!", typeof(T).Name)); - XmlNameAttribute a = (XmlNameAttribute)fi.GetCustomAttributes(typeof(XmlNameAttribute), false).First(); - return a.XmlName; - } - } - - /// - /// This attribute applied to enum's fields for definition their's real xml names in DocX file. - /// - /// - /// public enum MyEnum - /// { - /// [XmlName("one")] // This means, that xml element has 'val="one"' - /// ValueOne, - /// [XmlName("two")] // This means, that xml element has 'val="two"' - /// ValueTwo - /// } - /// - [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] - internal sealed class XmlNameAttribute : Attribute - { - /// - /// Real xml name - /// - public String XmlName { get; private set; } - - public XmlNameAttribute(String xmlName) - { - XmlName = xmlName; - } - } -} diff --git a/DocX/Container.cs b/DocX/Container.cs deleted file mode 100644 index 8d734e13..00000000 --- a/DocX/Container.cs +++ /dev/null @@ -1,1048 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Xml.Linq; -using System.IO.Packaging; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using System.Collections.ObjectModel; - -namespace Novacode -{ - public abstract class Container : DocXElement - { - - public virtual ReadOnlyCollection Contents - { - get - { - List contents = GetContents(); - - - - return contents.AsReadOnly(); - } - } - /// - /// Returns a list of all Paragraphs inside this container. - /// - /// - /// - /// Load a document. - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // All Paragraphs in this document. - /// ]]> documentParagraphs = document.Paragraphs; - /// - /// // Make sure this document contains at least one Table. - /// if (document.Tables.Count() > 0) - /// { - /// // Get the first Table in this document. - /// Table t = document.Tables[0]; - /// - /// // All Paragraphs in this Table. - /// ]]> tableParagraphs = t.Paragraphs; - /// - /// // Make sure this Table contains at least one Row. - /// if (t.Rows.Count() > 0) - /// { - /// // Get the first Row in this document. - /// Row r = t.Rows[0]; - /// - /// // All Paragraphs in this Row. - /// ]]> rowParagraphs = r.Paragraphs; - /// - /// // Make sure this Row contains at least one Cell. - /// if (r.Cells.Count() > 0) - /// { - /// // Get the first Cell in this document. - /// Cell c = r.Cells[0]; - /// - /// // All Paragraphs in this Cell. - /// ]]> cellParagraphs = c.Paragraphs; - /// } - /// } - /// } - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public virtual ReadOnlyCollection Paragraphs - { - get - { - List paragraphs = GetParagraphs(); - - 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(); - } - } - public virtual ReadOnlyCollection ParagraphsDeepSearch - { - get - { - List 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(); - } - } - /// - /// Removes paragraph at specified position - /// - /// Index of paragraph to remove - /// True if removed - public bool RemoveParagraphAt(int index) - { - int i = 0; - foreach (var paragraph in Xml.Descendants(DocX.w + "p")) - { - if (i == index) - { - paragraph.Remove(); - return true; - } - ++i; - - } - - return false; - } - - /// - /// Removes paragraph - /// - /// Paragraph to remove - /// True if removed - public bool RemoveParagraph(Paragraph p) - { - foreach (var paragraph in Xml.Descendants(DocX.w + "p")) - { - if (paragraph.Equals(p.Xml)) - { - paragraph.Remove(); - return true; - } - } - - return false; - } - - - public virtual List
Sections - { - get - { - var allParas = Paragraphs; - - var parasInASection = new List(); - var sections = new List
(); - - foreach (var para in allParas) - { - - var sectionInPara = para.Xml.Descendants().FirstOrDefault(s => s.Name.LocalName == "sectPr"); - - if (sectionInPara == null) - { - parasInASection.Add(para); - } - else - { - parasInASection.Add(para); - var section = new Section(Document, sectionInPara) { SectionParagraphs = parasInASection }; - sections.Add(section); - parasInASection = new List(); - } - - } - - XElement body = Xml.Element(XName.Get("body", DocX.w.NamespaceName)); - if (body != null) - { - XElement baseSectionXml = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - var baseSection = new Section(Document, baseSectionXml) { SectionParagraphs = parasInASection }; - sections.Add(baseSection); - } - return sections; - } - } - - - private void GetListItemType(Paragraph p) - { - var ilvlNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault(el => el.Name.LocalName == "ilvl"); - var ilvlValue = ilvlNode.Attribute(DocX.w + "val").Value; - - var numIdNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault(el => el.Name.LocalName == "numId"); - var numIdValue = numIdNode.Attribute(DocX.w + "val").Value; - - //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); - } - - } - - - public ContainerType ParentContainer; - - internal List GetContents(bool deepSearch = false) - { - // Need some memory that can be updated by the recursive search. - //int index = 0; - List contents = new List(); - foreach (XElement e in Xml.Descendants(XName.Get("sdt", DocX.w.NamespaceName))) - { - Content content = new Content(Document, e, 0); - XElement el = e.Elements(XName.Get("sdtPr", DocX.w.NamespaceName)).First(); - content.Name = GetAttribute(el, "alias", "val"); - content.Tag = GetAttribute(el, "tag", "val"); - - contents.Add(content); - } - - - return contents; - } - private string GetAttribute(XElement e, string localName, string attributeName) - { - string val = string.Empty; - try - { - val = e.Elements(XName.Get(localName, DocX.w.NamespaceName)).Attributes(XName.Get(attributeName, DocX.w.NamespaceName)).FirstOrDefault().Value; - } - catch (Exception) - { - val = "Missing"; - } - - return val; - } - - internal List GetParagraphs(bool deepSearch = false) - { - // Need some memory that can be updated by the recursive search. - int index = 0; - List paragraphs = new List(); - foreach (XElement e in Xml.Descendants(XName.Get("p", DocX.w.NamespaceName))) - { - Paragraph paragraph = new Paragraph(Document, e, index); - paragraphs.Add(paragraph); - index += HelperFunctions.GetText(e).Length; - } - // GetParagraphsRecursive(Xml, ref index, ref paragraphs, deepSearch); - - return paragraphs; - } - - internal void GetParagraphsRecursive(XElement Xml, ref int index, ref List 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; - } - if (keepSearching && Xml.HasElements) - { - foreach (XElement e in Xml.Elements()) - { - GetParagraphsRecursive(e, ref index, ref paragraphs, deepSearch); - } - } - } - - public virtual List
Tables - { - get - { - List
tables = - ( - from t in Xml.Descendants(DocX.w + "tbl") - select new Table(Document, t) - ).ToList(); - - return tables; - } - } - - public virtual List Lists - { - get - { - var lists = new List(); - var list = new List(Document, Xml); - - foreach (var paragraph in Paragraphs) - { - if (paragraph.IsListItem) - { - if (list.CanAddListItem(paragraph)) - { - list.AddItem(paragraph); - } - else - { - lists.Add(list); - list = new List(Document, Xml); - list.AddItem(paragraph); - } - } - } - - lists.Add(list); - - return lists; - } - } - - public virtual List Hyperlinks - { - get - { - List hyperlinks = new List(); - - foreach (Paragraph p in Paragraphs) - hyperlinks.AddRange(p.Hyperlinks); - - return hyperlinks; - } - } - - public virtual List Pictures - { - get - { - List pictures = new List(); - - foreach (Paragraph p in Paragraphs) - pictures.AddRange(p.Pictures); - - return pictures; - } - } - - /// - /// Sets the Direction of content. - /// - /// Direction either LeftToRight or RightToLeft - /// - /// Set the Direction of content in a Paragraph to RightToLeft. - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // Get the first Paragraph from this document. - /// Paragraph p = document.InsertParagraph(); - /// - /// // Set the Direction of this Paragraph. - /// p.Direction = Direction.RightToLeft; - /// - /// // Make sure the document contains at lest one Table. - /// if (document.Tables.Count() > 0) - /// { - /// // Get the first Table from this document. - /// Table t = document.Tables[0]; - /// - /// /* - /// * Set the direction of the entire Table. - /// * Note: The same function is available at the Row and Cell level. - /// */ - /// t.SetDirection(Direction.RightToLeft); - /// } - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public virtual void SetDirection(Direction direction) - { - foreach (Paragraph p in Paragraphs) - p.Direction = direction; - } - - public virtual List FindAll(string str) - { - return FindAll(str, RegexOptions.None); - } - - public virtual List FindAll(string str, RegexOptions options) - { - List list = new List(); - - foreach (Paragraph p in Paragraphs) - { - List indexes = p.FindAll(str, options); - - for (int i = 0; i < indexes.Count(); i++) - indexes[i] += p.startIndex; - - list.AddRange(indexes); - } - - return list; - } - - /// - /// Find all unique instances of the given Regex Pattern, - /// returning the list of the unique strings found - /// - /// - /// - /// - public virtual List FindUniqueByPattern(string pattern, RegexOptions options) - { - List rawResults = new List(); - - foreach (Paragraph p in Paragraphs) - { // accumulate the search results from all paragraphs - List partials = p.FindAllByPattern(pattern, options); - rawResults.AddRange(partials); - } - - // this dictionary is used to collect results and test for uniqueness - Dictionary uniqueResults = new Dictionary(); - - foreach (string currValue in rawResults) - { - if (!uniqueResults.ContainsKey(currValue)) - { // if the dictionary doesn't have it, add it - uniqueResults.Add(currValue, 0); - } - } - - 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, bool removeEmptyParagraph = true) - { - if (string.IsNullOrEmpty(searchValue)) - throw new ArgumentException("oldValue cannot be null or empty", "searchValue"); - - if (newValue == null) - throw new ArgumentException("newValue cannot be null or empty", "newValue"); - // ReplaceText in Headers of the document. - var headerList = new List
{ Document.Headers.first, Document.Headers.even, Document.Headers.odd }; - 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, removeEmptyParagraph); - - // ReplaceText int main body of document. - foreach (var paragraph in Paragraphs) - paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions, removeEmptyParagraph); - - // ReplaceText in Footers of the document. - var footerList = new List
{ 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, removeEmptyParagraph); - } - - /// - /// - /// - /// Value to find - /// A Func that accepts the matching regex search group value and passes it to this to return the replacement string - /// Enable trackchanges - /// Regex options - /// - /// - /// - /// Remove empty paragraph - public virtual void ReplaceText(string searchValue, Func 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"); - - if (regexMatchHandler == null) - throw new ArgumentException("regexMatchHandler cannot be null", "regexMatchHandler"); - - // ReplaceText in Headers/Footers of the document. - var containerList = new List { - Document.Headers.first, Document.Headers.even, Document.Headers.odd, - Document.Footers.first, Document.Footers.even, Document.Footers.odd }; - foreach (var container in containerList) - if (container != null) - foreach (var paragraph in container.Paragraphs) - 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, removeEmptyParagraph); - } - - /// - /// Removes all items with required formatting - /// - /// Numer of texts removed - public int RemoveTextInGivenFormat(Formatting matchFormatting, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch) - { - var deletedCount = 0; - foreach (var x in Xml.Elements()) - { - deletedCount += RemoveTextWithFormatRecursive(x, matchFormatting, fo); - } - - return deletedCount; - } - - internal int RemoveTextWithFormatRecursive(XElement element, Formatting matchFormatting, MatchFormattingOptions fo) - { - var deletedCount = 0; - foreach (var x in element.Elements()) - { - if ("rPr".Equals(x.Name.LocalName)) - { - if (HelperFunctions.ContainsEveryChildOf(matchFormatting.Xml, x, fo)) - { - x.Parent.Remove(); - ++deletedCount; - } - } - - deletedCount += RemoveTextWithFormatRecursive(x, matchFormatting, fo); - } - - return deletedCount; - } - - public virtual void InsertAtBookmark(string toInsert, string bookmarkName) - { - if (bookmarkName.IsNullOrWhiteSpace()) - throw new ArgumentException("bookmark cannot be null or empty", "bookmarkName"); - - var headerCollection = Document.Headers; - var headers = new List
{ headerCollection.first, headerCollection.even, headerCollection.odd }; - foreach (var header in headers.Where(x => x != null)) - foreach (var paragraph in header.Paragraphs) - paragraph.InsertAtBookmark(toInsert, bookmarkName); - - foreach (var paragraph in Paragraphs) - paragraph.InsertAtBookmark(toInsert, bookmarkName); - - var footerCollection = Document.Footers; - var footers = new List
{ footerCollection.first, footerCollection.even, footerCollection.odd }; - foreach (var footer in footers.Where(x => x != null)) - foreach (var paragraph in footer.Paragraphs) - paragraph.InsertAtBookmark(toInsert, bookmarkName); - } - - public string[] ValidateBookmarks(params string[] bookmarkNames) - { - var headers = new[] { Document.Headers.first, Document.Headers.even, Document.Headers.odd }.Where(h => h != null).ToList(); - var footers = new[] { Document.Footers.first, Document.Footers.even, Document.Footers.odd }.Where(f => f != null).ToList(); - - var nonMatching = new List(); - foreach (var bookmarkName in bookmarkNames) - { - if (headers.SelectMany(h => h.Paragraphs).Any(p => p.ValidateBookmark(bookmarkName))) return new string[0]; - if (footers.SelectMany(h => h.Paragraphs).Any(p => p.ValidateBookmark(bookmarkName))) return new string[0]; - if (Paragraphs.Any(p => p.ValidateBookmark(bookmarkName))) return new string[0]; - nonMatching.Add(bookmarkName); - } - - return nonMatching.ToArray(); - } - - public virtual Paragraph InsertParagraph(int index, string text, bool trackChanges) - { - return InsertParagraph(index, text, trackChanges, null); - } - - public virtual Paragraph InsertParagraph() - { - return InsertParagraph(string.Empty, false); - } - - public virtual Paragraph InsertParagraph(int index, Paragraph p) - { - XElement newXElement = new XElement(p.Xml); - p.Xml = newXElement; - - Paragraph paragraph = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index); - - if (paragraph == null) - Xml.Add(p.Xml); - else - { - XElement[] split = HelperFunctions.SplitParagraph(paragraph, index - paragraph.startIndex); - - paragraph.Xml.ReplaceWith - ( - split[0], - newXElement, - split[1] - ); - } - - GetParent(p); - - return p; - } - - public virtual Paragraph InsertParagraph(Paragraph p) - { - #region Styles - XDocument style_document; - - if (p.styles.Count() > 0) - { - Uri style_package_uri = new Uri("/word/styles.xml", UriKind.Relative); - if (!Document.package.PartExists(style_package_uri)) - { - PackagePart style_package = Document.package.CreatePart(style_package_uri, "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", CompressionOption.Maximum); - using (TextWriter tw = new StreamWriter(new PackagePartStream(style_package.GetStream()))) - { - style_document = new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - new XElement(XName.Get("styles", DocX.w.NamespaceName)) - ); - - style_document.Save(tw); - } - } - - PackagePart styles_document = Document.package.GetPart(style_package_uri); - using (TextReader tr = new StreamReader(styles_document.GetStream())) - { - style_document = XDocument.Load(tr); - XElement styles_element = style_document.Element(XName.Get("styles", DocX.w.NamespaceName)); - - var ids = from d in styles_element.Descendants(XName.Get("style", DocX.w.NamespaceName)) - let a = d.Attribute(XName.Get("styleId", DocX.w.NamespaceName)) - where a != null - select a.Value; - - foreach (XElement style in p.styles) - { - // If styles_element does not contain this element, then add it. - - if (!ids.Contains(style.Attribute(XName.Get("styleId", DocX.w.NamespaceName)).Value)) - styles_element.Add(style); - } - } - - using (TextWriter tw = new StreamWriter(new PackagePartStream(styles_document.GetStream()))) - style_document.Save(tw); - } - #endregion - - XElement newXElement = new XElement(p.Xml); - - Xml.Add(newXElement); - - int index = 0; - if (Document.paragraphLookup.Keys.Count() > 0) - { - index = Document.paragraphLookup.Last().Key; - - if (Document.paragraphLookup.Last().Value.Text.Length == 0) - index++; - else - index += Document.paragraphLookup.Last().Value.Text.Length; - } - - Paragraph newParagraph = new Paragraph(Document, newXElement, index); - Document.paragraphLookup.Add(index, newParagraph); - - GetParent(newParagraph); - - return newParagraph; - } - - public virtual Paragraph InsertParagraph(int index, string text, bool trackChanges, Formatting formatting) - { - Paragraph newParagraph = new Paragraph(Document, new XElement(DocX.w + "p"), index); - newParagraph.InsertText(0, text, trackChanges, formatting); - - Paragraph firstPar = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index); - - if (firstPar != null) - { - var splitindex = index - firstPar.startIndex; - if (splitindex <= 0) - { - firstPar.Xml.ReplaceWith(newParagraph.Xml, firstPar.Xml); - } - else - { - XElement[] splitParagraph = HelperFunctions.SplitParagraph(firstPar, splitindex); - - firstPar.Xml.ReplaceWith - ( - splitParagraph[0], - newParagraph.Xml, - splitParagraph[1] - ); - } - } - - else - Xml.Add(newParagraph); - - GetParent(newParagraph); - - return newParagraph; - } - - - private ContainerType GetParentFromXmlName(string xmlName) - { - ContainerType parent; - - switch (xmlName) - { - case "body": - parent = ContainerType.Body; - break; - case "p": - parent = ContainerType.Paragraph; - break; - case "tbl": - parent = ContainerType.Table; - break; - case "sectPr": - parent = ContainerType.Section; - break; - case "tc": - parent = ContainerType.Cell; - break; - default: - parent = ContainerType.None; - break; - } - return parent; - } - - private void GetParent(Paragraph newParagraph) - { - var containerType = GetType(); - - switch (containerType.Name) - { - - case "Body": - newParagraph.ParentContainer = ContainerType.Body; - break; - case "Table": - newParagraph.ParentContainer = ContainerType.Table; - break; - case "TOC": - newParagraph.ParentContainer = ContainerType.TOC; - break; - case "Section": - newParagraph.ParentContainer = ContainerType.Section; - break; - case "Cell": - newParagraph.ParentContainer = ContainerType.Cell; - break; - case "Header": - newParagraph.ParentContainer = ContainerType.Header; - break; - case "Footer": - newParagraph.ParentContainer = ContainerType.Footer; - break; - case "Paragraph": - newParagraph.ParentContainer = ContainerType.Paragraph; - break; - } - } - - - private ListItemType GetListItemType(string styleName) - { - ListItemType listItemType; - - switch (styleName) - { - case "bullet": - listItemType = ListItemType.Bulleted; - break; - default: - listItemType = ListItemType.Numbered; - break; - } - - return listItemType; - } - - - - public virtual void InsertSection() - { - InsertSection(false); - } - - public virtual void InsertSection(bool trackChanges) - { - var newParagraphSection = new XElement - ( - XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName), new XElement(XName.Get("sectPr", DocX.w.NamespaceName), new XElement(XName.Get("type", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", "continuous")))) - ); - - if (trackChanges) - newParagraphSection = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraphSection); - - Xml.Add(newParagraphSection); - } - - public virtual void InsertSectionPageBreak(bool trackChanges = false) - { - var newParagraphSection = new XElement - ( - XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName), new XElement(XName.Get("sectPr", DocX.w.NamespaceName))) - ); - - if (trackChanges) - newParagraphSection = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraphSection); - - Xml.Add(newParagraphSection); - } - - public virtual Paragraph InsertParagraph(string text) - { - return InsertParagraph(text, false, new Formatting()); - } - - public virtual Paragraph InsertParagraph(string text, bool trackChanges) - { - return InsertParagraph(text, trackChanges, new Formatting()); - } - - public virtual Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting) - { - XElement newParagraph = new XElement - ( - XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName)), HelperFunctions.FormatInput(text, formatting.Xml) - ); - - if (trackChanges) - newParagraph = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraph); - Xml.Add(newParagraph); - var paragraphAdded = new Paragraph(Document, newParagraph, 0); - if (this is Cell) - { - var cell = this as Cell; - paragraphAdded.PackagePart = cell.mainPart; - } - else if (this is DocX) - { - paragraphAdded.PackagePart = Document.mainPart; - } - else if (this is Footer) - { - var f = this as Footer; - paragraphAdded.mainPart = f.mainPart; - } - else if (this is Header) - { - var h = this as Header; - paragraphAdded.mainPart = h.mainPart; - } - else - { - Console.WriteLine("No idea what we are {0}", this); - paragraphAdded.PackagePart = Document.mainPart; - } - - - GetParent(paragraphAdded); - - return paragraphAdded; - } - - public virtual Paragraph InsertEquation(string equation) - { - Paragraph p = InsertParagraph(); - p.AppendEquation(equation); - return p; - } - - public virtual Paragraph InsertBookmark(String bookmarkName) - { - var p = InsertParagraph(); - p.AppendBookmark(bookmarkName); - return p; - } - - public virtual Table InsertTable(int rowCount, int columnCount) //Dmitchern, changed to virtual, and overrided in Table.Cell - { - XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount); - Xml.Add(newTable); - - return new Table(Document, newTable) { mainPart = mainPart }; - } - - public Table InsertTable(int index, int rowCount, int columnCount) - { - XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount); - - Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index); - - if (p == null) - Xml.Elements().First().AddFirst(newTable); - - else - { - XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex); - - p.Xml.ReplaceWith - ( - split[0], - newTable, - split[1] - ); - } - - - return new Table(Document, newTable) { mainPart = mainPart }; - } - - public Table InsertTable(Table t) - { - XElement newXElement = new XElement(t.Xml); - Xml.Add(newXElement); - - Table newTable = new Table(Document, newXElement) - { - mainPart = mainPart, - Design = t.Design - }; - - return newTable; - } - - public Table InsertTable(int index, Table t) - { - Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index); - - XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex); - XElement newXElement = new XElement(t.Xml); - p.Xml.ReplaceWith - ( - split[0], - newXElement, - split[1] - ); - - Table newTable = new Table(Document, newXElement) - { - mainPart = mainPart, - Design = t.Design - }; - - return newTable; - } - internal Container(DocX document, XElement xml) - : base(document, xml) - { - - } - - public List InsertList(List list) - { - foreach (var item in list.Items) - { - Xml.Add(item.Xml); - } - - return list; - } - public List InsertList(List list, double fontSize) - { - foreach (var item in list.Items) - { - item.FontSize(fontSize); - Xml.Add(item.Xml); - } - return list; - } - - public List InsertList(List list, Font fontFamily, double fontSize) - { - foreach (var item in list.Items) - { - item.Font(fontFamily); - item.FontSize(fontSize); - Xml.Add(item.Xml); - } - return list; - } - - public List InsertList(int index, List list) - { - Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index); - - XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex); - var elements = new List { split[0] }; - elements.AddRange(list.Items.Select(i => new XElement(i.Xml))); - elements.Add(split[1]); - p.Xml.ReplaceWith(elements.ToArray()); - - return list; - } - } -} diff --git a/DocX/Content.cs b/DocX/Content.cs deleted file mode 100644 index fc29930d..00000000 --- a/DocX/Content.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Linq; -using System.Collections.Generic; -using System.Xml.Linq; - -namespace Novacode -{ - public class Content : InsertBeforeOrAfter - { - - public string Name { get; set; } - public string Tag { get; set; } - public string Text { get; set; } - public List Sections { get; set; } - public ContainerType ParentContainer; - - - internal Content(DocX document, XElement xml, int startIndex) - : base(document, xml) - { - - } - - public void SetText(string newText) - { - Xml.Descendants(XName.Get("t", DocX.w.NamespaceName)).First().Value = newText; - } - - } -} diff --git a/DocX/ContentCollection.cs b/DocX/ContentCollection.cs deleted file mode 100644 index 9e351e44..00000000 --- a/DocX/ContentCollection.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Novacode -{ - public class ContentCollection : List - { - public Content this[string name] - { - get - { - return this.FirstOrDefault(content => string.Equals(content.Name, name, StringComparison.CurrentCultureIgnoreCase)); - } - } - } -} diff --git a/DocX/CustomProperty.cs b/DocX/CustomProperty.cs deleted file mode 100644 index 71f08bda..00000000 --- a/DocX/CustomProperty.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; - -namespace Novacode -{ - public class CustomProperty - { - /// - /// The name of this CustomProperty. - /// - public string Name { get; } - - /// - /// The value of this CustomProperty. - /// - public object Value { get; } - - internal string Type { get; } - - internal CustomProperty(string name, string type, string value) - { - object realValue; - switch (type) - { - case "lpwstr": - { - realValue = value; - break; - } - - case "i4": - { - realValue = int.Parse(value, System.Globalization.CultureInfo.InvariantCulture); - break; - } - - case "r8": - { - realValue = Double.Parse(value, System.Globalization.CultureInfo.InvariantCulture); - break; - } - - case "filetime": - { - realValue = DateTime.Parse(value, System.Globalization.CultureInfo.InvariantCulture); - break; - } - - case "bool": - { - realValue = bool.Parse(value); - break; - } - - default: throw new Exception(); - } - - Name = name; - Type = type; - Value = realValue; - } - - private CustomProperty(string name, string type, object value) - { - Name = name; - Type = type; - Value = value; - } - - /// - /// Create a new CustomProperty to hold a string. - /// - /// The name of this CustomProperty. - /// The value of this CustomProperty. - public CustomProperty(string name, string value) : this(name, "lpwstr", value as object) { } - - - /// - /// Create a new CustomProperty to hold an int. - /// - /// The name of this CustomProperty. - /// The value of this CustomProperty. - public CustomProperty(string name, int value) : this(name, "i4", value) { } - - - /// - /// Create a new CustomProperty to hold a double. - /// - /// The name of this CustomProperty. - /// The value of this CustomProperty. - public CustomProperty(string name, double value) : this(name, "r8", value) { } - - - /// - /// Create a new CustomProperty to hold a DateTime. - /// - /// The name of this CustomProperty. - /// The value of this CustomProperty. - public CustomProperty(string name, DateTime value) : this(name, "filetime", value.ToUniversalTime()) { } - - /// - /// Create a new CustomProperty to hold a bool. - /// - /// The name of this CustomProperty. - /// The value of this CustomProperty. - public CustomProperty(string name, bool value) : this(name, "bool", value) { } - } -} diff --git a/DocX/DocProperty.cs b/DocX/DocProperty.cs deleted file mode 100644 index 319f1d8a..00000000 --- a/DocX/DocProperty.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Xml.Linq; -using System.Text.RegularExpressions; - -namespace Novacode -{ - /// - /// Represents a field of type document property. This field displays the value stored in a custom property. - /// - public class DocProperty: DocXElement - { - internal Regex extractName = new Regex(@"DOCPROPERTY (?.*) "); - - /// - /// The custom property to display. - /// - public string Name { get; } - - internal DocProperty(DocX document, XElement xml):base(document, xml) - { - string instr = Xml.Attribute(XName.Get("instr", "http://schemas.openxmlformats.org/wordprocessingml/2006/main")).Value; - Name = extractName.Match(instr.Trim()).Groups["name"].Value; - } - } -} diff --git a/DocX/DocX.cs b/DocX/DocX.cs deleted file mode 100644 index 6f5832fd..00000000 --- a/DocX/DocX.cs +++ /dev/null @@ -1,4598 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.IO.Packaging; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml; -using System.Xml.Linq; - -namespace Novacode -{ - /// - /// Represents a document. - /// - public class DocX : Container, IDisposable - { - #region Namespaces - static internal XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; - static internal XNamespace rel = "http://schemas.openxmlformats.org/package/2006/relationships"; - - static internal XNamespace r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; - static internal XNamespace m = "http://schemas.openxmlformats.org/officeDocument/2006/math"; - static internal XNamespace customPropertiesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"; - static internal XNamespace customVTypesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"; - - static internal XNamespace wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"; - static internal XNamespace a = "http://schemas.openxmlformats.org/drawingml/2006/main"; - static internal XNamespace c = "http://schemas.openxmlformats.org/drawingml/2006/chart"; - - static internal XNamespace v = "urn:schemas-microsoft-com:vml"; - - internal static XNamespace n = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"; - #endregion - - internal const string relationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; - internal const string contentTypeApplicationRelationShipXml = "application/vnd.openxmlformats-package.relationships+xml"; - - internal float getMarginAttribute(XName name) - { - XElement body = mainDoc.Root.Element(XName.Get("body", w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", w.NamespaceName)); - XElement pgMar = sectPr?.Element(XName.Get("pgMar", w.NamespaceName)); - XAttribute top = pgMar?.Attribute(name); - if (top != null) - { - float f; - if (float.TryParse(top.Value, out f)) - return (int)(f / 20.0f); - } - - return 0; - } - - internal void setMarginAttribute(XName xName, float value) - { - XElement body = mainDoc.Root.Element(XName.Get("body", w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", w.NamespaceName)); - XElement pgMar = sectPr?.Element(XName.Get("pgMar", w.NamespaceName)); - XAttribute top = pgMar?.Attribute(xName); - top?.SetValue(value * 20); - } - - public BookmarkCollection Bookmarks - { - get - { - BookmarkCollection bookmarks = new BookmarkCollection(); - foreach (Paragraph paragraph in Paragraphs) - bookmarks.AddRange(paragraph.GetBookmarks()); - return bookmarks; - } - } - - /// - /// Top margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginTop - { - get - { - return getMarginAttribute(XName.Get("top", w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("top", w.NamespaceName), value); - } - } - - /// - /// Bottom margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginBottom - { - get - { - return getMarginAttribute(XName.Get("bottom", w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("bottom", w.NamespaceName), value); - } - } - - /// - /// Left margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginLeft - { - get - { - return getMarginAttribute(XName.Get("left", w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("left", w.NamespaceName), value); - } - } - - /// - /// Right margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginRight - { - get - { - return getMarginAttribute(XName.Get("right", w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("right", w.NamespaceName), value); - } - } - - /// - /// Header margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginHeader - { - get - { - return getMarginAttribute(XName.Get("header", w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("header", w.NamespaceName), value); - } - } - - /// - /// Footer margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float MarginFooter - { - get - { - return getMarginAttribute(XName.Get("footer", w.NamespaceName)); - } - - set - { - setMarginAttribute(XName.Get("footer", w.NamespaceName), value); - } - } - - /// - /// Mirror Margins boolean value. True when margins has to be mirrored. - /// - internal bool getMirrorMargins(XName name) - { - XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - if (sectPr != null) - { - XElement MarMirror = sectPr.Element(XName.Get("mirrorMargins", DocX.w.NamespaceName)); - if (MarMirror != null) - { - return true; - } - } - return false; - - } - - internal void setMirrorMargins(XName name, bool value) - { - XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - if (sectPr != null) - { - XElement MarMirror = sectPr.Element(XName.Get("mirrorMargins", DocX.w.NamespaceName)); - if (MarMirror != null) - { - if (!value) - { - MarMirror.Remove(); - } - } - else - { - sectPr.Add(new XElement(w + "mirrorMargins", string.Empty)); - } - } - } - - public bool MirrorMargins - { - get - { - return getMirrorMargins(XName.Get("mirrorMargins", DocX.w.NamespaceName)); - } - - set - { - setMirrorMargins(XName.Get("mirrorMargins", DocX.w.NamespaceName), value); - } - } - - /// - /// Page width value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float PageWidth - { - get - { - XElement body = mainDoc.Root.Element(XName.Get("body", w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", w.NamespaceName)); - XElement pgSz = sectPr?.Element(XName.Get("pgSz", w.NamespaceName)); - - if (pgSz != null) - { - XAttribute w = pgSz.Attribute(XName.Get("w", DocX.w.NamespaceName)); - if (w != null) - { - float f; - if (float.TryParse(w.Value, out f)) - return (int)(f / 20.0f); - } - } - - return (12240.0f / 20.0f); - } - - set - { - XElement body = mainDoc.Root.Element(XName.Get("body", w.NamespaceName)); - XElement sectPr = body?.Element(XName.Get("sectPr", w.NamespaceName)); - XElement pgSz = sectPr?.Element(XName.Get("pgSz", w.NamespaceName)); - pgSz?.SetAttributeValue(XName.Get("w", w.NamespaceName), value * 20); - } - } - - /// - /// Page height value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. - /// - public float PageHeight - { - get - { - XElement body = mainDoc.Root.Element(XName.Get("body", w.NamespaceName)); - XElement sectPr = body.Element(XName.Get("sectPr", w.NamespaceName)); - if (sectPr != null) - { - XElement pgSz = sectPr.Element(XName.Get("pgSz", w.NamespaceName)); - - if (pgSz != null) - { - XAttribute w = pgSz.Attribute(XName.Get("h", DocX.w.NamespaceName)); - if (w != null) - { - float f; - if (float.TryParse(w.Value, out f)) - return (int)(f / 20.0f); - } - } - } - - return (15840.0f / 20.0f); - } - - set - { - XElement body = mainDoc.Root.Element(XName.Get("body", w.NamespaceName)); - - if (body != null) - { - XElement sectPr = body.Element(XName.Get("sectPr", w.NamespaceName)); - - if (sectPr != null) - { - XElement pgSz = sectPr.Element(XName.Get("pgSz", w.NamespaceName)); - - if (pgSz != null) - { - pgSz.SetAttributeValue(XName.Get("h", w.NamespaceName), value * 20); - } - } - } - } - } - /// - /// Returns true if any editing restrictions are imposed on this document. - /// - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// if(document.isProtected) - /// Console.WriteLine("Protected"); - /// else - /// Console.WriteLine("Not protected"); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public bool isProtected - { - get - { - return settings.Descendants(XName.Get("documentProtection", w.NamespaceName)).Count() > 0; - } - } - - /// - /// Returns the type of editing protection imposed on this document. - /// - /// The type of editing protection imposed on this document. - /// - /// - /// Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Make sure the document is protected before checking the protection type. - /// if (document.isProtected) - /// { - /// EditRestrictions protection = document.GetProtectionType(); - /// Console.WriteLine("Document is protected using " + protection.ToString()); - /// } - /// - /// else - /// Console.WriteLine("Document is not protected."); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public EditRestrictions GetProtectionType() - { - if (isProtected) - { - XElement documentProtection = settings.Descendants(XName.Get("documentProtection", w.NamespaceName)).FirstOrDefault(); - string edit_type = documentProtection.Attribute(XName.Get("edit", w.NamespaceName)).Value; - return (EditRestrictions)Enum.Parse(typeof(EditRestrictions), edit_type); - } - - return EditRestrictions.none; - } - - /// - /// Add editing protection to this document. - /// - /// The type of protection to add to this document. - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Allow no editing, only the adding of comment. - /// document.AddProtection(EditRestrictions.comments); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public void AddProtection(EditRestrictions er) - { - // Call remove protection before adding a new protection element. - RemoveProtection(); - - if (er == EditRestrictions.none) - return; - - XElement documentProtection = new XElement(XName.Get("documentProtection", w.NamespaceName)); - documentProtection.Add(new XAttribute(XName.Get("edit", w.NamespaceName), er.ToString())); - documentProtection.Add(new XAttribute(XName.Get("enforcement", w.NamespaceName), "1")); - - settings.Root.AddFirst(documentProtection); - } - - public void AddProtection(EditRestrictions er, string strPassword) - { - // http://blogs.msdn.com/b/vsod/archive/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0.aspx - // Call remove protection before adding a new protection element. - RemoveProtection(); - - if (er == EditRestrictions.none) - return; - - XElement documentProtection = new XElement(XName.Get("documentProtection", w.NamespaceName)); - documentProtection.Add(new XAttribute(XName.Get("edit", w.NamespaceName), er.ToString())); - documentProtection.Add(new XAttribute(XName.Get("enforcement", w.NamespaceName), "1")); - - int[] InitialCodeArray = { 0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3 }; - int[,] EncryptionMatrix = new int[15, 7] - { - - /* char 1 */ {0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09}, - /* char 2 */ {0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF}, - /* char 3 */ {0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0}, - /* char 4 */ {0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40}, - /* char 5 */ {0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5}, - /* char 6 */ {0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A}, - /* char 7 */ {0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9}, - /* char 8 */ {0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0}, - /* char 9 */ {0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC}, - /* char 10 */ {0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10}, - /* char 11 */ {0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168}, - /* char 12 */ {0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C}, - /* char 13 */ {0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD}, - /* char 14 */ {0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC}, - /* char 15 */ {0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4} - }; - - // Generate the Salt - byte[] arrSalt = new byte[16]; - RandomNumberGenerator rand = new RNGCryptoServiceProvider(); - rand.GetNonZeroBytes(arrSalt); - - //Array to hold Key Values - byte[] generatedKey = new byte[4]; - - //Maximum length of the password is 15 chars. - int intMaxPasswordLength = 15; - - if (!String.IsNullOrEmpty(strPassword)) - { - strPassword = strPassword.Substring(0, Math.Min(strPassword.Length, intMaxPasswordLength)); - - byte[] arrByteChars = new byte[strPassword.Length]; - - for (int intLoop = 0; intLoop < strPassword.Length; intLoop++) - { - int intTemp = Convert.ToInt32(strPassword[intLoop]); - arrByteChars[intLoop] = Convert.ToByte(intTemp & 0x00FF); - if (arrByteChars[intLoop] == 0) - arrByteChars[intLoop] = Convert.ToByte((intTemp & 0xFF00) >> 8); - } - - int intHighOrderWord = InitialCodeArray[arrByteChars.Length - 1]; - - for (int intLoop = 0; intLoop < arrByteChars.Length; intLoop++) - { - int tmp = intMaxPasswordLength - arrByteChars.Length + intLoop; - for (int intBit = 0; intBit < 7; intBit++) - { - if ((arrByteChars[intLoop] & (0x0001 << intBit)) != 0) - { - intHighOrderWord ^= EncryptionMatrix[tmp, intBit]; - } - } - } - - int intLowOrderWord = 0; - - // For each character in the strPassword, going backwards - for (int intLoopChar = arrByteChars.Length - 1; intLoopChar >= 0; intLoopChar--) - { - intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars[intLoopChar]; - } - - intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars.Length ^ 0xCE4B; - - // Combine the Low and High Order Word - int intCombinedkey = (intHighOrderWord << 16) + intLowOrderWord; - - // The byte order of the result shall be reversed [Example: 0x64CEED7E becomes 7EEDCE64. end example], - // and that value shall be hashed as defined by the attribute values. - - for (int intTemp = 0; intTemp < 4; intTemp++) - { - generatedKey[intTemp] = Convert.ToByte(((uint)(intCombinedkey & (0x000000FF << (intTemp * 8)))) >> (intTemp * 8)); - } - } - - StringBuilder sb = new StringBuilder(); - for (int intTemp = 0; intTemp < 4; intTemp++) - { - sb.Append(Convert.ToString(generatedKey[intTemp], 16)); - } - generatedKey = Encoding.Unicode.GetBytes(sb.ToString().ToUpper()); - - byte[] tmpArray1 = generatedKey; - byte[] tmpArray2 = arrSalt; - byte[] tempKey = new byte[tmpArray1.Length + tmpArray2.Length]; - Buffer.BlockCopy(tmpArray2, 0, tempKey, 0, tmpArray2.Length); - Buffer.BlockCopy(tmpArray1, 0, tempKey, tmpArray2.Length, tmpArray1.Length); - generatedKey = tempKey; - - - int iterations = 100000; - - HashAlgorithm sha1 = new SHA1Managed(); - generatedKey = sha1.ComputeHash(generatedKey); - byte[] iterator = new byte[4]; - for (int intTmp = 0; intTmp < iterations; intTmp++) - { - - iterator[0] = Convert.ToByte((intTmp & 0x000000FF) >> 0); - iterator[1] = Convert.ToByte((intTmp & 0x0000FF00) >> 8); - iterator[2] = Convert.ToByte((intTmp & 0x00FF0000) >> 16); - iterator[3] = Convert.ToByte((intTmp & 0xFF000000) >> 24); - - generatedKey = concatByteArrays(iterator, generatedKey); - generatedKey = sha1.ComputeHash(generatedKey); - } - - documentProtection.Add(new XAttribute(XName.Get("cryptProviderType", w.NamespaceName), "rsaFull")); - documentProtection.Add(new XAttribute(XName.Get("cryptAlgorithmClass", w.NamespaceName), "hash")); - documentProtection.Add(new XAttribute(XName.Get("cryptAlgorithmType", w.NamespaceName), "typeAny")); - documentProtection.Add(new XAttribute(XName.Get("cryptAlgorithmSid", w.NamespaceName), "4")); // SHA1 - documentProtection.Add(new XAttribute(XName.Get("cryptSpinCount", w.NamespaceName), iterations.ToString())); - documentProtection.Add(new XAttribute(XName.Get("hash", w.NamespaceName), Convert.ToBase64String(generatedKey))); - documentProtection.Add(new XAttribute(XName.Get("salt", w.NamespaceName), Convert.ToBase64String(arrSalt))); - - settings.Root.AddFirst(documentProtection); - } - - private byte[] concatByteArrays(byte[] array1, byte[] array2) - { - byte[] result = new byte[array1.Length + array2.Length]; - Buffer.BlockCopy(array2, 0, result, 0, array2.Length); - Buffer.BlockCopy(array1, 0, result, array2.Length, array1.Length); - return result; - } - - /// - /// Remove editing protection from this document. - /// - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Remove any editing restrictions that are imposed on this document. - /// document.RemoveProtection(); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public void RemoveProtection() - { - // Remove every node of type documentProtection. - settings.Descendants(XName.Get("documentProtection", w.NamespaceName)).Remove(); - } - - public PageLayout PageLayout - { - get - { - XElement sectPr = Xml.Element(XName.Get("sectPr", w.NamespaceName)); - if (sectPr == null) - { - Xml.SetElementValue(XName.Get("sectPr", w.NamespaceName), string.Empty); - sectPr = Xml.Element(XName.Get("sectPr", w.NamespaceName)); - } - - return new PageLayout(this, sectPr); - } - } - - /// - /// Returns a collection of Headers in this Document. - /// A document typically contains three Headers. - /// A default one (odd), one for the first page and one for even pages. - /// - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add header support to this document. - /// document.AddHeaders(); - /// - /// // Get a collection of all headers in this document. - /// Headers headers = document.Headers; - /// - /// // The header used for the first page of this document. - /// Header first = headers.first; - /// - /// // The header used for odd pages of this document. - /// Header odd = headers.odd; - /// - /// // The header used for even pages of this document. - /// Header even = headers.even; - /// } - /// - /// - public Headers Headers - { - get - { - return headers; - } - } - private Headers headers; - - /// - /// Returns a collection of Footers in this Document. - /// A document typically contains three Footers. - /// A default one (odd), one for the first page and one for even pages. - /// - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add footer support to this document. - /// document.AddFooters(); - /// - /// // Get a collection of all footers in this document. - /// Footers footers = document.Footers; - /// - /// // The footer used for the first page of this document. - /// Footer first = footers.first; - /// - /// // The footer used for odd pages of this document. - /// Footer odd = footers.odd; - /// - /// // The footer used for even pages of this document. - /// Footer even = footers.even; - /// } - /// - /// - public Footers Footers - { - get - { - return footers; - } - } - - private Footers footers; - - /// - /// Should the Document use different Headers and Footers for odd and even pages? - /// - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add header support to this document. - /// document.AddHeaders(); - /// - /// // Get a collection of all headers in this document. - /// Headers headers = document.Headers; - /// - /// // The header used for odd pages of this document. - /// Header odd = headers.odd; - /// - /// // The header used for even pages of this document. - /// Header even = headers.even; - /// - /// // Force the document to use a different header for odd and even pages. - /// document.DifferentOddAndEvenPages = true; - /// - /// // Content can be added to the Headers in the same manor that it would be added to the main document. - /// Paragraph p1 = odd.InsertParagraph(); - /// p1.Append("This is the odd pages header."); - /// - /// Paragraph p2 = even.InsertParagraph(); - /// p2.Append("This is the even pages header."); - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public bool DifferentOddAndEvenPages - { - get - { - XDocument settings; - using (TextReader tr = new StreamReader(settingsPart.GetStream())) - settings = XDocument.Load(tr); - - XElement evenAndOddHeaders = settings.Root.Element(w + "evenAndOddHeaders"); - - return evenAndOddHeaders != null; - } - - set - { - XDocument settings; - using (TextReader tr = new StreamReader(settingsPart.GetStream())) - settings = XDocument.Load(tr); - - XElement evenAndOddHeaders = settings.Root.Element(w + "evenAndOddHeaders"); - if (evenAndOddHeaders == null) - { - if (value) - settings.Root.AddFirst(new XElement(w + "evenAndOddHeaders")); - } - else - { - if (!value) - evenAndOddHeaders.Remove(); - } - - using (TextWriter tw = new StreamWriter(new PackagePartStream(settingsPart.GetStream()))) - settings.Save(tw); - } - } - - /// - /// Should the Document use an independent Header and Footer for the first page? - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add header support to this document. - /// document.AddHeaders(); - /// - /// // The header used for the first page of this document. - /// Header first = document.Headers.first; - /// - /// // Force the document to use a different header for first page. - /// document.DifferentFirstPage = true; - /// - /// // Content can be added to the Headers in the same manor that it would be added to the main document. - /// Paragraph p = first.InsertParagraph(); - /// p.Append("This is the first pages header."); - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - public bool DifferentFirstPage - { - get - { - XElement body = mainDoc.Root.Element(w + "body"); - XElement sectPr = body.Element(w + "sectPr"); - - XElement titlePg = sectPr?.Element(w + "titlePg"); - return titlePg != null; - } - - set - { - XElement body = mainDoc.Root.Element(w + "body"); - - body.Add(new XElement(w + "sectPr", string.Empty)); - - var sectPr = body.Element(w + "sectPr"); - - var titlePg = sectPr.Element(w + "titlePg"); - if (titlePg == null) - { - if (value) - sectPr.Add(new XElement(w + "titlePg", string.Empty)); - } - else - { - if (!value) - titlePg.Remove(); - } - } - } - - private Header GetHeaderByType(string type) - { - return (Header)GetHeaderOrFooterByType(type, true); - } - - private Footer GetFooterByType(string type) - { - return (Footer)GetHeaderOrFooterByType(type, false); - } - - private object GetHeaderOrFooterByType(string type, bool isHeader) - { - // Switch which handles either case Header\Footer, this just cuts down on code duplication. - string reference = "footerReference"; - if (isHeader) - reference = "headerReference"; - - // Get the Id of the [default, even or first] [Header or Footer] - - string Id = - ( - from e in mainDoc.Descendants(XName.Get("body", w.NamespaceName)).Descendants() - where (e.Name.LocalName == reference) && (e.Attribute(w + "type").Value == type) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (Id != null) - { - // Get the Xml file for this Header or Footer. - Uri partUri = mainPart.GetRelationship(Id).TargetUri; - - // Weird problem with PackaePart API. - if (!partUri.OriginalString.StartsWith("/word/")) - partUri = new Uri("/word/" + partUri.OriginalString, UriKind.Relative); - - // Get the Part and open a stream to get the Xml file. - PackagePart part = package.GetPart(partUri); - - using (TextReader tr = new StreamReader(part.GetStream())) - { - var doc = XDocument.Load(tr); - - // Header and Footer extend Container. - Container c; - if (isHeader) - c = new Header(this, doc.Element(w + "hdr"), part); - else - c = new Footer(this, doc.Element(w + "ftr"), part); - - return c; - } - } - - // If we got this far something went wrong. - return null; - } - - - - public List
GetSections() - { - - var allParas = Paragraphs; - - var parasInASection = new List(); - var sections = new List
(); - - foreach (var para in allParas) - { - - var sectionInPara = para.Xml.Descendants().FirstOrDefault(s => s.Name.LocalName == "sectPr"); - - if (sectionInPara == null) - { - parasInASection.Add(para); - } - else - { - parasInASection.Add(para); - var section = new Section(Document, sectionInPara) { SectionParagraphs = parasInASection }; - sections.Add(section); - parasInASection = new List(); - } - - } - - XElement body = mainDoc.Root.Element(XName.Get("body", w.NamespaceName)); - XElement baseSectionXml = body.Element(XName.Get("sectPr", w.NamespaceName)); - var baseSection = new Section(Document, baseSectionXml) { SectionParagraphs = parasInASection }; - sections.Add(baseSection); - - return sections; - } - - - // Get the word\settings.xml part - internal PackagePart settingsPart; - internal PackagePart endnotesPart; - internal PackagePart footnotesPart; - internal PackagePart stylesPart; - internal PackagePart stylesWithEffectsPart; - internal PackagePart numberingPart; - internal PackagePart fontTablePart; - - #region Internal variables defined foreach DocX object - // Object representation of the .docx - internal Package package; - - // The mainDocument is loaded into a XDocument object for easy querying and editing - internal XDocument mainDoc; - internal XDocument settings; - internal XDocument endnotes; - internal XDocument footnotes; - internal XDocument styles; - internal XDocument stylesWithEffects; - internal XDocument numbering; - internal XDocument fontTable; - internal XDocument header1; - internal XDocument header2; - internal XDocument header3; - - // A lookup for the Paragraphs in this document. - internal Dictionary paragraphLookup = new Dictionary(); - // Every document is stored in a MemoryStream, all edits made to a document are done in memory. - internal MemoryStream memoryStream; - // The filename that this document was loaded from - internal string filename; - // The stream that this document was loaded from - internal Stream stream; - #endregion - - internal DocX(DocX document, XElement xml) - : base(document, xml) - { - - } - - /// - /// Returns a list of Images in this document. - /// - /// - /// Get the unique Id of every Image in this document. - /// - /// // Load a document. - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// // Loop through each Image in this document. - /// foreach (Novacode.Image i in document.Images) - /// { - /// // Get the unique Id which identifies this Image. - /// string uniqueId = i.Id; - /// } - /// - /// - /// - /// - /// - /// - /// - public List Images - { - get - { - PackageRelationshipCollection imageRelationships = mainPart.GetRelationshipsByType(relationshipImage); - if (imageRelationships.Any()) - { - return - ( - from i in imageRelationships - select new Image(this, i) - ).ToList(); - } - - return new List(); - } - } - - /// - /// Returns a list of custom properties in this document. - /// - /// - /// Method 1: Get the name, type and value of each CustomProperty in this document. - /// - /// // Load Example.docx - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// /* - /// * No two custom properties can have the same name, - /// * so a Dictionary is the perfect data structure to store them in. - /// * Each custom property can be accessed using its name. - /// */ - /// foreach (string name in document.CustomProperties.Keys) - /// { - /// // Grab a custom property using its name. - /// CustomProperty cp = document.CustomProperties[name]; - /// - /// // Write this custom properties details to Console. - /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value)); - /// } - /// - /// Console.WriteLine("Press any key..."); - /// - /// // Wait for the user to press a key before closing the Console. - /// Console.ReadKey(); - /// - /// - /// - /// Method 2: Get the name, type and value of each CustomProperty in this document. - /// - /// // Load Example.docx - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// /* - /// * No two custom properties can have the same name, - /// * so a Dictionary is the perfect data structure to store them in. - /// * The values of this Dictionary are CustomProperties. - /// */ - /// foreach (CustomProperty cp in document.CustomProperties.Values) - /// { - /// // Write this custom properties details to Console. - /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value)); - /// } - /// - /// Console.WriteLine("Press any key..."); - /// - /// // Wait for the user to press a key before closing the Console. - /// Console.ReadKey(); - /// - /// - /// - public Dictionary CustomProperties - { - get - { - if (package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative))) - { - PackagePart docProps_custom = package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative)); - XDocument customPropDoc; - using (TextReader tr = new StreamReader(docProps_custom.GetStream(FileMode.Open, FileAccess.Read))) - customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace); - - // Get all of the custom properties in this document - return - ( - from p in customPropDoc.Descendants(XName.Get("property", customPropertiesSchema.NamespaceName)) - let Name = p.Attribute(XName.Get("name")).Value - let Type = p.Descendants().Single().Name.LocalName - let Value = p.Descendants().Single().Value - select new CustomProperty(Name, Type, Value) - ).ToDictionary(p => p.Name, StringComparer.CurrentCultureIgnoreCase); - } - - return new Dictionary(); - } - } - - /// - /// Returns the list of document core properties with corresponding values. - /// - public Dictionary CoreProperties - { - get - { - if (package.PartExists(new Uri("/docProps/core.xml", UriKind.Relative))) - { - PackagePart docProps_Core = package.GetPart(new Uri("/docProps/core.xml", UriKind.Relative)); - XDocument corePropDoc; - using (TextReader tr = new StreamReader(docProps_Core.GetStream(FileMode.Open, FileAccess.Read))) - corePropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace); - - // Get all of the core properties in this document - return (from docProperty in corePropDoc.Root.Elements() - select - new KeyValuePair( - string.Format( - "{0}:{1}", - corePropDoc.Root.GetPrefixOfNamespace(docProperty.Name.Namespace), - docProperty.Name.LocalName), - docProperty.Value)).ToDictionary(p => p.Key, v => v.Value); - } - - return new Dictionary(); - } - } - - /// - /// Get the Text of this document. - /// - /// - /// Write to Console the Text from this document. - /// - /// // Load a document - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// // Get the text of this document. - /// string text = document.Text; - /// - /// // Write the text of this document to Console. - /// Console.Write(text); - /// - /// // Wait for the user to press a key before closing the console window. - /// Console.ReadKey(); - /// - /// - public string Text - { - get - { - return HelperFunctions.GetText(Xml); - } - } - /// - /// Get the text of each footnote from this document - /// - public IEnumerable FootnotesText - { - get - { - foreach (XElement footnote in footnotes.Root.Elements(w + "footnote")) - { - yield return HelperFunctions.GetText(footnote); - } - } - } - - /// - /// Get the text of each endnote from this document - /// - public IEnumerable EndnotesText - { - get - { - foreach (XElement endnote in endnotes.Root.Elements(w + "endnote")) - { - yield return HelperFunctions.GetText(endnote); - } - } - } - - - - internal string GetCollectiveText(List list) - { - string text = string.Empty; - - foreach (var hp in list) - { - using (TextReader tr = new StreamReader(hp.GetStream())) - { - XDocument d = XDocument.Load(tr); - - StringBuilder sb = new StringBuilder(); - - // Loop through each text item in this run - foreach (XElement descendant in d.Descendants()) - { - switch (descendant.Name.LocalName) - { - case "tab": - sb.Append("\t"); - break; - case "br": - sb.Append("\n"); - break; - case "t": - goto case "delText"; - case "delText": - sb.Append(descendant.Value); - break; - default: break; - } - } - - text += "\n" + sb; - } - } - - return text; - } - - /// - /// Insert the contents of another document at the end of this document. - /// - /// The document to insert at the end of this document. - /// If true, document is inserted at the end, otherwise document is inserted at the beginning. - /// - /// Create a new document and insert an old document into it. - /// - /// // Create a new document. - /// using (DocX newDocument = DocX.Create(@"NewDocument.docx")) - /// { - /// // Load an old document. - /// using (DocX oldDocument = DocX.Load(@"OldDocument.docx")) - /// { - /// // Insert the old document into the new document. - /// newDocument.InsertDocument(oldDocument); - /// - /// // Save the new document. - /// newDocument.Save(); - /// }// Release the old document from memory. - /// }// Release the new document from memory. - /// - /// - /// If the document being inserted contains Images, CustomProperties and or custom styles, these will be correctly inserted into the new document. In the case of Images, new ID's are generated for the Images being inserted to avoid ID conflicts. CustomProperties with the same name will be ignored not replaced. - /// - /// - public void InsertDocument(DocX remote_document, bool append = true) - { - // We don't want to effect the origional XDocument, so create a new one from the old one. - XDocument remote_mainDoc = new XDocument(remote_document.mainDoc); - - XDocument remote_footnotes = null; - if (remote_document.footnotes != null) - remote_footnotes = new XDocument(remote_document.footnotes); - - XDocument remote_endnotes = null; - if (remote_document.endnotes != null) - remote_endnotes = new XDocument(remote_document.endnotes); - - // Remove all header and footer references. - remote_mainDoc.Descendants(XName.Get("headerReference", w.NamespaceName)).Remove(); - remote_mainDoc.Descendants(XName.Get("footerReference", w.NamespaceName)).Remove(); - - // Get the body of the remote document. - XElement remote_body = remote_mainDoc.Root.Element(XName.Get("body", w.NamespaceName)); - - // Every file that is missing from the local document will have to be copied, every file that already exists will have to be merged. - PackagePartCollection ppc = remote_document.package.GetParts(); - - List ignoreContentTypes = new List - { - "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", - "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", - "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", - "application/vnd.openxmlformats-package.core-properties+xml", - "application/vnd.openxmlformats-officedocument.extended-properties+xml", - contentTypeApplicationRelationShipXml - }; - - List imageContentTypes = new List - { - "image/jpeg", - "image/jpg", - "image/png", - "image/bmp", - "image/gif", - "image/tiff", - "image/icon", - "image/pcx", - "image/emf", - "image/wmf" - }; - // Check if each PackagePart pp exists in this document. - foreach (PackagePart remote_pp in ppc) - { - if (ignoreContentTypes.Contains(remote_pp.ContentType) || imageContentTypes.Contains(remote_pp.ContentType)) - continue; - - // If this external PackagePart already exits then we must merge them. - if (package.PartExists(remote_pp.Uri)) - { - PackagePart local_pp = package.GetPart(remote_pp.Uri); - switch (remote_pp.ContentType) - { - case "application/vnd.openxmlformats-officedocument.custom-properties+xml": - merge_customs(remote_pp, local_pp, remote_mainDoc); - break; - - // Merge footnotes (and endnotes) before merging styles, then set the remote_footnotes to the just updated footnotes - case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": - 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; - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": - merge_styles(remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes); - break; - - // Merge styles after merging the footnotes, so the changes will be applied to the correct document/footnotes - case "application/vnd.ms-word.stylesWithEffects+xml": - merge_styles(remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes); - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml": - merge_fonts(remote_pp, local_pp, remote_mainDoc, remote_document); - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": - merge_numbering(remote_pp, local_pp, remote_mainDoc, remote_document); - break; - } - } - - // If this external PackagePart does not exits in the internal document then we can simply copy it. - else - { - var packagePart = clonePackagePart(remote_pp); - switch (remote_pp.ContentType) - { - case "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": - endnotesPart = packagePart; - endnotes = remote_endnotes; - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": - footnotesPart = packagePart; - footnotes = remote_footnotes; - break; - - case "application/vnd.openxmlformats-officedocument.custom-properties+xml": - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": - stylesPart = packagePart; - using (TextReader tr = new StreamReader(stylesPart.GetStream())) - styles = XDocument.Load(tr); - break; - - case "application/vnd.ms-word.stylesWithEffects+xml": - stylesWithEffectsPart = packagePart; - using (TextReader tr = new StreamReader(stylesWithEffectsPart.GetStream())) - stylesWithEffects = XDocument.Load(tr); - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml": - fontTablePart = packagePart; - using (TextReader tr = new StreamReader(fontTablePart.GetStream())) - fontTable = XDocument.Load(tr); - break; - - case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": - numberingPart = packagePart; - using (TextReader tr = new StreamReader(numberingPart.GetStream())) - numbering = XDocument.Load(tr); - break; - - } - - clonePackageRelationship(remote_document, remote_pp, remote_mainDoc); - } - } - - foreach (var hyperlink_rel in remote_document.mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")) - { - var old_rel_Id = hyperlink_rel.Id; - var new_rel_Id = mainPart.CreateRelationship(hyperlink_rel.TargetUri, hyperlink_rel.TargetMode, hyperlink_rel.RelationshipType).Id; - var hyperlink_refs = remote_mainDoc.Descendants(XName.Get("hyperlink", w.NamespaceName)); - foreach (var hyperlink_ref in hyperlink_refs) - { - XAttribute a0 = hyperlink_ref.Attribute(XName.Get("id", r.NamespaceName)); - if (a0 != null && a0.Value == old_rel_Id) - { - a0.SetValue(new_rel_Id); - } - } - } - - ////ole object links - foreach (var oleObject_rel in remote_document.mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject")) - { - var old_rel_Id = oleObject_rel.Id; - var new_rel_Id = mainPart.CreateRelationship(oleObject_rel.TargetUri, oleObject_rel.TargetMode, oleObject_rel.RelationshipType).Id; - var oleObject_refs = remote_mainDoc.Descendants(XName.Get("OLEObject", "urn:schemas-microsoft-com:office:office")); - foreach (var oleObject_ref in oleObject_refs) - { - XAttribute a0 = oleObject_ref.Attribute(XName.Get("id", r.NamespaceName)); - if (a0 != null && a0.Value == old_rel_Id) - { - a0.SetValue(new_rel_Id); - } - } - } - - - foreach (PackagePart remote_pp in ppc) - { - if (imageContentTypes.Contains(remote_pp.ContentType)) - { - merge_images(remote_pp, remote_document, remote_mainDoc, remote_pp.ContentType); - } - } - - int id = 0; - var local_docPrs = mainDoc.Root.Descendants(XName.Get("docPr", wp.NamespaceName)); - foreach (var local_docPr in local_docPrs) - { - XAttribute a_id = local_docPr.Attribute(XName.Get("id")); - int a_id_value; - if (a_id != null && int.TryParse(a_id.Value, out a_id_value)) - if (a_id_value > id) - id = a_id_value; - } - id++; - - // docPr must be sequential - var docPrs = remote_body.Descendants(XName.Get("docPr", wp.NamespaceName)); - foreach (var docPr in docPrs) - { - docPr.SetAttributeValue(XName.Get("id"), id); - id++; - } - - // Add the remote documents contents to this document. - XElement local_body = mainDoc.Root.Element(XName.Get("body", w.NamespaceName)); - if (append) - local_body.Add(remote_body.Elements()); - else - local_body.AddFirst(remote_body.Elements()); - - // Copy any missing root attributes to the local document. - foreach (XAttribute a in remote_mainDoc.Root.Attributes()) - { - if (mainDoc.Root.Attribute(a.Name) == null) - { - mainDoc.Root.SetAttributeValue(a.Name, a.Value); - } - } - - } - - private void merge_images(PackagePart remote_pp, DocX remote_document, XDocument remote_mainDoc, String contentType) - { - // Before doing any other work, check to see if this image is actually referenced in the document. - // 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; - } - String remote_Id = remote_rel.Id; - - String remote_hash = ComputeMD5HashString(remote_pp.GetStream()); - var image_parts = package.GetParts().Where(pp => pp.ContentType.Equals(contentType)); - - bool found = false; - foreach (var part in image_parts) - { - String local_hash = ComputeMD5HashString(part.GetStream()); - if (local_hash.Equals(remote_hash)) - { - // This image already exists in this document. - found = true; - - var local_rel = mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(part.Uri.OriginalString.Replace("/word/", ""))).FirstOrDefault(); - if (local_rel == null) - { - local_rel = mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(part.Uri.OriginalString)).FirstOrDefault(); - } - if (local_rel != null) - { - String new_Id = local_rel.Id; - - // Replace all instances of remote_Id in the local document with local_Id - var elems = remote_mainDoc.Descendants(XName.Get("blip", a.NamespaceName)); - foreach (var elem in elems) - { - XAttribute embed = elem.Attribute(XName.Get("embed", 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 (for shapes as well) - var v_elems = remote_mainDoc.Descendants(XName.Get("imagedata", v.NamespaceName)); - foreach (var elem in v_elems) - { - XAttribute id = elem.Attribute(XName.Get("id", r.NamespaceName)); - if (id != null && id.Value == remote_Id) - { - id.SetValue(new_Id); - } - } - } - - break; - } - } - - // This image does not exist in this document. - if (!found) - { - String new_uri = remote_pp.Uri.OriginalString; - new_uri = new_uri.Remove(new_uri.LastIndexOf("/")); - //new_uri = new_uri.Replace("word/", ""); - new_uri += "/" + Guid.NewGuid() + contentType.Replace("image/", "."); - if (!new_uri.StartsWith("/")) - new_uri = "/" + new_uri; - - PackagePart new_pp = package.CreatePart(new Uri(new_uri, UriKind.Relative), remote_pp.ContentType, CompressionOption.Normal); - - using (Stream s_read = remote_pp.GetStream()) - { - using (Stream s_write = new PackagePartStream(new_pp.GetStream(FileMode.Create))) - { - CopyStream(s_read, s_write); - } - } - - PackageRelationship pr = mainPart.CreateRelationship(new Uri(new_uri, UriKind.Relative), TargetMode.Internal, relationshipImage); - - String new_Id = pr.Id; - - //Check if the remote relationship id is a default rId from Word - Match defRelId = Regex.Match(remote_Id, @"rId\d+", RegexOptions.IgnoreCase); - - // Replace all instances of remote_Id in the local document with local_Id - var elems = remote_mainDoc.Descendants(XName.Get("blip", a.NamespaceName)); - foreach (var elem in elems) - { - XAttribute embed = elem.Attribute(XName.Get("embed", r.NamespaceName)); - if (embed != null && embed.Value == remote_Id) - { - embed.SetValue(new_Id); - } - } - - if (!defRelId.Success) - { - // Replace all instances of remote_Id in the local document with local_Id - var elems_local = mainDoc.Descendants(XName.Get("blip", a.NamespaceName)); - foreach (var elem in elems_local) - { - XAttribute embed = elem.Attribute(XName.Get("embed", 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", v.NamespaceName)); - foreach (var elem in v_elems_local) - { - XAttribute id = elem.Attribute(XName.Get("id", 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) - var v_elems = remote_mainDoc.Descendants(XName.Get("imagedata", v.NamespaceName)); - foreach (var elem in v_elems) - { - XAttribute id = elem.Attribute(XName.Get("id", r.NamespaceName)); - if (id != null && id.Value == remote_Id) - { - id.SetValue(new_Id); - } - } - } - } - - private string ComputeMD5HashString(Stream stream) - { - MD5 md5 = MD5.Create(); - byte[] hash = md5.ComputeHash(stream); - StringBuilder sb = new StringBuilder(); - foreach (byte b in hash) - sb.Append(b.ToString("X2")); - return sb.ToString(); - } - - private void merge_endnotes(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_endnotes) - { - IEnumerable ids = - ( - from d in endnotes.Root.Descendants() - where d.Name.LocalName == "endnote" - select int.Parse(d.Attribute(XName.Get("id", w.NamespaceName)).Value) - ); - - int max_id = ids.Max() + 1; - var endnoteReferences = remote_mainDoc.Descendants(XName.Get("endnoteReference", w.NamespaceName)); - - foreach (var endnote in remote_endnotes.Root.Elements().OrderBy(fr => fr.Attribute(XName.Get("id", r.NamespaceName))).Reverse()) - { - XAttribute id = endnote.Attribute(XName.Get("id", w.NamespaceName)); - int i; - if (id != null && int.TryParse(id.Value, out i)) - { - if (i > 0) - { - foreach (var endnoteRef in endnoteReferences) - { - XAttribute a = endnoteRef.Attribute(XName.Get("id", w.NamespaceName)); - if (a != null && int.Parse(a.Value).Equals(i)) - { - a.SetValue(max_id); - } - } - - // We care about copying this footnote. - endnote.SetAttributeValue(XName.Get("id", w.NamespaceName), max_id); - endnotes.Root.Add(endnote); - max_id++; - } - } - } - } - - private void merge_footnotes(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes) - { - IEnumerable ids = - ( - from d in footnotes.Root.Descendants() - where d.Name.LocalName == "footnote" - select int.Parse(d.Attribute(XName.Get("id", w.NamespaceName)).Value) - ); - - int max_id = ids.Max() + 1; - var footnoteReferences = remote_mainDoc.Descendants(XName.Get("footnoteReference", w.NamespaceName)); - - foreach (var footnote in remote_footnotes.Root.Elements().OrderBy(fr => fr.Attribute(XName.Get("id", r.NamespaceName))).Reverse()) - { - XAttribute id = footnote.Attribute(XName.Get("id", w.NamespaceName)); - int i; - if (id != null && int.TryParse(id.Value, out i)) - { - if (i > 0) - { - foreach (var footnoteRef in footnoteReferences) - { - XAttribute a = footnoteRef.Attribute(XName.Get("id", w.NamespaceName)); - if (a != null && int.Parse(a.Value).Equals(i)) - { - a.SetValue(max_id); - } - } - - // We care about copying this footnote. - footnote.SetAttributeValue(XName.Get("id", w.NamespaceName), max_id); - footnotes.Root.Add(footnote); - max_id++; - } - } - } - } - - private void merge_customs(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc) - { - // Get the remote documents custom.xml file. - XDocument remote_custom_document; - using (TextReader tr = new StreamReader(remote_pp.GetStream())) - remote_custom_document = XDocument.Load(tr); - - // Get the local documents custom.xml file. - XDocument local_custom_document; - using (TextReader tr = new StreamReader(local_pp.GetStream())) - local_custom_document = XDocument.Load(tr); - - IEnumerable pids = - ( - from d in remote_custom_document.Root.Descendants() - where d.Name.LocalName == "property" - select int.Parse(d.Attribute(XName.Get("pid")).Value) - ); - - int pid = pids.Max() + 1; - - foreach (XElement remote_property in remote_custom_document.Root.Elements()) - { - bool found = false; - foreach (XElement local_property in local_custom_document.Root.Elements()) - { - XAttribute remote_property_name = remote_property.Attribute(XName.Get("name")); - XAttribute local_property_name = local_property.Attribute(XName.Get("name")); - - if (remote_property != null && local_property_name != null && remote_property_name.Value.Equals(local_property_name.Value)) - found = true; - } - - if (!found) - { - remote_property.SetAttributeValue(XName.Get("pid"), pid); - local_custom_document.Root.Add(remote_property); - - pid++; - } - } - - // Save the modified local custom styles.xml file. - using (TextWriter tw = new StreamWriter(new PackagePartStream(local_pp.GetStream(FileMode.Create, FileAccess.Write)))) - local_custom_document.Save(tw, SaveOptions.None); - } - - private void merge_numbering(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote) - { - // Add each remote numbering to this document. - IEnumerable remote_abstractNums = remote.numbering.Root.Elements(XName.Get("abstractNum", w.NamespaceName)); - int guidd = 0; - foreach (var an in remote_abstractNums) - { - XAttribute a = an.Attribute(XName.Get("abstractNumId", w.NamespaceName)); - if (a != null) - { - int i; - if (int.TryParse(a.Value, out i)) - { - if (i > guidd) - guidd = i; - } - } - } - guidd++; - - IEnumerable remote_nums = remote.numbering.Root.Elements(XName.Get("num", w.NamespaceName)); - int guidd2 = 0; - foreach (var an in remote_nums) - { - XAttribute a = an.Attribute(XName.Get("numId", w.NamespaceName)); - if (a != null) - { - int i; - if (int.TryParse(a.Value, out i)) - { - if (i > guidd2) - guidd2 = i; - } - } - } - guidd2++; - - foreach (XElement remote_abstractNum in remote_abstractNums) - { - XAttribute abstractNumId = remote_abstractNum.Attribute(XName.Get("abstractNumId", w.NamespaceName)); - if (abstractNumId != null) - { - String abstractNumIdValue = abstractNumId.Value; - abstractNumId.SetValue(guidd); - - foreach (XElement remote_num in remote_nums) - { - var numIds = remote_mainDoc.Descendants(XName.Get("numId", w.NamespaceName)); - foreach (var numId in numIds) - { - XAttribute attr = numId.Attribute(XName.Get("val", w.NamespaceName)); - if (attr != null && attr.Value.Equals(remote_num.Attribute(XName.Get("numId", w.NamespaceName)).Value)) - { - attr.SetValue(guidd2); - } - - } - remote_num.SetAttributeValue(XName.Get("numId", w.NamespaceName), guidd2); - - XElement e = remote_num.Element(XName.Get("abstractNumId", w.NamespaceName)); - XAttribute a2 = e?.Attribute(XName.Get("val", w.NamespaceName)); - if (a2 != null && a2.Value.Equals(abstractNumIdValue)) - a2.SetValue(guidd); - - guidd2++; - } - } - - guidd++; - } - - // 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", w.NamespaceName)).Count() > 0) - numbering.Root.Elements(XName.Get("abstractNum", w.NamespaceName)).Last().AddAfterSelf(remote_abstractNums); - - if (numbering.Root.Elements(XName.Get("num", w.NamespaceName)).Count() > 0) - numbering.Root.Elements(XName.Get("num", w.NamespaceName)).Last().AddAfterSelf(remote_nums); - } - - private void merge_fonts(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote) - { - // Add each remote font to this document. - IEnumerable remote_fonts = remote.fontTable.Root.Elements(XName.Get("font", w.NamespaceName)); - IEnumerable local_fonts = fontTable.Root.Elements(XName.Get("font", w.NamespaceName)); - - foreach (XElement remote_font in remote_fonts) - { - bool flag_addFont = true; - foreach (XElement local_font in local_fonts) - { - if (local_font.Attribute(XName.Get("name", w.NamespaceName)).Value == remote_font.Attribute(XName.Get("name", w.NamespaceName)).Value) - { - flag_addFont = false; - break; - } - } - - if (flag_addFont) - { - fontTable.Root.Add(remote_font); - } - } - } - - private void merge_styles(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes, XDocument remote_endnotes) - { - var local_styles = new Dictionary(); - foreach (XElement local_style in styles.Root.Elements(XName.Get("style", w.NamespaceName))) - { - XElement temp = new XElement(local_style); - XAttribute styleId = temp.Attribute(XName.Get("styleId", w.NamespaceName)); - String value = styleId.Value; - styleId.Remove(); - String key = Regex.Replace(temp.ToString(), @"\s+", ""); - if (!local_styles.ContainsKey(key)) local_styles.Add(key, value); - } - - // Add each remote style to this document. - IEnumerable remote_styles = remote.styles.Root.Elements(XName.Get("style", w.NamespaceName)); - foreach (XElement remote_style in remote_styles) - { - XElement temp = new XElement(remote_style); - XAttribute styleId = temp.Attribute(XName.Get("styleId", w.NamespaceName)); - String value = styleId.Value; - styleId.Remove(); - String key = Regex.Replace(temp.ToString(), @"\s+", ""); - String guuid; - - // Check to see if the local document already contains the remote style. - if (local_styles.ContainsKey(key)) - { - String local_value; - local_styles.TryGetValue(key, out local_value); - - // If the styleIds are the same then nothing needs to be done. - if (local_value == value) - continue; - - // All we need to do is update the styleId. - guuid = local_value; - } - else - { - guuid = Guid.NewGuid().ToString(); - // Set the styleId in the remote_style to this new Guid - // [Fixed the issue that my document referred to a new Guid while my styles still had the old value ("Titel")] - remote_style.SetAttributeValue(XName.Get("styleId", w.NamespaceName), guuid); - } - - foreach (XElement e in remote_mainDoc.Root.Descendants(XName.Get("pStyle", w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - foreach (XElement e in remote_mainDoc.Root.Descendants(XName.Get("rStyle", w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - foreach (XElement e in remote_mainDoc.Root.Descendants(XName.Get("tblStyle", w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - if (remote_endnotes != null) - { - foreach (XElement e in remote_endnotes.Root.Descendants(XName.Get("rStyle", w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - foreach (XElement e in remote_endnotes.Root.Descendants(XName.Get("pStyle", w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - } - - if (remote_footnotes != null) - { - foreach (XElement e in remote_footnotes.Root.Descendants(XName.Get("rStyle", w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - - foreach (XElement e in remote_footnotes.Root.Descendants(XName.Get("pStyle", w.NamespaceName))) - { - XAttribute e_styleId = e.Attribute(XName.Get("val", w.NamespaceName)); - if (e_styleId != null && e_styleId.Value.Equals(styleId.Value)) - { - e_styleId.SetValue(guuid); - } - } - } - - // Make sure they don't clash by using a uuid. - styleId.SetValue(guuid); - styles.Root.Add(remote_style); - } - } - - protected void clonePackageRelationship(DocX remote_document, PackagePart pp, XDocument remote_mainDoc) - { - string url = pp.Uri.OriginalString.Replace("/", ""); - var remote_rels = remote_document.mainPart.GetRelationships(); - foreach (var remote_rel in remote_rels) - { - if (url.Equals("word" + remote_rel.TargetUri.OriginalString.Replace("/", ""))) - { - String remote_Id = remote_rel.Id; - String local_Id = mainPart.CreateRelationship(remote_rel.TargetUri, remote_rel.TargetMode, remote_rel.RelationshipType).Id; - - // Replace all instances of remote_Id in the local document with local_Id - var elems = remote_mainDoc.Descendants(XName.Get("blip", a.NamespaceName)); - foreach (var elem in elems) - { - XAttribute embed = elem.Attribute(XName.Get("embed", r.NamespaceName)); - if (embed != null && embed.Value == remote_Id) - { - embed.SetValue(local_Id); - } - } - - // 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", v.NamespaceName)); - foreach (var elem in v_elems) - { - XAttribute id = elem.Attribute(XName.Get("id", r.NamespaceName)); - if (id != null && id.Value == remote_Id) - { - id.SetValue(local_Id); - } - } - break; - } - } - } - - protected PackagePart clonePackagePart(PackagePart pp) - { - PackagePart new_pp = package.CreatePart(pp.Uri, pp.ContentType, CompressionOption.Normal); - - using (Stream s_read = pp.GetStream()) - { - using (Stream s_write = new PackagePartStream(new_pp.GetStream(FileMode.Create))) - { - CopyStream(s_read, s_write); - } - } - - return new_pp; - } - - protected string GetMD5HashFromStream(Stream stream) - { - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] retVal = md5.ComputeHash(stream); - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < retVal.Length; i++) - { - sb.Append(retVal[i].ToString("x2")); - } - return sb.ToString(); - } - - /// - /// Insert a new Table at the end of this document. - /// - /// The number of columns to create. - /// The number of rows to create. - /// A new Table. - /// - /// Insert a new Table with 2 columns and 3 rows, at the end of a document. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"C:\Example\Test.docx")) - /// { - /// // Create a new Table with 2 columns and 3 rows. - /// Table newTable = document.InsertTable(2, 3); - /// - /// // Set the design of this Table. - /// newTable.Design = TableDesign.LightShadingAccent2; - /// - /// // Set the column names. - /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false); - /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false); - /// - /// // Fill row 1 - /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false); - /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false); - /// - /// // Fill row 2 - /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false); - /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false); - /// - /// // Save all changes made to document b. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public new Table InsertTable(int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = base.InsertTable(rowCount, columnCount); - t.mainPart = mainPart; - return t; - } - - public Table AddTable(int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = new Table(this, HelperFunctions.CreateTable(rowCount, columnCount)); - t.mainPart = mainPart; - return t; - } - - /// - /// Create a new list with a list item. - /// - /// The text of the first element in the created list. - /// The indentation level of the element in the list. - /// The type of list to be created: Bulleted or Numbered. - /// The number start number for the list. - /// Enable change tracking - /// Set to true if you want to continue numbering from the previous numbered list - /// - /// The created List. Call AddListItem(...) to add more elements to the list. - /// Write the list to the Document with InsertList(...) once the list has all the desired - /// elements, otherwise the list will not be included in the working Document. - /// - public List AddList(string listText = null, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false) - { - return AddListItem(new List(this, null), listText, level, listType, startNumber, trackChanges, continueNumbering); - } - - /// - /// Add a list item to an already existing list. - /// - /// The list to add the new list item to. - /// The run text that should be in the new list item. - /// The indentation level of the new list element. - /// The number start number for the list. - /// Enable change tracking - /// Numbered or Bulleted list type. - /// /// Set to true if you want to continue numbering from the previous numbered list - /// - /// The created List. Call AddListItem(...) to add more elements to the list. - /// Write the list to the Document with InsertList(...) once the list has all the desired - /// elements, otherwise the list will not be included in the working Document. - /// - public List AddListItem(List list, string listText, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false) - { - if (startNumber.HasValue && continueNumbering) throw new InvalidOperationException("Cannot specify a start number and at the same time continue numbering from another list"); - var listToReturn = HelperFunctions.CreateItemInList(list, listText, level, listType, startNumber, trackChanges, continueNumbering); - var lastItem = listToReturn.Items.LastOrDefault(); - if (lastItem != null) - { - lastItem.PackagePart = mainPart; - } - return listToReturn; - - } - - /// - /// Insert list into the document. - /// - /// The list to insert into the document. - /// The list that was inserted into the document. - public new List InsertList(List list) - { - base.InsertList(list); - return list; - } - public new List InsertList(List list, Font fontFamily, double fontSize) - { - base.InsertList(list, fontFamily, fontSize); - return list; - } - public new List InsertList(List list, double fontSize) - { - base.InsertList(list, fontSize); - return list; - } - - /// - /// Insert a list at an index location in the document. - /// - /// Index in document to insert the list. - /// The list that was inserted into the document. - /// - public new List InsertList(int index, List list) - { - base.InsertList(index, list); - return list; - } - - internal XDocument AddStylesForList() - { - var wordStylesUri = new Uri("/word/styles.xml", UriKind.Relative); - - // If the internal document contains no /word/styles.xml create one. - if (!package.PartExists(wordStylesUri)) - HelperFunctions.AddDefaultStylesXml(package); - - // Load the styles.xml into memory. - XDocument wordStyles; - using (TextReader tr = new StreamReader(package.GetPart(wordStylesUri).GetStream())) - wordStyles = XDocument.Load(tr); - - bool listStyleExists = - ( - from s in wordStyles.Element(w + "styles").Elements() - let styleId = s.Attribute(XName.Get("styleId", w.NamespaceName)) - where (styleId != null && styleId.Value == "ListParagraph") - select s - ).Any(); - - if (!listStyleExists) - { - var style = new XElement - ( - w + "style", - new XAttribute(w + "type", "paragraph"), - new XAttribute(w + "styleId", "ListParagraph"), - new XElement(w + "name", new XAttribute(w + "val", "List Paragraph")), - new XElement(w + "basedOn", new XAttribute(w + "val", "Normal")), - new XElement(w + "uiPriority", new XAttribute(w + "val", "34")), - new XElement(w + "qformat"), - new XElement(w + "rsid", new XAttribute(w + "val", "00832EE1")), - new XElement - ( - w + "rPr", - new XElement(w + "ind", new XAttribute(w + "left", "720")), - new XElement - ( - w + "contextualSpacing" - ) - ) - ); - wordStyles.Element(w + "styles").Add(style); - - // Save the styles document. - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(wordStylesUri).GetStream()))) - wordStyles.Save(tw); - } - - return wordStyles; - } - - /// - /// Insert a Table into this document. The Table's source can be a completely different document. - /// - /// The Table to insert. - /// The index to insert this Table at. - /// The Table now associated with this document. - /// - /// Extract a Table from document a and insert it into document b, at index 10. - /// - /// // Place holder for a Table. - /// Table t; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx")) - /// { - /// // Get the first Table from this document. - /// t = documentA.Tables[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx")) - /// { - /// /* - /// * Insert the Table that was extracted from document a, into document b. - /// * This creates a new Table that is now associated with document b. - /// */ - /// Table newTable = documentB.InsertTable(10, t); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public new Table InsertTable(int index, Table t) - { - Table t2 = base.InsertTable(index, t); - t2.mainPart = mainPart; - return t2; - } - - /// - /// Insert a Table into this document. The Table's source can be a completely different document. - /// - /// The Table to insert. - /// The Table now associated with this document. - /// - /// Extract a Table from document a and insert it at the end of document b. - /// - /// // Place holder for a Table. - /// Table t; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx")) - /// { - /// // Get the first Table from this document. - /// t = documentA.Tables[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx")) - /// { - /// /* - /// * Insert the Table that was extracted from document a, into document b. - /// * This creates a new Table that is now associated with document b. - /// */ - /// Table newTable = documentB.InsertTable(t); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public new Table InsertTable(Table t) - { - t = base.InsertTable(t); - t.mainPart = mainPart; - return t; - } - - /// - /// Insert a new Table at the end of this document. - /// - /// The number of columns to create. - /// The number of rows to create. - /// The index to insert this Table at. - /// A new Table. - /// - /// Insert a new Table with 2 columns and 3 rows, at index 37 in this document. - /// - /// // Create a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Create a new Table with 3 rows and 2 columns. Insert this Table at index 37. - /// Table newTable = document.InsertTable(37, 3, 2); - /// - /// // Set the design of this Table. - /// newTable.Design = TableDesign.LightShadingAccent3; - /// - /// // Set the column names. - /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false); - /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false); - /// - /// // Fill row 1 - /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false); - /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false); - /// - /// // Fill row 2 - /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false); - /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false); - /// - /// // Save all changes made to document b. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public new Table InsertTable(int index, int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = base.InsertTable(index, rowCount, columnCount); - t.mainPart = mainPart; - return t; - } - - /// - /// Creates a document using a Stream. - /// - /// The Stream to create the document from. - /// - /// Returns a DocX object which represents the document. - /// - /// Creating a document from a FileStream. - /// - /// // Use a FileStream fs to create a new document. - /// using(FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Create)) - /// { - /// // Load the document using fs - /// using (DocX document = DocX.Create(fs)) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// } - /// - /// - /// - /// Creating a document in a SharePoint site. - /// - /// using(SPSite mySite = new SPSite("http://server/sites/site")) - /// { - /// // Open a connection to the SharePoint site - /// using(SPWeb myWeb = mySite.OpenWeb()) - /// { - /// // Create a MemoryStream ms. - /// using (MemoryStream ms = new MemoryStream()) - /// { - /// // Create a document using ms. - /// using (DocX document = DocX.Create(ms)) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory - /// - /// // Add the document to the SharePoint site - /// web.Files.Add("filename", ms.ToArray(), true); - /// } - /// } - /// } - /// - /// - /// - /// - /// - public static DocX Create(Stream stream, DocumentTypes documentType = DocumentTypes.Document) - { - // Store this document in memory - MemoryStream ms = new MemoryStream(); - - // Create the docx package - Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); - - PostCreation(package, documentType); - DocX document = Load(ms); - document.stream = stream; - return document; - } - - /// - /// Creates a document using a fully qualified or relative filename. - /// - /// The fully qualified or relative filename. - /// - /// Returns a DocX object which represents the document. - /// - /// - /// // Create a document using a relative filename. - /// using (DocX document = DocX.Create(@"..\Test.docx")) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory - /// - /// - /// // Create a document using a relative filename. - /// using (DocX document = DocX.Create(@"..\Test.docx")) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory - /// - /// - /// - /// - /// - public static DocX Create(string filename, DocumentTypes documentType = DocumentTypes.Document) - { - // Store this document in memory - MemoryStream ms = new MemoryStream(); - - // Create the docx package - //WordprocessingDocument wdDoc = WordprocessingDocument.Create(ms, DocumentFormat.OpenXml.WordprocessingDocumentType.Document); - Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); - - PostCreation(package, documentType); - DocX document = Load(ms); - document.filename = filename; - return document; - } - - internal static void PostCreation(Package package, DocumentTypes documentType = DocumentTypes.Document) - { - XDocument mainDoc, stylesDoc, numberingDoc; - - #region MainDocumentPart - // Create the main document part for this package - PackagePart mainDocumentPart; - if (documentType == DocumentTypes.Document) - { - mainDocumentPart = package.CreatePart(new Uri("/word/document.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", CompressionOption.Normal); - } - else - { - mainDocumentPart = package.CreatePart(new Uri("/word/document.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml", CompressionOption.Normal); - } - package.CreateRelationship(mainDocumentPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"); - - // Load the document part into a XDocument object - using (TextReader tr = new StreamReader(mainDocumentPart.GetStream(FileMode.Create, FileAccess.ReadWrite))) - { - mainDoc = XDocument.Parse - (@" - - - - - - - - - - " - ); - } - - // Save the main document - using (TextWriter tw = new StreamWriter(new PackagePartStream(mainDocumentPart.GetStream(FileMode.Create, FileAccess.Write)))) - mainDoc.Save(tw, SaveOptions.None); - #endregion - - #region StylePart - stylesDoc = HelperFunctions.AddDefaultStylesXml(package); - #endregion - - #region NumberingPart - numberingDoc = HelperFunctions.AddDefaultNumberingXml(package); - #endregion - - package.Close(); - } - - internal static DocX PostLoad(ref Package package) - { - DocX document = new DocX(null, null); - document.package = package; - document.Document = document; - - #region MainDocumentPart - document.mainPart = HelperFunctions.GetMainDocumentPart(package); - - using (TextReader tr = new StreamReader(document.mainPart.GetStream(FileMode.Open, FileAccess.Read))) - document.mainDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace); - #endregion - - PopulateDocument(document, package); - - using (TextReader tr = new StreamReader(document.settingsPart.GetStream())) - document.settings = XDocument.Load(tr); - - document.paragraphLookup.Clear(); - foreach (var paragraph in document.Paragraphs) - { - if (!document.paragraphLookup.ContainsKey(paragraph.endIndex)) - document.paragraphLookup.Add(paragraph.endIndex, paragraph); - } - - return document; - } - - private static void PopulateDocument(DocX document, Package package) - { - Headers headers = new Headers(); - headers.odd = document.GetHeaderByType("default"); - headers.even = document.GetHeaderByType("even"); - headers.first = document.GetHeaderByType("first"); - - Footers footers = new Footers(); - footers.odd = document.GetFooterByType("default"); - footers.even = document.GetFooterByType("even"); - footers.first = document.GetFooterByType("first"); - - //// Get the sectPr for this document. - //XElement sect = document.mainDoc.Descendants(XName.Get("sectPr", DocX.w.NamespaceName)).Single(); - - //if (sectPr != null) - //{ - // // Extract the even header reference - // var header_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even"); - // string id = header_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res = document.mainPart.GetRelationship(id); - // string ans = res.SourceUri.OriginalString; - // headers.even.xml_filename = ans; - - // // Extract the odd header reference - // var header_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default"); - // string id2 = header_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res2 = document.mainPart.GetRelationship(id2); - // string ans2 = res2.SourceUri.OriginalString; - // headers.odd.xml_filename = ans2; - - // // Extract the first header reference - // var header_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "h - //eaderReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first"); - // string id3 = header_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res3 = document.mainPart.GetRelationship(id3); - // string ans3 = res3.SourceUri.OriginalString; - // headers.first.xml_filename = ans3; - - // // Extract the even footer reference - // var footer_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even"); - // string id4 = footer_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res4 = document.mainPart.GetRelationship(id4); - // string ans4 = res4.SourceUri.OriginalString; - // footers.even.xml_filename = ans4; - - // // Extract the odd footer reference - // var footer_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default"); - // string id5 = footer_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res5 = document.mainPart.GetRelationship(id5); - // string ans5 = res5.SourceUri.OriginalString; - // footers.odd.xml_filename = ans5; - - // // Extract the first footer reference - // var footer_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first"); - // string id6 = footer_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - // var res6 = document.mainPart.GetRelationship(id6); - // string ans6 = res6.SourceUri.OriginalString; - // footers.first.xml_filename = ans6; - - //} - - document.Xml = document.mainDoc.Root.Element(w + "body"); - document.headers = headers; - document.footers = footers; - document.settingsPart = HelperFunctions.CreateOrGetSettingsPart(package); - - var ps = package.GetParts(); - - //document.endnotesPart = HelperFunctions.GetPart(); - - foreach (var rel in document.mainPart.GetRelationships()) - { - string url = "/word/" + rel.TargetUri.OriginalString.Replace("/word/", "").Replace("file://", ""); - - switch (rel.RelationshipType) - { - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes": - document.endnotesPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.endnotesPart.GetStream())) - document.endnotes = XDocument.Load(tr); - break; - - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes": - document.footnotesPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.footnotesPart.GetStream())) - document.footnotes = XDocument.Load(tr); - break; - - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles": - document.stylesPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.stylesPart.GetStream())) - document.styles = XDocument.Load(tr); - break; - - case "http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects": - document.stylesWithEffectsPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.stylesWithEffectsPart.GetStream())) - document.stylesWithEffects = XDocument.Load(tr); - break; - - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable": - document.fontTablePart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.fontTablePart.GetStream())) - document.fontTable = XDocument.Load(tr); - break; - - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering": - document.numberingPart = package.GetPart(new Uri(url, UriKind.Relative)); - using (TextReader tr = new StreamReader(document.numberingPart.GetStream())) - document.numbering = XDocument.Load(tr); - break; - - default: - break; - } - } - } - - /// - /// Saves and copies the document into a new DocX object - /// - /// - /// Returns a new DocX object with an identical document - /// - /// - /// - /// - /// - public DocX Copy() - { - MemoryStream ms = new MemoryStream(); - SaveAs(ms); - ms.Seek(0, SeekOrigin.Begin); - - return Load(ms); - } - - /// - /// Loads a document into a DocX object using a Stream. - /// - /// The Stream to load the document from. - /// - /// Returns a DocX object which represents the document. - /// - /// - /// Loading a document from a FileStream. - /// - /// // Open a FileStream fs to a document. - /// using (FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Open)) - /// { - /// // Load the document using fs. - /// using (DocX document = DocX.Load(fs)) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to the document. - /// document.Save(); - /// }// Release this document from memory. - /// } - /// - /// - /// - /// Loading a document from a SharePoint site. - /// - /// // Get the SharePoint site that you want to access. - /// using (SPSite mySite = new SPSite("http://server/sites/site")) - /// { - /// // Open a connection to the SharePoint site - /// using (SPWeb myWeb = mySite.OpenWeb()) - /// { - /// // Grab a document stored on this site. - /// SPFile file = web.GetFile("Source_Folder_Name/Source_File"); - /// - /// // DocX.Load requires a Stream, so open a Stream to this document. - /// Stream str = new MemoryStream(file.OpenBinary()); - /// - /// // Load the file using the Stream str. - /// using (DocX document = DocX.Load(str)) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to the document. - /// document.Save(); - /// }// Release this document from memory. - /// } - /// } - /// - /// - /// - /// - public static DocX Load(Stream stream) - { - MemoryStream ms = new MemoryStream(); - - stream.Position = 0; - byte[] data = new byte[stream.Length]; - stream.Read(data, 0, (int)stream.Length); - ms.Write(data, 0, (int)stream.Length); - - // Open the docx package - Package package = Package.Open(ms, FileMode.Open, FileAccess.ReadWrite); - - DocX document = PostLoad(ref package); - document.package = package; - document.memoryStream = ms; - document.stream = stream; - return document; - } - - /// - /// Loads a document into a DocX object using a fully qualified or relative filename. - /// - /// The fully qualified or relative filename. - /// - /// Returns a DocX object which represents the document. - /// - /// - /// - /// // Load a document using its fully qualified filename - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Do something with the document here - /// - /// // Save all changes made to document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// // Load a document using its relative filename. - /// using(DocX document = DocX.Load(@"..\..\Test.docx")) - /// { - /// // Do something with the document here. - /// - /// // Save all changes made to document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// - public static DocX Load(string filename) - { - if (!File.Exists(filename)) - throw new FileNotFoundException(string.Format("File could not be found {0}", filename)); - - MemoryStream ms = new MemoryStream(); - - using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - CopyStream(fs, ms); - } - - // Open the docx package - Package package = Package.Open(ms, FileMode.Open, FileAccess.ReadWrite); - - DocX document = PostLoad(ref package); - document.package = package; - document.filename = filename; - document.memoryStream = ms; - - return document; - } - - /// - /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. - /// - ///The path to the document template file. - ///The document template file not found. - public void ApplyTemplate(string templateFilePath) - { - ApplyTemplate(templateFilePath, true); - } - - /// - /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. - /// - ///The path to the document template file. - ///Whether to copy the document template text content to document. - ///The document template file not found. - public void ApplyTemplate(string templateFilePath, bool includeContent) - { - if (!File.Exists(templateFilePath)) - { - throw new FileNotFoundException(string.Format("File could not be found {0}", templateFilePath)); - } - using (FileStream packageStream = new FileStream(templateFilePath, FileMode.Open, FileAccess.Read)) - { - ApplyTemplate(packageStream, includeContent); - } - } - - /// - /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. - /// - ///The stream of the document template file. - public void ApplyTemplate(Stream templateStream) - { - ApplyTemplate(templateStream, true); - } - - /// - /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. - /// - ///The stream of the document template file. - ///Whether to copy the document template text content to document. - public void ApplyTemplate(Stream templateStream, bool includeContent) - { - Package templatePackage = Package.Open(templateStream); - try - { - PackagePart documentPart = null; - XDocument documentDoc = null; - foreach (PackagePart packagePart in templatePackage.GetParts()) - { - switch (packagePart.Uri.ToString()) - { - case "/word/document.xml": - documentPart = packagePart; - using (XmlReader xr = XmlReader.Create(packagePart.GetStream(FileMode.Open, FileAccess.Read))) - { - documentDoc = XDocument.Load(xr); - } - break; - case "/_rels/.rels": - if (!package.PartExists(packagePart.Uri)) - { - package.CreatePart(packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption); - } - PackagePart globalRelsPart = package.GetPart(packagePart.Uri); - using ( - StreamReader tr = new StreamReader( - packagePart.GetStream(FileMode.Open, FileAccess.Read), Encoding.UTF8)) - { - using ( - StreamWriter tw = new StreamWriter( - new PackagePartStream(globalRelsPart.GetStream(FileMode.Create, FileAccess.Write)), Encoding.UTF8)) - { - tw.Write(tr.ReadToEnd()); - } - } - break; - case "/word/_rels/document.xml.rels": - break; - default: - if (!package.PartExists(packagePart.Uri)) - { - package.CreatePart(packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption); - } - Encoding packagePartEncoding = Encoding.Default; - if (packagePart.Uri.ToString().EndsWith(".xml") || packagePart.Uri.ToString().EndsWith(".rels")) - { - packagePartEncoding = Encoding.UTF8; - } - PackagePart nativePart = package.GetPart(packagePart.Uri); - using ( - StreamReader tr = new StreamReader( - packagePart.GetStream(FileMode.Open, FileAccess.Read), packagePartEncoding)) - { - using ( - StreamWriter tw = new StreamWriter( - new PackagePartStream(nativePart.GetStream(FileMode.Create, FileAccess.Write)), tr.CurrentEncoding)) - { - tw.Write(tr.ReadToEnd()); - } - } - break; - } - } - if (documentPart != null) - { - string mainContentType = documentPart.ContentType.Replace("template.main", "document.main"); - if (package.PartExists(documentPart.Uri)) - { - package.DeletePart(documentPart.Uri); - } - PackagePart documentNewPart = package.CreatePart( - documentPart.Uri, mainContentType, documentPart.CompressionOption); - using (XmlWriter xw = XmlWriter.Create(new PackagePartStream(documentNewPart.GetStream(FileMode.Create, FileAccess.Write)))) - { - documentDoc.WriteTo(xw); - } - foreach (PackageRelationship documentPartRel in documentPart.GetRelationships()) - { - documentNewPart.CreateRelationship( - documentPartRel.TargetUri, - documentPartRel.TargetMode, - documentPartRel.RelationshipType, - documentPartRel.Id); - } - mainPart = documentNewPart; - mainDoc = documentDoc; - PopulateDocument(this, templatePackage); - - // DragonFire: I added next line and recovered ApplyTemplate method. - // I do it, becouse PopulateDocument(...) writes into field "settingsPart" the part of Template's package - // and after line "templatePackage.Close();" in finally, field "settingsPart" becomes not available and method "Save" throw an exception... - // That's why I recreated settingsParts and unlinked it from Template's package =) - settingsPart = HelperFunctions.CreateOrGetSettingsPart(package); - } - if (!includeContent) - { - foreach (Paragraph paragraph in Paragraphs) - { - paragraph.Remove(false); - } - } - } - finally - { - package.Flush(); - var documentRelsPart = package.GetPart(new Uri("/word/_rels/document.xml.rels", UriKind.Relative)); - using (TextReader tr = new StreamReader(documentRelsPart.GetStream(FileMode.Open, FileAccess.Read))) - { - tr.Read(); - } - templatePackage.Close(); - PopulateDocument(Document, package); - } - } - - /// - /// Add an Image into this document from a fully qualified or relative filename. - /// - /// The fully qualified or relative filename. - /// MIME type of image, guessed if not given. - /// An Image file. - /// - /// Add an Image into this document from a fully qualified filename. - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Add an Image from a file. - /// document.AddImage(@"C:\Example\Image.png"); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// - public Image AddImage(string filename) - { - string contentType = ""; - - // The extension this file has will be taken to be its format. - switch (Path.GetExtension(filename)) - { - case ".tiff": contentType = "image/tif"; break; - case ".tif": contentType = "image/tif"; break; - case ".png": contentType = "image/png"; break; - case ".bmp": contentType = "image/png"; break; - case ".gif": contentType = "image/gif"; break; - case ".jpg": contentType = "image/jpg"; break; - case ".jpeg": contentType = "image/jpeg"; break; - default: contentType = "image/jpg"; break; - } - - return AddImage(filename as object, contentType); - } - /// - /// Add an Image into this document from a Stream. - /// - /// A Stream stream. - /// MIME type of image. - /// An Image file. - /// - /// Add an Image into a document using a Stream. - /// - /// // Open a FileStream fs to an Image. - /// using (FileStream fs = new FileStream(@"C:\Example\Image.jpg", FileMode.Open)) - /// { - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Add an Image from a filestream fs. - /// document.AddImage(fs); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// } - /// - /// - /// - /// - public Image AddImage(Stream stream, string contentType = "image/jpeg") - { - return AddImage(stream as object, contentType); - } - - /// - /// Adds a hyperlink to a document and creates a Paragraph which uses it. - /// - /// The text as displayed by the hyperlink. - /// The hyperlink itself. - /// Returns a hyperlink that can be inserted into a Paragraph. - /// - /// Adds a hyperlink to a document and creates a Paragraph which uses it. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add a hyperlink to this document. - /// Hyperlink h = document.AddHyperlink("Google", new Uri("http://www.google.com")); - /// - /// // Add a new Paragraph to this document. - /// Paragraph p = document.InsertParagraph(); - /// p.Append("My favourite search engine is "); - /// p.AppendHyperlink(h); - /// p.Append(", I think it's great."); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public Hyperlink AddHyperlink(string text, Uri uri) - { - XElement i = new XElement - ( - XName.Get("hyperlink", w.NamespaceName), - new XAttribute(r + "id", string.Empty), - new XAttribute(w + "history", "1"), - new XElement(XName.Get("r", w.NamespaceName), - new XElement(XName.Get("rPr", w.NamespaceName), - new XElement(XName.Get("rStyle", w.NamespaceName), - new XAttribute(w + "val", "Hyperlink"))), - new XElement(XName.Get("t", w.NamespaceName), text)) - ); - - Hyperlink h = new Hyperlink(this, mainPart, i); - - h.text = text; - h.uri = uri; - - AddHyperlinkStyleIfNotPresent(); - - return h; - } - - internal void AddHyperlinkStyleIfNotPresent() - { - Uri word_styles_Uri = new Uri("/word/styles.xml", UriKind.Relative); - - // If the internal document contains no /word/styles.xml create one. - if (!package.PartExists(word_styles_Uri)) - HelperFunctions.AddDefaultStylesXml(package); - - // Load the styles.xml into memory. - XDocument word_styles; - using (TextReader tr = new StreamReader(package.GetPart(word_styles_Uri).GetStream())) - word_styles = XDocument.Load(tr); - - bool hyperlinkStyleExists = - ( - from s in word_styles.Element(w + "styles").Elements() - let styleId = s.Attribute(XName.Get("styleId", w.NamespaceName)) - where (styleId != null && styleId.Value == "Hyperlink") - select s - ).Count() > 0; - - if (!hyperlinkStyleExists) - { - XElement style = new XElement - ( - w + "style", - new XAttribute(w + "type", "character"), - new XAttribute(w + "styleId", "Hyperlink"), - new XElement(w + "name", new XAttribute(w + "val", "Hyperlink")), - new XElement(w + "basedOn", new XAttribute(w + "val", "DefaultParagraphFont")), - new XElement(w + "uiPriority", new XAttribute(w + "val", "99")), - new XElement(w + "unhideWhenUsed"), - new XElement(w + "rsid", new XAttribute(w + "val", "0005416C")), - new XElement - ( - w + "rPr", - new XElement(w + "color", new XAttribute(w + "val", "0000FF"), new XAttribute(w + "themeColor", "hyperlink")), - new XElement - ( - w + "u", - new XAttribute(w + "val", "single") - ) - ) - ); - word_styles.Element(w + "styles").Add(style); - - // Save the styles document. - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(word_styles_Uri).GetStream()))) - word_styles.Save(tw); - } - } - - private string GetNextFreeRelationshipID() - { - int id = ( - from r in mainPart.GetRelationships() - where r.Id.Substring(0, 3).Equals("rId") - select int.Parse(r.Id.Substring(3)) - ).DefaultIfEmpty().Max(); - - // The conventiom for ids is rid01, rid02, etc - string newId = id.ToString(); - int result; - if (int.TryParse(newId, out result)) - return ("rId" + (result + 1)); - String guid = String.Empty; - do - { - guid = Guid.NewGuid().ToString(); - } while (Char.IsDigit(guid[0])); - return guid; - } - - /// - /// Adds three new Headers to this document. One for the first page, one for odd pages and one for even pages. - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add header support to this document. - /// document.AddHeaders(); - /// - /// // Get a collection of all headers in this document. - /// Headers headers = document.Headers; - /// - /// // The header used for the first page of this document. - /// Header first = headers.first; - /// - /// // The header used for odd pages of this document. - /// Header odd = headers.odd; - /// - /// // The header used for even pages of this document. - /// Header even = headers.even; - /// - /// // Force the document to use a different header for first, odd and even pages. - /// document.DifferentFirstPage = true; - /// document.DifferentOddAndEvenPages = true; - /// - /// // Content can be added to the Headers in the same manor that it would be added to the main document. - /// Paragraph p = first.InsertParagraph(); - /// p.Append("This is the first pages header."); - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - public void AddHeaders() - { - AddHeadersOrFooters(true); - - headers.odd = Document.GetHeaderByType("default"); - headers.even = Document.GetHeaderByType("even"); - headers.first = Document.GetHeaderByType("first"); - } - - /// - /// Adds three new Footers to this document. One for the first page, one for odd pages and one for even pages. - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add footer support to this document. - /// document.AddFooters(); - /// - /// // Get a collection of all footers in this document. - /// Footers footers = document.Footers; - /// - /// // The footer used for the first page of this document. - /// Footer first = footers.first; - /// - /// // The footer used for odd pages of this document. - /// Footer odd = footers.odd; - /// - /// // The footer used for even pages of this document. - /// Footer even = footers.even; - /// - /// // Force the document to use a different footer for first, odd and even pages. - /// document.DifferentFirstPage = true; - /// document.DifferentOddAndEvenPages = true; - /// - /// // Content can be added to the Footers in the same manor that it would be added to the main document. - /// Paragraph p = first.InsertParagraph(); - /// p.Append("This is the first pages footer."); - /// - /// // Save all changes to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - public void AddFooters() - { - AddHeadersOrFooters(false); - - footers.odd = Document.GetFooterByType("default"); - footers.even = Document.GetFooterByType("even"); - footers.first = Document.GetFooterByType("first"); - } - - /// - /// Adds a Header to a document. - /// If the document already contains a Header it will be replaced. - /// - /// The Header that was added to the document. - internal void AddHeadersOrFooters(bool b) - { - string element = "ftr"; - string reference = "footer"; - if (b) - { - element = "hdr"; - reference = "header"; - } - - DeleteHeadersOrFooters(b); - - XElement sectPr = mainDoc.Root.Element(w + "body").Element(w + "sectPr"); - - for (int i = 1; i < 4; i++) - { - string header_uri = string.Format("/word/{0}{1}.xml", reference, i); - - PackagePart headerPart = package.CreatePart(new Uri(header_uri, UriKind.Relative), string.Format("application/vnd.openxmlformats-officedocument.wordprocessingml.{0}+xml", reference), CompressionOption.Normal); - PackageRelationship headerRelationship = mainPart.CreateRelationship(headerPart.Uri, TargetMode.Internal, string.Format("http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference)); - - XDocument header; - - // Load the document part into a XDocument object - using (TextReader tr = new StreamReader(headerPart.GetStream(FileMode.Create, FileAccess.ReadWrite))) - { - header = XDocument.Parse - (string.Format(@" - - - - - - - ", element, reference) - ); - } - - // Save the main document - using (TextWriter tw = new StreamWriter(new PackagePartStream(headerPart.GetStream(FileMode.Create, FileAccess.Write)))) - header.Save(tw, SaveOptions.None); - - string type; - switch (i) - { - case 1: type = "default"; break; - case 2: type = "even"; break; - case 3: type = "first"; break; - default: throw new ArgumentOutOfRangeException(); - } - - sectPr.Add - ( - new XElement - ( - w + string.Format("{0}Reference", reference), - new XAttribute(w + "type", type), - new XAttribute(r + "id", headerRelationship.Id) - ) - ); - } - } - - internal void DeleteHeadersOrFooters(bool b) - { - string reference = "footer"; - if (b) - reference = "header"; - - // Get all header Relationships in this document. - var header_relationships = mainPart.GetRelationshipsByType(string.Format("http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference)); - - foreach (PackageRelationship header_relationship in header_relationships) - { - // Get the TargetUri for this Part. - Uri header_uri = header_relationship.TargetUri; - - // Check to see if the document actually contains the Part. - if (!header_uri.OriginalString.StartsWith("/word/")) - header_uri = new Uri("/word/" + header_uri.OriginalString, UriKind.Relative); - - if (package.PartExists(header_uri)) - { - // Delete the Part - package.DeletePart(header_uri); - - // Get all references to this Relationship in the document. - var query = - ( - from e in mainDoc.Descendants(XName.Get("body", w.NamespaceName)).Descendants() - where (e.Name.LocalName == string.Format("{0}Reference", reference)) && (e.Attribute(r + "id").Value == header_relationship.Id) - select e - ); - - // Remove all references to this Relationship in the document. - for (int i = 0; i < query.Count(); i++) - query.ElementAt(i).Remove(); - - // Delete the Relationship. - package.DeleteRelationship(header_relationship.Id); - } - } - } - - internal Image AddImage(object o, string contentType = "image/jpeg") - { - // Open a Stream to the new image being added. - Stream newImageStream; - if (o is string) - newImageStream = new FileStream(o as string, FileMode.Open, FileAccess.Read); - else - newImageStream = o as Stream; - - // Get all image parts in word\document.xml - PackagePartCollection packagePartCollection = package.GetParts(); - - // Cache Uri.ToString which is expensive to be used in two loops - var parts = packagePartCollection.Select(x => new - { - UriString = x.Uri.ToString(), - Part = x - }).ToList(); - - var partLookup = parts.ToDictionary(x => x.UriString, x => x.Part, StringComparer.Ordinal); - - // Gather results manually to minimize closure allocation overhead - List imageParts = new List(); - foreach (var ir in mainPart.GetRelationshipsByType(relationshipImage)) - { - var targetUri = ir.TargetUri.ToString(); - PackagePart part; - if (partLookup.TryGetValue(targetUri, out part)) - { - imageParts.Add(part); - } - } - - IEnumerable relsParts = parts - .Where( - part => - part.Part.ContentType.Equals(contentTypeApplicationRelationShipXml, StringComparison.Ordinal) && - part.UriString.IndexOf("/word/", StringComparison.Ordinal) > -1) - .Select(part => part.Part); - - XName xNameTarget = XName.Get("Target"); - XName xNameTargetMode = XName.Get("TargetMode"); - - foreach (PackagePart relsPart in relsParts) - { - XDocument relsPartContent; - using (TextReader tr = new StreamReader(relsPart.GetStream(FileMode.Open, FileAccess.Read))) - { - relsPartContent = XDocument.Load(tr); - } - - IEnumerable imageRelationships = relsPartContent.Root.Elements() - .Where(imageRel => imageRel.Attribute(XName.Get("Type")).Value.Equals(relationshipImage)); - - foreach (XElement imageRelationship in imageRelationships) - { - XAttribute attribute = imageRelationship.Attribute(xNameTarget); - if (attribute != null) - { - string targetMode = string.Empty; - - XAttribute targetModeAttibute = imageRelationship.Attribute(xNameTargetMode); - if (targetModeAttibute != null) - { - targetMode = targetModeAttibute.Value; - } - - if (!targetMode.Equals("External")) - { - string imagePartUri = Path.Combine(Path.GetDirectoryName(relsPart.Uri.ToString()), - attribute.Value); - imagePartUri = Path.GetFullPath(imagePartUri.Replace("\\_rels", string.Empty)); - imagePartUri = imagePartUri.Replace(Path.GetFullPath("\\"), string.Empty).Replace("\\", "/"); - - if (!imagePartUri.StartsWith("/")) - { - imagePartUri = "/" + imagePartUri; - } - - PackagePart imagePart = package.GetPart(new Uri(imagePartUri, UriKind.Relative)); - imageParts.Add(imagePart); - } - } - } - } - - // Loop through each image part in this document. - foreach (PackagePart pp in imageParts) - { - // Get the image object for this image part - // Open a tempory Stream to this image part. - using (Stream tempStream = pp.GetStream(FileMode.Open, FileAccess.Read)) - { - // Compare this image to the new image being added. - if (HelperFunctions.IsSameFile(tempStream, newImageStream)) - { - // Return the Image object - PackageRelationship relationship = mainPart.GetRelationshipsByType(relationshipImage) - .First(x => x.TargetUri == pp.Uri); - - return new Image(this, relationship); - } - } - } - - string imgPartUriPath = string.Empty; - string extension = contentType.Substring(contentType.LastIndexOf("/") + 1); - do - { - // Create a new image part. - imgPartUriPath = string.Format - ( - "/word/media/{0}.{1}", - Guid.NewGuid(), // The unique part. - extension - ); - } while (package.PartExists(new Uri(imgPartUriPath, UriKind.Relative))); - - // We are now guareenteed that imgPartUriPath is unique. - PackagePart img = package.CreatePart(new Uri(imgPartUriPath, UriKind.Relative), contentType, - CompressionOption.Normal); - - // Create a new image relationship - PackageRelationship rel = mainPart.CreateRelationship(img.Uri, TargetMode.Internal, relationshipImage); - - // Open a Stream to the newly created Image part. - using (Stream stream = new PackagePartStream(img.GetStream(FileMode.Create, FileAccess.Write))) - { - // Using the Stream to the real image, copy this streams data into the newly create Image part. - using (newImageStream) - { - CopyStream(newImageStream, stream, bufferSize: 4096); - } // Close the Stream to the new image. - } // Close the Stream to the new image part. - - return new Image(this, rel); - } - - /// - /// Save this document back to the location it was loaded from. - /// - /// - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Add an Image from a file. - /// document.AddImage(@"C:\Example\Image.jpg"); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// - /// - /// - public void Save() - { - Headers headers = Headers; - - // Save the main document - using (TextWriter tw = new StreamWriter(new PackagePartStream(mainPart.GetStream(FileMode.Create, FileAccess.Write)))) - mainDoc.Save(tw, SaveOptions.None); - - if (settings == null) - { - using (TextReader tr = new StreamReader(settingsPart.GetStream())) - settings = XDocument.Load(tr); - } - - XElement body = mainDoc.Root.Element(w + "body"); - XElement sectPr = body.Descendants(w + "sectPr").FirstOrDefault(); - - if (sectPr != null) - { - var evenHeaderRef = - ( - from e in mainDoc.Descendants(w + "headerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("even", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (evenHeaderRef != null) - { - XElement even = headers.even.Xml; - - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(evenHeaderRef).TargetUri - ); - - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - even - ).Save(tw, SaveOptions.None); - } - } - - var oddHeaderRef = - ( - from e in mainDoc.Descendants(w + "headerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("default", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (oddHeaderRef != null) - { - XElement odd = headers.odd.Xml; - - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(oddHeaderRef).TargetUri - ); - - // Save header1 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - odd - ).Save(tw, SaveOptions.None); - } - } - - var firstHeaderRef = - ( - from e in mainDoc.Descendants(w + "headerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("first", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (firstHeaderRef != null) - { - XElement first = headers.first.Xml; - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(firstHeaderRef).TargetUri - ); - - // Save header3 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - first - ).Save(tw, SaveOptions.None); - } - } - - var oddFooterRef = - ( - from e in mainDoc.Descendants(w + "footerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("default", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (oddFooterRef != null) - { - XElement odd = footers.odd.Xml; - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(oddFooterRef).TargetUri - ); - - // Save header1 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - odd - ).Save(tw, SaveOptions.None); - } - } - - var evenFooterRef = - ( - from e in mainDoc.Descendants(w + "footerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("even", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (evenFooterRef != null) - { - XElement even = footers.even.Xml; - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(evenFooterRef).TargetUri - ); - - // Save header2 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - even - ).Save(tw, SaveOptions.None); - } - } - - var firstFooterRef = - ( - from e in mainDoc.Descendants(w + "footerReference") - let type = e.Attribute(w + "type") - where type != null && type.Value.Equals("first", StringComparison.CurrentCultureIgnoreCase) - select e.Attribute(r + "id").Value - ).LastOrDefault(); - - if (firstFooterRef != null) - { - XElement first = footers.first.Xml; - Uri target = PackUriHelper.ResolvePartUri - ( - mainPart.Uri, - mainPart.GetRelationship(firstFooterRef).TargetUri - ); - - // Save header3 - using (TextWriter tw = new StreamWriter(new PackagePartStream(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))) - { - new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - first - ).Save(tw, SaveOptions.None); - } - } - - // Save the settings document. - using (TextWriter tw = new StreamWriter(new PackagePartStream(settingsPart.GetStream(FileMode.Create, FileAccess.Write)))) - settings.Save(tw, SaveOptions.None); - - if (endnotesPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(endnotesPart.GetStream(FileMode.Create, FileAccess.Write)))) - endnotes.Save(tw, SaveOptions.None); - } - - if (footnotesPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(footnotesPart.GetStream(FileMode.Create, FileAccess.Write)))) - footnotes.Save(tw, SaveOptions.None); - } - - if (stylesPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(stylesPart.GetStream(FileMode.Create, FileAccess.Write)))) - styles.Save(tw, SaveOptions.None); - } - - if (stylesWithEffectsPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(stylesWithEffectsPart.GetStream(FileMode.Create, FileAccess.Write)))) - stylesWithEffects.Save(tw, SaveOptions.None); - } - - if (numberingPart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(numberingPart.GetStream(FileMode.Create, FileAccess.Write)))) - numbering.Save(tw, SaveOptions.None); - } - - if (fontTablePart != null) - { - using (TextWriter tw = new StreamWriter(new PackagePartStream(fontTablePart.GetStream(FileMode.Create, FileAccess.Write)))) - fontTable.Save(tw, SaveOptions.None); - } - } - - // Close the document so that it can be saved. - package.Flush(); - - #region Save this document back to a file or stream, that was specified by the user at save time. - if (filename != null) - { - using (FileStream fs = new FileStream(filename, FileMode.Create)) - { - // 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 - { - if (stream.CanSeek) // 2013-05-25: Check if stream can be seeked to support System.Web.HttpResponseStream - { - // Set the length of this stream to 0 - stream.SetLength(0); - - // Write to the beginning of the stream - stream.Position = 0; - } - - memoryStream.WriteTo(stream); - memoryStream.Flush(); - } - #endregion - } - - /// - /// Save this document to a file. - /// - /// The filename to save this document as. - /// - /// Load a document from one file and save it to another. - /// - /// // Load a document using its fully qualified filename. - /// DocX document = DocX.Load(@"C:\Example\Test1.docx"); - /// - /// // Insert a new Paragraph - /// document.InsertParagraph("Hello world!", false); - /// - /// // Save the document to a new location. - /// document.SaveAs(@"C:\Example\Test2.docx"); - /// - /// - /// - /// Load a document from a Stream and save it to a file. - /// - /// DocX document; - /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open)) - /// { - /// // Load a document using a stream. - /// document = DocX.Load(fs1); - /// - /// // Insert a new Paragraph - /// document.InsertParagraph("Hello world again!", false); - /// } - /// - /// // Save the document to a new location. - /// document.SaveAs(@"C:\Example\Test2.docx"); - /// - /// - /// - /// - /// - public void SaveAs(string filename) - { - this.filename = filename; - stream = null; - Save(); - } - - /// - /// Save this document to a Stream. - /// - /// The Stream to save this document to. - /// - /// Load a document from a file and save it to a Stream. - /// - /// // Place holder for a document. - /// DocX document; - /// - /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open)) - /// { - /// // Load a document using a stream. - /// document = DocX.Load(fs1); - /// - /// // Insert a new Paragraph - /// document.InsertParagraph("Hello world again!", false); - /// } - /// - /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create)) - /// { - /// // Save the document to a different stream. - /// document.SaveAs(fs2); - /// } - /// - /// // Release this document from memory. - /// document.Dispose(); - /// - /// - /// - /// Load a document from one Stream and save it to another. - /// - /// DocX document; - /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open)) - /// { - /// // Load a document using a stream. - /// document = DocX.Load(fs1); - /// - /// // Insert a new Paragraph - /// document.InsertParagraph("Hello world again!", false); - /// } - /// - /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create)) - /// { - /// // Save the document to a different stream. - /// document.SaveAs(fs2); - /// } - /// - /// - /// - /// - /// - public void SaveAs(Stream stream) - { - filename = null; - this.stream = stream; - Save(); - } - - /// - /// Add a core property to this document. If a core property already exists with the same name it will be replaced. Core property names are case insensitive. - /// - ///The property name. - ///The property value. - /// - /// Add a core properties of each type to a document. - /// - /// // Load Example.docx - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // If this document does not contain a core property called 'forename', create one. - /// if (!document.CoreProperties.ContainsKey("forename")) - /// { - /// // Create a new core property called 'forename' and set its value. - /// document.AddCoreProperty("forename", "Cathal"); - /// } - /// - /// // Get this documents core property called 'forename'. - /// string forenameValue = document.CoreProperties["forename"]; - /// - /// // Print all of the information about this core property to Console. - /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", "forename", forenameValue)); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } // Release this document from memory. - /// - /// // Wait for the user to press a key before exiting. - /// Console.ReadKey(); - /// - /// - /// - /// - /// - public void AddCoreProperty(string propertyName, string propertyValue) - { - string propertyNamespacePrefix = propertyName.Contains(":") ? propertyName.Split(':')[0] : "cp"; - string propertyLocalName = propertyName.Contains(":") ? propertyName.Split(':')[1] : propertyName; - - // If this document does not contain a coreFilePropertyPart create one.) - if (!package.PartExists(new Uri("/docProps/core.xml", UriKind.Relative))) - HelperFunctions.CreateCorePropertiesPart(this); - - XDocument corePropDoc; - PackagePart corePropPart = package.GetPart(new Uri("/docProps/core.xml", UriKind.Relative)); - using (TextReader tr = new StreamReader(corePropPart.GetStream(FileMode.Open, FileAccess.Read))) - { - corePropDoc = XDocument.Load(tr); - } - - XElement corePropElement = - (from propElement in corePropDoc.Root.Elements() - where (propElement.Name.LocalName.Equals(propertyLocalName)) - select propElement).SingleOrDefault(); - if (corePropElement != null) - { - corePropElement.SetValue(propertyValue); - } - else - { - var propertyNamespace = corePropDoc.Root.GetNamespaceOfPrefix(propertyNamespacePrefix); - corePropDoc.Root.Add(new XElement(XName.Get(propertyLocalName, propertyNamespace.NamespaceName), propertyValue)); - } - - using (TextWriter tw = new StreamWriter(new PackagePartStream(corePropPart.GetStream(FileMode.Create, FileAccess.Write)))) - { - corePropDoc.Save(tw); - } - UpdateCorePropertyValue(this, propertyLocalName, propertyValue); - } - - internal static void UpdateCorePropertyValue(DocX document, string corePropertyName, string corePropertyValue) - { - string matchPattern = string.Format(@"(DOCPROPERTY)?{0}\\\*MERGEFORMAT", corePropertyName).ToLower(); - foreach (XElement e in document.mainDoc.Descendants(XName.Get("fldSimple", w.NamespaceName))) - { - string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim().ToLower(); - - if (Regex.IsMatch(attr_value, matchPattern)) - { - XElement firstRun = e.Element(w + "r"); - XElement firstText = firstRun.Element(w + "t"); - XElement rPr = firstText.Element(w + "rPr"); - - // Delete everything and insert updated text value - e.RemoveNodes(); - - XElement t = new XElement(w + "t", rPr, corePropertyValue); - Novacode.Text.PreserveSpace(t); - e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t)); - } - } - - #region Headers - - IEnumerable headerParts = from headerPart in document.package.GetParts() - where (Regex.IsMatch(headerPart.Uri.ToString(), @"/word/header\d?.xml")) - select headerPart; - foreach (PackagePart pp in headerParts) - { - XDocument header = XDocument.Load(new StreamReader(pp.GetStream())); - - foreach (XElement e in header.Descendants(XName.Get("fldSimple", w.NamespaceName))) - { - string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim().ToLower(); - if (Regex.IsMatch(attr_value, matchPattern)) - { - XElement firstRun = e.Element(w + "r"); - - // Delete everything and insert updated text value - e.RemoveNodes(); - - XElement t = new XElement(w + "t", corePropertyValue); - Novacode.Text.PreserveSpace(t); - e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t)); - } - } - - using (TextWriter tw = new StreamWriter(new PackagePartStream(pp.GetStream(FileMode.Create, FileAccess.Write)))) - header.Save(tw); - } - #endregion - - #region Footers - IEnumerable footerParts = from footerPart in document.package.GetParts() - where (Regex.IsMatch(footerPart.Uri.ToString(), @"/word/footer\d?.xml")) - select footerPart; - foreach (PackagePart pp in footerParts) - { - XDocument footer = XDocument.Load(new StreamReader(pp.GetStream())); - - foreach (XElement e in footer.Descendants(XName.Get("fldSimple", w.NamespaceName))) - { - string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim().ToLower(); - if (Regex.IsMatch(attr_value, matchPattern)) - { - XElement firstRun = e.Element(w + "r"); - - // Delete everything and insert updated text value - e.RemoveNodes(); - - XElement t = new XElement(w + "t", corePropertyValue); - Novacode.Text.PreserveSpace(t); - e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t)); - } - } - - using (TextWriter tw = new StreamWriter(new PackagePartStream(pp.GetStream(FileMode.Create, FileAccess.Write)))) - footer.Save(tw); - } - #endregion - PopulateDocument(document, document.package); - } - - /// - /// Add a custom property to this document. If a custom property already exists with the same name it will be replace. CustomProperty names are case insensitive. - /// - /// The CustomProperty to add to this document. - /// - /// Add a custom properties of each type to a document. - /// - /// // Load Example.docx - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // A CustomProperty called forename which stores a string. - /// CustomProperty forename; - /// - /// // If this document does not contain a custom property called 'forename', create one. - /// if (!document.CustomProperties.ContainsKey("forename")) - /// { - /// // Create a new custom property called 'forename' and set its value. - /// document.AddCustomProperty(new CustomProperty("forename", "Cathal")); - /// } - /// - /// // Get this documents custom property called 'forename'. - /// forename = document.CustomProperties["forename"]; - /// - /// // Print all of the information about this CustomProperty to Console. - /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", forename.Name, forename.Value)); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } // Release this document from memory. - /// - /// // Wait for the user to press a key before exiting. - /// Console.ReadKey(); - /// - /// - /// - /// - public void AddCustomProperty(CustomProperty cp) - { - // If this document does not contain a customFilePropertyPart create one. - if (!package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative))) - HelperFunctions.CreateCustomPropertiesPart(this); - - XDocument customPropDoc; - PackagePart customPropPart = package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative)); - using (TextReader tr = new StreamReader(customPropPart.GetStream(FileMode.Open, FileAccess.Read))) - customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace); - - // Each custom property has a PID, get the highest PID in this document. - IEnumerable pids = - ( - from d in customPropDoc.Descendants() - where d.Name.LocalName == "property" - select int.Parse(d.Attribute(XName.Get("pid")).Value) - ); - - int pid = 1; - if (pids.Count() > 0) - pid = pids.Max(); - - // Check if a custom property already exists with this name - // 2013-05-25: IgnoreCase while searching for custom property as it would produce a currupted docx. - var customProperty = - ( - from d in customPropDoc.Descendants() - where (d.Name.LocalName == "property") && (d.Attribute(XName.Get("name")).Value.Equals(cp.Name, StringComparison.InvariantCultureIgnoreCase)) - select d - ).SingleOrDefault(); - - // If a custom property with this name already exists remove it. - if (customProperty != null) - customProperty.Remove(); - - XElement propertiesElement = customPropDoc.Element(XName.Get("Properties", customPropertiesSchema.NamespaceName)); - propertiesElement.Add - ( - new XElement - ( - XName.Get("property", customPropertiesSchema.NamespaceName), - new XAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"), - new XAttribute("pid", pid + 1), - new XAttribute("name", cp.Name), - new XElement(customVTypesSchema + cp.Type, cp.Value ?? "") - ) - ); - - // Save the custom properties - using (TextWriter tw = new StreamWriter(new PackagePartStream(customPropPart.GetStream(FileMode.Create, FileAccess.Write)))) - customPropDoc.Save(tw, SaveOptions.None); - - // Refresh all fields in this document which display this custom property. - UpdateCustomPropertyValue(this, cp.Name, (cp.Value ?? "").ToString()); - } - - /// - /// Update the custom properties inside the document - /// - /// The DocX document - /// The property used inside the document - /// The new value for the property - /// Different version of Word create different Document XML. - internal static void UpdateCustomPropertyValue(DocX document, string customPropertyName, string customPropertyValue) - { - // A list of documents, which will contain, The Main Document and if they exist: header1, header2, header3, footer1, footer2, footer3. - List documents = new List { document.mainDoc.Root }; - - // Check if each header exists and add if if so. - #region Headers - Headers headers = document.Headers; - if (headers.first != null) - documents.Add(headers.first.Xml); - if (headers.odd != null) - documents.Add(headers.odd.Xml); - if (headers.even != null) - documents.Add(headers.even.Xml); - #endregion - - // Check if each footer exists and add if if so. - #region Footers - Footers footers = document.Footers; - if (footers.first != null) - documents.Add(footers.first.Xml); - if (footers.odd != null) - documents.Add(footers.odd.Xml); - if (footers.even != null) - documents.Add(footers.even.Xml); - #endregion - - var matchCustomPropertyName = customPropertyName; - if (customPropertyName.Contains(" ")) matchCustomPropertyName = "\"" + customPropertyName + "\""; - string match_value = string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", matchCustomPropertyName).Replace(" ", string.Empty); - - // Process each document in the list. - foreach (XElement doc in documents) - { - #region Word 2010+ - foreach (XElement e in doc.Descendants(XName.Get("instrText", w.NamespaceName))) - { - - string attr_value = e.Value.Replace(" ", string.Empty).Trim(); - - if (attr_value.Equals(match_value, StringComparison.CurrentCultureIgnoreCase)) - { - XNode node = e.Parent.NextNode; - bool found = false; - while (true) - { - if (node.NodeType == XmlNodeType.Element) - { - var ele = node as XElement; - var match = ele.Descendants(XName.Get("t", w.NamespaceName)); - if (match.Any()) - { - if (!found) - { - match.First().Value = customPropertyValue; - found = true; - } - else - { - ele.RemoveNodes(); - } - } - else - { - match = ele.Descendants(XName.Get("fldChar", w.NamespaceName)); - if (match.Any()) - { - var endMatch = match.First().Attribute(XName.Get("fldCharType", w.NamespaceName)); - if (endMatch != null && endMatch.Value == "end") - { - break; - } - } - } - } - node = node.NextNode; - } - } - } - #endregion - - #region < Word 2010 - foreach (XElement e in doc.Descendants(XName.Get("fldSimple", w.NamespaceName))) - { - string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim(); - - if (attr_value.Equals(match_value, StringComparison.CurrentCultureIgnoreCase)) - { - XElement firstRun = e.Element(w + "r"); - XElement firstText = firstRun.Element(w + "t"); - XElement rPr = firstText.Element(w + "rPr"); - - // Delete everything and insert updated text value - e.RemoveNodes(); - - XElement t = new XElement(w + "t", rPr, customPropertyValue); - Novacode.Text.PreserveSpace(t); - e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t)); - } - } - #endregion - } - } - - public override Paragraph InsertParagraph() - { - Paragraph p = base.InsertParagraph(); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(int index, string text, bool trackChanges) - { - Paragraph p = base.InsertParagraph(index, text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(Paragraph p) - { - p.PackagePart = mainPart; - return base.InsertParagraph(p); - } - - public override Paragraph InsertParagraph(int index, Paragraph p) - { - p.PackagePart = mainPart; - return base.InsertParagraph(index, p); - } - - public override Paragraph InsertParagraph(int index, string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraph(index, text, trackChanges, formatting); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text) - { - Paragraph p = base.InsertParagraph(text); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text, bool trackChanges) - { - Paragraph p = base.InsertParagraph(text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraph(text, trackChanges, formatting); - p.PackagePart = mainPart; - - return p; - } - - public Paragraph[] InsertParagraphs(string text) - { - String[] textArray = text.Split('\n'); - List paragraphs = new List(); - foreach (var textForParagraph in textArray) - { - Paragraph p = base.InsertParagraph(text); - p.PackagePart = mainPart; - paragraphs.Add(p); - } - return paragraphs.ToArray(); - } - - public override ReadOnlyCollection Contents - { - get - { - ReadOnlyCollection l = base.Contents; - foreach (var content in l) - { - content.PackagePart = mainPart; - } - return l; - } - } - - public void SetContent(XElement el) - { - foreach (XElement e in el.Elements()) - { - (from d in Document.Contents - where d.Name == e.Name - select d).First().SetText(e.Value); - } - } - - public void SetContent(Dictionary dict) - { - foreach (KeyValuePair item in dict) - { - (from d in Document.Contents - where d.Name == item.Key - select d).First().SetText(item.Value); - } - } - - public void SetContent(string path) - { - XDocument doc = XDocument.Load(path); - SetContent(doc); - } - - public void SetContent(XDocument xmlDoc) - { - - foreach (XElement e in xmlDoc.ElementsAfterSelf()) - { - (from d in Document.Contents - where d.Name == e.Name - select d).First().SetText(e.Value); - } - } - - public override ReadOnlyCollection Paragraphs - { - get - { - ReadOnlyCollection l = base.Paragraphs; - foreach (var paragraph in l) - { - paragraph.PackagePart = mainPart; - } - return l; - } - } - - public override List Lists - { - get - { - List l = base.Lists; - l.ForEach(x => x.Items.ForEach(i => i.PackagePart = mainPart)); - return l; - } - } - - public override List
Tables - { - get - { - List
l = base.Tables; - l.ForEach(x => x.mainPart = mainPart); - return l; - } - } - - - /// - /// Create an equation and insert it in the new paragraph - /// - public override Paragraph InsertEquation(String equation) - { - Paragraph p = base.InsertEquation(equation); - p.PackagePart = mainPart; - return p; - } - - /// - /// Insert a chart in document - /// - public void InsertChart(Chart chart) - { - // Create a new chart part uri. - String chartPartUriPath = String.Empty; - Int32 chartIndex = 1; - do - { - chartPartUriPath = String.Format - ( - "/word/charts/chart{0}.xml", - chartIndex - ); - chartIndex++; - } while (package.PartExists(new Uri(chartPartUriPath, UriKind.Relative))); - - // Create chart part. - PackagePart chartPackagePart = package.CreatePart(new Uri(chartPartUriPath, UriKind.Relative), "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", CompressionOption.Normal); - - // Create a new chart relationship - String relID = GetNextFreeRelationshipID(); - PackageRelationship rel = mainPart.CreateRelationship(chartPackagePart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", relID); - - // Save a chart info the chartPackagePart - using (TextWriter tw = new StreamWriter(new PackagePartStream(chartPackagePart.GetStream(FileMode.Create, FileAccess.Write)))) - chart.Xml.Save(tw); - - // Insert a new chart into a paragraph. - Paragraph p = InsertParagraph(); - XElement chartElement = new XElement( - XName.Get("r", w.NamespaceName), - new XElement( - XName.Get("drawing", w.NamespaceName), - new XElement( - XName.Get("inline", wp.NamespaceName), - new XElement(XName.Get("extent", wp.NamespaceName), new XAttribute("cx", "5486400"), new XAttribute("cy", "3200400")), - new XElement(XName.Get("effectExtent", wp.NamespaceName), new XAttribute("l", "0"), new XAttribute("t", "0"), new XAttribute("r", "19050"), new XAttribute("b", "19050")), - new XElement(XName.Get("docPr", wp.NamespaceName), new XAttribute("id", "1"), new XAttribute("name", "chart")), - new XElement( - XName.Get("graphic", a.NamespaceName), - new XElement( - XName.Get("graphicData", a.NamespaceName), - new XAttribute("uri", c.NamespaceName), - new XElement( - XName.Get("chart", c.NamespaceName), - new XAttribute(XName.Get("id", r.NamespaceName), relID) - ) - ) - ) - ) - )); - p.Xml.Add(chartElement); - } - - /// - /// Insert a chart in document after paragraph - /// - public void InsertChartAfterParagraph(Chart chart, Paragraph paragraph) { - // Create a new chart part uri. - String chartPartUriPath = String.Empty; - Int32 chartIndex = 1; - do { - chartPartUriPath = String.Format - ( - "/word/charts/chart{0}.xml", - chartIndex - ); - chartIndex++; - } while (package.PartExists(new Uri(chartPartUriPath, UriKind.Relative))); - - // Create chart part. - PackagePart chartPackagePart = package.CreatePart(new Uri(chartPartUriPath, UriKind.Relative), "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", CompressionOption.Normal); - - // Create a new chart relationship - String relID = GetNextFreeRelationshipID(); - PackageRelationship rel = mainPart.CreateRelationship(chartPackagePart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", relID); - - // Save a chart info the chartPackagePart - using (TextWriter tw = new StreamWriter(chartPackagePart.GetStream(FileMode.Create, FileAccess.Write))) - chart.Xml.Save(tw); - - // Insert a new chart into a paragraph. - Paragraph p = paragraph; - XElement chartElement = new XElement( - XName.Get("r", DocX.w.NamespaceName), - new XElement( - XName.Get("drawing", DocX.w.NamespaceName), - new XElement( - XName.Get("inline", DocX.wp.NamespaceName), - new XElement(XName.Get("extent", DocX.wp.NamespaceName), new XAttribute("cx", "5486400"), new XAttribute("cy", "3200400")), - new XElement(XName.Get("effectExtent", DocX.wp.NamespaceName), new XAttribute("l", "0"), new XAttribute("t", "0"), new XAttribute("r", "19050"), new XAttribute("b", "19050")), - new XElement(XName.Get("docPr", DocX.wp.NamespaceName), new XAttribute("id", "1"), new XAttribute("name", "chart")), - new XElement( - XName.Get("graphic", DocX.a.NamespaceName), - new XElement( - XName.Get("graphicData", DocX.a.NamespaceName), - new XAttribute("uri", DocX.c.NamespaceName), - new XElement( - XName.Get("chart", DocX.c.NamespaceName), - new XAttribute(XName.Get("id", DocX.r.NamespaceName), relID) - ) - ) - ) - ) - )); - p.Xml.Add(chartElement); - } - - /// - /// Inserts a default TOC into the current document. - /// Title: Table of contents - /// Swithces will be: TOC \h \o '1-3' \u \z - /// - /// The inserted TableOfContents - public TableOfContents InsertDefaultTableOfContents() - { - return InsertTableOfContents("Table of contents", TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | TableOfContentsSwitches.U); - } - - /// - /// Inserts a TOC into the current document. - /// - /// The title of the TOC - /// Switches to be applied, see: http://officeopenxml.com/WPtableOfContents.php - /// Lets you set the style name of the TOC header - /// Lets you specify how many header levels should be included - default is 1-3 - /// Lets you override the right tab position - this is not common - /// The inserted TableOfContents - public TableOfContents InsertTableOfContents(string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null) - { - var toc = TableOfContents.CreateTableOfContents(this, title, switches, headerStyle, maxIncludeLevel, rightTabPos); - Xml.Add(toc.Xml); - return toc; - } - - /// - /// Inserts at TOC into the current document before the provided - /// - /// The paragraph to use as reference - /// The title of the TOC - /// Switches to be applied, see: http://officeopenxml.com/WPtableOfContents.php - /// Lets you set the style name of the TOC header - /// Lets you specify how many header levels should be included - default is 1-3 - /// Lets you override the right tab position - this is not common - /// The inserted TableOfContents - public TableOfContents InsertTableOfContents(Paragraph reference, string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null) - { - var toc = TableOfContents.CreateTableOfContents(this, title, switches, headerStyle, maxIncludeLevel, rightTabPos); - reference.Xml.AddBeforeSelf(toc.Xml); - return toc; - } - - private static void CopyStream(Stream input, Stream output, int bufferSize = 32768) - { - byte[] buffer = new byte[bufferSize]; - int read; - while ((read = input.Read(buffer, 0, buffer.Length)) > 0) - { - output.Write(buffer, 0, read); - } - } - - private readonly object nextFreeDocPrIdLock = new object(); - private long? nextFreeDocPrId; - - /// - /// Finds next free id for bookmarkStart/docPr. - /// - internal long GetNextFreeDocPrId() - { - lock (nextFreeDocPrIdLock) - { - if (nextFreeDocPrId != null) - { - nextFreeDocPrId++; - return nextFreeDocPrId.Value; - } - - // also loop thru all docPr ids - var xNameBookmarkStart = XName.Get("bookmarkStart", DocX.w.NamespaceName); - var xNameDocPr = XName.Get("docPr", DocX.wp.NamespaceName); - - long newDocPrId = 1; - HashSet existingIds = new HashSet(); - foreach (var bookmarkId in Xml.Descendants()) - { - if (bookmarkId.Name != xNameBookmarkStart - && bookmarkId.Name != xNameDocPr) - { - continue; - } - - var idAtt = bookmarkId.Attributes().FirstOrDefault(x => x.Name.LocalName == "id"); - if (idAtt != null) - { - existingIds.Add(idAtt.Value); - } - } - - while (existingIds.Contains(newDocPrId.ToString())) - { - newDocPrId++; - } - nextFreeDocPrId = newDocPrId; - return nextFreeDocPrId.Value; - } - } - - #region IDisposable Members - - /// - /// Releases all resources used by this document. - /// - /// - /// If you take advantage of the using keyword, Dispose() is automatically called for you. - /// - /// // Load document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // The document is only in memory while in this scope. - /// - /// }// Dispose() is automatically called at this point. - /// - /// - /// - /// This example is equilivant to the one above example. - /// - /// // Load document. - /// DocX document = DocX.Load(@"C:\Example\Test.docx"); - /// - /// // Do something with the document here. - /// - /// // Dispose of the document. - /// document.Dispose(); - /// - /// - public void Dispose() - { - package.Close(); - } - - #endregion - } -} diff --git a/DocX/DocX.csproj.vspscc b/DocX/DocX.csproj.vspscc deleted file mode 100644 index feffdeca..00000000 --- a/DocX/DocX.csproj.vspscc +++ /dev/null @@ -1,10 +0,0 @@ -"" -{ -"FILE_VERSION" = "9237" -"ENLISTMENT_CHOICE" = "NEVER" -"PROJECT_FILE_RELATIVE_PATH" = "" -"NUMBER_OF_EXCLUDED_FILES" = "0" -"ORIGINAL_PROJECT_FILE_PATH" = "" -"NUMBER_OF_NESTED_PROJECTS" = "0" -"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" -} diff --git a/DocX/DocumentTypes.cs b/DocX/DocumentTypes.cs deleted file mode 100644 index 049f8350..00000000 --- a/DocX/DocumentTypes.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Novacode -{ - public enum DocumentTypes - { - Document, - Template - } -} \ No newline at end of file diff --git a/DocX/ExtensionsHeadings.cs b/DocX/ExtensionsHeadings.cs deleted file mode 100644 index 83ccbfd2..00000000 --- a/DocX/ExtensionsHeadings.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.ComponentModel; -using System.Reflection; - -namespace Novacode -{ - public static class ExtensionsHeadings - { - public static Paragraph Heading(this Paragraph paragraph, HeadingType headingType) - { - string StyleName = headingType.EnumDescription(); - paragraph.StyleName = StyleName; - return paragraph; - } - - public static string EnumDescription(this Enum enumValue) - { - if (enumValue == null || enumValue.ToString() == "0") - { - return string.Empty; - } - FieldInfo enumInfo = enumValue.GetType().GetField(enumValue.ToString()); - DescriptionAttribute[] enumAttributes = (DescriptionAttribute[])enumInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); - if (enumAttributes.Length > 0) - { - return enumAttributes[0].Description; - } - return enumValue.ToString(); - } - - /// - /// From: http://stackoverflow.com/questions/4108828/generic-extension-method-to-see-if-an-enum-contains-a-flag - /// Check to see if a flags enumeration has a specific flag set. - /// - /// Flags enumeration to check - /// Flag to check for - /// - public static bool HasFlag(this Enum variable, Enum value) - { - if (variable == null) - return false; - - if (value == null) - throw new ArgumentNullException(nameof(value)); - - // Not as good as the .NET 4 version of this function, but should be good enough - if (!Enum.IsDefined(variable.GetType(), value)) - { - throw new ArgumentException(string.Format( - "Enumeration type mismatch. The flag is of type '{0}', was expecting '{1}'.", - value.GetType(), variable.GetType())); - } - - ulong num = Convert.ToUInt64(value); - return ((Convert.ToUInt64(variable) & num) == num); - - } - } -} diff --git a/DocX/Font.cs b/DocX/Font.cs deleted file mode 100644 index 5ceec540..00000000 --- a/DocX/Font.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; - -namespace Novacode -{ - /// - /// Represents a font family - /// - public sealed class Font - { - /// - /// Initializes a new instance of - /// - /// The name of the font family - public Font(string name) - { - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentNullException(nameof(name)); - } - - Name = name; - } - - /// - /// The name of the font family - /// - public string Name { get; private set; } - - /// - /// Returns a string representation of an object - /// - /// The name of the font family - public override string ToString() - { - return Name; - } - } -} \ No newline at end of file diff --git a/DocX/Footer.cs b/DocX/Footer.cs deleted file mode 100644 index 8864d896..00000000 --- a/DocX/Footer.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Xml.Linq; -using System.IO.Packaging; -using System.Collections.ObjectModel; - -namespace Novacode -{ - public class Footer : Container, IParagraphContainer - { - public bool PageNumbers - { - get - { - return false; - } - - set - { - XElement e = XElement.Parse - (@" - - - - - - - - - - - - - - - - - - - 1 - - - - - " - ); - - Xml.AddFirst(e); - } - } - - internal Footer(DocX document, XElement xml, PackagePart mainPart): base(document, xml) - { - this.mainPart = mainPart; - } - - public override Paragraph InsertParagraph() - { - Paragraph p = base.InsertParagraph(); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(int index, string text, bool trackChanges) - { - Paragraph p = base.InsertParagraph(index, text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(Paragraph p) - { - p.PackagePart = mainPart; - return base.InsertParagraph(p); - } - - public override Paragraph InsertParagraph(int index, Paragraph p) - { - p.PackagePart = mainPart; - return base.InsertParagraph(index, p); - } - - public override Paragraph InsertParagraph(int index, string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraph(index, text, trackChanges, formatting); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text) - { - Paragraph p = base.InsertParagraph(text); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text, bool trackChanges) - { - Paragraph p = base.InsertParagraph(text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraph(text, trackChanges, formatting); - p.PackagePart = mainPart; - - return p; - } - - public override Paragraph InsertEquation(String equation) - { - Paragraph p = base.InsertEquation(equation); - p.PackagePart = mainPart; - return p; - } - - public override ReadOnlyCollection Paragraphs - { - get - { - ReadOnlyCollection l = base.Paragraphs; - foreach (var paragraph in l) - { - paragraph.mainPart = mainPart; - } - return l; - } - } - - public override List
Tables - { - get - { - List
l = base.Tables; - l.ForEach(x => x.mainPart = mainPart); - return l; - } - } - public new Table InsertTable(int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = base.InsertTable(rowCount, columnCount); - t.mainPart = mainPart; - return t; - } - public new Table InsertTable(int index, Table t) - { - Table t2 = base.InsertTable(index, t); - t2.mainPart = mainPart; - return t2; - } - public new Table InsertTable(Table t) - { - t = base.InsertTable(t); - t.mainPart = mainPart; - return t; - } - public new Table InsertTable(int index, int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = base.InsertTable(index, rowCount, columnCount); - t.mainPart = mainPart; - return t; - } - } -} diff --git a/DocX/Footers.cs b/DocX/Footers.cs deleted file mode 100644 index f3461f3d..00000000 --- a/DocX/Footers.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Novacode -{ - public class Footers - { - internal Footers() - { - - } - - public Footer odd; - public Footer even; - public Footer first; - } -} diff --git a/DocX/FormattedText.cs b/DocX/FormattedText.cs deleted file mode 100644 index 5d4365ca..00000000 --- a/DocX/FormattedText.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -namespace Novacode -{ - public class FormattedText: IComparable - { - public FormattedText() - { - - } - - public int index; - public string text; - public Formatting formatting; - - public int CompareTo(object obj) - { - FormattedText other = (FormattedText)obj; - FormattedText tf = this; - - if (other.formatting == null || tf.formatting == null) - return -1; - - return tf.formatting.CompareTo(other.formatting); - } - } -} diff --git a/DocX/Formatting.cs b/DocX/Formatting.cs deleted file mode 100644 index e94d8c8a..00000000 --- a/DocX/Formatting.cs +++ /dev/null @@ -1,548 +0,0 @@ -using System; -using System.Linq; -using System.Xml.Linq; -using System.Drawing; -using System.Globalization; -namespace Novacode -{ - /// - /// A text formatting. - /// - public class Formatting : IComparable - { - private XElement rPr; - private bool? hidden; - private bool? bold; - private bool? italic; - private StrikeThrough? strikethrough; - private Script? script; - private Highlight? highlight; - private double? size; - private Color? fontColor; - private Color? underlineColor; - private UnderlineStyle? underlineStyle; - private Misc? misc; - private CapsStyle? capsStyle; - private Font fontFamily; - private int? percentageScale; - private int? kerning; - private int? position; - private double? spacing; - - private CultureInfo language; - - /// - /// A text formatting. - /// - public Formatting() - { - capsStyle = Novacode.CapsStyle.none; - strikethrough = Novacode.StrikeThrough.none; - script = Novacode.Script.none; - highlight = Novacode.Highlight.none; - underlineStyle = Novacode.UnderlineStyle.none; - misc = Novacode.Misc.none; - - // Use current culture by default - language = CultureInfo.CurrentCulture; - - rPr = new XElement(XName.Get("rPr", DocX.w.NamespaceName)); - } - - /// - /// Text language - /// - public CultureInfo Language - { - get - { - return language; - } - - set - { - language = value; - } - } - - /// - /// Returns a new identical instance of Formatting. - /// - /// - public Formatting Clone() - { - Formatting newf = new Formatting(); - newf.Bold = bold; - newf.CapsStyle = capsStyle; - newf.FontColor = fontColor; - newf.FontFamily = fontFamily; - newf.Hidden = hidden; - newf.Highlight = highlight; - newf.Italic = italic; - if (kerning.HasValue) { newf.Kerning = kerning; } - newf.Language = language; - newf.Misc = misc; - if (percentageScale.HasValue) { newf.PercentageScale = percentageScale; } - if (position.HasValue) { newf.Position = position; } - newf.Script = script; - if (size.HasValue) { newf.Size = size; } - if (spacing.HasValue) { newf.Spacing = spacing; } - newf.StrikeThrough = strikethrough; - newf.UnderlineColor = underlineColor; - newf.UnderlineStyle = underlineStyle; - return newf; - } - - public static Formatting Parse(XElement rPr) - { - Formatting formatting = new Formatting(); - - // Build up the Formatting object. - foreach (XElement option in rPr.Elements()) - { - switch (option.Name.LocalName) - { - case "lang": - formatting.Language = new CultureInfo( - option.GetAttribute(XName.Get("val", DocX.w.NamespaceName), null) ?? - option.GetAttribute(XName.Get("eastAsia", DocX.w.NamespaceName), null) ?? - option.GetAttribute(XName.Get("bidi", DocX.w.NamespaceName))); - break; - case "spacing": - formatting.Spacing = Double.Parse( - option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 20.0; - break; - case "position": - formatting.Position = Int32.Parse( - option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 2; - break; - case "kern": - formatting.Position = Int32.Parse( - option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 2; - break; - case "w": - formatting.PercentageScale = Int32.Parse( - option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))); - break; - // - case "sz": - formatting.Size = Int32.Parse( - option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 2; - break; - - - case "rFonts": - formatting.FontFamily = - new Font( - option.GetAttribute(XName.Get("cs", DocX.w.NamespaceName), null) ?? - option.GetAttribute(XName.Get("ascii", DocX.w.NamespaceName), null) ?? - option.GetAttribute(XName.Get("hAnsi", DocX.w.NamespaceName), null) ?? - option.GetAttribute(XName.Get("eastAsia", DocX.w.NamespaceName))); - break; - case "color" : - try - { - string color = option.GetAttribute(XName.Get("val", DocX.w.NamespaceName)); - formatting.FontColor = System.Drawing.ColorTranslator.FromHtml(string.Format("#{0}", color)); - } - catch { } - break; - case "vanish": formatting.hidden = true; break; - case "b": formatting.Bold = true; break; - case "i": formatting.Italic = true; break; - case "u": formatting.UnderlineStyle = HelperFunctions.GetUnderlineStyle(option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))); break; - case "vertAlign": - var script = option.GetAttribute(XName.Get("val", DocX.w.NamespaceName), null); - formatting.Script = (Script)Enum.Parse(typeof(Script), script); - break; - default: break; - } - } - - - return formatting; - } - - internal XElement Xml - { - get - { - rPr = new XElement(XName.Get("rPr", DocX.w.NamespaceName)); - - if (language != null) - rPr.Add(new XElement(XName.Get("lang", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), language.Name))); - - if(spacing.HasValue) - rPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), spacing.Value * 20))); - - if(position.HasValue) - rPr.Add(new XElement(XName.Get("position", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), position.Value * 2))); - - if (kerning.HasValue) - rPr.Add(new XElement(XName.Get("kern", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), kerning.Value * 2))); - - if (percentageScale.HasValue) - rPr.Add(new XElement(XName.Get("w", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), percentageScale))); - - if (fontFamily != null) - { - rPr.Add - ( - new XElement - ( - XName.Get("rFonts", DocX.w.NamespaceName), - new XAttribute(XName.Get("ascii", DocX.w.NamespaceName), fontFamily.Name), - new XAttribute(XName.Get("hAnsi", DocX.w.NamespaceName), fontFamily.Name), // Added by Maurits Elbers to support non-standard characters. See http://docx.codeplex.com/Thread/View.aspx?ThreadId=70097&ANCHOR#Post453865 - new XAttribute(XName.Get("cs", DocX.w.NamespaceName), fontFamily.Name), // Added by Maurits Elbers to support non-standard characters. See http://docx.codeplex.com/Thread/View.aspx?ThreadId=70097&ANCHOR#Post453865 - new XAttribute(XName.Get("eastAsia", DocX.w.NamespaceName), fontFamily.Name) // DOCX in china #57 - ) - ); - } - - if (hidden.HasValue && hidden.Value) - rPr.Add(new XElement(XName.Get("vanish", DocX.w.NamespaceName))); - - if (bold.HasValue && bold.Value) - rPr.Add(new XElement(XName.Get("b", DocX.w.NamespaceName))); - - if (italic.HasValue && italic.Value) - rPr.Add(new XElement(XName.Get("i", DocX.w.NamespaceName))); - - if (underlineStyle.HasValue) - { - switch (underlineStyle) - { - case Novacode.UnderlineStyle.none: - break; - case Novacode.UnderlineStyle.singleLine: - rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "single"))); - break; - case Novacode.UnderlineStyle.doubleLine: - rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "double"))); - break; - default: - rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), underlineStyle.ToString()))); - break; - } - } - - if(underlineColor.HasValue) - { - // If an underlineColor has been set but no underlineStyle has been set - if (underlineStyle == Novacode.UnderlineStyle.none) - { - // Set the underlineStyle to the default - underlineStyle = Novacode.UnderlineStyle.singleLine; - rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "single"))); - } - - rPr.Element(XName.Get("u", DocX.w.NamespaceName)).Add(new XAttribute(XName.Get("color", DocX.w.NamespaceName), underlineColor.Value.ToHex())); - } - - if (strikethrough.HasValue) - { - switch (strikethrough) - { - case Novacode.StrikeThrough.none: - break; - case Novacode.StrikeThrough.strike: - rPr.Add(new XElement(XName.Get("strike", DocX.w.NamespaceName))); - break; - case Novacode.StrikeThrough.doubleStrike: - rPr.Add(new XElement(XName.Get("dstrike", DocX.w.NamespaceName))); - break; - default: - break; - } - } - - if (script.HasValue) - { - switch (script) - { - case Novacode.Script.none: - break; - default: - rPr.Add(new XElement(XName.Get("vertAlign", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), script.ToString()))); - break; - } - } - - if (size.HasValue) - { - rPr.Add(new XElement(XName.Get("sz", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), (size * 2).ToString()))); - rPr.Add(new XElement(XName.Get("szCs", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), (size * 2).ToString()))); - } - - if(fontColor.HasValue) - rPr.Add(new XElement(XName.Get("color", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), fontColor.Value.ToHex()))); - - if (highlight.HasValue) - { - switch (highlight) - { - case Novacode.Highlight.none: - break; - default: - rPr.Add(new XElement(XName.Get("highlight", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), highlight.ToString()))); - break; - } - } - - if (capsStyle.HasValue) - { - switch (capsStyle) - { - case Novacode.CapsStyle.none: - break; - default: - rPr.Add(new XElement(XName.Get(capsStyle.ToString(), DocX.w.NamespaceName))); - break; - } - } - - if (misc.HasValue) - { - switch (misc) - { - case Novacode.Misc.none: - break; - case Novacode.Misc.outlineShadow: - rPr.Add(new XElement(XName.Get("outline", DocX.w.NamespaceName))); - rPr.Add(new XElement(XName.Get("shadow", DocX.w.NamespaceName))); - break; - case Novacode.Misc.engrave: - rPr.Add(new XElement(XName.Get("imprint", DocX.w.NamespaceName))); - break; - default: - rPr.Add(new XElement(XName.Get(misc.ToString(), DocX.w.NamespaceName))); - break; - } - } - - return rPr; - } - } - - /// - /// This formatting will apply Bold. - /// - public bool? Bold { get { return bold; } set { bold = value;} } - - /// - /// This formatting will apply Italic. - /// - public bool? Italic { get { return italic; } set { italic = value; } } - - /// - /// This formatting will apply StrickThrough. - /// - public StrikeThrough? StrikeThrough { get { return strikethrough; } set { strikethrough = value; } } - - /// - /// The script that this formatting should be, normal, superscript or subscript. - /// - public Script? Script { get { return script; } set { script = value; } } - - /// - /// The Size of this text, must be between 0 and 1638. - /// - public double? Size - { - get { return size; } - - set - { - double? temp = value * 2; - - if (temp - (int)temp == 0) - { - if(value > 0 && value < 1639) - size = value; - else - throw new ArgumentException("Size", "Value must be in the range 0 - 1638"); - } - - else - throw new ArgumentException("Size", "Value must be either a whole or half number, examples: 32, 32.5"); - } - } - - /// - /// Percentage scale must be one of the following values 200, 150, 100, 90, 80, 66, 50 or 33. - /// - public int? PercentageScale - { - get { return percentageScale; } - - set - { - if ((new int?[] { 200, 150, 100, 90, 80, 66, 50, 33 }).Contains(value)) - percentageScale = value; - else - throw new ArgumentOutOfRangeException("PercentageScale", "Value must be one of the following: 200, 150, 100, 90, 80, 66, 50 or 33"); - } - } - - /// - /// The Kerning to apply to this text must be one of the following values 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72. - /// - public int? Kerning - { - get { return kerning; } - - set - { - if(new int?[] {8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72}.Contains(value)) - kerning = value; - else - throw new ArgumentOutOfRangeException("Kerning", "Value must be one of the following: 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48 or 72"); - } - } - - /// - /// Text position must be in the range (-1585 - 1585). - /// - public int? Position - { - get { return position; } - - set - { - if (value > -1585 && value < 1585) - position = value; - else - throw new ArgumentOutOfRangeException("Position", "Value must be in the range -1585 - 1585"); - } - } - - /// - /// Text spacing must be in the range (-1585 - 1585). - /// - public double? Spacing - { - get { return spacing; } - - set - { - double? temp = value * 20; - - if (temp - (int)temp == 0) - { - if (value > -1585 && value < 1585) - spacing = value; - else - throw new ArgumentException("Spacing", "Value must be in the range: -1584 - 1584"); - } - - else - throw new ArgumentException("Spacing", "Value must be either a whole or acurate to one decimal, examples: 32, 32.1, 32.2, 32.9"); - } - } - - /// - /// The colour of the text. - /// - public Color? FontColor { get { return fontColor; } set { fontColor = value; } } - - /// - /// Highlight colour. - /// - public Highlight? Highlight { get { return highlight; } set { highlight = value; } } - - /// - /// The Underline style that this formatting applies. - /// - public UnderlineStyle? UnderlineStyle { get { return underlineStyle; } set { underlineStyle = value; } } - - /// - /// The underline colour. - /// - public Color? UnderlineColor { get { return underlineColor; } set { underlineColor = value; } } - - /// - /// Misc settings. - /// - public Misc? Misc { get { return misc; } set { misc = value; } } - - /// - /// Is this text hidden or visible. - /// - public bool? Hidden { get { return hidden; } set { hidden = value; } } - - /// - /// Capitalization style. - /// - public CapsStyle? CapsStyle { get { return capsStyle; } set { capsStyle = value; } } - - /// - /// The font family of this formatting. - /// - /// - public Font FontFamily { get { return fontFamily; } set { fontFamily = value; } } - - public int CompareTo(object obj) - { - Formatting other = (Formatting)obj; - - if(other.hidden != this.hidden) - return -1; - - if(other.bold != this.bold) - return -1; - - if(other.italic != this.italic) - return -1; - - if(other.strikethrough != this.strikethrough) - return -1; - - if(other.script != this.script) - return -1; - - if(other.highlight != this.highlight) - return -1; - - if(other.size != this.size) - return -1; - - if(other.fontColor != this.fontColor) - return -1; - - if(other.underlineColor != this.underlineColor) - return -1; - - if(other.underlineStyle != this.underlineStyle) - return -1; - - if(other.misc != this.misc) - return -1; - - if(other.capsStyle != this.capsStyle) - return -1; - - if(other.fontFamily != this.fontFamily) - return -1; - - if(other.percentageScale != this.percentageScale) - return -1; - - if(other.kerning != this.kerning) - return -1; - - if(other.position != this.position) - return -1; - - if(other.spacing != this.spacing) - return -1; - - if (!other.language.Equals(this.language)) - return -1; - - return 0; - } - } -} diff --git a/DocX/Header.cs b/DocX/Header.cs deleted file mode 100644 index b8a53c20..00000000 --- a/DocX/Header.cs +++ /dev/null @@ -1,197 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; -using System.IO.Packaging; -using System.Collections.ObjectModel; - -namespace Novacode -{ - public class Header : Container, IParagraphContainer - { - public bool PageNumbers - { - get - { - return false; - } - - set - { - XElement e = XElement.Parse - (@" - - - - - - - - - - - - - - - - - - - 1 - - - - - " - ); - - Xml.AddFirst(e); - - PageNumberParagraph = new Paragraph(Document, e.Descendants(XName.Get("p", DocX.w.NamespaceName)).SingleOrDefault(), 0); - } - } - - public Paragraph PageNumberParagraph; - - internal Header(DocX document, XElement xml, PackagePart mainPart):base(document, xml) - { - this.mainPart = mainPart; - } - - public override Paragraph InsertParagraph() - { - Paragraph p = base.InsertParagraph(); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(int index, string text, bool trackChanges) - { - Paragraph p = base.InsertParagraph(index, text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(Paragraph p) - { - p.PackagePart = mainPart; - return base.InsertParagraph(p); - } - - public override Paragraph InsertParagraph(int index, Paragraph p) - { - p.PackagePart = mainPart; - return base.InsertParagraph(index, p); - } - - public override Paragraph InsertParagraph(int index, string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraph(index, text, trackChanges, formatting); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text) - { - Paragraph p = base.InsertParagraph(text); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text, bool trackChanges) - { - Paragraph p = base.InsertParagraph(text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - public override Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraph(text, trackChanges, formatting); - p.PackagePart = mainPart; - - return p; - } - - public override Paragraph InsertEquation(String equation) - { - Paragraph p = base.InsertEquation(equation); - p.PackagePart = mainPart; - return p; - } - - - public override ReadOnlyCollection Paragraphs - { - get - { - ReadOnlyCollection l = base.Paragraphs; - foreach (var paragraph in l) - { - paragraph.mainPart = mainPart; - } - return l; - } - } - - public override List
Tables - { - get - { - List
l = base.Tables; - l.ForEach(x => x.mainPart = mainPart); - return l; - } - } - - public List Images - { - get - { - PackageRelationshipCollection imageRelationships = mainPart.GetRelationshipsByType(DocX.relationshipImage); - if (imageRelationships.Count() > 0) - { - return - ( - from i in imageRelationships - select new Image(Document, i) - ).ToList(); - } - - return new List(); - } - } - public new Table InsertTable(int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = base.InsertTable(rowCount, columnCount); - t.mainPart = mainPart; - return t; - } - public new Table InsertTable(int index, Table t) - { - Table t2 = base.InsertTable(index, t); - t2.mainPart = mainPart; - return t2; - } - public new Table InsertTable(Table t) - { - t = base.InsertTable(t); - t.mainPart = mainPart; - return t; - } - public new Table InsertTable(int index, int rowCount, int columnCount) - { - if (rowCount < 1 || columnCount < 1) - throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero."); - - Table t = base.InsertTable(index, rowCount, columnCount); - t.mainPart = mainPart; - return t; - } - - } -} diff --git a/DocX/Headers.cs b/DocX/Headers.cs deleted file mode 100644 index bb6bd814..00000000 --- a/DocX/Headers.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Novacode -{ - public class Headers - { - internal Headers() - { - } - - public Header odd; - public Header even; - public Header first; - } -} diff --git a/DocX/Help/DocX v1.0.0.10 - Documentation.chm b/DocX/Help/DocX v1.0.0.10 - Documentation.chm deleted file mode 100644 index 4f749c37..00000000 Binary files a/DocX/Help/DocX v1.0.0.10 - Documentation.chm and /dev/null differ diff --git a/DocX/Help/Read Me.docx b/DocX/Help/Read Me.docx deleted file mode 100644 index 4d23fdaa..00000000 Binary files a/DocX/Help/Read Me.docx and /dev/null differ diff --git a/DocX/HelperFunctions.cs b/DocX/HelperFunctions.cs deleted file mode 100644 index b99632e1..00000000 --- a/DocX/HelperFunctions.cs +++ /dev/null @@ -1,773 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.IO.Packaging; -using System.Linq; -using System.Reflection; -using System.Security.Principal; -using System.Text; -using System.Xml.Linq; - -namespace Novacode -{ - internal static class HelperFunctions - { - public const string DOCUMENT_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"; - public const string TEMPLATE_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml"; - public const string MACRO_DOCUMENTTYPE = "application/vnd.ms-word.document.macroEnabled.main+xml"; - - /// - /// List of restricted character in xml: [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F] - /// See: https://www.w3.org/TR/xml11/#sec-xml11 - /// - public static readonly char[] RestrictedXmlChar = new char[] { - '\x1','\x2','\x3','\x4','\x5','\x6','\x7','\x8','\xb','\xc','\xe','\xf', - '\x10','\x11','\x12','\x13','\x14','\x15','\x16','\x17','\x18','\x19','\x1a','\x1b','\x1c','\x1e','\x1f', - '\x7f','\x80','\x81','\x82','\x83','\x84','\x86','\x87','\x88','\x89','\x8a','\x8b','\x8c','\x8d','\x8e','\x8f', - '\x90','\x91','\x92','\x93','\x94','\x95','\x96','\x97','\x98','\x99','\x9a','\x9b','\x9c','\x9d','\x9e','\x9f' - }; - - public static bool IsNullOrWhiteSpace(this string value) - { - if (value == null) return true; - return string.IsNullOrEmpty(value.Trim()); - } - - /// - /// Checks whether 'toCheck' has all children that 'desired' has and values of 'val' attributes are the same - /// - /// - /// - /// Matching options whether check if desired attributes are inder a, or a has exactly and only these attributes as b has. - /// - internal static bool ContainsEveryChildOf(XElement desired, XElement toCheck, MatchFormattingOptions fo) - { - foreach (XElement e in desired.Elements()) - { - // If a formatting property has the same name and 'val' attribute's value, its considered to be equivalent. - if (!toCheck.Elements(e.Name).Where(bElement => bElement.GetAttribute(XName.Get("val", DocX.w.NamespaceName)) == e.GetAttribute(XName.Get("val", DocX.w.NamespaceName))).Any()) - return false; - } - - // If the formatting has to be exact, no additionaly formatting must exist. - if (fo == MatchFormattingOptions.ExactMatch) - return desired.Elements().Count() == toCheck.Elements().Count(); - - return true; - } - internal static void CreateRelsPackagePart(DocX Document, Uri uri) - { - PackagePart pp = Document.package.CreatePart(uri, DocX.contentTypeApplicationRelationShipXml, CompressionOption.Maximum); - using (TextWriter tw = new StreamWriter(new PackagePartStream(pp.GetStream()))) - { - XDocument d = new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - new XElement(XName.Get("Relationships", DocX.rel.NamespaceName)) - ); - var root = d.Root; - d.Save(tw); - } - } - - internal static int GetSize(XElement Xml) - { - switch (Xml.Name.LocalName) - { - case "tab": - return 1; - case "br": - return 1; - case "t": - goto case "delText"; - case "delText": - return Xml.Value.Length; - case "tr": - goto case "br"; - case "tc": - goto case "br"; - default: - return 0; - } - } - - internal static string GetText(XElement e) - { - StringBuilder sb = new StringBuilder(); - GetTextRecursive(e, ref sb); - return sb.ToString(); - } - - internal static void GetTextRecursive(XElement Xml, ref StringBuilder sb) - { - sb.Append(ToText(Xml)); - - if (Xml.HasElements) - foreach (XElement e in Xml.Elements()) - GetTextRecursive(e, ref sb); - } - - internal static List GetFormattedText(XElement e) - { - List alist = new List(); - GetFormattedTextRecursive(e, ref alist); - return alist; - } - - internal static void GetFormattedTextRecursive(XElement Xml, ref List alist) - { - FormattedText ft = ToFormattedText(Xml); - FormattedText last = null; - - if (ft != null) - { - if (alist.Count() > 0) - last = alist.Last(); - - if (last != null && last.CompareTo(ft) == 0) - { - // Update text of last entry. - last.text += ft.text; - } - else - { - if (last != null) - ft.index = last.index + last.text.Length; - - alist.Add(ft); - } - } - - if (Xml.HasElements) - foreach (XElement e in Xml.Elements()) - GetFormattedTextRecursive(e, ref alist); - } - - internal static FormattedText ToFormattedText(XElement e) - { - // The text representation of e. - String text = ToText(e); - if (text == String.Empty) - return null; - - // e is a w:t element, it must exist inside a w:r element or a w:tabs, lets climb until we find it. - while (!e.Name.Equals(XName.Get("r", DocX.w.NamespaceName)) && - !e.Name.Equals(XName.Get("tabs", DocX.w.NamespaceName))) - e = e.Parent; - - // e is a w:r element, lets find the rPr element. - XElement rPr = e.Element(XName.Get("rPr", DocX.w.NamespaceName)); - - FormattedText ft = new FormattedText(); - ft.text = text; - ft.index = 0; - ft.formatting = null; - - // Return text with formatting. - if (rPr != null) - ft.formatting = Formatting.Parse(rPr); - - return ft; - } - - internal static string ToText(XElement e) - { - switch (e.Name.LocalName) - { - case "tab": - return "\t"; - case "br": - return "\n"; - case "t": - goto case "delText"; - case "delText": - { - if (e.Parent != null && e.Parent.Name.LocalName == "r") - { - XElement run = e.Parent; - var rPr = run.Elements().FirstOrDefault(a => a.Name.LocalName == "rPr"); - if (rPr != null) - { - var caps = rPr.Elements().FirstOrDefault(a => a.Name.LocalName == "caps"); - - if (caps != null) - return e.Value.ToUpper(); - } - } - - return e.Value; - } - case "tr": - goto case "br"; - case "tc": - goto case "tab"; - default: return ""; - } - } - - internal static XElement CloneElement(XElement element) - { - return new XElement - ( - element.Name, - element.Attributes(), - element.Nodes().Select - ( - n => - { - XElement e = n as XElement; - if (e != null) - return CloneElement(e); - return n; - } - ) - ); - } - - internal static PackagePart GetMainDocumentPart(Package package) - { - return package.GetParts().Single(p => p.ContentType.Equals(DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase) || - p.ContentType.Equals(TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase) || - p.ContentType.Equals(MACRO_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase)); - } - - internal static PackagePart CreateOrGetSettingsPart(Package package) - { - PackagePart settingsPart; - - Uri settingsUri = new Uri("/word/settings.xml", UriKind.Relative); - if (!package.PartExists(settingsUri)) - { - settingsPart = package.CreatePart(settingsUri, "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml", CompressionOption.Maximum); - - PackagePart mainDocumentPart = GetMainDocumentPart(package); - - mainDocumentPart.CreateRelationship(settingsUri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"); - - XDocument settings = XDocument.Parse - (@" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " - ); - - XElement themeFontLang = settings.Root.Element(XName.Get("themeFontLang", DocX.w.NamespaceName)); - themeFontLang.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), CultureInfo.CurrentCulture); - - // Save the settings document. - using (TextWriter tw = new StreamWriter(new PackagePartStream(settingsPart.GetStream()))) - settings.Save(tw); - } - else - settingsPart = package.GetPart(settingsUri); - return settingsPart; - } - - internal static void CreateCorePropertiesPart(DocX document) - { - PackagePart corePropertiesPart = document.package.CreatePart(new Uri("/docProps/core.xml", UriKind.Relative), "application/vnd.openxmlformats-package.core-properties+xml", CompressionOption.Maximum); - - XDocument corePropDoc = XDocument.Parse(@" - - - - - - - - 1 - "+ DateTime.UtcNow.ToString("s") + "Z" + @" - " + DateTime.UtcNow.ToString("s") + "Z" + @" -"); - - using (TextWriter tw = new StreamWriter(new PackagePartStream(corePropertiesPart.GetStream(FileMode.Create, FileAccess.Write)))) - corePropDoc.Save(tw, SaveOptions.None); - - document.package.CreateRelationship(corePropertiesPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"); - } - - internal static void CreateCustomPropertiesPart(DocX document) - { - PackagePart customPropertiesPart = document.package.CreatePart(new Uri("/docProps/custom.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.custom-properties+xml", CompressionOption.Maximum); - - XDocument customPropDoc = new XDocument - ( - new XDeclaration("1.0", "UTF-8", "yes"), - new XElement - ( - XName.Get("Properties", DocX.customPropertiesSchema.NamespaceName), - new XAttribute(XNamespace.Xmlns + "vt", DocX.customVTypesSchema) - ) - ); - - using (TextWriter tw = new StreamWriter(new PackagePartStream(customPropertiesPart.GetStream(FileMode.Create, FileAccess.Write)))) - customPropDoc.Save(tw, SaveOptions.None); - - document.package.CreateRelationship(customPropertiesPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties"); - } - - internal static XDocument DecompressXMLResource(string manifest_resource_name) - { - // XDocument to load the compressed Xml resource into. - XDocument document; - - // Get a reference to the executing assembly. - Assembly assembly = Assembly.GetExecutingAssembly(); - - // Open a Stream to the embedded resource. - Stream stream = assembly.GetManifestResourceStream(manifest_resource_name); - - // Decompress the embedded resource. - using (GZipStream zip = new GZipStream(stream, CompressionMode.Decompress)) - { - // Load this decompressed embedded resource into an XDocument using a TextReader. - using (TextReader sr = new StreamReader(zip)) - { - document = XDocument.Load(sr); - } - } - - // Return the decompressed Xml as an XDocument. - return document; - } - - - /// - /// If this document does not contain a /word/numbering.xml add the default one generated by Microsoft Word - /// when the default bullet, numbered and multilevel lists are added to a blank document - /// - /// - /// - internal static XDocument AddDefaultNumberingXml(Package package) - { - XDocument numberingDoc; - // Create the main document part for this package - PackagePart wordNumbering = package.CreatePart(new Uri("/word/numbering.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", CompressionOption.Maximum); - - numberingDoc = DecompressXMLResource("Novacode.Resources.numbering.xml.gz"); - - // Save /word/numbering.xml - using (TextWriter tw = new StreamWriter(new PackagePartStream(wordNumbering.GetStream(FileMode.Create, FileAccess.Write)))) - numberingDoc.Save(tw, SaveOptions.None); - - PackagePart mainDocumentPart = GetMainDocumentPart(package); - - mainDocumentPart.CreateRelationship(wordNumbering.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"); - return numberingDoc; - } - - - - /// - /// If this document does not contain a /word/styles.xml add the default one generated by Microsoft Word. - /// - /// - /// - internal static XDocument AddDefaultStylesXml(Package package) - { - XDocument stylesDoc; - // Create the main document part for this package - PackagePart word_styles = package.CreatePart(new Uri("/word/styles.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", CompressionOption.Maximum); - - stylesDoc = HelperFunctions.DecompressXMLResource("Novacode.Resources.default_styles.xml.gz"); - XElement lang = stylesDoc.Root.Element(XName.Get("docDefaults", DocX.w.NamespaceName)).Element(XName.Get("rPrDefault", DocX.w.NamespaceName)).Element(XName.Get("rPr", DocX.w.NamespaceName)).Element(XName.Get("lang", DocX.w.NamespaceName)); - lang.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), CultureInfo.CurrentCulture); - - // Save /word/styles.xml - using (TextWriter tw = new StreamWriter(new PackagePartStream(word_styles.GetStream(FileMode.Create, FileAccess.Write)))) - stylesDoc.Save(tw, SaveOptions.None); - - PackagePart mainDocumentPart = GetMainDocumentPart(package); - - mainDocumentPart.CreateRelationship(word_styles.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"); - return stylesDoc; - } - - internal static XElement CreateEdit(EditType t, DateTime edit_time, object content) - { - if (t == EditType.del) - { - foreach (object o in (IEnumerable)content) - { - if (o is XElement) - { - XElement e = (o as XElement); - IEnumerable ts = e.DescendantsAndSelf(XName.Get("t", DocX.w.NamespaceName)); - - for (int i = 0; i < ts.Count(); i++) - { - XElement text = ts.ElementAt(i); - text.ReplaceWith(new XElement(DocX.w + "delText", text.Attributes(), text.Value)); - } - } - } - } - - return - ( - new XElement(DocX.w + t.ToString(), - new XAttribute(DocX.w + "id", 0), - new XAttribute(DocX.w + "author", WindowsIdentity.GetCurrent().Name), - new XAttribute(DocX.w + "date", edit_time), - content) - ); - } - - internal static XElement CreateTable(int rowCount, int columnCount) - { - int[] columnWidths = new int[columnCount]; - for (int i = 0; i < columnCount; i++) - { - columnWidths[i] = 2310; - } - return CreateTable(rowCount, columnWidths); - } - - internal static XElement CreateTable(int rowCount, int[] columnWidths) - { - XElement newTable = - new XElement - ( - XName.Get("tbl", DocX.w.NamespaceName), - new XElement - ( - XName.Get("tblPr", DocX.w.NamespaceName), - new XElement(XName.Get("tblStyle", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "TableGrid")), - new XElement(XName.Get("tblW", DocX.w.NamespaceName), new XAttribute(XName.Get("w", DocX.w.NamespaceName), "5000"), new XAttribute(XName.Get("type", DocX.w.NamespaceName), "auto")), - new XElement(XName.Get("tblLook", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "04A0")) - ) - ); - - /*XElement tableGrid = new XElement(XName.Get("tblGrid", DocX.w.NamespaceName)); - for (int i = 0; i < columnWidths.Length; i++) - tableGrid.Add(new XElement(XName.Get("gridCol", DocX.w.NamespaceName), new XAttribute(XName.Get("w", DocX.w.NamespaceName), XmlConvert.ToString(columnWidths[i])))); - - newTable.Add(tableGrid);*/ - - for (int i = 0; i < rowCount; i++) - { - XElement row = new XElement(XName.Get("tr", DocX.w.NamespaceName)); - - for (int j = 0; j < columnWidths.Length; j++) - { - XElement cell = CreateTableCell(); - row.Add(cell); - } - - newTable.Add(row); - } - return newTable; - } - - /// - /// Create and return a cell of a table - /// - internal static XElement CreateTableCell(double w = 2310) - { - return new XElement - ( - XName.Get("tc", DocX.w.NamespaceName), - new XElement(XName.Get("tcPr", DocX.w.NamespaceName), - new XElement(XName.Get("tcW", DocX.w.NamespaceName), - new XAttribute(XName.Get("w", DocX.w.NamespaceName), w), - new XAttribute(XName.Get("type", DocX.w.NamespaceName), "dxa"))), - new XElement(XName.Get("p", DocX.w.NamespaceName), - new XElement(XName.Get("pPr", DocX.w.NamespaceName))) - ); - } - - internal static List CreateItemInList(List list, string listText, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false) - { - if (list.NumId == 0) - { - list.CreateNewNumberingNumId(level, listType, startNumber, continueNumbering); - } - - if (listText != null) //I see no reason why you shouldn't be able to insert an empty element. It simplifies tasks such as populating an item from html. - { - var newParagraphSection = new XElement - ( - XName.Get("p", DocX.w.NamespaceName), - new XElement(XName.Get("pPr", DocX.w.NamespaceName), - new XElement(XName.Get("numPr", DocX.w.NamespaceName), - new XElement(XName.Get("ilvl", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", level)), - new XElement(XName.Get("numId", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", list.NumId)))), - new XElement(XName.Get("r", DocX.w.NamespaceName), new XElement(XName.Get("t", DocX.w.NamespaceName), listText)) - ); - - if (trackChanges) - newParagraphSection = CreateEdit(EditType.ins, DateTime.Now, newParagraphSection); - - if (startNumber == null) - { - list.AddItem(new Paragraph(list.Document, newParagraphSection, 0, ContainerType.Paragraph)); - } - else - { - list.AddItemWithStartValue(new Paragraph(list.Document, newParagraphSection, 0, ContainerType.Paragraph), (int)startNumber); - } - } - - return list; - } - - internal static void RenumberIDs(DocX document) - { - IEnumerable trackerIDs = - (from d in document.mainDoc.Descendants() - where d.Name.LocalName == "ins" || d.Name.LocalName == "del" - select d.Attribute(XName.Get("id", "http://schemas.openxmlformats.org/wordprocessingml/2006/main"))); - - for (int i = 0; i < trackerIDs.Count(); i++) - trackerIDs.ElementAt(i).Value = i.ToString(); - } - - internal static Paragraph GetFirstParagraphEffectedByInsert(DocX document, int index) - { - // This document contains no Paragraphs and insertion is at index 0 - if (document.Paragraphs.Count() == 0 && index == 0) - return null; - - foreach (Paragraph p in document.Paragraphs) - { - if (p.endIndex >= index) - return p; - } - - throw new ArgumentOutOfRangeException(); - } - - internal static List FormatInput(string text, XElement rPr) - { - List newRuns = new List(); - XElement tabRun = new XElement(DocX.w + "tab"); - XElement breakRun = new XElement(DocX.w + "br"); - - StringBuilder sb = new StringBuilder(); - - if (string.IsNullOrEmpty(text)) - { - return newRuns; //I dont wanna get an exception if text == null, so just return empy list - } - - char lastChar = '\0'; - - foreach (char c in text) - { - switch (c) - { - case '\t': - if (sb.Length > 0) - { - XElement t = new XElement(DocX.w + "t", sb.ToString()); - Novacode.Text.PreserveSpace(t); - newRuns.Add(new XElement(DocX.w + "r", rPr, t)); - sb = new StringBuilder(); - } - newRuns.Add(new XElement(DocX.w + "r", rPr, tabRun)); - break; - case '\r': - if (sb.Length > 0) - { - XElement t = new XElement(DocX.w + "t", sb.ToString()); - Novacode.Text.PreserveSpace(t); - newRuns.Add(new XElement(DocX.w + "r", rPr, t)); - sb = new StringBuilder(); - } - newRuns.Add(new XElement(DocX.w + "r", rPr, breakRun)); - break; - case '\n': - if (lastChar == '\r') break; - - if (sb.Length > 0) - { - XElement t = new XElement(DocX.w + "t", sb.ToString()); - Novacode.Text.PreserveSpace(t); - newRuns.Add(new XElement(DocX.w + "r", rPr, t)); - sb = new StringBuilder(); - } - newRuns.Add(new XElement(DocX.w + "r", rPr, breakRun)); - break; - - default: - // Check the character against restricted list: - // RestrictedChar ::= [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F] - // See https://www.w3.org/TR/xml11/#sec-xml11 - if( RestrictedXmlChar.Contains( c ) ) - { - // skip the character - } - else - sb.Append(c); - break; - } - - lastChar = c; - } - - if (sb.Length > 0) - { - XElement t = new XElement(DocX.w + "t", sb.ToString()); - Novacode.Text.PreserveSpace(t); - newRuns.Add(new XElement(DocX.w + "r", rPr, t)); - } - - return newRuns; - } - - internal static XElement[] SplitParagraph(Paragraph p, int index) - { - // In this case edit dosent really matter, you have a choice. - Run r = p.GetFirstRunEffectedByEdit(index, EditType.ins); - - XElement[] split; - XElement before, after; - - if (r.Xml.Parent.Name.LocalName == "ins") - { - split = p.SplitEdit(r.Xml.Parent, index, EditType.ins); - before = new XElement(p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsBeforeSelf(), split[0]); - after = new XElement(p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsAfterSelf(), split[1]); - } - else if (r.Xml.Parent.Name.LocalName == "del") - { - split = p.SplitEdit(r.Xml.Parent, index, EditType.del); - - before = new XElement(p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsBeforeSelf(), split[0]); - after = new XElement(p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsAfterSelf(), split[1]); - } - else - { - split = Run.SplitRun(r, index); - - before = new XElement(p.Xml.Name, p.Xml.Attributes(), r.Xml.ElementsBeforeSelf(), split[0]); - after = new XElement(p.Xml.Name, p.Xml.Attributes(), split[1], r.Xml.ElementsAfterSelf()); - } - - if (before.Elements().Count() == 0) - before = null; - - if (after.Elements().Count() == 0) - after = null; - - return new XElement[] { before, after }; - } - - /// - internal static bool IsSameFile(Stream streamOne, Stream streamTwo) - { - int file1byte, file2byte; - - if (streamOne.Length != streamTwo.Length) - { - // Return false to indicate files are different - return false; - } - - // Read and compare a byte from each file until either a - // non-matching set of bytes is found or until the end of - // file1 is reached. - do - { - // Read one byte from each file. - file1byte = streamOne.ReadByte(); - file2byte = streamTwo.ReadByte(); - } - while ((file1byte == file2byte) && (file1byte != -1)); - - // Return the success of the comparison. "file1byte" is - // equal to "file2byte" at this point only if the files are - // the same. - - streamOne.Position = 0; - streamTwo.Position = 0; - - return ((file1byte - file2byte) == 0); - } - - internal static UnderlineStyle GetUnderlineStyle(string underlineStyle) - { - switch (underlineStyle) - { - case "single": - return UnderlineStyle.singleLine; - case "double": - return UnderlineStyle.doubleLine; - case "thick": - return UnderlineStyle.thick; - case "dotted": - return UnderlineStyle.dotted; - case "dottedHeavy": - return UnderlineStyle.dottedHeavy; - case "dash": - return UnderlineStyle.dash; - case "dashedHeavy": - return UnderlineStyle.dashedHeavy; - case "dashLong": - return UnderlineStyle.dashLong; - case "dashLongHeavy": - return UnderlineStyle.dashLongHeavy; - case "dotDash": - return UnderlineStyle.dotDash; - case "dashDotHeavy": - return UnderlineStyle.dashDotHeavy; - case "dotDotDash": - return UnderlineStyle.dotDotDash; - case "dashDotDotHeavy": - return UnderlineStyle.dashDotDotHeavy; - case "wave": - return UnderlineStyle.wave; - case "wavyHeavy": - return UnderlineStyle.wavyHeavy; - case "wavyDouble": - return UnderlineStyle.wavyDouble; - case "words": - return UnderlineStyle.words; - default: - return UnderlineStyle.none; - } - } - - - - } -} diff --git a/DocX/Hyperlink.cs b/DocX/Hyperlink.cs deleted file mode 100644 index 605b1c94..00000000 --- a/DocX/Hyperlink.cs +++ /dev/null @@ -1,232 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml.Linq; -using System.IO.Packaging; - -namespace Novacode -{ - /// - /// Represents a Hyperlink in a document. - /// - public class Hyperlink: DocXElement - { - internal Uri uri; - internal String text; - - internal Dictionary hyperlink_rels; - internal int type; - internal String id; - internal XElement instrText; - internal List runs; - - /// - /// Remove a Hyperlink from this Paragraph only. - /// - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add a hyperlink to this document. - /// Hyperlink h = document.AddHyperlink("link", new Uri("http://www.google.com")); - /// - /// // Add a Paragraph to this document and insert the hyperlink - /// Paragraph p1 = document.InsertParagraph(); - /// p1.Append("This is a cool ").AppendHyperlink(h).Append(" ."); - /// - /// /* - /// * Remove the hyperlink from this Paragraph only. - /// * Note a reference to the hyperlink will still exist in the document and it can thus be reused. - /// */ - /// p1.Hyperlinks[0].Remove(); - /// - /// // Add a new Paragraph to this document and reuse the hyperlink h. - /// Paragraph p2 = document.InsertParagraph(); - /// p2.Append("This is the same cool ").AppendHyperlink(h).Append(" ."); - /// - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public void Remove() - { - Xml.Remove(); - } - - /// - /// Change the Text of a Hyperlink. - /// - /// - /// Change the Text of a Hyperlink. - /// - /// // Create a document. - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // Get all of the hyperlinks in this document - /// List<Hyperlink> hyperlinks = document.Hyperlinks; - /// - /// // Change the first hyperlinks text and Uri - /// Hyperlink h0 = hyperlinks[0]; - /// h0.Text = "DocX"; - /// h0.Uri = new Uri("http://docx.codeplex.com"); - /// - /// // Save this document. - /// document.Save(); - /// } - /// - /// - public string Text - { - get - { - return this.text; - } - - set - { - XElement rPr = - new XElement - ( - DocX.w + "rPr", - new XElement - ( - DocX.w + "rStyle", - new XAttribute(DocX.w + "val", "Hyperlink") - ) - ); - - // Format and add the new text. - List newRuns = HelperFunctions.FormatInput(value, rPr); - - if (type == 0) - { - // Get all the runs in this Text. - var runs = from r in Xml.Elements() - where r.Name.LocalName == "r" - select r; - - // Remove each run. - for (int i = 0; i < runs.Count(); i++) - runs.Remove(); - - Xml.Add(newRuns); - } - - else - { - XElement separate = XElement.Parse(@" - - - "); - - XElement end = XElement.Parse(@" - - - "); - - runs.Last().AddAfterSelf(separate, newRuns, end); - runs.ForEach(r => r.Remove()); - } - - this.text = value; - } - } - - /// - /// Change the Uri of a Hyperlink. - /// - /// - /// Change the Uri of a Hyperlink. - /// - /// hyperlinks = document.Hyperlinks; - /// - /// // Change the first hyperlinks text and Uri - /// Hyperlink h0 = hyperlinks[0]; - /// h0.Text = "DocX"; - /// h0.Uri = new Uri("http://docx.codeplex.com"); - /// - /// // Save this document. - /// document.Save(); - /// } - /// ]]> - /// - /// - public Uri Uri - { - get - { - if (type == 0 && id != String.Empty) - { - PackageRelationship r = mainPart.GetRelationship(id); - return r.TargetUri; - } - - return this.uri; - } - - set - { - if (type == 0) - { - PackageRelationship r = mainPart.GetRelationship(id); - - // Get all of the information about this relationship. - TargetMode r_tm = r.TargetMode; - string r_rt = r.RelationshipType; - string r_id = r.Id; - - // Delete the relationship - mainPart.DeleteRelationship(r_id); - mainPart.CreateRelationship(value, r_tm, r_rt, r_id); - } - - else - { - instrText.Value = "HYPERLINK " + "\"" + value + "\""; - } - - this.uri = value; - } - } - - internal Hyperlink(DocX document, PackagePart mainPart, XElement i): base(document, i) - { - this.type = 0; - this.id = i.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; - - StringBuilder sb = new StringBuilder(); - HelperFunctions.GetTextRecursive(i, ref sb); - this.text = sb.ToString(); - } - - internal Hyperlink(DocX document, XElement instrText, List runs) : base(document, null) - { - this.type = 1; - this.instrText = instrText; - this.runs = runs; - - try - { - int start = instrText.Value.IndexOf("HYPERLINK \"") + "HYPERLINK \"".Length; - int end = instrText.Value.IndexOf("\"", start); - if (start != -1 && end != -1) - { - this.uri = new Uri(instrText.Value.Substring(start, end - start), UriKind.Absolute); - - StringBuilder sb = new StringBuilder(); - HelperFunctions.GetTextRecursive(new XElement(XName.Get("temp", DocX.w.NamespaceName), runs), ref sb); - this.text = sb.ToString(); - } - } - - catch (Exception e){throw e;} - } - } -} diff --git a/DocX/IContentContainer.cs b/DocX/IContentContainer.cs deleted file mode 100644 index 4505f9e1..00000000 --- a/DocX/IContentContainer.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.ObjectModel; - -namespace Novacode -{ - interface IContentContainer - { - ReadOnlyCollection Paragraphs { get; } - } -} diff --git a/DocX/IParagraphContainer.cs b/DocX/IParagraphContainer.cs deleted file mode 100644 index 7a4bd814..00000000 --- a/DocX/IParagraphContainer.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.ObjectModel; - -namespace Novacode -{ - public interface IParagraphContainer - { - ReadOnlyCollection Paragraphs { get; } - } -} \ No newline at end of file diff --git a/DocX/Image.cs b/DocX/Image.cs deleted file mode 100644 index f2704743..00000000 --- a/DocX/Image.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.IO.Packaging; -using System.IO; - -namespace Novacode -{ - /// - /// Represents an Image embedded in a document. - /// - public class Image - { - /// - /// A unique id which identifies this Image. - /// - private string id; - private DocX document; - internal PackageRelationship pr; - - public Stream GetStream(FileMode mode, FileAccess access) - { - string temp = pr.SourceUri.OriginalString; - string start = temp.Remove(temp.LastIndexOf('/')); - string end = pr.TargetUri.OriginalString; - string full = end.Contains(start) ? end : start + "/" + end; - - return (new PackagePartStream(document.package.GetPart(new Uri(full, UriKind.Relative)).GetStream(mode, access))); - } - - /// - /// Returns the id of this Image. - /// - public string Id - { - get {return id;} - } - - internal Image(DocX document, PackageRelationship pr) - { - this.document = document; - this.pr = pr; - this.id = pr.Id; - } - - /// - /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append. - /// - /// - /// - /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append. - /// - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Add an image to the document. - /// Image i = document.AddImage(@"Image.jpg"); - /// - /// // Create a picture i.e. (A custom view of an image) - /// Picture p = i.CreatePicture(); - /// p.FlipHorizontal = true; - /// p.Rotation = 10; - /// - /// // Create a new Paragraph. - /// Paragraph par = document.InsertParagraph(); - /// - /// // Append content to the Paragraph. - /// par.Append("Here is a cool picture") - /// .AppendPicture(p) - /// .Append(" don't you think so?"); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public Picture CreatePicture() - { - return Paragraph.CreatePicture(document, id, string.Empty, string.Empty); - } - public Picture CreatePicture(int height, int width) { - Picture picture = Paragraph.CreatePicture(document, id, string.Empty, string.Empty); - picture.Height = height; - picture.Width = width; - return picture; - } - - /// - /// Returns the name of the image file. - /// - public string FileName - { - get - { - return Path.GetFileName(this.pr.TargetUri.ToString()); - } - } - } -} diff --git a/DocX/KeyWithoutPassword.snk b/DocX/KeyWithoutPassword.snk deleted file mode 100644 index 9a9fc9c7..00000000 Binary files a/DocX/KeyWithoutPassword.snk and /dev/null differ diff --git a/DocX/License/License.html b/DocX/License/License.html deleted file mode 100644 index 93e03003..00000000 --- a/DocX/License/License.html +++ /dev/null @@ -1,7 +0,0 @@ - - -
- Microsoft Public License (Ms-PL)

This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.

1. Definitions

The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.

A "contribution" is the original software, or any additions or changes to the software.

A "contributor" is any person that distributes its contribution under this license.

"Licensed patents" are a contributor's patent claims that read directly on its contribution.

2. Grant of Rights

(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.

(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.

3. Conditions and Limitations

(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.

(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.

(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.

(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.

(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
-
- - \ No newline at end of file diff --git a/DocX/List.cs b/DocX/List.cs deleted file mode 100644 index 3e44a174..00000000 --- a/DocX/List.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; - -namespace Novacode -{ - /// - /// Represents a List in a document. - /// - public class List : InsertBeforeOrAfter - { - /// - /// This is a list of paragraphs that will be added to the document - /// when the list is inserted into the document. - /// The paragraph needs a numPr defined to be in this items collection. - /// - public List Items { get; private set; } - /// - /// The numId used to reference the list settings in the numbering.xml - /// - public int NumId { get; private set; } - /// - /// The ListItemType (bullet or numbered) of the list. - /// - public ListItemType? ListType { get; private set; } - - internal List(DocX document, XElement xml) - : base(document, xml) - { - Items = new List(); - ListType = null; - } - - /// - /// Adds an item to the list. - /// - /// - /// - /// Throws an InvalidOperationException if the item cannot be added to the list. - /// - public void AddItem(Paragraph paragraph) - { - if (paragraph.IsListItem) - { - var numIdNode = paragraph.Xml.Descendants().First(s => s.Name.LocalName == "numId"); - var numId = Int32.Parse(numIdNode.Attribute(DocX.w + "val").Value); - - if (CanAddListItem(paragraph)) - { - NumId = numId; - Items.Add(paragraph); - } - else - throw new InvalidOperationException("New list items can only be added to this list if they are have the same numId."); - } - } - - public void AddItemWithStartValue(Paragraph paragraph, int start) - { - //TODO: Update the numbering - UpdateNumberingForLevelStartNumber(int.Parse(paragraph.IndentLevel.ToString()), start); - if (ContainsLevel(start)) - throw new InvalidOperationException("Cannot add a paragraph with a start value if another element already exists in this list with that level."); - AddItem(paragraph); - } - - private void UpdateNumberingForLevelStartNumber(int iLevel, int start) - { - var abstractNum = GetAbstractNum(NumId); - var level = abstractNum.Descendants().First(el => el.Name.LocalName == "lvl" && el.GetAttribute(DocX.w + "ilvl") == iLevel.ToString()); - level.Descendants().First(el => el.Name.LocalName == "start").SetAttributeValue(DocX.w + "val", start); - } - - /// - /// Determine if it is able to add the item to the list - /// - /// - /// - /// Return true if AddItem(...) will succeed with the given paragraph. - /// - public bool CanAddListItem(Paragraph paragraph) - { - if (paragraph.IsListItem) - { - //var lvlNode = paragraph.Xml.Descendants().First(s => s.Name.LocalName == "ilvl"); - var numIdNode = paragraph.Xml.Descendants().First(s => s.Name.LocalName == "numId"); - var numId = Int32.Parse(numIdNode.Attribute(DocX.w + "val").Value); - - //Level = Int32.Parse(lvlNode.Attribute(DocX.w + "val").Value); - if (NumId == 0 || (numId == NumId && numId > 0)) - { - return true; - } - } - return false; - } - - public bool ContainsLevel(int ilvl) - { - return Items.Any(i => i.ParagraphNumberProperties.Descendants().First(el => el.Name.LocalName == "ilvl").Value == ilvl.ToString()); - } - - internal void CreateNewNumberingNumId(int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool continueNumbering = false) - { - ValidateDocXNumberingPartExists(); - if (Document.numbering.Root == null) - { - throw new InvalidOperationException("Numbering section did not instantiate properly."); - } - - ListType = listType; - - var numId = GetMaxNumId() + 1; - var abstractNumId = GetMaxAbstractNumId() + 1; - - XDocument listTemplate; - switch (listType) - { - case ListItemType.Bulleted: - listTemplate = HelperFunctions.DecompressXMLResource("Novacode.Resources.numbering.default_bullet_abstract.xml.gz"); - break; - case ListItemType.Numbered: - listTemplate = HelperFunctions.DecompressXMLResource("Novacode.Resources.numbering.default_decimal_abstract.xml.gz"); - break; - default: - throw new InvalidOperationException(string.Format("Unable to deal with ListItemType: {0}.", listType.ToString())); - } - - var abstractNumTemplate = listTemplate.Descendants().Single(d => d.Name.LocalName == "abstractNum"); - abstractNumTemplate.SetAttributeValue(DocX.w + "abstractNumId", abstractNumId); - - //Fixing an issue where numbering would continue from previous numbered lists. Setting startOverride assures that a numbered list starts on the provided number. - //The override needs only be on level 0 as this will cascade to the rest of the list. - var abstractNumXml = GetAbstractNumXml(abstractNumId, numId, startNumber, continueNumbering); - - var abstractNumNode = Document.numbering.Root.Descendants().LastOrDefault(xElement => xElement.Name.LocalName == "abstractNum"); - var numXml = Document.numbering.Root.Descendants().LastOrDefault(xElement => xElement.Name.LocalName == "num"); - - if (abstractNumNode == null || numXml == null) - { - Document.numbering.Root.Add(abstractNumTemplate); - Document.numbering.Root.Add(abstractNumXml); - } - else - { - abstractNumNode.AddAfterSelf(abstractNumTemplate); - numXml.AddAfterSelf( - abstractNumXml - ); - } - - NumId = numId; - } - - private XElement GetAbstractNumXml(int abstractNumId, int numId, int? startNumber, bool continueNumbering) - { - //Fixing an issue where numbering would continue from previous numbered lists. Setting startOverride assures that a numbered list starts on the provided number. - //The override needs only be on level 0 as this will cascade to the rest of the list. - var startOverride = new XElement(XName.Get("startOverride", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", startNumber ?? 1)); - var lvlOverride = new XElement(XName.Get("lvlOverride", DocX.w.NamespaceName), new XAttribute(DocX.w + "ilvl", 0), startOverride); - var abstractNumIdElement = new XElement(XName.Get("abstractNumId", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", abstractNumId)); - return continueNumbering - ? new XElement(XName.Get("num", DocX.w.NamespaceName), new XAttribute(DocX.w + "numId", numId), abstractNumIdElement) - : new XElement(XName.Get("num", DocX.w.NamespaceName), new XAttribute(DocX.w + "numId", numId), abstractNumIdElement, lvlOverride); - } - - /// - /// Method to determine the last numId for a list element. - /// Also useful for determining the next numId to use for inserting a new list element into the document. - /// - /// - /// 0 if there are no elements in the list already. - /// Increment the return for the next valid value of a new list element. - /// - private int GetMaxNumId() - { - const int defaultValue = 0; - if (Document.numbering == null) - return defaultValue; - - var numlist = Document.numbering.Descendants().Where(d => d.Name.LocalName == "num").ToList(); - if (numlist.Any()) - return numlist.Attributes(DocX.w + "numId").Max(e => int.Parse(e.Value)); - return defaultValue; - } - - /// - /// Method to determine the last abstractNumId for a list element. - /// Also useful for determining the next abstractNumId to use for inserting a new list element into the document. - /// - /// - /// -1 if there are no elements in the list already. - /// Increment the return for the next valid value of a new list element. - /// - private int GetMaxAbstractNumId() - { - const int defaultValue = -1; - - if (Document.numbering == null) - return defaultValue; - - var numlist = Document.numbering.Descendants().Where(d => d.Name.LocalName == "abstractNum").ToList(); - if (numlist.Any()) - { - var maxAbstractNumId = numlist.Attributes(DocX.w + "abstractNumId").Max(e => int.Parse(e.Value)); - return maxAbstractNumId; - } - return defaultValue; - } - - /// - /// Get the abstractNum definition for the given numId - /// - /// The numId on the pPr element - /// XElement representing the requested abstractNum - internal XElement GetAbstractNum(int numId) - { - var num = Document.numbering.Descendants().First(d => d.Name.LocalName == "num" && d.GetAttribute(DocX.w + "numId").Equals(numId.ToString())); - var abstractNumId = num.Descendants().First(d => d.Name.LocalName == "abstractNumId"); - return Document.numbering.Descendants().First(d => d.Name.LocalName == "abstractNum" && d.GetAttribute("abstractNumId").Equals(abstractNumId.Value)); - } - - private void ValidateDocXNumberingPartExists() - { - var numberingUri = new Uri("/word/numbering.xml", UriKind.Relative); - - // If the internal document contains no /word/numbering.xml create one. - if (!Document.package.PartExists(numberingUri)) - Document.numbering = HelperFunctions.AddDefaultNumberingXml(Document.package); - } - } -} diff --git a/DocX/PackagePartStream.cs b/DocX/PackagePartStream.cs deleted file mode 100644 index b8c0b4ba..00000000 --- a/DocX/PackagePartStream.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.IO; - -namespace Novacode -{ - /// - /// OpenXML Isolated Storage access is not thread safe. - /// Use app domain wide lock for writing. - /// - public class PackagePartStream : Stream - { - private static readonly object lockObject = new object(); - - private readonly Stream stream; - - public PackagePartStream(Stream stream) - { - this.stream = stream; - } - - public override bool CanRead - { - get { return this.stream.CanRead; } - } - - public override bool CanSeek - { - get { return this.stream.CanSeek; } - } - - public override bool CanWrite - { - get { return this.stream.CanWrite; } - } - - public override long Length - { - get { return this.stream.Length; } - } - - public override long Position - { - get { return this.stream.Position; } - set { this.stream.Position = value; } - } - - public override long Seek(long offset, SeekOrigin origin) - { - return this.stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - this.stream.SetLength(value); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return this.stream.Read(buffer, offset, count); - } - - public override void Write(byte[] buffer, int offset, int count) - { - lock (lockObject) - { - this.stream.Write(buffer, offset, count); - } - } - - public override void Flush() - { - lock (lockObject) - { - this.stream.Flush(); - } - } - - public override void Close() - { - this.stream.Close(); - } - - protected override void Dispose(bool disposing) - { - this.stream.Dispose(); - } - } -} diff --git a/DocX/PageLayout.cs b/DocX/PageLayout.cs deleted file mode 100644 index ee832958..00000000 --- a/DocX/PageLayout.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Xml.Linq; - -namespace Novacode -{ - public class PageLayout: DocXElement - { - internal PageLayout(DocX document, XElement xml):base(document, xml) - { - - } - - - public Orientation Orientation - { - get - { - /* - * Get the pgSz (page size) element for this Section, - * null will be return if no such element exists. - */ - XElement pgSz = Xml.Element(XName.Get("pgSz", DocX.w.NamespaceName)); - - if (pgSz == null) - return Orientation.Portrait; - - // Get the attribute of the pgSz element. - XAttribute val = pgSz.Attribute(XName.Get("orient", DocX.w.NamespaceName)); - - // If val is null, this cell contains no information. - if (val == null) - return Orientation.Portrait; - - if (val.Value.Equals("Landscape", StringComparison.CurrentCultureIgnoreCase)) - return Orientation.Landscape; - else - return Orientation.Portrait; - } - - set - { - // Check if already correct value. - if (Orientation == value) - return; - - /* - * Get the pgSz (page size) element for this Section, - * null will be return if no such element exists. - */ - XElement pgSz = Xml.Element(XName.Get("pgSz", DocX.w.NamespaceName)); - - if (pgSz == null) - { - Xml.SetElementValue(XName.Get("pgSz", DocX.w.NamespaceName), string.Empty); - pgSz = Xml.Element(XName.Get("pgSz", DocX.w.NamespaceName)); - } - - pgSz.SetAttributeValue(XName.Get("orient", DocX.w.NamespaceName), value.ToString().ToLower()); - - if(value == Novacode.Orientation.Landscape) - { - pgSz.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), "16838"); - pgSz.SetAttributeValue(XName.Get("h", DocX.w.NamespaceName), "11906"); - } - - else if (value == Novacode.Orientation.Portrait) - { - pgSz.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), "11906"); - pgSz.SetAttributeValue(XName.Get("h", DocX.w.NamespaceName), "16838"); - } - } - } - } -} diff --git a/DocX/Paragraph.cs b/DocX/Paragraph.cs deleted file mode 100644 index 64f6e8de..00000000 --- a/DocX/Paragraph.cs +++ /dev/null @@ -1,4732 +0,0 @@ -using System; -using System.Linq; -using System.Drawing; -using System.Xml.Linq; -using System.Collections; -using System.IO.Packaging; -using System.Globalization; -using System.Security.Principal; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; - - -namespace Novacode -{ - /// - /// Represents a document paragraph. - /// - public class Paragraph : InsertBeforeOrAfter - { - - // The Append family of functions use this List to apply style. - internal List runs; - - // This paragraphs text alignment - private Alignment alignment; - - public ContainerType ParentContainer; - - private XElement ParagraphNumberPropertiesBacker { get; set; } - /// - /// Fetch the paragraph number properties for a list element. - /// - public XElement ParagraphNumberProperties - { - get - { - return ParagraphNumberPropertiesBacker ?? (ParagraphNumberPropertiesBacker = GetParagraphNumberProperties()); - } - } - - private XElement GetParagraphNumberProperties() - { - var numPrNode = Xml.Descendants().FirstOrDefault(el => el.Name.LocalName == "numPr"); - if (numPrNode != null) - { - var numIdNode = numPrNode.Descendants().First(numId => numId.Name.LocalName == "numId"); - var numIdAttribute = numIdNode.Attribute(DocX.w + "val"); - if (numIdAttribute != null && numIdAttribute.Value.Equals("0")) - { - return null; - } - } - - return numPrNode; - } - - private bool? IsListItemBacker { get; set; } - /// - /// Determine if this paragraph is a list element. - /// - public bool IsListItem - { - get - { - IsListItemBacker = IsListItemBacker ?? (ParagraphNumberProperties != null); - return (bool)IsListItemBacker; - } - } - - private int? IndentLevelBacker { get; set; } - /// - /// If this element is a list item, get the indentation level of the list item. - /// - public int? IndentLevel - { - get - { - if (!IsListItem) - { - return null; - } - return IndentLevelBacker ?? (IndentLevelBacker = int.Parse(ParagraphNumberProperties.Descendants().First(el => el.Name.LocalName == "ilvl").GetAttribute(DocX.w + "val"))); - } - } - - /// - /// Determine if the list element is a numbered list of bulleted list element - /// - public ListItemType ListItemType; - - internal int startIndex, endIndex; - - /// - /// Returns a list of all Pictures in a Paragraph. - /// - /// - /// Returns a list of all Pictures in a Paragraph. - /// - /// pictures = p.Pictures; - /// - /// // Save this document. - /// document.Save(); - /// } - /// ]]> - /// - /// - public List Pictures - { - get - { - if (Xml == null) - { - return new List(); - } - - List pictures = - ( - from p in Xml.Descendants() - where (p.Name.LocalName == "drawing") - let id = - ( - from e in p.Descendants() - where e.Name.LocalName.Equals("blip") - select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")).Value - ).SingleOrDefault() - where id != null - let img = new Image(Document, mainPart.GetRelationship(id)) - select new Picture(Document, p, img) - ).ToList(); - - List shapes = - ( - from p in Xml.Descendants() - where (p.Name.LocalName == "pict") - let id = - ( - from e in p.Descendants() - where e.Name.LocalName.Equals("imagedata") - select e.Attribute(XName.Get("id", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")).Value - ).SingleOrDefault() - where id != null - let img = new Image(Document, mainPart.GetRelationship(id)) - select new Picture(Document, p, img) - ).ToList(); - - foreach (Picture p in shapes) - pictures.Add(p); - - - return pictures; - } - } - - /// - /// Returns a list of Hyperlinks in this Paragraph. - /// - /// - /// - /// // Create a document. - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // Get the first Paragraph in this document. - /// Paragraph p = document.Paragraphs[0]; - /// - /// // Get all of the hyperlinks in this Paragraph. - /// ]]> hyperlinks = paragraph.Hyperlinks; - /// - /// // Change the first hyperlinks text and Uri - /// Hyperlink h0 = hyperlinks[0]; - /// h0.Text = "DocX"; - /// h0.Uri = new Uri("http://docx.codeplex.com"); - /// - /// // Save this document. - /// document.Save(); - /// } - /// - /// - public List Hyperlinks - { - get - { - List hyperlinks = new List(); - - List hyperlink_elements = - ( - from h in Xml.Descendants() - where (h.Name.LocalName == "hyperlink" || h.Name.LocalName == "instrText") - select h - ).ToList(); - - foreach (XElement he in hyperlink_elements) - { - if (he.Name.LocalName == "hyperlink") - { - try - { - Hyperlink h = new Hyperlink(Document, mainPart, he); - h.mainPart = mainPart; - hyperlinks.Add(h); - } - - catch (Exception) { } - } - - else - { - // Find the parent run, no matter how deeply nested we are. - XElement e = he; - while (e.Name.LocalName != "r") - e = e.Parent; - - // Take every element until we reach w:fldCharType="end" - List hyperlink_runs = new List(); - foreach (XElement r in e.ElementsAfterSelf(XName.Get("r", DocX.w.NamespaceName))) - { - // Add this run to the list. - hyperlink_runs.Add(r); - - XElement fldChar = r.Descendants(XName.Get("fldChar", DocX.w.NamespaceName)).SingleOrDefault(); - if (fldChar != null) - { - XAttribute fldCharType = fldChar.Attribute(XName.Get("fldCharType", DocX.w.NamespaceName)); - if (fldCharType != null && fldCharType.Value.Equals("end", StringComparison.CurrentCultureIgnoreCase)) - { - try - { - Hyperlink h = new Hyperlink(Document, he, hyperlink_runs); - h.mainPart = mainPart; - hyperlinks.Add(h); - } - - catch (Exception) { } - - break; - } - } - } - } - } - - return hyperlinks; - } - } - - /// - /// The style name of the paragraph. - /// - public string StyleName - { - get - { - var element = this.GetOrCreate_pPr(); - var styleElement = element.Element(XName.Get("pStyle", DocX.w.NamespaceName)); - var attr = styleElement?.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (!string.IsNullOrEmpty(attr?.Value)) - { - return attr.Value; - } - return "Normal"; - } - set - { - if (string.IsNullOrEmpty(value)) - { - value = "Normal"; - } - var element = this.GetOrCreate_pPr(); - var styleElement = element.Element(XName.Get("pStyle", DocX.w.NamespaceName)); - if (styleElement == null) - { - element.Add(new XElement(XName.Get("pStyle", DocX.w.NamespaceName))); - styleElement = element.Element(XName.Get("pStyle", DocX.w.NamespaceName)); - } - styleElement.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), value); - } - } - - // A collection of field type DocProperty. - private List docProperties; - - internal List styles = new List(); - - /// - /// Returns a list of field type DocProperty in this document. - /// - public List DocumentProperties - { - get { return docProperties; } - } - - internal Paragraph(DocX document, XElement xml, int startIndex, ContainerType parent = ContainerType.None) - : base(document, xml) - { - ParentContainer = parent; - this.startIndex = startIndex; - this.endIndex = startIndex + GetElementTextLength(xml); - - RebuildDocProperties(); - - // As per Unused code affecting performance (Wiki Link: [discussion:454191]) and coffeycathal suggestion no longer requeried - //#region It's possible that a Paragraph may have pStyle references - //// Check if this Paragraph references any pStyle elements. - //var stylesElements = xml.Descendants(XName.Get("pStyle", DocX.w.NamespaceName)); - - //// If one or more pStyles are referenced. - //if (stylesElements.Count() > 0) - //{ - // Uri style_package_uri = new Uri("/word/styles.xml", UriKind.Relative); - // PackagePart styles_document = document.package.GetPart(style_package_uri); - - // using (TextReader tr = new StreamReader(styles_document.GetStream())) - // { - // XDocument style_document = XDocument.Load(tr); - // XElement styles_element = style_document.Element(XName.Get("styles", DocX.w.NamespaceName)); - - // var styles_element_ids = stylesElements.Select(e => e.Attribute(XName.Get("val", DocX.w.NamespaceName)).Value); - - // //foreach(string id in styles_element_ids) - // //{ - // // var style = - // // ( - // // from d in styles_element.Descendants() - // // let styleId = d.Attribute(XName.Get("styleId", DocX.w.NamespaceName)) - // // let type = d.Attribute(XName.Get("type", DocX.w.NamespaceName)) - // // where type != null && type.Value == "paragraph" && styleId != null && styleId.Value == id - // // select d - // // ).First(); - - // // styles.Add(style); - // //} - // } - //} - //#endregion - - this.runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).ToList(); - } - - /// - /// Insert a new Table before this Paragraph, this Table can be from this document or another document. - /// - /// The Table t to be inserted. - /// A new Table inserted before this Paragraph. - /// - /// Insert a new Table before this Paragraph. - /// - /// // Place holder for a Table. - /// Table t; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"a.docx")) - /// { - /// // Get the first Table from this document. - /// t = documentA.Tables[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"b.docx")) - /// { - /// // Get the first Paragraph in document b. - /// Paragraph p2 = documentB.Paragraphs[0]; - /// - /// // Insert the Table from document a before this Paragraph. - /// Table newTable = p2.InsertTableBeforeSelf(t); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public override Table InsertTableBeforeSelf(Table t) - { - t = base.InsertTableBeforeSelf(t); - t.mainPart = mainPart; - return t; - } - - private Direction direction; - /// - /// Gets or Sets the Direction of content in this Paragraph. - /// - /// Create a Paragraph with content that flows right to left. Default is left to right. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Create a new Paragraph with the text "Hello World". - /// Paragraph p = document.InsertParagraph("Hello World."); - /// - /// // Make this Paragraph flow right to left. Default is left to right. - /// p.Direction = Direction.RightToLeft; - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - /// - public Direction Direction - { - get - { - XElement pPr = GetOrCreate_pPr(); - XElement bidi = pPr.Element(XName.Get("bidi", DocX.w.NamespaceName)); - - return bidi == null ? Direction.LeftToRight : Direction.RightToLeft; - } - - set - { - direction = value; - - XElement pPr = GetOrCreate_pPr(); - XElement bidi = pPr.Element(XName.Get("bidi", DocX.w.NamespaceName)); - - if (direction == Direction.RightToLeft) - { - if (bidi == null) - pPr.Add(new XElement(XName.Get("bidi", DocX.w.NamespaceName))); - } - else - { - bidi?.Remove(); - } - } - } - - 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; - } - } - /// - /// This paragraph will be kept on the same page as the next paragraph - /// - /// - /// Create a Paragraph that will stay on the same page as the paragraph that comes next - /// - /// // Create a new document. - /// using (DocX document = DocX.Create("Test.docx")) - /// - /// { - /// // Create a new Paragraph with the text "Hello World". - /// Paragraph p = document.InsertParagraph("Hello World."); - /// p.KeepWithNext(); - /// document.InsertParagraph("Previous paragraph will appear on the same page as this paragraph"); - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - /// - /// - - public Paragraph KeepWithNext(bool keepWithNext = true) - { - var pPr = GetOrCreate_pPr(); - var keepWithNextE = pPr.Element(XName.Get("keepNext", DocX.w.NamespaceName)); - if (keepWithNextE == null && keepWithNext) - { - pPr.Add(new XElement(XName.Get("keepNext", DocX.w.NamespaceName))); - } - if (!keepWithNext && keepWithNextE != null) - { - keepWithNextE.Remove(); - } - return this; - - } - /// - /// Keep all lines in this paragraph together on a page - /// - /// - /// Create a Paragraph whose lines will stay together on a single page - /// - /// // Create a new document. - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Create a new Paragraph with the text "Hello World". - /// Paragraph p = document.InsertParagraph("All lines of this paragraph will appear on the same page...\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6..."); - /// p.KeepLinesTogether(); - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - /// - /// - public Paragraph KeepLinesTogether(bool keepTogether = true) - { - var pPr = GetOrCreate_pPr(); - var keepLinesE = pPr.Element(XName.Get("keepLines", DocX.w.NamespaceName)); - if (keepLinesE == null && keepTogether) - { - pPr.Add(new XElement(XName.Get("keepLines", DocX.w.NamespaceName))); - } - if (!keepTogether) - { - keepLinesE?.Remove(); - } - return this; - } - /// - /// If the pPr element doesent exist it is created, either way it is returned by this function. - /// - /// The pPr element for this Paragraph. - internal XElement GetOrCreate_pPr() - { - // Get the element. - XElement pPr = Xml.Element(XName.Get("pPr", DocX.w.NamespaceName)); - - // If it dosen't exist, create it. - if (pPr == null) - { - Xml.AddFirst(new XElement(XName.Get("pPr", DocX.w.NamespaceName))); - pPr = Xml.Element(XName.Get("pPr", DocX.w.NamespaceName)); - } - - // Return the pPr element for this Paragraph. - return pPr; - } - - /// - /// If the ind element doesent exist it is created, either way it is returned by this function. - /// - /// The ind element for this Paragraphs pPr. - internal XElement GetOrCreate_pPr_ind() - { - // Get the element. - XElement pPr = GetOrCreate_pPr(); - XElement ind = pPr.Element(XName.Get("ind", DocX.w.NamespaceName)); - - // If it dosen't exist, create it. - if (ind == null) - { - pPr.Add(new XElement(XName.Get("ind", DocX.w.NamespaceName))); - ind = pPr.Element(XName.Get("ind", DocX.w.NamespaceName)); - } - - // Return the pPr element for this Paragraph. - return ind; - } - - private float indentationFirstLine; - /// - /// Get or set the indentation of the first line of this Paragraph. - /// - /// - /// Indent only the first line of a Paragraph. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Create a new Paragraph. - /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3"); - /// - /// // Indent only the first line of the Paragraph. - /// p.IndentationFirstLine = 2.0f; - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public float IndentationFirstLine - { - get - { - GetOrCreate_pPr(); - XElement ind = GetOrCreate_pPr_ind(); - XAttribute firstLine = ind.Attribute(XName.Get("firstLine", DocX.w.NamespaceName)); - - if (firstLine != null) - return float.Parse(firstLine.Value); - - return 0.0f; - } - - set - { - if (IndentationFirstLine != value) - { - indentationFirstLine = value; - - XElement pPr = GetOrCreate_pPr(); - XElement ind = GetOrCreate_pPr_ind(); - - // Paragraph can either be firstLine or hanging (Remove hanging). - XAttribute hanging = ind.Attribute(XName.Get("hanging", DocX.w.NamespaceName)); - hanging?.Remove(); - - string indentation = ((indentationFirstLine / 0.1) * 57).ToString(); - XAttribute firstLine = ind.Attribute(XName.Get("firstLine", DocX.w.NamespaceName)); - if (firstLine != null) - firstLine.Value = indentation; - else - ind.Add(new XAttribute(XName.Get("firstLine", DocX.w.NamespaceName), indentation)); - } - } - } - - private float indentationHanging; - /// - /// Get or set the indentation of all but the first line of this Paragraph. - /// - /// - /// Indent all but the first line of a Paragraph. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Create a new Paragraph. - /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3"); - /// - /// // Indent all but the first line of the Paragraph. - /// p.IndentationHanging = 1.0f; - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public float IndentationHanging - { - get - { - GetOrCreate_pPr(); - XElement ind = GetOrCreate_pPr_ind(); - XAttribute hanging = ind.Attribute(XName.Get("hanging", DocX.w.NamespaceName)); - - if (hanging != null) - return float.Parse(hanging.Value) / (57 * 10); - - return 0.0f; - } - - set - { - if (IndentationHanging != value) - { - indentationHanging = value; - - XElement pPr = GetOrCreate_pPr(); - XElement ind = GetOrCreate_pPr_ind(); - - // Paragraph can either be firstLine or hanging (Remove firstLine). - XAttribute firstLine = ind.Attribute(XName.Get("firstLine", DocX.w.NamespaceName)); - if (firstLine != null) - firstLine.Remove(); - - string indentation = ((indentationHanging / 0.1) * 57).ToString(); - XAttribute hanging = ind.Attribute(XName.Get("hanging", DocX.w.NamespaceName)); - if (hanging != null) - hanging.Value = indentation; - else - ind.Add(new XAttribute(XName.Get("hanging", DocX.w.NamespaceName), indentation)); - } - } - } - - private float indentationBefore; - /// - /// Set the before indentation in cm for this Paragraph. - /// - /// - /// // Indent an entire Paragraph from the left. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Create a new Paragraph. - /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3"); - /// - /// // Indent this entire Paragraph from the left. - /// p.IndentationBefore = 2.0f; - /// - /// // Save all changes made to this document. - /// document.Save(); - ///} - /// - /// - public float IndentationBefore - { - get - { - XElement pPr = GetOrCreate_pPr(); - XElement ind = GetOrCreate_pPr_ind(); - - XAttribute left = ind.Attribute(XName.Get("left", DocX.w.NamespaceName)); - if (left != null) - return float.Parse(left.Value) / (57 * 10); - - return 0.0f; - } - - set - { - if (IndentationBefore != value) - { - indentationBefore = value; - - XElement pPr = GetOrCreate_pPr(); - XElement ind = GetOrCreate_pPr_ind(); - - string indentation = ((indentationBefore / 0.1) * 57).ToString(CultureInfo.GetCultureInfo("en-GB")); - - XAttribute left = ind.Attribute(XName.Get("left", DocX.w.NamespaceName)); - if (left != null) - left.Value = indentation; - else - ind.Add(new XAttribute(XName.Get("left", DocX.w.NamespaceName), indentation)); - } - } - } - - private float indentationAfter; - /// - /// Set the after indentation in cm for this Paragraph. - /// - /// - /// // Indent an entire Paragraph from the right. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Create a new Paragraph. - /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3"); - /// - /// // Make the content of this Paragraph flow right to left. - /// p.Direction = Direction.RightToLeft; - /// - /// // Indent this entire Paragraph from the right. - /// p.IndentationAfter = 2.0f; - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public float IndentationAfter - { - get - { - GetOrCreate_pPr(); - XElement ind = GetOrCreate_pPr_ind(); - - XAttribute right = ind.Attribute(XName.Get("right", DocX.w.NamespaceName)); - if (right != null) - return float.Parse(right.Value); - - return 0.0f; - } - - set - { - if (IndentationAfter != value) - { - indentationAfter = value; - - XElement pPr = GetOrCreate_pPr(); - XElement ind = GetOrCreate_pPr_ind(); - - string indentation = ((indentationAfter / 0.1) * 57).ToString(); - - XAttribute right = ind.Attribute(XName.Get("right", DocX.w.NamespaceName)); - if (right != null) - right.Value = indentation; - else - ind.Add(new XAttribute(XName.Get("right", DocX.w.NamespaceName), indentation)); - } - } - } - - /// - /// Insert a new Table into this document before this Paragraph. - /// - /// The number of rows this Table should have. - /// The number of columns this Table should have. - /// A new Table inserted before this Paragraph. - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// //Insert a Paragraph into this document. - /// Paragraph p = document.InsertParagraph("Hello World", false); - /// - /// // Insert a new Table before this Paragraph. - /// Table newTable = p.InsertTableBeforeSelf(2, 2); - /// newTable.Design = TableDesign.LightShadingAccent2; - /// newTable.Alignment = Alignment.center; - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public override Table InsertTableBeforeSelf(int rowCount, int columnCount) - { - return base.InsertTableBeforeSelf(rowCount, columnCount); - } - - /// - /// Insert a new Table after this Paragraph. - /// - /// The Table t to be inserted. - /// A new Table inserted after this Paragraph. - /// - /// Insert a new Table after this Paragraph. - /// - /// // Place holder for a Table. - /// Table t; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"a.docx")) - /// { - /// // Get the first Table from this document. - /// t = documentA.Tables[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"b.docx")) - /// { - /// // Get the first Paragraph in document b. - /// Paragraph p2 = documentB.Paragraphs[0]; - /// - /// // Insert the Table from document a after this Paragraph. - /// Table newTable = p2.InsertTableAfterSelf(t); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public override Table InsertTableAfterSelf(Table t) - { - t = base.InsertTableAfterSelf(t); - t.mainPart = mainPart; - return t; - } - - /// - /// Insert a new Table into this document after this Paragraph. - /// - /// The number of rows this Table should have. - /// The number of columns this Table should have. - /// A new Table inserted after this Paragraph. - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// //Insert a Paragraph into this document. - /// Paragraph p = document.InsertParagraph("Hello World", false); - /// - /// // Insert a new Table after this Paragraph. - /// Table newTable = p.InsertTableAfterSelf(2, 2); - /// newTable.Design = TableDesign.LightShadingAccent2; - /// newTable.Alignment = Alignment.center; - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public override Table InsertTableAfterSelf(int rowCount, int columnCount) - { - return base.InsertTableAfterSelf(rowCount, columnCount); - } - - /// - /// Insert a Paragraph before this Paragraph, this Paragraph may have come from the same or another document. - /// - /// The Paragraph to insert. - /// The Paragraph now associated with this document. - /// - /// Take a Paragraph from document a, and insert it into document b before this Paragraph. - /// - /// // Place holder for a Paragraph. - /// Paragraph p; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"a.docx")) - /// { - /// // Get the first paragraph from this document. - /// p = documentA.Paragraphs[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"b.docx")) - /// { - /// // Get the first Paragraph in document b. - /// Paragraph p2 = documentB.Paragraphs[0]; - /// - /// // Insert the Paragraph from document a before this Paragraph. - /// Paragraph newParagraph = p2.InsertParagraphBeforeSelf(p); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public override Paragraph InsertParagraphBeforeSelf(Paragraph p) - { - Paragraph p2 = base.InsertParagraphBeforeSelf(p); - p2.PackagePart = mainPart; - return p2; - } - - /// - /// Insert a new Paragraph before this Paragraph. - /// - /// The initial text for this new Paragraph. - /// A new Paragraph inserted before this Paragraph. - /// - /// Insert a new paragraph before the first Paragraph in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Paragraph into this document. - /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); - /// - /// p.InsertParagraphBeforeSelf("I was inserted before the next Paragraph."); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphBeforeSelf(string text) - { - Paragraph p = base.InsertParagraphBeforeSelf(text); - p.PackagePart = mainPart; - return p; - } - - /// - /// Insert a new Paragraph before this Paragraph. - /// - /// The initial text for this new Paragraph. - /// Should this insertion be tracked as a change? - /// A new Paragraph inserted before this Paragraph. - /// - /// Insert a new paragraph before the first Paragraph in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Paragraph into this document. - /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); - /// - /// p.InsertParagraphBeforeSelf("I was inserted before the next Paragraph.", false); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphBeforeSelf(string text, bool trackChanges) - { - Paragraph p = base.InsertParagraphBeforeSelf(text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - /// - /// Insert a new Paragraph before this Paragraph. - /// - /// The initial text for this new Paragraph. - /// Should this insertion be tracked as a change? - /// The formatting to apply to this insertion. - /// A new Paragraph inserted before this Paragraph. - /// - /// Insert a new paragraph before the first Paragraph in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Paragraph into this document. - /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); - /// - /// Formatting boldFormatting = new Formatting(); - /// boldFormatting.Bold = true; - /// - /// p.InsertParagraphBeforeSelf("I was inserted before the next Paragraph.", false, boldFormatting); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphBeforeSelf(string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraphBeforeSelf(text, trackChanges, formatting); - p.PackagePart = mainPart; - return p; - } - - /// - /// Insert a page break before a Paragraph. - /// - /// - /// Insert 2 Paragraphs into a document with a page break between them. - /// - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p1 = document.InsertParagraph("Paragraph 1", false); - /// - /// // Insert a new Paragraph. - /// Paragraph p2 = document.InsertParagraph("Paragraph 2", false); - /// - /// // Insert a page break before Paragraph two. - /// p2.InsertPageBreakBeforeSelf(); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public override void InsertPageBreakBeforeSelf() - { - base.InsertPageBreakBeforeSelf(); - } - - /// - /// Insert a page break after a Paragraph. - /// - /// - /// Insert 2 Paragraphs into a document with a page break between them. - /// - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p1 = document.InsertParagraph("Paragraph 1", false); - /// - /// // Insert a page break after this Paragraph. - /// p1.InsertPageBreakAfterSelf(); - /// - /// // Insert a new Paragraph. - /// Paragraph p2 = document.InsertParagraph("Paragraph 2", false); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public override void InsertPageBreakAfterSelf() - { - base.InsertPageBreakAfterSelf(); - } - - [Obsolete("Instead use: InsertHyperlink(Hyperlink h, int index)")] - public Paragraph InsertHyperlink(int index, Hyperlink h) { return InsertHyperlink(h, index); } - - /// - /// This function inserts a hyperlink into a Paragraph at a specified character index. - /// - /// The index to insert at. - /// The hyperlink to insert. - /// The Paragraph with the Hyperlink inserted at the specified index. - /// - public Paragraph InsertHyperlink(Hyperlink h, int index = 0) - { - // Convert the path of this mainPart to its equilivant rels file path. - string path = mainPart.Uri.OriginalString.Replace("/word/", ""); - Uri rels_path = new Uri(String.Format("/word/_rels/{0}.rels", path), UriKind.Relative); - - // Check to see if the rels file exists and create it if not. - if (!Document.package.PartExists(rels_path)) - HelperFunctions.CreateRelsPackagePart(Document, rels_path); - - // Check to see if a rel for this Picture exists, create it if not. - var Id = GetOrGenerateRel(h); - - XElement h_xml; - if (index == 0) - { - // Add this hyperlink as the first element. - Xml.AddFirst(h.Xml); - - // Extract the picture back out of the DOM. - h_xml = (XElement)Xml.FirstNode; - } - - else - { - // Get the first run effected by this Insert - Run run = GetFirstRunEffectedByEdit(index); - - if (run == null) - { - // Add this hyperlink as the last element. - Xml.Add(h.Xml); - - // Extract the picture back out of the DOM. - h_xml = (XElement)Xml.LastNode; - } - - else - { - // Split this run at the point you want to insert - XElement[] splitRun = Run.SplitRun(run, index); - - // Replace the origional run. - run.Xml.ReplaceWith - ( - splitRun[0], - h.Xml, - splitRun[1] - ); - - // Get the first run effected by this Insert - run = GetFirstRunEffectedByEdit(index); - - // The picture has to be the next element, extract it back out of the DOM. - h_xml = (XElement)run.Xml.NextNode; - } - - } - h_xml.SetAttributeValue( DocX.r + "id", Id ); - - this.runs = Xml.Elements().Last().Elements( XName.Get( "r", DocX.w.NamespaceName ) ).ToList(); - - return this; - } - - /// - /// Remove the Hyperlink at the provided index. The first hyperlink is at index 0. - /// Using a negative index or an index greater than the index of the last hyperlink will cause an ArgumentOutOfRangeException() to be thrown. - /// - /// The index of the hyperlink to be removed. - /// - /// - /// // Crete a new document. - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Add a Hyperlink into this document. - /// Hyperlink h = document.AddHyperlink("link", new Uri("http://www.google.com")); - /// - /// // Insert a new Paragraph into the document. - /// Paragraph p1 = document.InsertParagraph("AC"); - /// - /// // Insert the hyperlink into this Paragraph. - /// p1.InsertHyperlink(1, h); - /// Assert.IsTrue(p1.Text == "AlinkC"); // Make sure the hyperlink was inserted correctly; - /// - /// // Remove the hyperlink - /// p1.RemoveHyperlink(0); - /// Assert.IsTrue(p1.Text == "AC"); // Make sure the hyperlink was removed correctly; - /// } - /// - /// - public void RemoveHyperlink(int index) - { - // Dosen't make sense to remove a Hyperlink at a negative index. - if (index < 0) - throw new ArgumentOutOfRangeException(); - - // Need somewhere to store the count. - int count = 0; - bool found = false; - RemoveHyperlinkRecursive(Xml, index, ref count, ref found); - - // If !found then the user tried to remove a hyperlink at an index greater than the last. - if (!found) - throw new ArgumentOutOfRangeException(); - } - - internal void RemoveHyperlinkRecursive(XElement xml, int index, ref int count, ref bool found) - { - if (xml.Name.LocalName.Equals("hyperlink", StringComparison.CurrentCultureIgnoreCase)) - { - // This is the hyperlink to be removed. - if (count == index) - { - found = true; - xml.Remove(); - } - - else - count++; - } - - if (xml.HasElements) - foreach (XElement e in xml.Elements()) - if (!found) - RemoveHyperlinkRecursive(e, index, ref count, ref found); - } - - /// - /// Insert a Paragraph after this Paragraph, this Paragraph may have come from the same or another document. - /// - /// The Paragraph to insert. - /// The Paragraph now associated with this document. - /// - /// Take a Paragraph from document a, and insert it into document b after this Paragraph. - /// - /// // Place holder for a Paragraph. - /// Paragraph p; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"a.docx")) - /// { - /// // Get the first paragraph from this document. - /// p = documentA.Paragraphs[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"b.docx")) - /// { - /// // Get the first Paragraph in document b. - /// Paragraph p2 = documentB.Paragraphs[0]; - /// - /// // Insert the Paragraph from document a after this Paragraph. - /// Paragraph newParagraph = p2.InsertParagraphAfterSelf(p); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public override Paragraph InsertParagraphAfterSelf(Paragraph p) - { - Paragraph p2 = base.InsertParagraphAfterSelf(p); - p2.PackagePart = mainPart; - return p2; - } - - /// - /// Insert a new Paragraph after this Paragraph. - /// - /// The initial text for this new Paragraph. - /// Should this insertion be tracked as a change? - /// The formatting to apply to this insertion. - /// A new Paragraph inserted after this Paragraph. - /// - /// Insert a new paragraph after the first Paragraph in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Paragraph into this document. - /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); - /// - /// Formatting boldFormatting = new Formatting(); - /// boldFormatting.Bold = true; - /// - /// p.InsertParagraphAfterSelf("I was inserted after the previous Paragraph.", false, boldFormatting); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphAfterSelf(string text, bool trackChanges, Formatting formatting) - { - Paragraph p = base.InsertParagraphAfterSelf(text, trackChanges, formatting); - p.PackagePart = mainPart; - return p; - } - - /// - /// Insert a new Paragraph after this Paragraph. - /// - /// The initial text for this new Paragraph. - /// Should this insertion be tracked as a change? - /// A new Paragraph inserted after this Paragraph. - /// - /// Insert a new paragraph after the first Paragraph in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Paragraph into this document. - /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); - /// - /// p.InsertParagraphAfterSelf("I was inserted after the previous Paragraph.", false); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphAfterSelf(string text, bool trackChanges) - { - Paragraph p = base.InsertParagraphAfterSelf(text, trackChanges); - p.PackagePart = mainPart; - return p; - } - - /// - /// Insert a new Paragraph after this Paragraph. - /// - /// The initial text for this new Paragraph. - /// A new Paragraph inserted after this Paragraph. - /// - /// Insert a new paragraph after the first Paragraph in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Paragraph into this document. - /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); - /// - /// p.InsertParagraphAfterSelf("I was inserted after the previous Paragraph."); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphAfterSelf(string text) - { - Paragraph p = base.InsertParagraphAfterSelf(text); - p.PackagePart = mainPart; - return p; - } - - private void RebuildDocProperties() - { - docProperties = - ( - from xml in Xml.Descendants(XName.Get("fldSimple", DocX.w.NamespaceName)) - select new DocProperty(Document, xml) - ).ToList(); - } - - /// - /// Gets or set this Paragraphs text alignment. - /// - public Alignment Alignment - { - get - { - XElement pPr = GetOrCreate_pPr(); - XElement jc = pPr.Element(XName.Get("jc", DocX.w.NamespaceName)); - - if (jc != null) - { - XAttribute a = jc.Attribute(XName.Get("val", DocX.w.NamespaceName)); - - switch (a.Value.ToLower()) - { - case "left": return Novacode.Alignment.left; - case "right": return Novacode.Alignment.right; - case "center": return Novacode.Alignment.center; - case "both": return Novacode.Alignment.both; - } - } - - return Novacode.Alignment.left; - } - - set - { - alignment = value; - - XElement pPr = GetOrCreate_pPr(); - XElement jc = pPr.Element(XName.Get("jc", DocX.w.NamespaceName)); - - if (alignment != Novacode.Alignment.left) - { - if (jc == null) - pPr.Add(new XElement(XName.Get("jc", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), alignment.ToString()))); - else - jc.Attribute(XName.Get("val", DocX.w.NamespaceName)).Value = alignment.ToString(); - } - - else - { - if (jc != null) - jc.Remove(); - } - } - } - - /// - /// Remove this Paragraph from the document. - /// - /// Should this remove be tracked as a change? - /// - /// Remove a Paragraph from a document and track it as a change. - /// - /// // Create a document using a relative filename. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Create and Insert a new Paragraph into this document. - /// Paragraph p = document.InsertParagraph("Hello", false); - /// - /// // Remove the Paragraph and track this as a change. - /// p.Remove(true); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public void Remove(bool trackChanges) - { - if (trackChanges) - { - DateTime now = DateTime.Now.ToUniversalTime(); - - List elements = Xml.Elements().ToList(); - List temp = new List(); - for (int i = 0; i < elements.Count(); i++) - { - XElement e = elements[i]; - - if (e.Name.LocalName != "del") - { - temp.Add(e); - e.Remove(); - } - - else - { - if (temp.Count() > 0) - { - e.AddBeforeSelf(CreateEdit(EditType.del, now, temp.Elements())); - temp.Clear(); - } - } - } - - if (temp.Count() > 0) - Xml.Add(CreateEdit(EditType.del, now, temp)); - } - - else - { - // If this is the only Paragraph in the Cell then we cannot remove it. - if (Xml.Parent.Name.LocalName == "tc" && Xml.Parent.Elements(XName.Get("p", DocX.w.NamespaceName)).Count() == 1) - Xml.Value = string.Empty; - - else - { - // Remove this paragraph from the document - Xml.Remove(); - Xml = null; - } - } - } - - /// - /// Gets the text value of this Paragraph. - /// - public string Text - { - // Returns the underlying XElement's Value property. - get - { - return HelperFunctions.GetText(Xml); - } - } - - /// - /// Gets the formatted text value of this Paragraph. - /// - public List MagicText - { - // Returns the underlying XElement's Value property. - get - { - try - { - return HelperFunctions.GetFormattedText(Xml); - - } - catch (Exception) - { - return null; - } - - } - } - - //public Picture InsertPicture(Picture picture) - //{ - // Picture newPicture = picture; - // newPicture.i = new XElement(picture.i); - - // xml.Add(newPicture.i); - // pictures.Add(newPicture); - // return newPicture; - //} - - // - // Insert a Picture at the end of this paragraph. - // - // A string to describe this Picture. - // The unique id that identifies the Image this Picture represents. - // The name of this image. - // A Picture. - // - // - // // Create a document using a relative filename. - // using (DocX document = DocX.Create(@"Test.docx")) - // { - // // Add a new Paragraph to this document. - // Paragraph p = document.InsertParagraph("Here is Picture 1", false); - // - // // Add an Image to this document. - // Novacode.Image img = document.AddImage(@"Image.jpg"); - // - // // Insert pic at the end of Paragraph p. - // Picture pic = p.InsertPicture(img.Id, "Photo 31415", "A pie I baked."); - // - // // Rotate the Picture clockwise by 30 degrees. - // pic.Rotation = 30; - // - // // Resize the Picture. - // pic.Width = 400; - // pic.Height = 300; - // - // // Set the shape of this Picture to be a cube. - // pic.SetPictureShape(BasicShapes.cube); - // - // // Flip the Picture Horizontally. - // pic.FlipHorizontal = true; - // - // // Save all changes made to this document. - // document.Save(); - // }// Release this document from memory. - // - // - // Removed to simplify the API. - //public Picture InsertPicture(string imageID, string name, string description) - //{ - // Picture p = CreatePicture(Document, imageID, name, description); - // Xml.Add(p.Xml); - // return p; - //} - - // Removed because it confusses the API. - //public Picture InsertPicture(string imageID) - //{ - // return InsertPicture(imageID, string.Empty, string.Empty); - //} - - //public Picture InsertPicture(int index, Picture picture) - //{ - // Picture p = picture; - // p.i = new XElement(picture.i); - - // Run run = GetFirstRunEffectedByEdit(index); - - // if (run == null) - // xml.Add(p.i); - // else - // { - // // Split this run at the point you want to insert - // XElement[] splitRun = Run.SplitRun(run, index); - - // // Replace the origional run - // run.Xml.ReplaceWith - // ( - // splitRun[0], - // p.i, - // splitRun[1] - // ); - // } - - // // Rebuild the run lookup for this paragraph - // runLookup.Clear(); - // BuildRunLookup(xml); - // DocX.RenumberIDs(document); - // return p; - //} - - // - // Insert a Picture into this Paragraph at a specified index. - // - // A string to describe this Picture. - // The unique id that identifies the Image this Picture represents. - // The name of this image. - // The index to insert this Picture at. - // A Picture. - // - // - // // Create a document using a relative filename. - // using (DocX document = DocX.Create(@"Test.docx")) - // { - // // Add a new Paragraph to this document. - // Paragraph p = document.InsertParagraph("Here is Picture 1", false); - // - // // Add an Image to this document. - // Novacode.Image img = document.AddImage(@"Image.jpg"); - // - // // Insert pic at the start of Paragraph p. - // Picture pic = p.InsertPicture(0, img.Id, "Photo 31415", "A pie I baked."); - // - // // Rotate the Picture clockwise by 30 degrees. - // pic.Rotation = 30; - // - // // Resize the Picture. - // pic.Width = 400; - // pic.Height = 300; - // - // // Set the shape of this Picture to be a cube. - // pic.SetPictureShape(BasicShapes.cube); - // - // // Flip the Picture Horizontally. - // pic.FlipHorizontal = true; - // - // // Save all changes made to this document. - // document.Save(); - // }// Release this document from memory. - // - // - // Removed to simplify API. - //public Picture InsertPicture(int index, string imageID, string name, string description) - //{ - // Picture picture = CreatePicture(Document, imageID, name, description); - - // Run run = GetFirstRunEffectedByEdit(index); - - // if (run == null) - // Xml.Add(picture.Xml); - // else - // { - // // Split this run at the point you want to insert - // XElement[] splitRun = Run.SplitRun(run, index); - - // // Replace the origional run - // run.Xml.ReplaceWith - // ( - // splitRun[0], - // picture.Xml, - // splitRun[1] - // ); - // } - - // HelperFunctions.RenumberIDs(Document); - // return picture; - //} - - /// - /// Create a new Picture. - /// - /// - /// A unique id that identifies an Image embedded in this document. - /// The name of this Picture. - /// The description of this Picture. - static internal Picture CreatePicture(DocX document, string id, string name, string descr) - { - PackagePart part = document.package.GetPart(document.mainPart.GetRelationship(id).TargetUri); - - long newDocPrId = document.GetNextFreeDocPrId(); - int cx, cy; - - using (PackagePartStream packagePartStream = new PackagePartStream(part.GetStream())) - { - using (System.Drawing.Image img = System.Drawing.Image.FromStream(packagePartStream, useEmbeddedColorManagement: false, validateImageData: false)) - { - cx = img.Width*9526; - cy = img.Height*9526; - } - } - - XElement xml = XElement.Parse - (string.Format(@" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ", cx, cy, id, name, descr, newDocPrId.ToString())); - - return new Picture(document, xml, new Image(document, document.mainPart.GetRelationship(id))); - } - - /// - /// Replaces a Picture with a new one. - /// - /// - /// Only the content of the picture will be replaced - positioning inside the document and all other attributes will be preserved. - /// - /// The picture object to be replaced. - /// The picture object that should be inserted instead of . - /// The new object that replaces the old one. - public Picture ReplacePicture(Picture toBeReplaced, Picture replaceWith) - { - var document = this.Document; - var newDocPrId = document.GetNextFreeDocPrId(); - - var xml = XElement.Parse(toBeReplaced.Xml.ToString()); - foreach (var element in xml.Descendants(XName.Get("docPr", DocX.wp.NamespaceName))) - { - element.SetAttributeValue(XName.Get("id"), newDocPrId); - } - - foreach (var element in xml.Descendants(XName.Get("blip", DocX.a.NamespaceName))) - { - element.SetAttributeValue(XName.Get("embed", DocX.r.NamespaceName), replaceWith.Id); - } - - var replacePicture = new Picture(document, xml, new Image(document, document.mainPart.GetRelationship(replaceWith.Id))); - this.AppendPicture(replacePicture); - toBeReplaced.Remove(); - return replacePicture; - } - - // Removed because it confusses the API. - //public Picture InsertPicture(int index, string imageID) - //{ - // return InsertPicture(index, imageID, string.Empty, string.Empty); - //} - - /// - /// Creates an Edit either a ins or a del with the specified content and date - /// - /// The type of this edit (ins or del) - /// The time stamp to use for this edit - /// The initial content of this edit - /// - internal static XElement CreateEdit(EditType t, DateTime edit_time, object content) - { - if (t == EditType.del) - { - foreach (object o in (IEnumerable)content) - { - if (o is XElement) - { - XElement e = (o as XElement); - IEnumerable ts = e.DescendantsAndSelf(XName.Get("t", DocX.w.NamespaceName)); - - for (int i = 0; i < ts.Count(); i++) - { - XElement text = ts.ElementAt(i); - text.ReplaceWith(new XElement(DocX.w + "delText", text.Attributes(), text.Value)); - } - } - } - } - - return - ( - new XElement(DocX.w + t.ToString(), - new XAttribute(DocX.w + "id", 0), - new XAttribute(DocX.w + "author", WindowsIdentity.GetCurrent().Name), - new XAttribute(DocX.w + "date", edit_time), - content) - ); - } - - internal Run GetFirstRunEffectedByEdit(int index, EditType type = EditType.ins) - { - int len = HelperFunctions.GetText(Xml).Length; - - // Make sure we are looking within an acceptable index range. - if (index < 0 || ((type == EditType.ins && index > len) || (type == EditType.del && index >= len))) - throw new ArgumentOutOfRangeException(); - - // Need some memory that can be updated by the recursive search for the XElement to Split. - int count = 0; - Run theOne = null; - - GetFirstRunEffectedByEditRecursive(Xml, index, ref count, ref theOne, type); - - return theOne; - } - - internal void GetFirstRunEffectedByEditRecursive(XElement Xml, int index, ref int count, ref Run theOne, EditType type) - { - count += HelperFunctions.GetSize(Xml); - - // If the EditType is deletion then we must return the next blah - if (count > 0 && ((type == EditType.del && count > index) || (type == EditType.ins && count >= index))) - { - // Correct the index - foreach (XElement e in Xml.ElementsBeforeSelf()) - count -= HelperFunctions.GetSize(e); - - count -= HelperFunctions.GetSize(Xml); - - // We have found the element, now find the run it belongs to. - while ((Xml.Name.LocalName != "r") && (Xml.Name.LocalName != "pPr")) - Xml = Xml.Parent; - - theOne = new Run(Document, Xml, count); - return; - } - - if (Xml.HasElements) - foreach (XElement e in Xml.Elements()) - if (theOne == null) - GetFirstRunEffectedByEditRecursive(e, index, ref count, ref theOne, type); - } - - /// - static internal int GetElementTextLength(XElement run) - { - int count = 0; - - if (run == null) - return count; - - foreach (var d in run.Descendants()) - { - switch (d.Name.LocalName) - { - case "tab": - if (d.Parent.Name.LocalName != "tabs") - goto case "br"; break; - case "br": count++; break; - case "t": goto case "delText"; - case "delText": count += d.Value.Length; break; - default: break; - } - } - return count; - } - - internal XElement[] SplitEdit(XElement edit, int index, EditType type) - { - Run run = GetFirstRunEffectedByEdit(index, type); - - XElement[] splitRun = Run.SplitRun(run, index, type); - - XElement splitLeft = new XElement(edit.Name, edit.Attributes(), run.Xml.ElementsBeforeSelf(), splitRun[0]); - if (GetElementTextLength(splitLeft) == 0) - splitLeft = null; - - XElement splitRight = new XElement(edit.Name, edit.Attributes(), splitRun[1], run.Xml.ElementsAfterSelf()); - if (GetElementTextLength(splitRight) == 0) - splitRight = null; - - return - ( - new XElement[] - { - splitLeft, - splitRight - } - ); - } - - /// - /// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position. - /// - /// - /// - /// // Create a document using a relative filename. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Create a text formatting. - /// Formatting f = new Formatting(); - /// f.FontColor = Color.Red; - /// f.Size = 30; - /// - /// // Iterate through the Paragraphs in this document. - /// foreach (Paragraph p in document.Paragraphs) - /// { - /// // Insert the string "Start: " at the begining of every Paragraph and flag it as a change. - /// p.InsertText("Start: ", true, f); - /// } - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// Inserting tabs using the \t switch. - /// - /// // Create a document using a relative filename. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Create a text formatting. - /// Formatting f = new Formatting(); - /// f.FontColor = Color.Red; - /// f.Size = 30; - /// - /// // Iterate through the paragraphs in this document. - /// foreach (Paragraph p in document.Paragraphs) - /// { - /// // Insert the string "\tEnd" at the end of every paragraph and flag it as a change. - /// p.InsertText("\tEnd", true, f); - /// } - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// - /// The System.String to insert. - /// Flag this insert as a change. - /// The text formatting. - public void InsertText(string value, bool trackChanges = false, Formatting formatting = null) - { - // Default values for optional parameters must be compile time constants. - // Would have like to write 'public void InsertText(string value, bool trackChanges = false, Formatting formatting = new Formatting()) - if (formatting == null) formatting = new Formatting(); - - List newRuns = HelperFunctions.FormatInput(value, formatting.Xml); - Xml.Add(newRuns); - - HelperFunctions.RenumberIDs(Document); - } - - /// - /// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position. - /// - /// - /// - /// // Create a document using a relative filename. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Create a text formatting. - /// Formatting f = new Formatting(); - /// f.FontColor = Color.Red; - /// f.Size = 30; - /// - /// // Iterate through the Paragraphs in this document. - /// foreach (Paragraph p in document.Paragraphs) - /// { - /// // Insert the string "Start: " at the begining of every Paragraph and flag it as a change. - /// p.InsertText(0, "Start: ", true, f); - /// } - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// Inserting tabs using the \t switch. - /// - /// // Create a document using a relative filename. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Create a text formatting. - /// Formatting f = new Formatting(); - /// f.FontColor = Color.Red; - /// f.Size = 30; - /// - /// // Iterate through the paragraphs in this document. - /// foreach (Paragraph p in document.Paragraphs) - /// { - /// // Insert the string "\tStart:\t" at the begining of every paragraph and flag it as a change. - /// p.InsertText(0, "\tStart:\t", true, f); - /// } - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// - /// The index position of the insertion. - /// The System.String to insert. - /// Flag this insert as a change. - /// The text formatting. - public void InsertText(int index, string value, bool trackChanges = false, Formatting formatting = null) - { - // Timestamp to mark the start of insert - DateTime now = DateTime.Now; - DateTime insert_datetime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc); - - // Get the first run effected by this Insert - Run run = GetFirstRunEffectedByEdit(index); - - if (run == null) - { - object insert; - if (formatting != null) //not sure how to get original formatting here when run == null - insert = HelperFunctions.FormatInput(value, formatting.Xml); - else - insert = HelperFunctions.FormatInput(value, null); - - if (trackChanges) - insert = CreateEdit(EditType.ins, insert_datetime, insert); - Xml.Add(insert); - } - - else - { - object newRuns; - var rprel = run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)); - if (formatting != null) - { - //merge 2 formattings properly - Formatting finfmt = null; - Formatting oldfmt = null; - - if (rprel != null) - { - oldfmt = Formatting.Parse(rprel); - } - - if (oldfmt != null) - { - finfmt = oldfmt.Clone(); - if (formatting.Bold.HasValue) { finfmt.Bold = formatting.Bold; } - if (formatting.CapsStyle.HasValue) { finfmt.CapsStyle = formatting.CapsStyle; } - if (formatting.FontColor.HasValue) { finfmt.FontColor = formatting.FontColor; } - finfmt.FontFamily = formatting.FontFamily; - if (formatting.Hidden.HasValue) { finfmt.Hidden = formatting.Hidden; } - if (formatting.Highlight.HasValue) { finfmt.Highlight = formatting.Highlight; } - if (formatting.Italic.HasValue) { finfmt.Italic = formatting.Italic; } - if (formatting.Kerning.HasValue) { finfmt.Kerning = formatting.Kerning; } - finfmt.Language = formatting.Language; - if (formatting.Misc.HasValue) { finfmt.Misc = formatting.Misc; } - if (formatting.PercentageScale.HasValue) { finfmt.PercentageScale = formatting.PercentageScale; } - if (formatting.Position.HasValue) { finfmt.Position = formatting.Position; } - if (formatting.Script.HasValue) { finfmt.Script = formatting.Script; } - if (formatting.Size.HasValue) { finfmt.Size = formatting.Size; } - if (formatting.Spacing.HasValue) { finfmt.Spacing = formatting.Spacing; } - if (formatting.StrikeThrough.HasValue) { finfmt.StrikeThrough = formatting.StrikeThrough; } - if (formatting.UnderlineColor.HasValue) { finfmt.UnderlineColor = formatting.UnderlineColor; } - if (formatting.UnderlineStyle.HasValue) { finfmt.UnderlineStyle = formatting.UnderlineStyle; } - } - else - { - finfmt = formatting; - } - - newRuns = HelperFunctions.FormatInput(value, finfmt.Xml); - } - else - { - newRuns = HelperFunctions.FormatInput(value, rprel); - } - - // The parent of this Run - XElement parentElement = run.Xml.Parent; - switch (parentElement.Name.LocalName) - { - case "ins": - { - // The datetime that this ins was created - DateTime parent_ins_date = DateTime.Parse(parentElement.Attribute(XName.Get("date", DocX.w.NamespaceName)).Value); - - /* - * Special case: You want to track changes, - * and the first Run effected by this insert - * has a datetime stamp equal to now. - */ - if (trackChanges && parent_ins_date.CompareTo(insert_datetime) == 0) - { - /* - * Inserting into a non edit and this special case, is the same procedure. - */ - goto default; - } - - /* - * If not the special case above, - * then inserting into an ins or a del, is the same procedure. - */ - goto case "del"; - } - - case "del": - { - object insert = newRuns; - if (trackChanges) - insert = CreateEdit(EditType.ins, insert_datetime, newRuns); - - // Split this Edit at the point you want to insert - XElement[] splitEdit = SplitEdit(parentElement, index, EditType.ins); - - // Replace the origional run - parentElement.ReplaceWith - ( - splitEdit[0], - insert, - splitEdit[1] - ); - - break; - } - - default: - { - object insert = newRuns; - if (trackChanges && !parentElement.Name.LocalName.Equals("ins")) - insert = CreateEdit(EditType.ins, insert_datetime, newRuns); - - // Special case to deal with Page Number elements. - //if (parentElement.Name.LocalName.Equals("fldSimple")) - // parentElement.AddBeforeSelf(insert); - - else - { - // Split this run at the point you want to insert - XElement[] splitRun = Run.SplitRun(run, index); - - // Replace the origional run - run.Xml.ReplaceWith - ( - splitRun[0], - insert, - splitRun[1] - ); - } - - break; - } - } - } - - HelperFunctions.RenumberIDs(Document); - } - - /// - /// For use with Append() and AppendLine() - /// - /// This Paragraph in curent culture - /// - /// Add a new Paragraph with russian text to this document and then set language of text to local culture. - /// - /// // Load a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph with russian text and set curent local culture to it. - /// Paragraph p = document.InsertParagraph("Привет мир!").CurentCulture(); - /// - /// // Save this document. - /// document.Save(); - /// } - /// - /// - public Paragraph CurentCulture() - { - ApplyTextFormattingProperty(XName.Get("lang", DocX.w.NamespaceName), - string.Empty, - new XAttribute(XName.Get("val", DocX.w.NamespaceName), CultureInfo.CurrentCulture.Name)); - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// The CultureInfo for text - /// This Paragraph in curent culture - /// - /// Add a new Paragraph with russian text to this document and then set language of text to local culture. - /// - /// // Load a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph with russian text and set specific culture to it. - /// Paragraph p = document.InsertParagraph("Привет мир").Culture(CultureInfo.CreateSpecificCulture("ru-RU")); - /// - /// // Save this document. - /// document.Save(); - /// } - /// - /// - public Paragraph Culture(CultureInfo culture) - { - ApplyTextFormattingProperty(XName.Get("lang", DocX.w.NamespaceName), string.Empty, - new XAttribute(XName.Get("val", DocX.w.NamespaceName), culture.Name)); - return this; - } - - /// - /// Append text to this Paragraph. - /// - /// The text to append. - /// This Paragraph with the new text appened. - /// - /// Add a new Paragraph to this document and then append some text to it. - /// - /// // Load a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph and Append some text to it. - /// Paragraph p = document.InsertParagraph().Append("Hello World!!!"); - /// - /// // Save this document. - /// document.Save(); - /// } - /// - /// - public Paragraph Append(string text) - { - List newRuns = HelperFunctions.FormatInput(text, null); - Xml.Add(newRuns); - - this.runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).Reverse().Take(newRuns.Count()).ToList(); - - return this; - } - - - public void InsertHorizontalLine(string lineType = "single", int size = 6, int space = 1, string color = "auto") - { - var pPr = this.GetOrCreate_pPr(); - var border = pPr.Element(XName.Get("pBdr", DocX.w.NamespaceName)); - if (border == null) - { - pPr.Add(new XElement(XName.Get("pBdr", DocX.w.NamespaceName))); - border = pPr.Element(XName.Get("pBdr", DocX.w.NamespaceName)); - border.Add(new XElement(XName.Get("bottom", DocX.w.NamespaceName))); - var bottom = border.Element(XName.Get("bottom", DocX.w.NamespaceName)); - bottom.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), lineType); - bottom.SetAttributeValue(XName.Get("sz", DocX.w.NamespaceName), size.ToString()); - bottom.SetAttributeValue(XName.Get("space", DocX.w.NamespaceName), space.ToString()); - bottom.SetAttributeValue(XName.Get("color", DocX.w.NamespaceName), color); - } - } - - /// - /// Append a hyperlink to a Paragraph. - /// - /// The hyperlink to append. - /// The Paragraph with the hyperlink appended. - /// - /// Creates a Paragraph with some text and a hyperlink. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add a hyperlink to this document. - /// Hyperlink h = document.AddHyperlink("Google", new Uri("http://www.google.com")); - /// - /// // Add a new Paragraph to this document. - /// Paragraph p = document.InsertParagraph(); - /// p.Append("My favourite search engine is "); - /// p.AppendHyperlink(h); - /// p.Append(", I think it's great."); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public Paragraph AppendHyperlink(Hyperlink h) - { - // Convert the path of this mainPart to its equilivant rels file path. - string path = mainPart.Uri.OriginalString.Replace("/word/", ""); - Uri rels_path = new Uri("/word/_rels/" + path + ".rels", UriKind.Relative); - - // Check to see if the rels file exists and create it if not. - if (!Document.package.PartExists(rels_path)) - HelperFunctions.CreateRelsPackagePart(Document, rels_path); - - // Check to see if a rel for this Hyperlink exists, create it if not. - var Id = GetOrGenerateRel(h); - - Xml.Add(h.Xml); - Xml.Elements().Last().SetAttributeValue(DocX.r + "id", Id); - - this.runs = Xml.Elements().Last().Elements(XName.Get("r", DocX.w.NamespaceName)).ToList(); - - return this; - } - - /// - /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append. - /// - /// The Picture to append. - /// The Paragraph with the Picture now appended. - /// - /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append. - /// - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Add an image to the document. - /// Image i = document.AddImage(@"Image.jpg"); - /// - /// // Create a picture i.e. (A custom view of an image) - /// Picture p = i.CreatePicture(); - /// p.FlipHorizontal = true; - /// p.Rotation = 10; - /// - /// // Create a new Paragraph. - /// Paragraph par = document.InsertParagraph(); - /// - /// // Append content to the Paragraph. - /// par.Append("Here is a cool picture") - /// .AppendPicture(p) - /// .Append(" don't you think so?"); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public Paragraph AppendPicture(Picture p) - { - // Convert the path of this mainPart to its equilivant rels file path. - string path = mainPart.Uri.OriginalString.Replace("/word/", ""); - Uri rels_path = new Uri("/word/_rels/" + path + ".rels", UriKind.Relative); - - // Check to see if the rels file exists and create it if not. - if (!Document.package.PartExists(rels_path)) - HelperFunctions.CreateRelsPackagePart(Document, rels_path); - - // Check to see if a rel for this Picture exists, create it if not. - var Id = GetOrGenerateRel(p); - - // Add the Picture Xml to the end of the Paragragraph Xml. - Xml.Add(p.Xml); - - // Extract the attribute id from the Pictures Xml. - XAttribute a_id = - ( - from e in Xml.Elements().Last().Descendants() - where e.Name.LocalName.Equals("blip") - select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")) - ).Single(); - - // Set its value to the Pictures relationships id. - a_id.SetValue(Id); - - // For formatting such as .Bold() - this.runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).Reverse().Take(p.Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).Count()).ToList(); - - return this; - } - - /// - /// Add an equation to a document. - /// - /// The Equation to append. - /// The Paragraph with the Equation now appended. - /// - /// Add an equation to a document. - /// - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Add an equation to the document. - /// document.AddEquation("x=y+z"); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public Paragraph AppendEquation(String equation) - { - // Create equation element - XElement oMathPara = - new XElement - ( - XName.Get("oMathPara", DocX.m.NamespaceName), - new XElement - ( - XName.Get("oMath", DocX.m.NamespaceName), - new XElement - ( - XName.Get("r", DocX.w.NamespaceName), - new Formatting() { FontFamily = new Font("Cambria Math") }.Xml, // create formatting - new XElement(XName.Get("t", DocX.m.NamespaceName), equation) // create equation string - ) - ) - ); - - // Add equation element into paragraph xml and update runs collection - Xml.Add(oMathPara); - runs = Xml.Elements(XName.Get("oMathPara", DocX.m.NamespaceName)).ToList(); - - // Return paragraph with equation - return this; - } - - public bool ValidateBookmark(string bookmarkName) - { - return GetBookmarks().Any(b => b.Name.Equals(bookmarkName)); - } - - public Paragraph AppendBookmark(String bookmarkName) - { - XElement wBookmarkStart = new XElement( - XName.Get("bookmarkStart", DocX.w.NamespaceName), - new XAttribute(XName.Get("id", DocX.w.NamespaceName), 0), - new XAttribute(XName.Get("name", DocX.w.NamespaceName), bookmarkName)); - Xml.Add(wBookmarkStart); - - XElement wBookmarkEnd = new XElement( - XName.Get("bookmarkEnd", DocX.w.NamespaceName), - new XAttribute(XName.Get("id", DocX.w.NamespaceName), 0), - new XAttribute(XName.Get("name", DocX.w.NamespaceName), bookmarkName)); - Xml.Add(wBookmarkEnd); - - return this; - } - - public IEnumerable GetBookmarks() - { - return Xml.Descendants(XName.Get("bookmarkStart", DocX.w.NamespaceName)) - .Select(x => x.Attribute(XName.Get("name", DocX.w.NamespaceName))) - .Select(x => new Bookmark - { - Name = x.Value, - Paragraph = this - }); - } - - public void InsertAtBookmark(string toInsert, string bookmarkName) - { - var bookmark = Xml.Descendants(XName.Get("bookmarkStart", DocX.w.NamespaceName)) - .Where(x => x.Attribute(XName.Get("name", DocX.w.NamespaceName)).Value == bookmarkName).SingleOrDefault(); - if (bookmark != null) - { - - var run = HelperFunctions.FormatInput(toInsert, null); - bookmark.AddBeforeSelf(run); - runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).ToList(); - HelperFunctions.RenumberIDs(Document); - } - } - - public void ReplaceAtBookmark(string toInsert, string bookmarkName) - { - XElement bookmark = Xml.Descendants(XName.Get("bookmarkStart", DocX.w.NamespaceName)) - .Where(x => x.Attribute(XName.Get("name", DocX.w.NamespaceName)).Value == bookmarkName) - .SingleOrDefault(); - if (bookmark == null) - return; - - XNode nextNode = bookmark.NextNode; - XElement nextElement = nextNode as XElement; - while (nextElement == null || nextElement.Name.NamespaceName != DocX.w.NamespaceName || (nextElement.Name.LocalName != "r" && nextElement.Name.LocalName != "bookmarkEnd")) - { - nextNode = nextNode.NextNode; - nextElement = nextNode as XElement; - } - - // Check if next element is a bookmarkEnd - if (nextElement.Name.LocalName == "bookmarkEnd") - { - ReplaceAtBookmark_Add(toInsert, bookmark); - return; - } - - XElement contentElement = nextElement.Elements(XName.Get("t", DocX.w.NamespaceName)).FirstOrDefault(); - if (contentElement == null) - { - ReplaceAtBookmark_Add(toInsert, bookmark); - return; - } - - contentElement.Value = toInsert; - } - - private void ReplaceAtBookmark_Add(string toInsert, XElement bookmark) - { - var run = HelperFunctions.FormatInput(toInsert, null); - bookmark.AddAfterSelf(run); - runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).ToList(); - HelperFunctions.RenumberIDs(Document); - } - - - internal string GetOrGenerateRel(Picture p) - { - string image_uri_string = p.img.pr.TargetUri.OriginalString; - - // Search for a relationship with a TargetUri that points at this Image. - string id = null; - foreach (var r in mainPart.GetRelationshipsByType(DocX.relationshipImage)) - { - if (string.Equals(r.TargetUri.OriginalString, image_uri_string, StringComparison.Ordinal)) - { - id = r.Id; - break; - } - } - - // If such a relation doesn't exist, create one. - if (id == null) - { - // Check to see if a relationship for this Picture exists and create it if not. - PackageRelationship pr = mainPart.CreateRelationship(p.img.pr.TargetUri, TargetMode.Internal, DocX.relationshipImage); - id = pr.Id; - } - return id; - } - - internal string GetOrGenerateRel(Hyperlink h) - { - string image_uri_string = h.Uri.OriginalString; - - // Search for a relationship with a TargetUri that points at this Image. - var Id = - ( - from r in mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink") - where r.TargetUri.OriginalString == image_uri_string - select r.Id - ).SingleOrDefault(); - - // If such a relation dosen't exist, create one. - if (Id == null) - { - // Check to see if a relationship for this Picture exists and create it if not. - PackageRelationship pr = mainPart.CreateRelationship(h.Uri, TargetMode.External, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"); - Id = pr.Id; - } - return Id; - } - - /// - /// Insert a Picture into a Paragraph at the given text index. - /// If not index is provided defaults to 0. - /// - /// The Picture to insert. - /// The text index to insert at. - /// The modified Paragraph. - /// - /// - ///Load test document. - ///using (DocX document = DocX.Create("Test.docx")) - ///{ - /// // Add Headers and Footers into this document. - /// document.AddHeaders(); - /// document.AddFooters(); - /// document.DifferentFirstPage = true; - /// document.DifferentOddAndEvenPages = true; - /// - /// // Add an Image to this document. - /// Novacode.Image img = document.AddImage(directory_documents + "purple.png"); - /// - /// // Create a Picture from this Image. - /// Picture pic = img.CreatePicture(); - /// - /// // Main document. - /// Paragraph p0 = document.InsertParagraph("Hello"); - /// p0.InsertPicture(pic, 3); - /// - /// // Header first. - /// Paragraph p1 = document.Headers.first.InsertParagraph("----"); - /// p1.InsertPicture(pic, 2); - /// - /// // Header odd. - /// Paragraph p2 = document.Headers.odd.InsertParagraph("----"); - /// p2.InsertPicture(pic, 2); - /// - /// // Header even. - /// Paragraph p3 = document.Headers.even.InsertParagraph("----"); - /// p3.InsertPicture(pic, 2); - /// - /// // Footer first. - /// Paragraph p4 = document.Footers.first.InsertParagraph("----"); - /// p4.InsertPicture(pic, 2); - /// - /// // Footer odd. - /// Paragraph p5 = document.Footers.odd.InsertParagraph("----"); - /// p5.InsertPicture(pic, 2); - /// - /// // Footer even. - /// Paragraph p6 = document.Footers.even.InsertParagraph("----"); - /// p6.InsertPicture(pic, 2); - /// - /// // Save this document. - /// document.Save(); - ///} - /// - /// - public Paragraph InsertPicture(Picture p, int index = 0) - { - // Convert the path of this mainPart to its equilivant rels file path. - string path = mainPart.Uri.OriginalString.Replace("/word/", ""); - Uri rels_path = new Uri("/word/_rels/" + path + ".rels", UriKind.Relative); - - // Check to see if the rels file exists and create it if not. - if (!Document.package.PartExists(rels_path)) - HelperFunctions.CreateRelsPackagePart(Document, rels_path); - - // Check to see if a rel for this Picture exists, create it if not. - var Id = GetOrGenerateRel(p); - - XElement p_xml; - if (index == 0) - { - // Add this hyperlink as the last element. - Xml.AddFirst(p.Xml); - - // Extract the picture back out of the DOM. - p_xml = (XElement)Xml.FirstNode; - } - - else - { - // Get the first run effected by this Insert - Run run = GetFirstRunEffectedByEdit(index); - - if (run == null) - { - // Add this picture as the last element. - Xml.Add(p.Xml); - - // Extract the picture back out of the DOM. - p_xml = (XElement)Xml.LastNode; - } - - else - { - // Split this run at the point you want to insert - XElement[] splitRun = Run.SplitRun(run, index); - - // Replace the origional run. - run.Xml.ReplaceWith - ( - splitRun[0], - p.Xml, - splitRun[1] - ); - - // Get the first run effected by this Insert - run = GetFirstRunEffectedByEdit(index); - - // The picture has to be the next element, extract it back out of the DOM. - p_xml = (XElement)run.Xml.NextNode; - } - } - // Extract the attribute id from the Pictures Xml. - XAttribute a_id = - ( - from e in p_xml.Descendants() - where e.Name.LocalName.Equals("blip") - select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")) - ).Single(); - - // Set its value to the Pictures relationships id. - a_id.SetValue(Id); - - - return this; - } - - /// - /// Append text on a new line to this Paragraph. - /// - /// The text to append. - /// This Paragraph with the new text appened. - /// - /// Add a new Paragraph to this document and then append a new line with some text to it. - /// - /// // Load a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph and Append a new line with some text to it. - /// Paragraph p = document.InsertParagraph().AppendLine("Hello World!!!"); - /// - /// // Save this document. - /// document.Save(); - /// } - /// - /// - public Paragraph AppendLine(string text) - { - return Append("\n" + text); - } - - /// - /// Append a new line to this Paragraph. - /// - /// This Paragraph with a new line appeneded. - /// - /// Add a new Paragraph to this document and then append a new line to it. - /// - /// // Load a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph and Append a new line with some text to it. - /// Paragraph p = document.InsertParagraph().AppendLine(); - /// - /// // Save this document. - /// document.Save(); - /// } - /// - /// - public Paragraph AppendLine() - { - return Append("\n"); - } - - internal void ApplyTextFormattingProperty(XName textFormatPropName, string value, object content) - { - XElement rPr = null; - - if (runs.Count == 0) - { - XElement pPr = Xml.Element(XName.Get("pPr", DocX.w.NamespaceName)); - if (pPr == null) - { - Xml.AddFirst(new XElement(XName.Get("pPr", DocX.w.NamespaceName))); - pPr = Xml.Element(XName.Get("pPr", DocX.w.NamespaceName)); - } - - rPr = pPr.Element(XName.Get("rPr", DocX.w.NamespaceName)); - if (rPr == null) - { - pPr.AddFirst(new XElement(XName.Get("rPr", DocX.w.NamespaceName))); - rPr = pPr.Element(XName.Get("rPr", DocX.w.NamespaceName)); - } - - rPr.SetElementValue(textFormatPropName, value); - var last = rPr.Elements(textFormatPropName).Last(); - if (content as XAttribute != null)//If content is an attribute - { - if (last.Attribute(((XAttribute)(content)).Name) == null) - { - last.Add(content); //Add this attribute if element doesn't have it - } - else - { - last.Attribute(((XAttribute)(content)).Name).Value = ((XAttribute)(content)).Value; //Apply value only if element already has it - } - } - return; - } - - var contentIsListOfFontProperties = false; - var fontProps = content as IEnumerable; - if (fontProps != null) - { - foreach (object property in fontProps) - { - contentIsListOfFontProperties = (property as XAttribute != null); - } - } - - foreach (XElement run in runs) - { - rPr = run.Element(XName.Get("rPr", DocX.w.NamespaceName)); - if (rPr == null) - { - run.AddFirst(new XElement(XName.Get("rPr", DocX.w.NamespaceName))); - rPr = run.Element(XName.Get("rPr", DocX.w.NamespaceName)); - } - - rPr.SetElementValue(textFormatPropName, value); - XElement last = rPr.Elements(textFormatPropName).Last(); - - if (contentIsListOfFontProperties) //if content is a list of attributes, as in the case when specifying a font family - { - foreach (object property in fontProps) - { - if (last.Attribute(((XAttribute)(property)).Name) == null) - { - last.Add(property); //Add this attribute if element doesn't have it - } - else - { - last.Attribute(((XAttribute)(property)).Name).Value = - ((XAttribute)(property)).Value; //Apply value only if element already has it - } - } - } - - if (content as XAttribute != null)//If content is an attribute - { - if (last.Attribute(((XAttribute)(content)).Name) == null) - { - last.Add(content); //Add this attribute if element doesn't have it - } - else - { - last.Attribute(((XAttribute)(content)).Name).Value = ((XAttribute)(content)).Value; //Apply value only if element already has it - } - } - else - { - //IMPORTANT - //But what to do if it is not? - } - } - } - - /// - /// For use with Append() and AppendLine() - /// - /// This Paragraph with the last appended text bold. - /// - /// Append text to this Paragraph and then make it bold. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("Bold").Bold() - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph Bold() - { - ApplyTextFormattingProperty(XName.Get("b", DocX.w.NamespaceName), string.Empty, null); - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// This Paragraph with the last appended text italic. - /// - /// Append text to this Paragraph and then make it italic. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("Italic").Italic() - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph Italic() - { - ApplyTextFormattingProperty(XName.Get("i", DocX.w.NamespaceName), string.Empty, null); - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// A color to use on the appended text. - /// This Paragraph with the last appended text colored. - /// - /// Append text to this Paragraph and then color it. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("Blue").Color(Color.Blue) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph Color(Color c) - { - ApplyTextFormattingProperty(XName.Get("color", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), c.ToHex())); - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// The underline style to use for the appended text. - /// This Paragraph with the last appended text underlined. - /// - /// Append text to this Paragraph and then underline it. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("Underlined").UnderlineStyle(UnderlineStyle.doubleLine) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph UnderlineStyle(UnderlineStyle underlineStyle) - { - string value; - switch (underlineStyle) - { - case Novacode.UnderlineStyle.none: value = string.Empty; break; - case Novacode.UnderlineStyle.singleLine: value = "single"; break; - case Novacode.UnderlineStyle.doubleLine: value = "double"; break; - default: value = underlineStyle.ToString(); break; - } - - ApplyTextFormattingProperty(XName.Get("u", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), value)); - return this; - } - - private Table followingTable; - - /// - /// Returns table following the paragraph. Null if the following element isn't table. - /// - public Table FollowingTable - { - get - { - return followingTable; - } - internal set - { - followingTable = value; - } - } - - /// - /// For use with Append() and AppendLine() - /// - /// The font size to use for the appended text. - /// This Paragraph with the last appended text resized. - /// - /// Append text to this Paragraph and then resize it. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("Big").FontSize(20) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph FontSize(double fontSize) - { - double temp = fontSize * 2; - - if (temp - (int)temp == 0) - { - if (!(fontSize > 0 && fontSize < 1639)) - throw new ArgumentException("Size", "Value must be in the range 0 - 1638"); - } - - 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)); - - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// The font to use for the appended text. - /// This Paragraph with the last appended text's font changed. - public Paragraph Font(string fontName) - { - return Font(new Font(fontName)); - } - - /// - /// For use with Append() and AppendLine() - /// - /// The font to use for the appended text. - /// This Paragraph with the last appended text's font changed. - /// - /// Append text to this Paragraph and then change its font. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("Times new roman").Font(new FontFamily("Times new roman")) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph Font(Font fontFamily) - { - ApplyTextFormattingProperty - ( - XName.Get("rFonts", DocX.w.NamespaceName), - string.Empty, - new[] - { - new XAttribute(XName.Get("ascii", DocX.w.NamespaceName), fontFamily.Name), - new XAttribute(XName.Get("hAnsi", DocX.w.NamespaceName), fontFamily.Name), // Added by Maurits Elbers to support non-standard characters. See http://docx.codeplex.com/Thread/View.aspx?ThreadId=70097&ANCHOR#Post453865 - new XAttribute(XName.Get("cs", DocX.w.NamespaceName), fontFamily.Name), // Added by Maurits Elbers to support non-standard characters. See http://docx.codeplex.com/Thread/View.aspx?ThreadId=70097&ANCHOR#Post453865 - new XAttribute(XName.Get("eastAsia", DocX.w.NamespaceName), fontFamily.Name) // DOCX in china #57 - } - ); - - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// The caps style to apply to the last appended text. - /// This Paragraph with the last appended text's caps style changed. - /// - /// Append text to this Paragraph and then set it to full caps. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("Capitalized").CapsStyle(CapsStyle.caps) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph CapsStyle(CapsStyle capsStyle) - { - switch (capsStyle) - { - case Novacode.CapsStyle.none: - break; - - default: - { - ApplyTextFormattingProperty(XName.Get(capsStyle.ToString(), DocX.w.NamespaceName), string.Empty, null); - break; - } - } - - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// The script style to apply to the last appended text. - /// This Paragraph with the last appended text's script style changed. - /// - /// Append text to this Paragraph and then set it to superscript. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("superscript").Script(Script.superscript) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph Script(Script script) - { - switch (script) - { - case Novacode.Script.none: - break; - - default: - { - ApplyTextFormattingProperty(XName.Get("vertAlign", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), script.ToString())); - break; - } - } - - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - ///The highlight to apply to the last appended text. - /// This Paragraph with the last appended text highlighted. - /// - /// Append text to this Paragraph and then highlight it. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("highlighted").Highlight(Highlight.green) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph Highlight(Highlight highlight) - { - switch (highlight) - { - case Novacode.Highlight.none: - break; - - default: - { - ApplyTextFormattingProperty(XName.Get("highlight", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), highlight.ToString())); - break; - } - } - - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// The miscellaneous property to set. - /// This Paragraph with the last appended text changed by a miscellaneous property. - /// - /// Append text to this Paragraph and then apply a miscellaneous property. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("outlined").Misc(Misc.outline) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph Misc(Misc misc) - { - switch (misc) - { - case Novacode.Misc.none: - break; - - case Novacode.Misc.outlineShadow: - { - ApplyTextFormattingProperty(XName.Get("outline", DocX.w.NamespaceName), string.Empty, null); - ApplyTextFormattingProperty(XName.Get("shadow", DocX.w.NamespaceName), string.Empty, null); - - break; - } - - case Novacode.Misc.engrave: - { - ApplyTextFormattingProperty(XName.Get("imprint", DocX.w.NamespaceName), string.Empty, null); - - break; - } - - default: - { - ApplyTextFormattingProperty(XName.Get(misc.ToString(), DocX.w.NamespaceName), string.Empty, null); - - break; - } - } - - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// The strike through style to used on the last appended text. - /// This Paragraph with the last appended text striked. - /// - /// Append text to this Paragraph and then strike it. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("striked").StrikeThrough(StrikeThrough.doubleStrike) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph StrikeThrough(StrikeThrough strikeThrough) - { - string value; - switch (strikeThrough) - { - case Novacode.StrikeThrough.strike: value = "strike"; break; - case Novacode.StrikeThrough.doubleStrike: value = "dstrike"; break; - default: return this; - } - - ApplyTextFormattingProperty(XName.Get(value, DocX.w.NamespaceName), string.Empty, null); - - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// The underline color to use, if no underline is set, a single line will be used. - /// This Paragraph with the last appended text underlined in a color. - /// - /// Append text to this Paragraph and then underline it using a color. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("color underlined").UnderlineStyle(UnderlineStyle.dotted).UnderlineColor(Color.Orange) - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph UnderlineColor(Color underlineColor) - { - foreach (XElement run in runs) - { - XElement rPr = run.Element(XName.Get("rPr", DocX.w.NamespaceName)); - if (rPr == null) - { - run.AddFirst(new XElement(XName.Get("rPr", DocX.w.NamespaceName))); - rPr = run.Element(XName.Get("rPr", DocX.w.NamespaceName)); - } - - XElement u = rPr.Element(XName.Get("u", DocX.w.NamespaceName)); - if (u == null) - { - rPr.SetElementValue(XName.Get("u", DocX.w.NamespaceName), string.Empty); - u = rPr.Element(XName.Get("u", DocX.w.NamespaceName)); - u.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), "single"); - } - - u.SetAttributeValue(XName.Get("color", DocX.w.NamespaceName), underlineColor.ToHex()); - } - - return this; - } - - /// - /// For use with Append() and AppendLine() - /// - /// This Paragraph with the last appended text hidden. - /// - /// Append text to this Paragraph and then hide it. - /// - /// // Create a document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p = document.InsertParagraph(); - /// - /// p.Append("I am ") - /// .Append("hidden").Hide() - /// .Append(" I am not"); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public Paragraph Hide() - { - ApplyTextFormattingProperty(XName.Get("vanish", DocX.w.NamespaceName), string.Empty, null); - - return this; - } - - public float LineSpacing - { - get - { - XElement pPr = GetOrCreate_pPr(); - XElement spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); - - if (spacing != null) - { - XAttribute line = spacing.Attribute(XName.Get("line", DocX.w.NamespaceName)); - if (line != null) - { - float f; - - if (float.TryParse(line.Value, out f)) - return f / 20.0f; - } - } - - return 1.1f * 20.0f; - } - - set - { - Spacing(value); - } - } - - - /// - /// Set the linespacing for this paragraph manually. - /// - /// The type of spacing to be set, can be either Before, After or Line (Standard line spacing). - /// A float value of the amount of spacing. Equals the value that van be set in Word using the "Line and Paragraph spacing" button. - public void SetLineSpacing(LineSpacingType spacingType, float spacingFloat) - { - spacingFloat = spacingFloat * 240; - int spacingValue = (int)spacingFloat; - - var pPr = this.GetOrCreate_pPr(); - var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); - if (spacing == null) - { - pPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName))); - spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); - } - - string spacingTypeAttribute = ""; - switch (spacingType) - { - case LineSpacingType.Line: - { - spacingTypeAttribute = "line"; - break; - } - case LineSpacingType.Before: - { - spacingTypeAttribute = "before"; - break; - } - case LineSpacingType.After: - { - spacingTypeAttribute = "after"; - break; - } - - } - - spacing.SetAttributeValue(XName.Get(spacingTypeAttribute, DocX.w.NamespaceName), spacingValue); - } - - /// - /// Set the linespacing for this paragraph using the Auto value. - /// - /// The type of spacing to be set automatically. Using Auto will set both Before and After. None will remove any linespacing. - public void SetLineSpacing(LineSpacingTypeAuto spacingType) - { - int spacingValue = 100; - - var pPr = this.GetOrCreate_pPr(); - var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); - - if (spacingType.Equals(LineSpacingTypeAuto.None)) - { - if (spacing != null) - { - spacing.Remove(); - } - } - - else - { - - if (spacing == null) - { - pPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName))); - spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); - } - - string spacingTypeAttribute = ""; - string autoSpacingTypeAttribute = ""; - switch (spacingType) - { - case LineSpacingTypeAuto.AutoBefore: - { - spacingTypeAttribute = "before"; - autoSpacingTypeAttribute = "beforeAutospacing"; - break; - } - case LineSpacingTypeAuto.AutoAfter: - { - spacingTypeAttribute = "after"; - autoSpacingTypeAttribute = "afterAutospacing"; - break; - } - case LineSpacingTypeAuto.Auto: - { - spacingTypeAttribute = "before"; - autoSpacingTypeAttribute = "beforeAutospacing"; - spacing.SetAttributeValue(XName.Get("after", DocX.w.NamespaceName), spacingValue); - spacing.SetAttributeValue(XName.Get("afterAutospacing", DocX.w.NamespaceName), 1); - break; - } - - } - - spacing.SetAttributeValue(XName.Get(autoSpacingTypeAttribute, DocX.w.NamespaceName), 1); - spacing.SetAttributeValue(XName.Get(spacingTypeAttribute, DocX.w.NamespaceName), spacingValue); - - } - - } - - - public Paragraph Spacing(double spacing) - { - spacing *= 20; - - if (spacing - (int)spacing == 0) - { - if (!(spacing > -1585 && spacing < 1585)) - throw new ArgumentException("Spacing", "Value must be in the range: -1584 - 1584"); - } - - else - throw new ArgumentException("Spacing", "Value must be either a whole or acurate to one decimal, examples: 32, 32.1, 32.2, 32.9"); - - ApplyTextFormattingProperty(XName.Get("spacing", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), spacing)); - - return this; - } - - public Paragraph SpacingBefore(double spacingBefore) - { - spacingBefore *= 20; - - var pPr = GetOrCreate_pPr(); - var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); - if (spacingBefore > 0) - { - 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 - attr.SetValue(spacingBefore); - } - if (Math.Abs(spacingBefore) < 0.1f && spacing != null) - { - var attr = spacing.Attribute(XName.Get("before", DocX.w.NamespaceName)); - attr.Remove(); - if (!spacing.HasAttributes) - spacing.Remove(); - } - - return this; - } - - public Paragraph SpacingAfter(double spacingAfter) - { - spacingAfter *= 20; - - var pPr = GetOrCreate_pPr(); - var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); - if (spacingAfter > 0) - { - if (spacing == null) - { - spacing = new XElement(XName.Get("spacing", DocX.w.NamespaceName)); - pPr.Add(spacing); - } - var attr = spacing.Attribute(XName.Get("after", DocX.w.NamespaceName)); - if (attr == null) - spacing.SetAttributeValue(XName.Get("after", DocX.w.NamespaceName), spacingAfter); - else - attr.SetValue(spacingAfter); - } - if (Math.Abs(spacingAfter) < 0.1f && spacing != null) - { - var attr = spacing.Attribute(XName.Get("after", DocX.w.NamespaceName)); - attr.Remove(); - 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; - } - - public Paragraph Kerning(int kerning) - { - if (!new int?[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72 }.Contains(kerning)) - throw new ArgumentOutOfRangeException("Kerning", "Value must be one of the following: 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48 or 72"); - - ApplyTextFormattingProperty(XName.Get("kern", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), kerning * 2)); - return this; - } - - public Paragraph Position(double position) - { - if (!(position > -1585 && position < 1585)) - throw new ArgumentOutOfRangeException("Position", "Value must be in the range -1585 - 1585"); - - ApplyTextFormattingProperty(XName.Get("position", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), position * 2)); - - return this; - } - - public Paragraph PercentageScale(int percentageScale) - { - if (!(new int?[] { 200, 150, 100, 90, 80, 66, 50, 33 }).Contains(percentageScale)) - throw new ArgumentOutOfRangeException("PercentageScale", "Value must be one of the following: 200, 150, 100, 90, 80, 66, 50 or 33"); - - ApplyTextFormattingProperty(XName.Get("w", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), percentageScale)); - - return this; - } - - /// - /// Append a field of type document property, this field will display the custom property cp, at the end of this paragraph. - /// - /// The custom property to display. - /// - /// The formatting to use for this text. - /// - /// Create, add and display a custom property in a document. - /// - /// // Load a document. - ///using (DocX document = DocX.Create("CustomProperty_Add.docx")) - ///{ - /// // Add a few Custom Properties to this document. - /// document.AddCustomProperty(new CustomProperty("fname", "cathal")); - /// document.AddCustomProperty(new CustomProperty("age", 24)); - /// document.AddCustomProperty(new CustomProperty("male", true)); - /// document.AddCustomProperty(new CustomProperty("newyear2012", new DateTime(2012, 1, 1))); - /// document.AddCustomProperty(new CustomProperty("fav_num", 3.141592)); - /// - /// // Insert a new Paragraph and append a load of DocProperties. - /// Paragraph p = document.InsertParagraph("fname: ") - /// .AppendDocProperty(document.CustomProperties["fname"]) - /// .Append(", age: ") - /// .AppendDocProperty(document.CustomProperties["age"]) - /// .Append(", male: ") - /// .AppendDocProperty(document.CustomProperties["male"]) - /// .Append(", newyear2012: ") - /// .AppendDocProperty(document.CustomProperties["newyear2012"]) - /// .Append(", fav_num: ") - /// .AppendDocProperty(document.CustomProperties["fav_num"]); - /// - /// // Save the changes to the document. - /// document.Save(); - ///} - /// - /// - public Paragraph AppendDocProperty(CustomProperty cp, bool trackChanges = false, Formatting f = null) - { - this.InsertDocProperty(cp, trackChanges, f); - return this; - } - - /// - /// Insert a field of type document property, this field will display the custom property cp, at the end of this paragraph. - /// - /// The custom property to display. - /// - /// The formatting to use for this text. - /// - /// Create, add and display a custom property in a document. - /// - /// // Load a document - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Create a custom property. - /// CustomProperty name = new CustomProperty("name", "Cathal Coffey"); - /// - /// // Add this custom property to this document. - /// document.AddCustomProperty(name); - /// - /// // Create a text formatting. - /// Formatting f = new Formatting(); - /// f.Bold = true; - /// f.Size = 14; - /// f.StrikeThrough = StrickThrough.strike; - /// - /// // Insert a new paragraph. - /// Paragraph p = document.InsertParagraph("Author: ", false, f); - /// - /// // Insert a field of type document property to display the custom property name and track this change. - /// p.InsertDocProperty(name, true, f); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public DocProperty InsertDocProperty(CustomProperty cp, bool trackChanges = false, Formatting f = null) - { - XElement f_xml = null; - if (f != null) - f_xml = f.Xml; - - XElement e = new XElement - ( - XName.Get("fldSimple", DocX.w.NamespaceName), - new XAttribute(XName.Get("instr", DocX.w.NamespaceName), string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", cp.Name)), - new XElement(XName.Get("r", DocX.w.NamespaceName), - new XElement(XName.Get("t", DocX.w.NamespaceName), f_xml, cp.Value)) - ); - - XElement xml = e; - if (trackChanges) - { - DateTime now = DateTime.Now; - DateTime insert_datetime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc); - e = CreateEdit(EditType.ins, insert_datetime, e); - } - - Xml.Add(e); - - return new DocProperty(Document, xml); - } - - /// - /// Removes characters from a Novacode.DocX.Paragraph. - /// - /// - /// - /// // 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. - /// - /// - /// - /// - /// The position to begin deleting characters. - /// The number of characters to delete - /// Track changes - /// Remove empty paragraph - public void RemoveText(int index, int count, bool trackChanges = false, bool removeEmptyParagraph = true) - { - // Timestamp to mark the start of insert - DateTime now = DateTime.Now; - DateTime remove_datetime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc); - - // The number of characters processed so far - int processed = 0; - - do - { - // Get the first run effected by this Remove - Run run = GetFirstRunEffectedByEdit(index, EditType.del); - - // The parent of this Run - XElement parentElement = run.Xml.Parent; - switch (parentElement.Name.LocalName) - { - case "ins": - { - XElement[] splitEditBefore = SplitEdit(parentElement, index, EditType.del); - int min = Math.Min(count - processed, run.Xml.ElementsAfterSelf().Sum(e => GetElementTextLength(e))); - XElement[] splitEditAfter = SplitEdit(parentElement, index + min, EditType.del); - - XElement temp = SplitEdit(splitEditBefore[1], index + min, EditType.del)[0]; - object middle = CreateEdit(EditType.del, remove_datetime, temp.Elements()); - processed += GetElementTextLength(middle as XElement); - - if (!trackChanges) - middle = null; - - parentElement.ReplaceWith - ( - splitEditBefore[0], - middle, - splitEditAfter[1] - ); - - processed += GetElementTextLength(middle as XElement); - break; - } - - case "del": - { - if (trackChanges) - { - // You cannot delete from a deletion, advance processed to the end of this del - processed += GetElementTextLength(parentElement); - } - - else - goto case "ins"; - - break; - } - - default: - { - XElement[] splitRunBefore = Run.SplitRun(run, index, EditType.del); - //int min = Math.Min(index + processed + (count - processed), run.EndIndex); - int min = Math.Min(index + (count - processed), run.EndIndex); - XElement[] splitRunAfter = Run.SplitRun(run, min, EditType.del); - - object middle = CreateEdit(EditType.del, remove_datetime, new List() { Run.SplitRun(new Run(Document, splitRunBefore[1], run.StartIndex + GetElementTextLength(splitRunBefore[0])), min, EditType.del)[0] }); - processed += GetElementTextLength(middle as XElement); - - if (!trackChanges) - middle = null; - - run.Xml.ReplaceWith - ( - splitRunBefore[0], - middle, - splitRunAfter[1] - ); - - break; - } - } - - // 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); - - HelperFunctions.RenumberIDs(Document); - } - - - /// - /// Removes characters from a Novacode.DocX.Paragraph. - /// - /// - /// - /// // 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 all but the first 2 characters from this Paragraph. - /// p.RemoveText(2, false); - /// } - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - /// - /// - /// The position to begin deleting characters. - /// Track changes - public void RemoveText(int index, bool trackChanges = false) - { - RemoveText(index, Text.Length - index, trackChanges); - } - - /// - /// Replaces all occurrences of a specified System.String in this instance, with another specified System.String. - /// - /// - /// - /// // 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. - /// - /// - /// - /// - /// - /// - /// A System.String to replace all occurrences of oldValue. - /// A System.String to be replaced. - /// A bitwise OR combination of RegexOption enumeration options. - /// Track changes - /// The formatting to apply to the text being inserted. - /// The formatting that the text must match in order to be replaced. - /// How should formatting be matched? - /// True if the oldValue needs to be escaped, otherwise false. If it represents a valid RegEx pattern this should be false. - /// True if RegEx-like replace should be performed, i.e. if newValue contains RegEx substitutions. Does not perform named-group substitutions (only numbered groups). - /// Remove empty paragraph - 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; - MatchCollection mc = Regex.Matches(tText, escapeRegEx ? Regex.Escape(oldValue) : oldValue, options); - - // Loop through the matches in reverse order - foreach (Match m in mc.Cast().Reverse()) - { - // Assume the formatting matches until proven otherwise. - bool formattingMatch = true; - - // Does the user want to match formatting? - if (matchFormatting != null) - { - // The number of characters processed so far - int processed = 0; - - do - { - // Get the next run effected - Run run = GetFirstRunEffectedByEdit(m.Index + processed); - - // Get this runs properties - XElement rPr = run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)); - - if (rPr == null) - rPr = new Formatting().Xml; - - /* - * Make sure that every formatting element in f.xml is also in this run, - * if this is not true, then their formatting does not match. - */ - if (!HelperFunctions.ContainsEveryChildOf(matchFormatting.Xml, rPr, fo)) - { - formattingMatch = false; - break; - } - - // We have processed some characters, so update the counter. - processed += run.Value.Length; - - } while (processed < m.Length); - } - - // If the formatting matches, do the replace. - if (formattingMatch) - { - string repl = newValue; - //perform RegEx substitutions. Only named groups are not supported. Everything else is supported. However character escapes are not covered. - if (useRegExSubstitutions && !String.IsNullOrEmpty(repl)) - { - repl = repl.Replace("$&", m.Value); - if (m.Groups.Count > 0) - { - int lastcap = 0; - for (int k = 0; k < m.Groups.Count; k++) - { - var g = m.Groups[k]; - if ((g == null) || (g.Value == "")) - continue; - repl = repl.Replace("$" + k.ToString(), g.Value); - lastcap = k; - //cannot get named groups ATM - } - repl = repl.Replace("$+", m.Groups[lastcap].Value); - } - if (m.Index > 0) - { - repl = repl.Replace("$`", tText.Substring(0, m.Index)); - } - if ((m.Index + m.Length) < tText.Length) - { - repl = repl.Replace("$'", tText.Substring(m.Index + m.Length)); - } - repl = repl.Replace("$_", tText); - repl = repl.Replace("$$", "$"); - } - if (!String.IsNullOrEmpty(repl)) - InsertText(m.Index + m.Length, repl, trackChanges, newFormatting); - if (m.Length > 0) - RemoveText(m.Index, m.Length, trackChanges, removeEmptyParagraph); - } - } - } - - /// - /// Find pattern regex must return a group match. - /// - /// Regex pattern that must include one group match. ie (.*) - /// A func that accepts the matching find grouping text and returns a replacement value - /// - /// - /// - /// - /// - /// Remove empty paragraph - public void ReplaceText(string findPattern, Func 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); - - // Loop through the matches in reverse order - foreach (var match in matchCollection.Cast().Reverse()) - { - // Assume the formatting matches until proven otherwise. - bool formattingMatch = true; - - // Does the user want to match formatting? - if (matchFormatting != null) - { - // The number of characters processed so far - int processed = 0; - - do - { - // Get the next run effected - Run run = GetFirstRunEffectedByEdit(match.Index + processed); - - // Get this runs properties - XElement rPr = run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)); - - if (rPr == null) - rPr = new Formatting().Xml; - - /* - * Make sure that every formatting element in f.xml is also in this run, - * if this is not true, then their formatting does not match. - */ - if (!HelperFunctions.ContainsEveryChildOf(matchFormatting.Xml, rPr, fo)) - { - formattingMatch = false; - break; - } - - // We have processed some characters, so update the counter. - processed += run.Value.Length; - - } while (processed < match.Length); - } - - // If the formatting matches, do the replace. - if (formattingMatch) - { - var newValue = regexMatchHandler.Invoke(match.Groups[1].Value); - InsertText(match.Index + match.Value.Length, newValue, trackChanges, newFormatting); - RemoveText(match.Index, match.Value.Length, trackChanges, removeEmptyParagraph); - } - } - } - - - /// - /// Find all instances of a string in this paragraph and return their indexes in a List. - /// - /// The string to find - /// A list of indexes. - /// - /// Find all instances of Hello in this document and insert 'don't' in frount of them. - /// - /// // Load a document - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // Loop through the paragraphs in this document. - /// foreach(Paragraph p in document.Paragraphs) - /// { - /// // Find all instances of 'go' in this paragraph. - /// ]]> gos = document.FindAll("go"); - /// - /// /* - /// * Insert 'don't' in frount of every instance of 'go' in this document to produce 'don't go'. - /// * An important trick here is to do the inserting in reverse document order. If you inserted - /// * in document order, every insert would shift the index of the remaining matches. - /// */ - /// gos.Reverse(); - /// foreach (int index in gos) - /// { - /// p.InsertText(index, "don't ", false); - /// } - /// } - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public List FindAll(string str) - { - return FindAll(str, RegexOptions.None); - } - - /// - /// Find all instances of a string in this paragraph and return their indexes in a List. - /// - /// The string to find - /// The options to use when finding a string match. - /// A list of indexes. - /// - /// Find all instances of Hello in this document and insert 'don't' in frount of them. - /// - /// // Load a document - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // Loop through the paragraphs in this document. - /// foreach(Paragraph p in document.Paragraphs) - /// { - /// // Find all instances of 'go' in this paragraph (Ignore case). - /// ]]> gos = document.FindAll("go", RegexOptions.IgnoreCase); - /// - /// /* - /// * Insert 'don't' in frount of every instance of 'go' in this document to produce 'don't go'. - /// * An important trick here is to do the inserting in reverse document order. If you inserted - /// * in document order, every insert would shift the index of the remaining matches. - /// */ - /// gos.Reverse(); - /// foreach (int index in gos) - /// { - /// p.InsertText(index, "don't ", false); - /// } - /// } - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public List FindAll(string str, RegexOptions options) - { - MatchCollection mc = Regex.Matches(this.Text, Regex.Escape(str), options); - - var query = - ( - from m in mc.Cast() - select m.Index - ).ToList(); - - return query; - } - - /// - /// Find all unique instances of the given Regex Pattern - /// - /// - /// - /// - public List FindAllByPattern(string str, RegexOptions options) - { - MatchCollection mc = Regex.Matches(this.Text, str, options); - - var query = - ( - from m in mc.Cast() - select m.Value - ).ToList(); - - return query; - } - - /// - /// Insert a PageNumber place holder into a Paragraph. - /// This place holder should only be inserted into a Header or Footer Paragraph. - /// Word will not automatically update this field if it is inserted into a document level Paragraph. - /// - /// The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...) - /// The text index to insert this PageNumber place holder at. - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add Headers to the document. - /// document.AddHeaders(); - /// - /// // Get the default Header. - /// Header header = document.Headers.odd; - /// - /// // Insert a Paragraph into the Header. - /// Paragraph p0 = header.InsertParagraph("Page ( of )"); - /// - /// // Insert place holders for PageNumber and PageCount into the Header. - /// // Word will replace these with the correct value for each Page. - /// p0.InsertPageNumber(PageNumberFormat.normal, 6); - /// p0.InsertPageCount(PageNumberFormat.normal, 11); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public void InsertPageNumber(PageNumberFormat pnf, int index = 0) - { - XElement fldSimple = new XElement(XName.Get("fldSimple", DocX.w.NamespaceName)); - - if (pnf == PageNumberFormat.normal) - fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" PAGE \* MERGEFORMAT ")); - else - fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" PAGE \* ROMAN \* MERGEFORMAT ")); - - XElement content = XElement.Parse - ( - @" - - - - 1 - " - ); - - fldSimple.Add(content); - - if (index == 0) - Xml.AddFirst(fldSimple); - else - { - Run r = GetFirstRunEffectedByEdit(index, EditType.ins); - XElement[] splitEdit = SplitEdit(r.Xml, index, EditType.ins); - r.Xml.ReplaceWith - ( - splitEdit[0], - fldSimple, - splitEdit[1] - ); - } - } - - /// - /// Append a PageNumber place holder onto the end of a Paragraph. - /// - /// The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...) - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add Headers to the document. - /// document.AddHeaders(); - /// - /// // Get the default Header. - /// Header header = document.Headers.odd; - /// - /// // Insert a Paragraph into the Header. - /// Paragraph p0 = header.InsertParagraph(); - /// - /// // Appemd place holders for PageNumber and PageCount into the Header. - /// // Word will replace these with the correct value for each Page. - /// p0.Append("Page ("); - /// p0.AppendPageNumber(PageNumberFormat.normal); - /// p0.Append(" of "); - /// p0.AppendPageCount(PageNumberFormat.normal); - /// p0.Append(")"); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public void AppendPageNumber(PageNumberFormat pnf) - { - XElement fldSimple = new XElement(XName.Get("fldSimple", DocX.w.NamespaceName)); - - if (pnf == PageNumberFormat.normal) - fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" PAGE \* MERGEFORMAT ")); - else - fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" PAGE \* ROMAN \* MERGEFORMAT ")); - - XElement content = XElement.Parse - ( - @" - - - - 1 - " - ); - - fldSimple.Add(content); - Xml.Add(fldSimple); - } - - /// - /// Insert a PageCount place holder into a Paragraph. - /// This place holder should only be inserted into a Header or Footer Paragraph. - /// Word will not automatically update this field if it is inserted into a document level Paragraph. - /// - /// The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...) - /// The text index to insert this PageCount place holder at. - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add Headers to the document. - /// document.AddHeaders(); - /// - /// // Get the default Header. - /// Header header = document.Headers.odd; - /// - /// // Insert a Paragraph into the Header. - /// Paragraph p0 = header.InsertParagraph("Page ( of )"); - /// - /// // Insert place holders for PageNumber and PageCount into the Header. - /// // Word will replace these with the correct value for each Page. - /// p0.InsertPageNumber(PageNumberFormat.normal, 6); - /// p0.InsertPageCount(PageNumberFormat.normal, 11); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public void InsertPageCount(PageNumberFormat pnf, int index = 0) - { - XElement fldSimple = new XElement(XName.Get("fldSimple", DocX.w.NamespaceName)); - - if (pnf == PageNumberFormat.normal) - fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" NUMPAGES \* MERGEFORMAT ")); - else - fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" NUMPAGES \* ROMAN \* MERGEFORMAT ")); - - XElement content = XElement.Parse - ( - @" - - - - 1 - " - ); - - fldSimple.Add(content); - - if (index == 0) - Xml.AddFirst(fldSimple); - else - { - Run r = GetFirstRunEffectedByEdit(index, EditType.ins); - XElement[] splitEdit = SplitEdit(r.Xml, index, EditType.ins); - r.Xml.ReplaceWith - ( - splitEdit[0], - fldSimple, - splitEdit[1] - ); - } - } - - /// - /// Append a PageCount place holder onto the end of a Paragraph. - /// - /// The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...) - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Add Headers to the document. - /// document.AddHeaders(); - /// - /// // Get the default Header. - /// Header header = document.Headers.odd; - /// - /// // Insert a Paragraph into the Header. - /// Paragraph p0 = header.InsertParagraph(); - /// - /// // Appemd place holders for PageNumber and PageCount into the Header. - /// // Word will replace these with the correct value for each Page. - /// p0.Append("Page ("); - /// p0.AppendPageNumber(PageNumberFormat.normal); - /// p0.Append(" of "); - /// p0.AppendPageCount(PageNumberFormat.normal); - /// p0.Append(")"); - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - /// - /// - /// - public void AppendPageCount(PageNumberFormat pnf) - { - XElement fldSimple = new XElement(XName.Get("fldSimple", DocX.w.NamespaceName)); - - if (pnf == PageNumberFormat.normal) - fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" NUMPAGES \* MERGEFORMAT ")); - else - fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" NUMPAGES \* ROMAN \* MERGEFORMAT ")); - - XElement content = XElement.Parse - ( - @" - - - - 1 - " - ); - - fldSimple.Add(content); - Xml.Add(fldSimple); - } - - public float LineSpacingBefore - { - get - { - XElement pPr = GetOrCreate_pPr(); - XElement spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); - - if (spacing != null) - { - XAttribute line = spacing.Attribute(XName.Get("before", DocX.w.NamespaceName)); - if (line != null) - { - float f; - - if (float.TryParse(line.Value, out f)) - return f / 20.0f; - } - } - - return 0.0f; - } - - set - { - SpacingBefore(value); - } - } - - public float LineSpacingAfter - { - get - { - XElement pPr = GetOrCreate_pPr(); - XElement spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); - - if (spacing != null) - { - XAttribute line = spacing.Attribute(XName.Get("after", DocX.w.NamespaceName)); - if (line != null) - { - float f; - - if (float.TryParse(line.Value, out f)) - return f / 20.0f; - } - } - - return 10.0f; - } - - - set - { - SpacingAfter(value); - } - } - } - - public class Run : DocXElement - { - // A lookup for the text elements in this paragraph - Dictionary textLookup = new Dictionary(); - - private int startIndex; - private int endIndex; - private string text; - - /// - /// Gets the start index of this Text (text length before this text) - /// - public int StartIndex { get { return startIndex; } } - - /// - /// Gets the end index of this Text (text length before this text + this texts length) - /// - public int EndIndex { get { return endIndex; } } - - /// - /// The text value of this text element - /// - internal string Value { set { text = value; } get { return text; } } - - internal Run(DocX document, XElement xml, int startIndex) - : base(document, xml) - { - this.startIndex = startIndex; - - // Get the text elements in this run - IEnumerable texts = xml.Descendants(); - - int start = startIndex; - - // Loop through each text in this run - foreach (XElement te in texts) - { - switch (te.Name.LocalName) - { - case "tab": - { - textLookup.Add(start + 1, new Text(Document, te, start)); - text += "\t"; - start++; - break; - } - case "br": - { - textLookup.Add(start + 1, new Text(Document, te, start)); - text += "\n"; - start++; - break; - } - case "t": goto case "delText"; - case "delText": - { - // Only add strings which are not empty - if (te.Value.Length > 0) - { - textLookup.Add(start + te.Value.Length, new Text(Document, te, start)); - text += te.Value; - start += te.Value.Length; - } - break; - } - default: break; - } - } - - endIndex = start; - } - - static internal XElement[] SplitRun(Run r, int index, EditType type = EditType.ins) - { - index = index - r.StartIndex; - - Text t = r.GetFirstTextEffectedByEdit(index, type); - XElement[] splitText = Text.SplitText(t, index); - - XElement splitLeft = new XElement(r.Xml.Name, r.Xml.Attributes(), r.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), t.Xml.ElementsBeforeSelf().Where(n => n.Name.LocalName != "rPr"), splitText[0]); - if (Paragraph.GetElementTextLength(splitLeft) == 0) - splitLeft = null; - - XElement splitRight = new XElement(r.Xml.Name, r.Xml.Attributes(), r.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), splitText[1], t.Xml.ElementsAfterSelf().Where(n => n.Name.LocalName != "rPr")); - if (Paragraph.GetElementTextLength(splitRight) == 0) - splitRight = null; - - return - ( - new XElement[] - { - splitLeft, - splitRight - } - ); - } - - internal Text GetFirstTextEffectedByEdit(int index, EditType type = EditType.ins) - { - // Make sure we are looking within an acceptable index range. - if (index < 0 || index > HelperFunctions.GetText(Xml).Length) - throw new ArgumentOutOfRangeException(); - - // Need some memory that can be updated by the recursive search for the XElement to Split. - int count = 0; - Text theOne = null; - - GetFirstTextEffectedByEditRecursive(Xml, index, ref count, ref theOne, type); - - return theOne; - } - - internal void GetFirstTextEffectedByEditRecursive(XElement Xml, int index, ref int count, ref Text theOne, EditType type = EditType.ins) - { - count += HelperFunctions.GetSize(Xml); - if (count > 0 && ((type == EditType.del && count > index) || (type == EditType.ins && count >= index))) - { - theOne = new Text(Document, Xml, count - HelperFunctions.GetSize(Xml)); - return; - } - - if (Xml.HasElements) - foreach (XElement e in Xml.Elements()) - if (theOne == null) - GetFirstTextEffectedByEditRecursive(e, index, ref count, ref theOne); - } - } - - internal class Text : DocXElement - { - private int startIndex; - private int endIndex; - private string text; - - /// - /// Gets the start index of this Text (text length before this text) - /// - public int StartIndex { get { return startIndex; } } - - /// - /// Gets the end index of this Text (text length before this text + this texts length) - /// - public int EndIndex { get { return endIndex; } } - - /// - /// The text value of this text element - /// - public string Value { get { return text; } } - - internal Text(DocX document, XElement xml, int startIndex) - : base(document, xml) - { - this.startIndex = startIndex; - - switch (Xml.Name.LocalName) - { - case "t": - { - goto case "delText"; - } - - case "delText": - { - endIndex = startIndex + xml.Value.Length; - text = xml.Value; - break; - } - - case "br": - { - text = "\n"; - endIndex = startIndex + 1; - break; - } - - case "tab": - { - text = "\t"; - endIndex = startIndex + 1; - break; - } - default: - { - break; - } - } - } - - internal static XElement[] SplitText(Text t, int index) - { - if (index < t.startIndex || index > t.EndIndex) - throw new ArgumentOutOfRangeException(nameof(index)); - - XElement splitLeft = null, splitRight = null; - if (t.Xml.Name.LocalName == "t" || t.Xml.Name.LocalName == "delText") - { - // The origional text element, now containing only the text before the index point. - splitLeft = new XElement(t.Xml.Name, t.Xml.Attributes(), t.Xml.Value.Substring(0, index - t.startIndex)); - if (splitLeft.Value.Length == 0) - splitLeft = null; - else - PreserveSpace(splitLeft); - - // The origional text element, now containing only the text after the index point. - splitRight = new XElement(t.Xml.Name, t.Xml.Attributes(), t.Xml.Value.Substring(index - t.startIndex, t.Xml.Value.Length - (index - t.startIndex))); - if (splitRight.Value.Length == 0) - splitRight = null; - else - PreserveSpace(splitRight); - } - - else - { - if (index == t.EndIndex) - splitLeft = t.Xml; - - else - splitRight = t.Xml; - } - - return - ( - new XElement[] - { - splitLeft, - splitRight - } - ); - } - - /// - /// If a text element or delText element, starts or ends with a space, - /// it must have the attribute space, otherwise it must not have it. - /// - /// The (t or delText) element check - public static void PreserveSpace(XElement e) - { - // PreserveSpace should only be used on (t or delText) elements - if (!e.Name.Equals(DocX.w + "t") && !e.Name.Equals(DocX.w + "delText")) - throw new ArgumentException("SplitText can only split elements of type t or delText", "e"); - - // Check if this w:t contains a space atribute - XAttribute space = e.Attributes().Where(a => a.Name.Equals(XNamespace.Xml + "space")).SingleOrDefault(); - - // This w:t's text begins or ends with whitespace - if (e.Value.StartsWith(" ") || e.Value.EndsWith(" ")) - { - // If this w:t contains no space attribute, add one. - if (space == null) - e.Add(new XAttribute(XNamespace.Xml + "space", "preserve")); - } - - // This w:t's text does not begin or end with a space - else - { - // If this w:r contains a space attribute, remove it. - if (space != null) - space.Remove(); - } - } - } -} diff --git a/DocX/Picture.cs b/DocX/Picture.cs deleted file mode 100644 index 531bb818..00000000 --- a/DocX/Picture.cs +++ /dev/null @@ -1,421 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; -using System.IO.Packaging; - -namespace Novacode -{ - /// - /// Represents a Picture in this document, a Picture is a customized view of an Image. - /// - public class Picture: DocXElement - { - private const int EmusInPixel = 9525; - - internal Dictionary picture_rels; - - internal Image img; - private string id; - private string name; - private string descr; - private int cx, cy; - //private string fileName; - private uint rotation; - private bool hFlip, vFlip; - private object pictureShape; - private XElement xfrm; - private XElement prstGeom; - - /// - /// Remove this Picture from this document. - /// - public void Remove() - { - Xml.Remove(); - } - - /// - /// Wraps an XElement as an Image - /// - /// - /// The XElement i to wrap - /// - internal Picture(DocX document, XElement i, Image img):base(document, i) - { - picture_rels = new Dictionary(); - - this.img = img; - - this.id = - ( - from e in Xml.Descendants() - where e.Name.LocalName.Equals("blip") - select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")).Value - ).SingleOrDefault(); - - if (this.id == null) - { - this.id = - ( - from e in Xml.Descendants() - where e.Name.LocalName.Equals("imagedata") - select e.Attribute(XName.Get("id", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")).Value - ).SingleOrDefault(); - } - - this.name = - ( - from e in Xml.Descendants() - let a = e.Attribute(XName.Get("name")) - where (a != null) - select a.Value - ).FirstOrDefault(); - - if (this.name == null) - { - this.name = - ( - from e in Xml.Descendants() - let a = e.Attribute(XName.Get("title")) - where (a != null) - select a.Value - ).FirstOrDefault(); - } - - this.descr = - ( - from e in Xml.Descendants() - let a = e.Attribute(XName.Get("descr")) - where (a != null) - select a.Value - ).FirstOrDefault(); - - this.cx = - ( - from e in Xml.Descendants() - let a = e.Attribute(XName.Get("cx")) - where (a != null) - select int.Parse(a.Value) - ).FirstOrDefault(); - - if (this.cx == 0) - { - XAttribute style = - ( - from e in Xml.Descendants() - let a = e.Attribute(XName.Get("style")) - where (a != null) - select a - ).FirstOrDefault(); - - string fromWidth = style.Value.Substring(style.Value.IndexOf("width:") + 6); - var widthInt = ((double.Parse((fromWidth.Substring(0, fromWidth.IndexOf("pt"))).Replace(".", ","))) / 72.0) * 914400; - cx = System.Convert.ToInt32(widthInt); - } - - this.cy = - ( - from e in Xml.Descendants() - let a = e.Attribute(XName.Get("cy")) - where (a != null) - select int.Parse(a.Value) - ).FirstOrDefault(); - - if (this.cy == 0) - { - XAttribute style = - ( - from e in Xml.Descendants() - let a = e.Attribute(XName.Get("style")) - where (a != null) - select a - ).FirstOrDefault(); - - string fromHeight = style.Value.Substring(style.Value.IndexOf("height:") + 7); - var heightInt = ((double.Parse((fromHeight.Substring(0, fromHeight.IndexOf("pt"))).Replace(".", ","))) / 72.0) * 914400; - cy = System.Convert.ToInt32(heightInt); - } - - this.xfrm = - ( - from d in Xml.Descendants() - where d.Name.LocalName.Equals("xfrm") - select d - ).SingleOrDefault(); - - this.prstGeom = - ( - from d in Xml.Descendants() - where d.Name.LocalName.Equals("prstGeom") - select d - ).SingleOrDefault(); - - if (xfrm != null) - this.rotation = xfrm.Attribute(XName.Get("rot")) == null ? 0 : uint.Parse(xfrm.Attribute(XName.Get("rot")).Value); - } - - private void SetPictureShape(object shape) - { - this.pictureShape = shape; - - XAttribute prst = prstGeom.Attribute(XName.Get("prst")); - if (prst == null) - prstGeom.Add(new XAttribute(XName.Get("prst"), "rectangle")); - - prstGeom.Attribute(XName.Get("prst")).Value = shape.ToString(); - } - - /// - /// Set the shape of this Picture to one in the BasicShapes enumeration. - /// - /// A shape from the BasicShapes enumeration. - public void SetPictureShape(BasicShapes shape) - { - SetPictureShape((object)shape); - } - - /// - /// Set the shape of this Picture to one in the RectangleShapes enumeration. - /// - /// A shape from the RectangleShapes enumeration. - public void SetPictureShape(RectangleShapes shape) - { - SetPictureShape((object)shape); - } - - /// - /// Set the shape of this Picture to one in the BlockArrowShapes enumeration. - /// - /// A shape from the BlockArrowShapes enumeration. - public void SetPictureShape(BlockArrowShapes shape) - { - SetPictureShape((object)shape); - } - - /// - /// Set the shape of this Picture to one in the EquationShapes enumeration. - /// - /// A shape from the EquationShapes enumeration. - public void SetPictureShape(EquationShapes shape) - { - SetPictureShape((object)shape); - } - - /// - /// Set the shape of this Picture to one in the FlowchartShapes enumeration. - /// - /// A shape from the FlowchartShapes enumeration. - public void SetPictureShape(FlowchartShapes shape) - { - SetPictureShape((object)shape); - } - - /// - /// Set the shape of this Picture to one in the StarAndBannerShapes enumeration. - /// - /// A shape from the StarAndBannerShapes enumeration. - public void SetPictureShape(StarAndBannerShapes shape) - { - SetPictureShape((object)shape); - } - - /// - /// Set the shape of this Picture to one in the CalloutShapes enumeration. - /// - /// A shape from the CalloutShapes enumeration. - public void SetPictureShape(CalloutShapes shape) - { - SetPictureShape((object)shape); - } - - /// - /// A unique id that identifies an Image embedded in this document. - /// - public string Id - { - get { return id; } - } - - /// - /// Flip this Picture Horizontally. - /// - public bool FlipHorizontal - { - get { return hFlip; } - - set - { - hFlip = value; - - XAttribute flipH = xfrm.Attribute(XName.Get("flipH")); - if (flipH == null) - xfrm.Add(new XAttribute(XName.Get("flipH"), "0")); - - xfrm.Attribute(XName.Get("flipH")).Value = hFlip ? "1" : "0"; - } - } - - /// - /// Flip this Picture Vertically. - /// - public bool FlipVertical - { - get { return vFlip; } - - set - { - vFlip = value; - - XAttribute flipV = xfrm.Attribute(XName.Get("flipV")); - if (flipV == null) - xfrm.Add(new XAttribute(XName.Get("flipV"), "0")); - - xfrm.Attribute(XName.Get("flipV")).Value = vFlip ? "1" : "0"; - } - } - - /// - /// The rotation in degrees of this image, actual value = value % 360 - /// - public uint Rotation - { - get { return rotation / 60000; } - - set - { - rotation = (value % 360) * 60000; - XElement xfrm = - (from d in Xml.Descendants() - where d.Name.LocalName.Equals("xfrm") - select d).Single(); - - XAttribute rot = xfrm.Attribute(XName.Get("rot")); - if(rot == null) - xfrm.Add(new XAttribute(XName.Get("rot"), 0)); - - xfrm.Attribute(XName.Get("rot")).Value = rotation.ToString(); - } - } - - /// - /// Gets or sets the name of this Image. - /// - public string Name - { - get { return name; } - - set - { - name = value; - - foreach (XAttribute a in Xml.Descendants().Attributes(XName.Get("name"))) - a.Value = name; - } - } - - /// - /// Gets or sets the description for this Image. - /// - public string Description - { - get { return descr; } - - set - { - descr = value; - - foreach (XAttribute a in Xml.Descendants().Attributes(XName.Get("descr"))) - a.Value = descr; - } - } - - /// - /// Returns the name of the image file for the picture. - /// - public string FileName - { - get - { - return img.FileName; - } - } - - /// - /// Get or sets the Width of this Image. - /// - public int Width - { - get { return cx / EmusInPixel; } - - set - { - cx = value * EmusInPixel; - - foreach (XAttribute a in Xml.Descendants().Attributes(XName.Get("cx"))) - a.Value = (cx).ToString(); - } - } - - /// - /// Get or sets the height of this Image. - /// - public int Height - { - get { return cy / EmusInPixel; } - - set - { - cy = value * EmusInPixel; - - foreach (XAttribute a in Xml.Descendants().Attributes(XName.Get("cy"))) - a.Value = (cy).ToString(); - } - } - - // refs: - // https://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/ - // http://lcorneliussen.de/raw/dashboards/ooxml/ - private const int InchToEmuFactor = 914400; - private const double EmuToInchFactor = 1d / InchToEmuFactor; - - /// - /// Get or sets the Width of this Image (inches). - /// - public double WidthInches - { - get - { - return Width * EmusInPixel * EmuToInchFactor; - } - set - { - Width = (int)(value * InchToEmuFactor / EmusInPixel); - } - } - - /// - /// Get or sets the Height of this Image (inches). - /// - public double HeightInches - { - get - { - return Height * EmusInPixel * EmuToInchFactor; - } - set - { - Height = (int)(value * InchToEmuFactor / EmusInPixel); - } - } - - //public void Delete() - //{ - // // Remove xml - // i.Remove(); - - // // Rebuild the image collection for this paragraph - // // Requires that every Image have a link to its paragraph - - //} - } -} diff --git a/DocX/Properties/AssemblyInfo.cs b/DocX/Properties/AssemblyInfo.cs deleted file mode 100644 index de4382df..00000000 --- a/DocX/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Docx")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("DocX")] -[assembly: AssemblyProduct("Docx")] -[assembly: AssemblyCopyright("DocX @ 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Allow the UnitTests to get at internal stuff. -[assembly: InternalsVisibleTo( "UnitTests, PublicKey=" + -"0024000004800000940000000602000000240000525341310004000001000100b739555cdacfd1" + -"f59b61e7fb189ed886849ae10d0f8a876cd700d36286addf1d4a6854bb23b12fad5700b64787e9" + -"9b0b9f0ed0d64d86d591a32e58080470bdc9a61845301edf6cbb447c3578718763d3f93694a2ac" + -"fdac1c2d096343f3d7085ea1c20fcfeb1d8bac4153204c9faa40c29be2dc38056116e756ff7bbf" + -"9d82e3ab" )] - -// 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 -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("16123f21-f3d1-47bb-ae9a-eb7c82c0f3c8")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.23")] -[assembly: AssemblyFileVersion("1.0.0.23")] \ No newline at end of file diff --git a/DocX/Section.cs b/DocX/Section.cs deleted file mode 100644 index 650cf532..00000000 --- a/DocX/Section.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Xml.Linq; - -namespace Novacode -{ - public class Section : Container - { - - public SectionBreakType SectionBreakType; - - internal Section(DocX document, XElement xml) : base(document, xml) - { - } - - public List SectionParagraphs { get; set; } - } -} \ No newline at end of file diff --git a/DocX/Table.cs b/DocX/Table.cs deleted file mode 100644 index 2498c44c..00000000 --- a/DocX/Table.cs +++ /dev/null @@ -1,3910 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; -using System.IO.Packaging; -using System.IO; -using System.Drawing; -using System.Globalization; -using System.Collections.ObjectModel; - -namespace Novacode -{ - /// - /// Represents a Table in a document. - /// - public class Table : InsertBeforeOrAfter - { - private Alignment alignment; - private AutoFit autofit; - private float[] ColumnWidthsValue; - /// - /// Merge cells in given column starting with startRow and ending with endRow. - /// - /// - /// Added by arudoy patch: 11608 - /// - public void MergeCellsInColumn(int columnIndex, int startRow, int endRow) - { - // Check for valid start and end indexes. - if (columnIndex < 0 || columnIndex >= ColumnCount) - throw new IndexOutOfRangeException(); - - if (startRow < 0 || endRow <= startRow || endRow >= Rows.Count) - throw new IndexOutOfRangeException(); - // Foreach each Cell between startIndex and endIndex inclusive. - foreach (Row row in Rows.Where((z, i) => i > startRow && i <= endRow)) - { - Cell c = row.Cells[columnIndex]; - XElement tcPr = c.Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - c.Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = c.Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - XElement vMerge = tcPr.Element(XName.Get("vMerge", DocX.w.NamespaceName)); - if (vMerge == null) - { - tcPr.SetElementValue(XName.Get("vMerge", DocX.w.NamespaceName), string.Empty); - vMerge = tcPr.Element(XName.Get("vMerge", DocX.w.NamespaceName)); - } - } - - /* - * 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; - 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); - start_tcPr = Rows[startRow].Cells[columnIndex].Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the gridSpan element of this row, - * null will be returned if no such element exists. - */ - XElement start_vMerge = start_tcPr.Element(XName.Get("vMerge", DocX.w.NamespaceName)); - if (start_vMerge == null) - { - start_tcPr.SetElementValue(XName.Get("vMerge", DocX.w.NamespaceName), string.Empty); - start_vMerge = start_tcPr.Element(XName.Get("vMerge", DocX.w.NamespaceName)); - } - - start_vMerge.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), "restart"); - } - - /// - /// Returns a list of all Paragraphs inside this container. - /// - /// - public virtual List Paragraphs - { - get - { - var paragraphs = new List(); - - foreach (Row r in Rows) - paragraphs.AddRange(r.Paragraphs); - - return paragraphs; - } - } - - /// - /// Returns a list of all Pictures in a Table. - /// - /// - /// Returns a list of all Pictures in a Table. - /// - /// pictures = t.Pictures; - /// - /// // Save this document. - /// document.Save(); - /// } - /// ]]> - /// - /// - public List Pictures - { - get - { - var pictures = new List(); - - foreach (Row r in Rows) - pictures.AddRange(r.Pictures); - - return pictures; - } - } - - /// - /// Set the direction of all content in this Table. - /// - /// (Left to Right) or (Right to Left) - /// - /// Set the content direction for all content in a table to RightToLeft. - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // Get the first table in a document. - /// Table table = document.Tables[0]; - /// - /// // Set the content direction for all content in this table to RightToLeft. - /// table.SetDirection(Direction.RightToLeft); - /// - /// // Save all changes made to this document. - /// document.Save(); - /// } - /// - /// - public void SetDirection(Direction direction) - { - XElement tblPr = GetOrCreate_tblPr(); - tblPr.Add(new XElement(DocX.w + "bidiVisual")); - - foreach (Row r in Rows) - r.SetDirection(direction); - } - - /// - /// Get all of the Hyperlinks in this Table. - /// - /// - /// Get all of the Hyperlinks in this Table. - /// - /// // Create a document. - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // Get the first Table in this document. - /// Table t = document.Tables[0]; - /// - /// // Get a list of all Hyperlinks in this Table. - /// List<Hyperlink> hyperlinks = t.Hyperlinks; - /// - /// // Save this document. - /// document.Save(); - /// } - /// - /// - public List Hyperlinks - { - get - { - var hyperlinks = new List(); - - foreach (Row r in Rows) - hyperlinks.AddRange(r.Hyperlinks); - - return hyperlinks; - } - } - - public void SetWidths(float[] widths) - { - this.ColumnWidthsValue = widths; - //set widths for existing rows - foreach (var r in Rows) - { - for (var c = 0; c < widths.Length; c++) - { - if (r.Cells.Count > c) - r.Cells[c].Width = widths[c]; - } - - } - } - - /// - /// Set Table column width by prescribing percent - /// - /// column width % list - /// Total table width. Will be calculated if null sent. - public void SetWidthsPercentage(float[] widthsPercentage, float? totalWidth) - { - if (totalWidth == null) totalWidth = this.Document.PageWidth - this.Document.MarginLeft - this.Document.MarginRight; // calculate total table width - List widths = new List(widthsPercentage.Length); // empty list, will hold actual width - widthsPercentage.ToList().ForEach(pWidth => { widths.Add((pWidth * totalWidth.Value / 100) * (96 / 72)); }); // convert percentage to actual width for all values in array - SetWidths(widths.ToArray()); // set actual column width - } - - - /// - /// If the tblPr element doesent exist it is created, either way it is returned by this function. - /// - /// The tblPr element for this Table. - internal XElement GetOrCreate_tblPr() - { - // Get the element. - XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - - // If it dosen't exist, create it. - if (tblPr == null) - { - Xml.AddFirst(new XElement(XName.Get("tblPr", DocX.w.NamespaceName))); - tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - } - - // Return the pPr element for this Paragraph. - return tblPr; - } - -#pragma warning disable CS1584 // XML comment has syntactically incorrect cref attribute - /// - /// Set the specified cell margin for the table-level. - /// - /// The side of the cell margin. - /// The value for the specified cell margin. - /// More information can be found here - public void SetTableCellMargin(TableCellMarginType type, double margin) -#pragma warning restore CS1584 // XML comment has syntactically incorrect cref attribute - { - XElement tblPr = GetOrCreate_tblPr(); - - // find (or create) the element with the cell margins - XElement tblCellMar = tblPr.Element(XName.Get("tblCellMar", DocX.w.NamespaceName)); - if (tblCellMar == null) - { - tblPr.AddFirst(new XElement(XName.Get("tblCellMar", DocX.w.NamespaceName))); - tblCellMar = tblPr.Element(XName.Get("tblCellMar", DocX.w.NamespaceName)); - } - - // find (or create) the element with cell margin for the specified side - XElement tblMargin = tblCellMar.Element(XName.Get(type.ToString(), DocX.w.NamespaceName)); - if (tblMargin == null) - { - tblCellMar.AddFirst(new XElement(XName.Get(type.ToString(), DocX.w.NamespaceName))); - tblMargin = tblCellMar.Element(XName.Get(type.ToString(), DocX.w.NamespaceName)); - } - - tblMargin.RemoveAttributes(); - // set the value for the cell margin - tblMargin.Add(new XAttribute(XName.Get("w", DocX.w.NamespaceName), margin)); - // set the side of cell margin - tblMargin.Add(new XAttribute(XName.Get("type", DocX.w.NamespaceName), "dxa")); - } - - /// - /// Gets the column width for a given column index. - /// - /// - public Double GetColumnWidth(Int32 index) - { - List widths = ColumnWidths; - if (widths == null || index > widths.Count - 1) return Double.NaN; - - return widths[index]; - } - - /// - /// Sets the column width for the given index. - /// - /// Column index - /// Colum width - public void SetColumnWidth(Int32 index, Double width) - { - List widths = ColumnWidths; - if (widths == null || index > widths.Count - 1) - { - if (Rows.Count == 0) throw new Exception("There is at least one row required to detect the existing columns."); - // use width of last row cells - // may not work for merged cell! - widths = new List(); - foreach (Cell c in Rows[Rows.Count - 1].Cells) - { - widths.Add(c.Width); - } - } - - // check if index is matching table columns - if (index > widths.Count - 1) throw new Exception("The index is greather than the available table columns."); - - // get the table grid props - XElement grid = Xml.Element(XName.Get("tblGrid", DocX.w.NamespaceName)); - // if null; append a new grid below tblPr - if (grid == null) - { - XElement tblPr = GetOrCreate_tblPr(); - tblPr.AddAfterSelf(new XElement(XName.Get("tblGrid", DocX.w.NamespaceName))); - grid = Xml.Element(XName.Get("tblGrid", DocX.w.NamespaceName)); - } - - // remove all existing values - grid?.RemoveAll(); - - // append new column widths - Int32 i = 0; - foreach (var w in widths) - { - double value = w; - if (i == index) value = width; - var gridCol = new XElement(XName.Get("gridCol", DocX.w.NamespaceName), - new XAttribute(XName.Get("w", DocX.w.NamespaceName), value)); - grid?.Add(gridCol); - i += 1; - } - - // remove cell widths - foreach (Row r in Rows) - foreach (Cell c in r.Cells) - c.Width = -1; - - // set fitting to fixed; this will add/set additional table properties - this.AutoFit = AutoFit.Fixed; - } - - - /// - /// Gets a list of all column widths for this table. - /// - public List ColumnWidths - { - get - { - var widths = new List(); - // get the table grid props - XElement grid = Xml.Element(XName.Get("tblGrid", DocX.w.NamespaceName)); - - // get col properties - var cols = grid?.Elements(XName.Get("gridCol", DocX.w.NamespaceName)); - if (cols == null) return null; - - foreach (var col in cols) - { - string value = col.GetAttribute(XName.Get("w", DocX.w.NamespaceName)); - widths.Add(Convert.ToDouble(value)); - } - return widths; - } - } - - - /// - /// Returns the number of rows in this table. - /// - public Int32 RowCount - { - get - { - return Xml.Elements(XName.Get("tr", DocX.w.NamespaceName)).Count(); - } - } - - private int _cachedColCount = -1; - /// - /// Returns the number of columns in this table. - /// - public Int32 ColumnCount - { - get - { - if (RowCount == 0) - return 0; - if (_cachedColCount == -1) - _cachedColCount = Rows.First().ColumnCount; - return _cachedColCount; - } - } - - /// - /// Returns a list of rows in this table. - /// - public List Rows - { - get - { - List rows = - ( - from r in Xml.Elements(XName.Get("tr", DocX.w.NamespaceName)) - select new Row(this, Document, r) - ).ToList(); - - return rows; - } - } - - private TableDesign design; - - - internal Table(DocX document, XElement xml) - : base(document, xml) - { - autofit = AutoFit.ColumnWidth; - this.Xml = xml; - this.mainPart = document.mainPart; - - XElement properties = xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - - XElement style = properties?.Element(XName.Get("tblStyle", DocX.w.NamespaceName)); - if (style != null) - { - XAttribute val = style.Attribute(XName.Get("val", DocX.w.NamespaceName)); - - if (val != null) - { - String cleanValue = val.Value.Replace("-", string.Empty); - if (Enum.IsDefined(typeof(TableDesign), cleanValue)) - { - design = (TableDesign)Enum.Parse(typeof(TableDesign), cleanValue); - } - else - { - design = TableDesign.Custom; - } - } - else - design = TableDesign.None; - } - - else - design = TableDesign.None; - - XElement tableLook = properties?.Element(XName.Get("tblLook", DocX.w.NamespaceName)); - if (tableLook != null) - { - TableLook = new TableLook - { - FirstRow = tableLook.GetAttribute(XName.Get("firstRow", DocX.w.NamespaceName)) == "1", - LastRow = tableLook.GetAttribute(XName.Get("lastRow", DocX.w.NamespaceName)) == "1", - FirstColumn = tableLook.GetAttribute(XName.Get("firstColumn", DocX.w.NamespaceName)) == "1", - LastColumn = tableLook.GetAttribute(XName.Get("lastColumn", DocX.w.NamespaceName)) == "1", - NoHorizontalBanding = tableLook.GetAttribute(XName.Get("noHBand", DocX.w.NamespaceName)) == "1", - NoVerticalBanding = tableLook.GetAttribute(XName.Get("noVBand", DocX.w.NamespaceName)) == "1" - }; - } - - } - /// - /// Extra property for Custom Table Style provided by carpfisher - Thanks - /// - private string _customTableDesignName; - /// - /// Extra property for Custom Table Style provided by carpfisher - Thanks - /// - public string CustomTableDesignName - { - set - { - _customTableDesignName = value; - this.Design = TableDesign.Custom; - } - - get - { - return _customTableDesignName; - } - } - - /// - /// String containing the Table Caption value (the table's Alternate Text Title) - /// - private string _tableCaption; - /// - /// Gets or Sets the value of the Table Caption (Alternate Text Title) of this table. - /// - public string TableCaption - { - set - { - XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - if (tblPr != null) - { - XElement tblCaption = - tblPr.Descendants(XName.Get("tblCaption", DocX.w.NamespaceName)).FirstOrDefault(); - - if (tblCaption != null) - tblCaption.Remove(); - - tblCaption = new XElement(XName.Get("tblCaption", DocX.w.NamespaceName), - new XAttribute(XName.Get("val", DocX.w.NamespaceName), value)); - tblPr.Add(tblCaption); - } - } - - get - { - XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - XElement caption = tblPr?.Element(XName.Get("tblCaption", DocX.w.NamespaceName)); - if (caption != null) - { - _tableCaption = caption.GetAttribute(XName.Get("val", DocX.w.NamespaceName)); - } - return _tableCaption; - } - } - - /// - /// String containing the Table Description (the table's Alternate Text Description). - /// - private string _tableDescription; - /// - /// Gets or Sets the value of the Table Description (Alternate Text Description) of this table. - /// - public string TableDescription - { - set - { - XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - if (tblPr != null) - { - XElement tblDescription = - tblPr.Descendants(XName.Get("tblDescription", DocX.w.NamespaceName)).FirstOrDefault(); - - tblDescription?.Remove(); - - tblDescription = new XElement(XName.Get("tblDescription", DocX.w.NamespaceName), - new XAttribute(XName.Get("val", DocX.w.NamespaceName), value)); - tblPr.Add(tblDescription); - } - } - - get - { - XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - XElement caption = tblPr?.Element(XName.Get("tblDescription", DocX.w.NamespaceName)); - if (caption != null) - { - _tableDescription = caption.GetAttribute(XName.Get("val", DocX.w.NamespaceName)); - } - return _tableDescription; - } - } - - - public TableLook TableLook { get; set; } - - public Alignment Alignment - { - get { return alignment; } - set - { - string alignmentString = string.Empty; - switch (value) - { - case Alignment.left: - { - alignmentString = "left"; - break; - } - - case Alignment.both: - { - alignmentString = "both"; - break; - } - - - case Alignment.right: - { - alignmentString = "right"; - break; - } - - case Alignment.center: - { - alignmentString = "center"; - break; - } - } - - XElement tblPr = Xml.Descendants(XName.Get("tblPr", DocX.w.NamespaceName)).First(); - XElement jc = tblPr.Descendants(XName.Get("jc", DocX.w.NamespaceName)).FirstOrDefault(); - - jc?.Remove(); - - jc = new XElement(XName.Get("jc", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), alignmentString)); - tblPr.Add(jc); - alignment = value; - } - } - - /// - /// Auto size this table according to some rule. - /// - /// Added by Roger Saele, April 2012. Thank you for your contribution Roger. - public AutoFit AutoFit - { - get { return autofit; } - - set - { - string tableAttributeValue = string.Empty; - string columnAttributeValue = string.Empty; - switch (value) - { - case AutoFit.ColumnWidth: - { - tableAttributeValue = "auto"; - columnAttributeValue = "dxa"; - - // Disable "Automatically resize to fit contents" option - XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - if (tblPr != null) - { - XElement layout = tblPr.Element(XName.Get("tblLayout", DocX.w.NamespaceName)); - if (layout == null) - { - tblPr.Add(new XElement(XName.Get("tblLayout", DocX.w.NamespaceName))); - layout = tblPr.Element(XName.Get("tblLayout", DocX.w.NamespaceName)); - } - - XAttribute type = layout.Attribute(XName.Get("type", DocX.w.NamespaceName)); - if (type == null) - { - layout.Add(new XAttribute(XName.Get("type", DocX.w.NamespaceName), String.Empty)); - type = layout.Attribute(XName.Get("type", DocX.w.NamespaceName)); - } - - type.Value = "fixed"; - } - - break; - } - - case AutoFit.Contents: - { - tableAttributeValue = columnAttributeValue = "auto"; - break; - } - - case AutoFit.Window: - { - tableAttributeValue = columnAttributeValue = "pct"; - break; - } - - case AutoFit.Fixed: - // DL added - 20150816: - // Set fixed width for the whole table; columns width is definied in the node: tblGrid - { - tableAttributeValue = columnAttributeValue = "dxa"; - - XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - XElement tblLayout = tblPr.Element(XName.Get("tblLayout", DocX.w.NamespaceName)); - - if (tblLayout == null) - { - XElement tmp = tblPr.Element(XName.Get("tblInd", DocX.w.NamespaceName)) ?? - tblPr.Element(XName.Get("tblW", DocX.w.NamespaceName)); - - tmp.AddAfterSelf(new XElement(XName.Get("tblLayout", DocX.w.NamespaceName))); - tmp = tblPr.Element(XName.Get("tblLayout", DocX.w.NamespaceName)); - tmp.SetAttributeValue(XName.Get("type", DocX.w.NamespaceName), "fixed"); - - tmp = tblPr.Element(XName.Get("tblW", DocX.w.NamespaceName)); - Double i = 0; - foreach (Double w in ColumnWidths) - i += w; - - tmp.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), i.ToString()); - - - break; - - } - else - { - var qry = from d in Xml.Descendants() - let type = d.Attribute(XName.Get("type", DocX.w.NamespaceName)) - where (d.Name.LocalName == "tblLayout") && type != null - select type; - - foreach (XAttribute type in qry) - type.Value = "fixed"; - - - XElement tmp = tblPr.Element(XName.Get("tblW", DocX.w.NamespaceName)); - Double i = 0; - foreach (Double w in ColumnWidths) - i += w; - - tmp.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), i.ToString()); - break; - } - - } - } - - // Set table attributes - var query = from d in Xml.Descendants() - let type = d.Attribute(XName.Get("type", DocX.w.NamespaceName)) - where (d.Name.LocalName == "tblW") && type != null - select type; - - foreach (XAttribute type in query) - type.Value = tableAttributeValue; - - // Set column attributes - query = from d in Xml.Descendants() - let type = d.Attribute(XName.Get("type", DocX.w.NamespaceName)) - where (d.Name.LocalName == "tcW") && type != null - select type; - - foreach (XAttribute type in query) - type.Value = columnAttributeValue; - - autofit = value; - } - } - /// - /// The design\style to apply to this table. - /// - /// Patch1. Patch to code for Custom Table Style support by carpfisher - /// - /// - /// Example code for custom table style usage - /// - /// - /// Novacode.DocX document = Novacode.DocX.Load(“DOC01.doc”); // load document with custom table style defined - /// Novacode.Table t = document.AddTable(2, 2); // adds table - /// t.CustomTableDesignName = “MyStyle01”; // assigns Custom Table Design style to newly created table - /// - /// - /// - /// - /// - public TableDesign Design - { - get { return design; } - set - { - XElement tblPr = Xml.Element(XName.Get("tblPr", DocX.w.NamespaceName)); - XElement style = tblPr.Element(XName.Get("tblStyle", DocX.w.NamespaceName)); - if (style == null) - { - tblPr.Add(new XElement(XName.Get("tblStyle", DocX.w.NamespaceName))); - style = tblPr.Element(XName.Get("tblStyle", DocX.w.NamespaceName)); - } - - XAttribute val = style.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (val == null) - { - style.Add(new XAttribute(XName.Get("val", DocX.w.NamespaceName), "")); - val = style.Attribute(XName.Get("val", DocX.w.NamespaceName)); - } - - design = value; - - if (design == TableDesign.None) - style.Remove(); - - if (design == TableDesign.Custom) - { - #region Code is commented out - // The code gives a problem while copiing a table. - // Look at Test_Clone_Table_Twice method in test. - //Example: - //Table tab1 = doc.Tables[ 0 ]; - //Table tab2 = doc.InsertTable( tab1 ); - //Table tab3 = doc.InsertTable( tab2 ); - here we have exception at "var styleElement =" line below in this method - // The source of the problem is loosing the "" by the commented code - - //if (string.IsNullOrEmpty(_customTableDesignName)) - //{ - // design = TableDesign.None; - // if (style != null) - // style.Remove(); - - //} - //else - //{ - // val.Value = _customTableDesignName; - //} - #endregion - } - else - { - switch (design) - { - case TableDesign.TableNormal: - val.Value = "TableNormal"; - break; - case TableDesign.TableGrid: - val.Value = "TableGrid"; - break; - case TableDesign.LightShading: - val.Value = "LightShading"; - break; - case TableDesign.LightShadingAccent1: - val.Value = "LightShading-Accent1"; - break; - case TableDesign.LightShadingAccent2: - val.Value = "LightShading-Accent2"; - break; - case TableDesign.LightShadingAccent3: - val.Value = "LightShading-Accent3"; - break; - case TableDesign.LightShadingAccent4: - val.Value = "LightShading-Accent4"; - break; - case TableDesign.LightShadingAccent5: - val.Value = "LightShading-Accent5"; - break; - case TableDesign.LightShadingAccent6: - val.Value = "LightShading-Accent6"; - break; - case TableDesign.LightList: - val.Value = "LightList"; - break; - case TableDesign.LightListAccent1: - val.Value = "LightList-Accent1"; - break; - case TableDesign.LightListAccent2: - val.Value = "LightList-Accent2"; - break; - case TableDesign.LightListAccent3: - val.Value = "LightList-Accent3"; - break; - case TableDesign.LightListAccent4: - val.Value = "LightList-Accent4"; - break; - case TableDesign.LightListAccent5: - val.Value = "LightList-Accent5"; - break; - case TableDesign.LightListAccent6: - val.Value = "LightList-Accent6"; - break; - case TableDesign.LightGrid: - val.Value = "LightGrid"; - break; - case TableDesign.LightGridAccent1: - val.Value = "LightGrid-Accent1"; - break; - case TableDesign.LightGridAccent2: - val.Value = "LightGrid-Accent2"; - break; - case TableDesign.LightGridAccent3: - val.Value = "LightGrid-Accent3"; - break; - case TableDesign.LightGridAccent4: - val.Value = "LightGrid-Accent4"; - break; - case TableDesign.LightGridAccent5: - val.Value = "LightGrid-Accent5"; - break; - case TableDesign.LightGridAccent6: - val.Value = "LightGrid-Accent6"; - break; - case TableDesign.MediumShading1: - val.Value = "MediumShading1"; - break; - case TableDesign.MediumShading1Accent1: - val.Value = "MediumShading1-Accent1"; - break; - case TableDesign.MediumShading1Accent2: - val.Value = "MediumShading1-Accent2"; - break; - case TableDesign.MediumShading1Accent3: - val.Value = "MediumShading1-Accent3"; - break; - case TableDesign.MediumShading1Accent4: - val.Value = "MediumShading1-Accent4"; - break; - case TableDesign.MediumShading1Accent5: - val.Value = "MediumShading1-Accent5"; - break; - case TableDesign.MediumShading1Accent6: - val.Value = "MediumShading1-Accent6"; - break; - case TableDesign.MediumShading2: - val.Value = "MediumShading2"; - break; - case TableDesign.MediumShading2Accent1: - val.Value = "MediumShading2-Accent1"; - break; - case TableDesign.MediumShading2Accent2: - val.Value = "MediumShading2-Accent2"; - break; - case TableDesign.MediumShading2Accent3: - val.Value = "MediumShading2-Accent3"; - break; - case TableDesign.MediumShading2Accent4: - val.Value = "MediumShading2-Accent4"; - break; - case TableDesign.MediumShading2Accent5: - val.Value = "MediumShading2-Accent5"; - break; - case TableDesign.MediumShading2Accent6: - val.Value = "MediumShading2-Accent6"; - break; - case TableDesign.MediumList1: - val.Value = "MediumList1"; - break; - case TableDesign.MediumList1Accent1: - val.Value = "MediumList1-Accent1"; - break; - case TableDesign.MediumList1Accent2: - val.Value = "MediumList1-Accent2"; - break; - case TableDesign.MediumList1Accent3: - val.Value = "MediumList1-Accent3"; - break; - case TableDesign.MediumList1Accent4: - val.Value = "MediumList1-Accent4"; - break; - case TableDesign.MediumList1Accent5: - val.Value = "MediumList1-Accent5"; - break; - case TableDesign.MediumList1Accent6: - val.Value = "MediumList1-Accent6"; - break; - case TableDesign.MediumList2: - val.Value = "MediumList2"; - break; - case TableDesign.MediumList2Accent1: - val.Value = "MediumList2-Accent1"; - break; - case TableDesign.MediumList2Accent2: - val.Value = "MediumList2-Accent2"; - break; - case TableDesign.MediumList2Accent3: - val.Value = "MediumList2-Accent3"; - break; - case TableDesign.MediumList2Accent4: - val.Value = "MediumList2-Accent4"; - break; - case TableDesign.MediumList2Accent5: - val.Value = "MediumList2-Accent5"; - break; - case TableDesign.MediumList2Accent6: - val.Value = "MediumList2-Accent6"; - break; - case TableDesign.MediumGrid1: - val.Value = "MediumGrid1"; - break; - case TableDesign.MediumGrid1Accent1: - val.Value = "MediumGrid1-Accent1"; - break; - case TableDesign.MediumGrid1Accent2: - val.Value = "MediumGrid1-Accent2"; - break; - case TableDesign.MediumGrid1Accent3: - val.Value = "MediumGrid1-Accent3"; - break; - case TableDesign.MediumGrid1Accent4: - val.Value = "MediumGrid1-Accent4"; - break; - case TableDesign.MediumGrid1Accent5: - val.Value = "MediumGrid1-Accent5"; - break; - case TableDesign.MediumGrid1Accent6: - val.Value = "MediumGrid1-Accent6"; - break; - case TableDesign.MediumGrid2: - val.Value = "MediumGrid2"; - break; - case TableDesign.MediumGrid2Accent1: - val.Value = "MediumGrid2-Accent1"; - break; - case TableDesign.MediumGrid2Accent2: - val.Value = "MediumGrid2-Accent2"; - break; - case TableDesign.MediumGrid2Accent3: - val.Value = "MediumGrid2-Accent3"; - break; - case TableDesign.MediumGrid2Accent4: - val.Value = "MediumGrid2-Accent4"; - break; - case TableDesign.MediumGrid2Accent5: - val.Value = "MediumGrid2-Accent5"; - break; - case TableDesign.MediumGrid2Accent6: - val.Value = "MediumGrid2-Accent6"; - break; - case TableDesign.MediumGrid3: - val.Value = "MediumGrid3"; - break; - case TableDesign.MediumGrid3Accent1: - val.Value = "MediumGrid3-Accent1"; - break; - case TableDesign.MediumGrid3Accent2: - val.Value = "MediumGrid3-Accent2"; - break; - case TableDesign.MediumGrid3Accent3: - val.Value = "MediumGrid3-Accent3"; - break; - case TableDesign.MediumGrid3Accent4: - val.Value = "MediumGrid3-Accent4"; - break; - case TableDesign.MediumGrid3Accent5: - val.Value = "MediumGrid3-Accent5"; - break; - case TableDesign.MediumGrid3Accent6: - val.Value = "MediumGrid3-Accent6"; - break; - - case TableDesign.DarkList: - val.Value = "DarkList"; - break; - case TableDesign.DarkListAccent1: - val.Value = "DarkList-Accent1"; - break; - case TableDesign.DarkListAccent2: - val.Value = "DarkList-Accent2"; - break; - case TableDesign.DarkListAccent3: - val.Value = "DarkList-Accent3"; - break; - case TableDesign.DarkListAccent4: - val.Value = "DarkList-Accent4"; - break; - case TableDesign.DarkListAccent5: - val.Value = "DarkList-Accent5"; - break; - case TableDesign.DarkListAccent6: - val.Value = "DarkList-Accent6"; - break; - - case TableDesign.ColorfulShading: - val.Value = "ColorfulShading"; - break; - case TableDesign.ColorfulShadingAccent1: - val.Value = "ColorfulShading-Accent1"; - break; - case TableDesign.ColorfulShadingAccent2: - val.Value = "ColorfulShading-Accent2"; - break; - case TableDesign.ColorfulShadingAccent3: - val.Value = "ColorfulShading-Accent3"; - break; - case TableDesign.ColorfulShadingAccent4: - val.Value = "ColorfulShading-Accent4"; - break; - case TableDesign.ColorfulShadingAccent5: - val.Value = "ColorfulShading-Accent5"; - break; - case TableDesign.ColorfulShadingAccent6: - val.Value = "ColorfulShading-Accent6"; - break; - - case TableDesign.ColorfulList: - val.Value = "ColorfulList"; - break; - case TableDesign.ColorfulListAccent1: - val.Value = "ColorfulList-Accent1"; - break; - case TableDesign.ColorfulListAccent2: - val.Value = "ColorfulList-Accent2"; - break; - case TableDesign.ColorfulListAccent3: - val.Value = "ColorfulList-Accent3"; - break; - case TableDesign.ColorfulListAccent4: - val.Value = "ColorfulList-Accent4"; - break; - case TableDesign.ColorfulListAccent5: - val.Value = "ColorfulList-Accent5"; - break; - case TableDesign.ColorfulListAccent6: - val.Value = "ColorfulList-Accent6"; - break; - - case TableDesign.ColorfulGrid: - val.Value = "ColorfulGrid"; - break; - case TableDesign.ColorfulGridAccent1: - val.Value = "ColorfulGrid-Accent1"; - break; - case TableDesign.ColorfulGridAccent2: - val.Value = "ColorfulGrid-Accent2"; - break; - case TableDesign.ColorfulGridAccent3: - val.Value = "ColorfulGrid-Accent3"; - break; - case TableDesign.ColorfulGridAccent4: - val.Value = "ColorfulGrid-Accent4"; - break; - case TableDesign.ColorfulGridAccent5: - val.Value = "ColorfulGrid-Accent5"; - break; - case TableDesign.ColorfulGridAccent6: - val.Value = "ColorfulGrid-Accent6"; - break; - } - } - if (Document.styles == null) - { - PackagePart word_styles = Document.package.GetPart(new Uri("/word/styles.xml", UriKind.Relative)); - using (TextReader tr = new StreamReader(word_styles.GetStream())) - Document.styles = XDocument.Load(tr); - } - - var tableStyle = - ( - from e in Document.styles.Descendants() - let styleId = e.Attribute(XName.Get("styleId", DocX.w.NamespaceName)) - where (styleId != null && styleId.Value == val.Value) - select e - ).FirstOrDefault(); - - if (tableStyle == null) - { - XDocument external_style_doc = HelperFunctions.DecompressXMLResource("Novacode.Resources.styles.xml.gz"); - - var styleElement = - ( - from e in external_style_doc.Descendants() - let styleId = e.Attribute(XName.Get("styleId", DocX.w.NamespaceName)) - where (styleId != null && styleId.Value == val.Value) - select e - ).FirstOrDefault(); - - if( styleElement != null ) - Document.styles.Element(XName.Get("styles", DocX.w.NamespaceName)).Add(styleElement); - } - } - } - - /// - /// Returns the index of this Table. - /// - /// - /// Replace the first table in this document with a new Table. - /// - /// // Load a document into memory. - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // Get the first Table in this document. - /// Table t = document.Tables[0]; - /// - /// // Get the character index of Table t in this document. - /// int index = t.Index; - /// - /// // Remove Table t. - /// t.Remove(); - /// - /// // Insert a new Table at the original index of Table t. - /// Table newTable = document.InsertTable(index, 4, 4); - /// - /// // Set the design of this new Table, so that we can see it. - /// newTable.Design = TableDesign.LightShadingAccent1; - /// - /// // Save all changes made to the document. - /// document.Save(); - /// } // Release this document from memory. - /// - /// - public int Index - { - get - { - int index = 0; - IEnumerable previous = Xml.ElementsBeforeSelf(); - - foreach (XElement e in previous) - index += Paragraph.GetElementTextLength(e); - - return index; - } - } - - /// - /// Remove this Table from this document. - /// - /// - /// Remove the first Table from this document. - /// - /// // Load a document into memory. - /// using (DocX document = DocX.Load(@"Test.docx")) - /// { - /// // Get the first Table in this document. - /// Table t = d.Tables[0]; - /// - /// // Remove this Table. - /// t.Remove(); - /// - /// // Save all changes made to the document. - /// document.Save(); - /// } // Release this document from memory. - /// - /// - public void Remove() - { - Xml.Remove(); - } - - /// - /// Insert a row at the end of this table. - /// - /// - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Get the first table in this document. - /// Table table = document.Tables[0]; - /// - /// // Insert a new row at the end of this table. - /// Row row = table.InsertRow(); - /// - /// // Loop through each cell in this new row. - /// foreach (Cell c in row.Cells) - /// { - /// // Set the text of each new cell to "Hello". - /// c.Paragraphs[0].InsertText("Hello", false); - /// } - /// - /// // Save the document to a new file. - /// document.SaveAs(@"C:\Example\Test2.docx"); - /// }// Release this document from memory. - /// - /// - /// A new row. - public Row InsertRow() - { - return InsertRow(RowCount); - } - - /// - /// Insert a copy of a row at the end of this table. - /// - /// A new row. - /// The row to insert - /// True to clone everithing, False to clone cell structure only. - /// - public Row InsertRow(Row row, bool keepFormatting = false) - { - return InsertRow(row, RowCount, keepFormatting); - } - - /// - /// Insert a column to the right of a Table. - /// - /// - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Get the first Table in this document. - /// Table table = document.Tables[0]; - /// - /// // Insert a new column to this right of this table. - /// table.InsertColumn(); - /// - /// // Set the new columns text to "Row no." - /// table.Rows[0].Cells[table.ColumnCount - 1].Paragraph.InsertText("Row no.", false); - /// - /// // Loop through each row in the table. - /// for (int i = 1; i < table.Rows.Count; i++) - /// { - /// // The current row. - /// Row row = table.Rows[i]; - /// - /// // The cell in this row that belongs to the new column. - /// Cell cell = row.Cells[table.ColumnCount - 1]; - /// - /// // The first Paragraph that this cell houses. - /// Paragraph p = cell.Paragraphs[0]; - /// - /// // Insert this rows index. - /// p.InsertText(i.ToString(), false); - /// } - /// - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public void InsertColumn() - { - InsertColumn(ColumnCount, true); - } - - /// - /// Remove the last row from this Table. - /// - /// - /// Remove the last row from a Table. - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Get the first table in this document. - /// Table table = document.Tables[0]; - /// - /// // Remove the last row from this table. - /// table.RemoveRow(); - /// - /// // Save the document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public void RemoveRow() - { - RemoveRow(RowCount - 1); - } - - /// - /// Remove a row from this Table. - /// - /// The row to remove. - /// - /// Remove the first row from a Table. - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Get the first table in this document. - /// Table table = document.Tables[0]; - /// - /// // Remove the first row from this table. - /// table.RemoveRow(0); - /// - /// // Save the document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public void RemoveRow(int index) - { - if (index < 0 || index > RowCount - 1) - throw new IndexOutOfRangeException(); - - Rows[index].Xml.Remove(); - if (Rows.Count == 0) - Remove(); - } - - /// - /// Remove the last column for this Table. - /// - /// - /// Remove the last column from a Table. - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Get the first table in this document. - /// Table table = document.Tables[0]; - /// - /// // Remove the last column from this table. - /// table.RemoveColumn(); - /// - /// // Save the document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public void RemoveColumn() - { - RemoveColumn(ColumnCount - 1); - } - - /// - /// Remove a column from this Table. - /// - /// The column to remove. - /// - /// Remove the first column from a Table. - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Get the first table in this document. - /// Table table = document.Tables[0]; - /// - /// // Remove the first column from this table. - /// table.RemoveColumn(0); - /// - /// // Save the document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public void RemoveColumn(int index) - { - if (index < 0 || index > ColumnCount - 1) - throw new IndexOutOfRangeException(); - - foreach (Row r in Rows) - if (r.Cells.Count < ColumnCount) - { - var positionIndex = 0; - var actualPosition = 0; - var gridAfterVal = 0; - // checks to see if there is a deleted cell - gridAfterVal = r.gridAfter; - - // goes through iteration of cells to find the one the that contains the index number - foreach (Cell rowCell in r.Cells) - { - // checks if the cell has a gridspan - var gridSpanVal = 0; - - if (rowCell.GridSpan != 0) - { - gridSpanVal = rowCell.GridSpan - 1; - } - - // checks to see if the index is within its lowest and highest cell value - if ((index - gridAfterVal) >= actualPosition - && (index - gridAfterVal) <= (actualPosition + gridSpanVal)) - { - r.Cells[positionIndex].Xml.Remove(); - break; - } - positionIndex += 1; - actualPosition += gridSpanVal + 1; - } - } - else - { - r.Cells[index].Xml.Remove(); - } - - _cachedColCount = -1; - } - - /// - /// Insert a row into this table. - /// - /// - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Get the first table in this document. - /// Table table = document.Tables[0]; - /// - /// // Insert a new row at index 1 in this table. - /// Row row = table.InsertRow(1); - /// - /// // Loop through each cell in this new row. - /// foreach (Cell c in row.Cells) - /// { - /// // Set the text of each new cell to "Hello". - /// c.Paragraphs[0].InsertText("Hello", false); - /// } - /// - /// // Save the document to a new file. - /// document.SaveAs(@"C:\Example\Test2.docx"); - /// }// Release this document from memory. - /// - /// - /// Index to insert row at. - /// A new Row - public Row InsertRow(int index) - { - if (index < 0 || index > RowCount) - throw new IndexOutOfRangeException(); - - List content = new List(); - for (int i = 0; i < ColumnCount; i++) - { - var w = 2310d; - if (ColumnWidthsValue != null && ColumnWidthsValue.Length > i) - w = ColumnWidthsValue[i] * 15; - XElement cell = HelperFunctions.CreateTableCell(w); - content.Add(cell); - } - - return InsertRow(content, index); - } - - /// - /// Insert a copy of a row into this table. - /// - /// Row to copy and insert. - /// Index to insert row at. - /// True to clone everithing, False to clone cell structure only. - /// A new Row - 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 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 content, Int32 index) - { - Row newRow = new Row(this, Document, new XElement(XName.Get("tr", DocX.w.NamespaceName), content)); - - XElement rowXml; - if (index == Rows.Count) - { - rowXml = Rows.Last().Xml; - rowXml.AddAfterSelf(newRow.Xml); - } - - else - { - rowXml = Rows[index].Xml; - rowXml.AddBeforeSelf(newRow.Xml); - } - - return newRow; - } - - /// - /// Insert a column into a table. - /// - /// The index to insert the column at. - /// The side in which you wish to place the colum(True right, false left) - /// - /// Insert a column to the left of a table. - /// - /// // Load a document. - /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) - /// { - /// // Get the first Table in this document. - /// Table table = document.Tables[0]; - /// - /// // Insert a new column to this left of this table. - /// table.InsertColumn(0, false); - /// - /// // Set the new columns text to "Row no." - /// table.Rows[0].Cells[table.ColumnCount - 1].Paragraph.InsertText("Row no.", false); - /// - /// // Loop through each row in the table. - /// for (int i = 1; i < table.Rows.Count; i++) - /// { - /// // The current row. - /// Row row = table.Rows[i]; - /// - /// // The cell in this row that belongs to the new column. - /// Cell cell = row.Cells[table.ColumnCount - 1]; - /// - /// // The first Paragraph that this cell houses. - /// Paragraph p = cell.Paragraphs[0]; - /// - /// // Insert this rows index. - /// p.InsertText(i.ToString(), false); - /// } - /// - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public void InsertColumn(int index, bool direction) - { - var columnCount = ColumnCount; - if (RowCount > 0) - { - if (index > 0 && index <= columnCount) - { - _cachedColCount = -1; - foreach (Row r in Rows) - { - // create cell - XElement cell = HelperFunctions.CreateTableCell(); - - // insert cell - // checks if it is in bounds of index - if (r.Cells.Count < columnCount) - { - if (index >= columnCount) - { - AddCellToRow(r, cell, r.Cells.Count, direction); - } - else - { - var positionIndex = 1; - var actualPosition = 1; - var gridAfterVal = 0; - // checks to see if there is a deleted cell - - gridAfterVal = r.gridAfter; - - // goes through iteration of cells to find the one the that contains the index number - foreach (Cell rowCell in r.Cells) - { - // checks if the cell has a gridspan - var gridSpanVal = 0; - - if (rowCell.GridSpan != 0) - { - gridSpanVal = rowCell.GridSpan - 1; - } - - // checks to see if the index is within its lowest and highest cell value - if ((index - gridAfterVal) >= actualPosition - && (index - gridAfterVal) <= (actualPosition + gridSpanVal)) - { - bool directionTest; - if (index == (actualPosition + gridSpanVal) && direction) - { - directionTest = true; - } - else - { - directionTest = false; - } - AddCellToRow(r, cell, positionIndex, directionTest); - break; - } - positionIndex += 1; - actualPosition += gridSpanVal + 1; - } - } - } - else if (r.Cells.Count == index) - { - AddCellToRow(r, cell, index, direction); - } - else - AddCellToRow(r, cell, index, direction); - } - } - else - { - throw new IndexOutOfRangeException("Out of index bounds, column count is " + columnCount + " you input " + index); - } - } - } - - /// - /// Adds a cell to the right or left of a cell - /// - /// is the row you are adding - /// is the cell you are adding - /// the cell index position you are refferencing from - /// which side of the cell you wish to add cell - - private void AddCellToRow(Row row, XElement cell, int index, bool direction) - { - index -= 1; - if (direction) - { - row.Cells[index].Xml.AddAfterSelf(cell); - } - else - { - row.Cells[index].Xml.AddBeforeSelf(cell); - } - } - /// - /// Deletes a cell in a row - /// - /// index of the row you want to remove the cell - /// index of the cell you want to remove - public void DeleteAndShiftCellsLeft(int rowIndex, int celIndex) - { - - var trPr = Rows[rowIndex].Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); - if (trPr != null) - { - var gridAfter = trPr.Element(XName.Get("gridAfter", DocX.w.NamespaceName)); - if (gridAfter != null) - { - var val = gridAfter.Attribute(XName.Get("val", DocX.w.NamespaceName)); - val.Value = (int.Parse(val.Value) + 1).ToString(); - } - else - { - gridAfter.SetAttributeValue("val", 1); - } - } - else - { - XElement trPrXElement = new XElement(XName.Get("trPr", DocX.w.NamespaceName)); - XElement gridAfterElement = new XElement(XName.Get("gridAfter", DocX.w.NamespaceName)); - XAttribute gridAfterValAttribute = new XAttribute(XName.Get("val", DocX.w.NamespaceName), 1); - gridAfterElement.Add(gridAfterValAttribute); - trPrXElement.Add(gridAfterElement); - Rows[rowIndex].Xml.AddFirst(trPrXElement); - } - var columnCount = this.ColumnCount; - if (celIndex <= this.ColumnCount && this.Rows[rowIndex].ColumnCount <= this.ColumnCount) - { - Rows[rowIndex].Cells[celIndex].Xml.Remove(); - } - } - - /// - /// Insert a page break before a Table. - /// - /// - /// Insert a Table and a Paragraph into a document with a page break between them. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Paragraph. - /// Paragraph p1 = document.InsertParagraph("Paragraph", false); - /// - /// // Insert a new Table. - /// Table t1 = document.InsertTable(2, 2); - /// t1.Design = TableDesign.LightShadingAccent1; - /// - /// // Insert a page break before this Table. - /// t1.InsertPageBreakBeforeSelf(); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public override void InsertPageBreakBeforeSelf() - { - base.InsertPageBreakBeforeSelf(); - } - - - /// - /// Insert a page break after a Table. - /// - /// - /// Insert a Table and a Paragraph into a document with a page break between them. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a new Table. - /// Table t1 = document.InsertTable(2, 2); - /// t1.Design = TableDesign.LightShadingAccent1; - /// - /// // Insert a page break after this Table. - /// t1.InsertPageBreakAfterSelf(); - /// - /// // Insert a new Paragraph. - /// Paragraph p1 = document.InsertParagraph("Paragraph", false); - /// - /// // Save this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public override void InsertPageBreakAfterSelf() - { - base.InsertPageBreakAfterSelf(); - } - - /// - /// Insert a new Table before this Table, this Table can be from this document or another document. - /// - /// The Table t to be inserted - /// A new Table inserted before this Table. - /// - /// Insert a new Table before this Table. - /// - /// // Place holder for a Table. - /// Table t; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"a.docx")) - /// { - /// // Get the first Table from this document. - /// t = documentA.Tables[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"b.docx")) - /// { - /// // Get the first Table in document b. - /// Table t2 = documentB.Tables[0]; - /// - /// // Insert the Table from document a before this Table. - /// Table newTable = t2.InsertTableBeforeSelf(t); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public override Table InsertTableBeforeSelf(Table t) - { - return base.InsertTableBeforeSelf(t); - } - - /// - /// Insert a new Table into this document before this Table. - /// - /// The number of rows this Table should have. - /// The number of columns this Table should have. - /// A new Table inserted before this Table. - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// //Insert a Table into this document. - /// Table t = document.InsertTable(2, 2); - /// t.Design = TableDesign.LightShadingAccent1; - /// t.Alignment = Alignment.center; - /// - /// // Insert a new Table before this Table. - /// Table newTable = t.InsertTableBeforeSelf(2, 2); - /// newTable.Design = TableDesign.LightShadingAccent2; - /// newTable.Alignment = Alignment.center; - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public override Table InsertTableBeforeSelf(int rowCount, int columnCount) - { - return base.InsertTableBeforeSelf(rowCount, columnCount); - } - - /// - /// Insert a new Table after this Table, this Table can be from this document or another document. - /// - /// The Table t to be inserted - /// A new Table inserted after this Table. - /// - /// Insert a new Table after this Table. - /// - /// // Place holder for a Table. - /// Table t; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"a.docx")) - /// { - /// // Get the first Table from this document. - /// t = documentA.Tables[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"b.docx")) - /// { - /// // Get the first Table in document b. - /// Table t2 = documentB.Tables[0]; - /// - /// // Insert the Table from document a after this Table. - /// Table newTable = t2.InsertTableAfterSelf(t); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public override Table InsertTableAfterSelf(Table t) - { - return base.InsertTableAfterSelf(t); - } - - /// - /// Insert a new Table into this document after this Table. - /// - /// The number of rows this Table should have. - /// The number of columns this Table should have. - /// A new Table inserted before this Table. - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// //Insert a Table into this document. - /// Table t = document.InsertTable(2, 2); - /// t.Design = TableDesign.LightShadingAccent1; - /// t.Alignment = Alignment.center; - /// - /// // Insert a new Table after this Table. - /// Table newTable = t.InsertTableAfterSelf(2, 2); - /// newTable.Design = TableDesign.LightShadingAccent2; - /// newTable.Alignment = Alignment.center; - /// - /// // Save all changes made to this document. - /// document.Save(); - /// }// Release this document from memory. - /// - /// - public override Table InsertTableAfterSelf(int rowCount, int columnCount) - { - return base.InsertTableAfterSelf(rowCount, columnCount); - } - - /// - /// Insert a Paragraph before this Table, this Paragraph may have come from the same or another document. - /// - /// The Paragraph to insert. - /// The Paragraph now associated with this document. - /// - /// Take a Paragraph from document a, and insert it into document b before this Table. - /// - /// // Place holder for a Paragraph. - /// Paragraph p; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"a.docx")) - /// { - /// // Get the first paragraph from this document. - /// p = documentA.Paragraphs[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"b.docx")) - /// { - /// // Get the first Table in document b. - /// Table t = documentB.Tables[0]; - /// - /// // Insert the Paragraph from document a before this Table. - /// Paragraph newParagraph = t.InsertParagraphBeforeSelf(p); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public override Paragraph InsertParagraphBeforeSelf(Paragraph p) - { - return base.InsertParagraphBeforeSelf(p); - } - - /// - /// Insert a new Paragraph before this Table. - /// - /// The initial text for this new Paragraph. - /// A new Paragraph inserted before this Table. - /// - /// Insert a new Paragraph before the first Table in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Table into this document. - /// Table t = document.InsertTable(2, 2); - /// - /// t.InsertParagraphBeforeSelf("I was inserted before the next Table."); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphBeforeSelf(string text) - { - return base.InsertParagraphBeforeSelf(text); - } - - /// - /// Insert a new Paragraph before this Table. - /// - /// The initial text for this new Paragraph. - /// Should this insertion be tracked as a change? - /// A new Paragraph inserted before this Table. - /// - /// Insert a new paragraph before the first Table in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Table into this document. - /// Table t = document.InsertTable(2, 2); - /// - /// t.InsertParagraphBeforeSelf("I was inserted before the next Table.", false); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphBeforeSelf(string text, bool trackChanges) - { - return base.InsertParagraphBeforeSelf(text, trackChanges); - } - - /// - /// Insert a new Paragraph before this Table. - /// - /// The initial text for this new Paragraph. - /// Should this insertion be tracked as a change? - /// The formatting to apply to this insertion. - /// A new Paragraph inserted before this Table. - /// - /// Insert a new paragraph before the first Table in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Table into this document. - /// Table t = document.InsertTable(2, 2); - /// - /// Formatting boldFormatting = new Formatting(); - /// boldFormatting.Bold = true; - /// - /// t.InsertParagraphBeforeSelf("I was inserted before the next Table.", false, boldFormatting); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphBeforeSelf(string text, bool trackChanges, Formatting formatting) - { - return base.InsertParagraphBeforeSelf(text, trackChanges, formatting); - } - - /// - /// Insert a Paragraph after this Table, this Paragraph may have come from the same or another document. - /// - /// The Paragraph to insert. - /// The Paragraph now associated with this document. - /// - /// Take a Paragraph from document a, and insert it into document b after this Table. - /// - /// // Place holder for a Paragraph. - /// Paragraph p; - /// - /// // Load document a. - /// using (DocX documentA = DocX.Load(@"a.docx")) - /// { - /// // Get the first paragraph from this document. - /// p = documentA.Paragraphs[0]; - /// } - /// - /// // Load document b. - /// using (DocX documentB = DocX.Load(@"b.docx")) - /// { - /// // Get the first Table in document b. - /// Table t = documentB.Tables[0]; - /// - /// // Insert the Paragraph from document a after this Table. - /// Paragraph newParagraph = t.InsertParagraphAfterSelf(p); - /// - /// // Save all changes made to document b. - /// documentB.Save(); - /// }// Release this document from memory. - /// - /// - public override Paragraph InsertParagraphAfterSelf(Paragraph p) - { - return base.InsertParagraphAfterSelf(p); - } - - /// - /// Insert a new Paragraph after this Table. - /// - /// The initial text for this new Paragraph. - /// Should this insertion be tracked as a change? - /// The formatting to apply to this insertion. - /// A new Paragraph inserted after this Table. - /// - /// Insert a new paragraph after the first Table in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Table into this document. - /// Table t = document.InsertTable(2, 2); - /// - /// Formatting boldFormatting = new Formatting(); - /// boldFormatting.Bold = true; - /// - /// t.InsertParagraphAfterSelf("I was inserted after the previous Table.", false, boldFormatting); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphAfterSelf(string text, bool trackChanges, Formatting formatting) - { - return base.InsertParagraphAfterSelf(text, trackChanges, formatting); - } - - /// - /// Insert a new Paragraph after this Table. - /// - /// The initial text for this new Paragraph. - /// Should this insertion be tracked as a change? - /// A new Paragraph inserted after this Table. - /// - /// Insert a new paragraph after the first Table in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Table into this document. - /// Table t = document.InsertTable(2, 2); - /// - /// t.InsertParagraphAfterSelf("I was inserted after the previous Table.", false); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphAfterSelf(string text, bool trackChanges) - { - return base.InsertParagraphAfterSelf(text, trackChanges); - } - - /// - /// Insert a new Paragraph after this Table. - /// - /// The initial text for this new Paragraph. - /// A new Paragraph inserted after this Table. - /// - /// Insert a new Paragraph after the first Table in this document. - /// - /// // Create a new document. - /// using (DocX document = DocX.Create(@"Test.docx")) - /// { - /// // Insert a Table into this document. - /// Table t = document.InsertTable(2, 2); - /// - /// t.InsertParagraphAfterSelf("I was inserted after the previous Table."); - /// - /// // Save all changes made to this new document. - /// document.Save(); - /// }// Release this new document form memory. - /// - /// - public override Paragraph InsertParagraphAfterSelf(string text) - { - return base.InsertParagraphAfterSelf(text); - } - - /// - /// Set a table border - /// Added by lckuiper @ 20101117 - /// - /// - /// - /// // Create a new document. - ///using (DocX document = DocX.Create("Test.docx")) - ///{ - /// // Insert a table into this document. - /// Table t = document.InsertTable(3, 3); - /// - /// // Create a large blue border. - /// Border b = new Border(BorderStyle.Tcbs_single, BorderSize.seven, 0, Color.Blue); - /// - /// // Set the tables Top, Bottom, Left and Right Borders to b. - /// t.SetBorder(TableBorderType.Top, b); - /// t.SetBorder(TableBorderType.Bottom, b); - /// t.SetBorder(TableBorderType.Left, b); - /// t.SetBorder(TableBorderType.Right, b); - /// - /// // Save the document. - /// document.Save(); - ///} - /// - /// - /// The table border to set - /// Border object to set the table border - 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. - */ - var 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()); - } - } - - /// - /// Get a table border - /// Added by lckuiper @ 20101117 - /// - /// The table border to get - public Border GetBorder(TableBorderType borderType) - { - // instance with default border values - Border b = new 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) - { - // uses default border style - } - - /* - * 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) - { - // uses default border style - } - - /* - * Get the 'borderType' (table border) element for this Table, - * null will be return if no such element exists. - */ - var 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(tbordertype, DocX.w.NamespaceName)); - if (tblBorderType == null) - { - // uses default border style - } - - // The val attribute is used for the border style - XAttribute val = tblBorderType.Attribute(XName.Get("val", DocX.w.NamespaceName)); - // If val is null, this table contains no border information. - if (val == null) - { - // uses default border style - } - else - { - try - { - string bordertype = "Tcbs_" + val.Value; - b.Tcbs = (BorderStyle)Enum.Parse(typeof(BorderStyle), bordertype); - } - catch - { - val.Remove(); - // uses default border style - } - } - - // The sz attribute is used for the border size - XAttribute sz = tblBorderType.Attribute(XName.Get("sz", DocX.w.NamespaceName)); - // If sz is null, this border contains no size information. - if (sz == null) - { - // uses default border style - } - else - { - // If sz is not an int, something is wrong with this attributes value, so remove it - int numerical_size; - if (!int.TryParse(sz.Value, out numerical_size)) - sz.Remove(); - else - { - switch (numerical_size) - { - case 2: b.Size = BorderSize.one; break; - case 4: b.Size = BorderSize.two; break; - case 6: b.Size = BorderSize.three; break; - case 8: b.Size = BorderSize.four; break; - case 12: b.Size = BorderSize.five; break; - case 18: b.Size = BorderSize.six; break; - case 24: b.Size = BorderSize.seven; break; - case 36: b.Size = BorderSize.eight; break; - case 48: b.Size = BorderSize.nine; break; - default: b.Size = BorderSize.one; break; - } - } - } - - // The space attribute is used for the border spacing (probably '0') - XAttribute space = tblBorderType.Attribute(XName.Get("space", DocX.w.NamespaceName)); - // If space is null, this border contains no space information. - if (space == null) - { - // uses default border style - } - else - { - // If space is not an int, something is wrong with this attributes value, so remove it - int borderspace; - if (!int.TryParse(space.Value, out borderspace)) - { - space.Remove(); - // uses default border style - } - else - { - b.Space = borderspace; - } - } - - // The color attribute is used for the border color - XAttribute color = tblBorderType.Attribute(XName.Get("color", DocX.w.NamespaceName)); - if (color == null) - { - // uses default border style - } - else - { - // If color is not a Color, something is wrong with this attributes value, so remove it - try - { - b.Color = ColorTranslator.FromHtml(string.Format("#{0}", color.Value)); - } - catch - { - color.Remove(); - // uses default border style - } - } - return b; - } - - } - - /// - /// Represents a single row in a Table. - /// - public class Row : Container - { - /// - /// Calculates columns count in the row, taking spanned cells into account - /// - public Int32 ColumnCount - { - get - { - int gridSpanSum = 0; - - gridSpanSum += gridAfter; - - // Foreach each Cell between startIndex and endIndex inclusive. - foreach (Cell c in Cells) - { - if (c.GridSpan != 0) - { - gridSpanSum += c.GridSpan - 1; - } - } - - // return cells count + count of spanned cells - return Cells.Count + gridSpanSum; - } - } - - /// - /// Returns the GridAfter of a row ie. The amount of cells that are deleted - /// - public int gridAfter - { - get - { - var gridAfterValue = 0; - var trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); - if (trPr != null) - { - var gridAfter = trPr.Element(XName.Get("gridAfter", DocX.w.NamespaceName)); - var val = gridAfter?.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (val != null) - { - gridAfterValue += int.Parse(val.Value); - } - } - return gridAfterValue; - } - } - - /// - /// A list of Cells in this Row. - /// - public List Cells - { - get - { - List cells = - ( - from c in Xml.Elements(XName.Get("tc", DocX.w.NamespaceName)) - select new Cell(this, Document, c) - ).ToList(); - - return cells; - } - } - - public void Remove() - { - XElement table = Xml.Parent; - - Xml.Remove(); - if (!table.Elements(XName.Get("tr", DocX.w.NamespaceName)).Any()) - table.Remove(); - } - - public override ReadOnlyCollection Paragraphs - { - get - { - List paragraphs = - ( - from p in Xml.Descendants(DocX.w + "p") - select new Paragraph(Document, p, 0) - ).ToList(); - - foreach (Paragraph p in paragraphs) - p.PackagePart = table.mainPart; - - return paragraphs.AsReadOnly(); - } - } - - internal Table table; - internal Row(Table table, DocX document, XElement xml) - : base(document, xml) - { - this.table = table; - this.mainPart = table.mainPart; - } - - /// - /// The property name to set when specifiying an exact height - /// - /// Nick Kusters - const string _hRule_Exact = "exact"; - /// - /// The property name to set when specifying a minimum height - /// - /// Nick Kusters - const string _hRule_AtLeast = "atLeast"; - /// - /// Height in pixels. // Added by Joel, refactored by Cathal. - /// - public double Height - { - get - { - // Get the trPr (table row properties) element for this Row, - // null will be return if no such element exists. - XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); - - // If trPr is null, this row contains no height information. - // 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)); - - // If trHeight is null, this row contains no height information. - // Get the val attribute for this trHeight element. - XAttribute val = trHeight?.Attribute(XName.Get("val", DocX.w.NamespaceName)); - - // If w is null, this cell contains no width information. - if (val == null) - return double.NaN; - - // If val is not a double, something is wrong with this attributes value, so remove it and return double.NaN; - double heightInWordUnits; - if (!double.TryParse(val.Value, out heightInWordUnits)) - { - val.Remove(); - return double.NaN; - } - - // 15 "word units" in one pixel - return (heightInWordUnits / 15); - } - set - { - SetHeight(value, true); - } - } - /// - /// Helper method to set either the exact height or the min-height - /// - /// The height value to set (in pixels) - /// - /// If true, the height will be forced. - /// If false, it will be treated as a minimum height, auto growing past it if need be. - /// - /// Nick Kusters - void SetHeight(double height, bool exact) - { - /* - * Get the trPr (table row properties) element for this Row, - * null will be return if no such element exists. - */ - 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)); - - // 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)); - if (trHeight == null) - { - trPr.SetElementValue(XName.Get("trHeight", DocX.w.NamespaceName), string.Empty); - trHeight = trPr.Element(XName.Get("trHeight", DocX.w.NamespaceName)); - } - - // The hRule attribute needs to be set to 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), - ((int)(Math.Round(height * 15,0))).ToString( CultureInfo.InvariantCulture )); // national separators anf fraction should be avoided - } - /// - /// Min-Height in pixels. // Added by Nick Kusters. - /// - /// - /// Value will be treated as a minimum height, auto growing past it if need be. - /// - /// Nick Kusters - public double MinHeight - { - get - { - // Just return the value from the normal height property since it doesn't care if you've set an exact or minimum height. - return Height; - } - set - { - SetHeight(value, false); - } - } - - - /// - /// Set to true to make this row the table header row that will be repeated on each page - /// - public bool TableHeader - { - get - { - XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); - if (trPr == null) - return false; - XElement tblHeader = trPr.Element(XName.Get("tblHeader", DocX.w.NamespaceName)); - return tblHeader != null; - } - 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(); - } - } - } - - - /// - /// Allow row to break across pages. - /// The default value is true: Word will break the contents of the row across pages. - /// If set to false, the contents of the row will not be split across pages, the entire row will be moved to the next page instead. - /// - public bool BreakAcrossPages - { - get - { - XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); - - XElement trCantSplit = trPr?.Element(XName.Get("cantSplit", DocX.w.NamespaceName)); - - return trCantSplit == null; - } - - 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); - } - else - { - XElement trPr = Xml.Element(XName.Get("trPr", DocX.w.NamespaceName)); - XElement trCantSplit = trPr?.Element(XName.Get("cantSplit", DocX.w.NamespaceName)); - trCantSplit?.Remove(); - } - } - } - - /// - /// Merge cells starting with startIndex and ending with endIndex. - /// - public void MergeCells(int startIndex, int endIndex) - { - // Check for valid start and end indexes. - if (startIndex < 0 || endIndex <= startIndex || endIndex > Cells.Count + 1) - throw new IndexOutOfRangeException(); - - // The sum of all merged gridSpans. - int gridSpanSum = 0; - - // Foreach each Cell between startIndex and endIndex inclusive. - foreach (Cell c in Cells.Where((z, i) => i > startIndex && i <= endIndex)) - { - XElement tcPr = c.Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - XElement gridSpan = tcPr?.Element(XName.Get("gridSpan", DocX.w.NamespaceName)); - if (gridSpan != null) - { - XAttribute val = gridSpan.Attribute(XName.Get("val", DocX.w.NamespaceName)); - - int value; - if (val != null && int.TryParse(val.Value, out value)) - gridSpanSum += value - 1; - } - - // Add this cells Pragraph to the merge start Cell. - Cells[startIndex].Xml.Add(c.Xml.Elements(XName.Get("p", DocX.w.NamespaceName))); - - // Remove this Cell. - c.Xml.Remove(); - } - - /* - * 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 = Cells[startIndex].Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (start_tcPr == null) - { - Cells[startIndex].Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - start_tcPr = Cells[startIndex].Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the gridSpan element of this row, - * null will be returned if no such element exists. - */ - XElement start_gridSpan = start_tcPr.Element(XName.Get("gridSpan", DocX.w.NamespaceName)); - if (start_gridSpan == null) - { - start_tcPr.SetElementValue(XName.Get("gridSpan", DocX.w.NamespaceName), string.Empty); - start_gridSpan = start_tcPr.Element(XName.Get("gridSpan", DocX.w.NamespaceName)); - } - - /* - * Get the val attribute of this row, - * null will be returned if no such element exists. - */ - XAttribute start_val = start_gridSpan.Attribute(XName.Get("val", DocX.w.NamespaceName)); - - int start_value = 0; - if (start_val != null) - if (int.TryParse(start_val.Value, out start_value)) - gridSpanSum += start_value - 1; - - // Set the val attribute to the number of merged cells. - start_gridSpan.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), (gridSpanSum + (endIndex - startIndex + 1)).ToString()); - } - } - - public class Cell : Container - { - internal Row row; - - internal Cell(Row row, DocX document, XElement xml) - : base(document, xml) - { - this.row = row; - this.mainPart = row.mainPart; - } - - public override ReadOnlyCollection Paragraphs - { - get - { - ReadOnlyCollection paragraphs = base.Paragraphs; - - foreach (Paragraph p in paragraphs) - p.PackagePart = row.table.mainPart; - - return paragraphs; - } - } - /// - /// Returns the GridSpan of a specific Cell ie. How many cells are merged - /// - public int GridSpan - { - get - { - var gridSpanVal = 0; - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - XElement gridSpan = tcPr?.Element(XName.Get("gridSpan", DocX.w.NamespaceName)); - if (gridSpan != null) - { - XAttribute val = gridSpan.Attribute(XName.Get("val", DocX.w.NamespaceName)); - - int value; - if (val != null && int.TryParse(val.Value, out value)) - gridSpanVal = value; - } - return gridSpanVal; - } - } - - /// - /// Gets or Sets this Cells vertical alignment. - /// - /// - /// - /// Creates a table with 3 cells and sets the vertical alignment of each to 1 of the 3 available options. - /// - /// // Create a new document. - ///using(DocX document = DocX.Create("Test.docx")) - ///{ - /// // Insert a Table into this document. - /// Table t = document.InsertTable(3, 1); - /// - /// // Set the design of the Table such that we can easily identify cell boundaries. - /// t.Design = TableDesign.TableGrid; - /// - /// // Set the height of the row bigger than default. - /// // We need to be able to see the difference in vertical cell alignment options. - /// t.Rows[0].Height = 100; - /// - /// // Set the vertical alignment of cell0 to top. - /// Cell c0 = t.Rows[0].Cells[0]; - /// c0.InsertParagraph("VerticalAlignment.Top"); - /// c0.VerticalAlignment = VerticalAlignment.Top; - /// - /// // Set the vertical alignment of cell1 to center. - /// Cell c1 = t.Rows[0].Cells[1]; - /// c1.InsertParagraph("VerticalAlignment.Center"); - /// c1.VerticalAlignment = VerticalAlignment.Center; - /// - /// // Set the vertical alignment of cell2 to bottom. - /// Cell c2 = t.Rows[0].Cells[2]; - /// c2.InsertParagraph("VerticalAlignment.Bottom"); - /// c2.VerticalAlignment = VerticalAlignment.Bottom; - /// - /// // Save the document. - /// document.Save(); - ///} - /// - /// - public VerticalAlignment VerticalAlignment - { - get - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - - // If tcPr is null, this cell contains no width information. - // Get the vAlign (table cell vertical alignment) element for this Cell, - // null will be return if no such element exists. - XElement vAlign = tcPr?.Element(XName.Get("vAlign", DocX.w.NamespaceName)); - - // If vAlign is null, this cell contains no vertical alignment information. - // Get the val attribute of the vAlign element. - XAttribute val = vAlign?.Attribute(XName.Get("val", DocX.w.NamespaceName)); - - // If val is null, this cell contains no vAlign information. - if (val == null) - return VerticalAlignment.Center; - - // If val is not a VerticalAlign enum, something is wrong with this attributes value, so remove it and return VerticalAlignment.Center; - try - { - return (VerticalAlignment)Enum.Parse(typeof(VerticalAlignment), val.Value, true); - } - - catch - { - val.Remove(); - return VerticalAlignment.Center; - } - } - - set - { - // Get the tcPr (table cell properties) element for this Cell, - // null will be return if no such element exists. - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - - // Get the vAlign (table cell vertical alignment) element for this Cell, - // null will be return if no such element exists. - XElement vAlign = tcPr.Element(XName.Get("vAlign", DocX.w.NamespaceName)); - if (vAlign == null) - { - tcPr.SetElementValue(XName.Get("vAlign", DocX.w.NamespaceName), string.Empty); - vAlign = tcPr.Element(XName.Get("vAlign", DocX.w.NamespaceName)); - } - - // Set the VerticalAlignment in 'val' - vAlign.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), value.ToString().ToLower()); - } - } - - public Color Shading - { - get - { - // Get the tcPr (table cell properties) element for this Cell, - // null will be return if no such element exists. - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - - // If tcPr is null, this cell contains no Color information. - // Get the shd (table shade) element for this Cell, - // null will be return if no such element exists. - XElement shd = tcPr?.Element(XName.Get("shd", DocX.w.NamespaceName)); - - // If shd is null, this cell contains no Color information. - // Get the w attribute of the tcW element. - XAttribute fill = shd?.Attribute(XName.Get("fill", DocX.w.NamespaceName)); - - // If fill is null, this cell contains no Color information. - if (fill == null) - return Color.White; - - return ColorTranslator.FromHtml(string.Format("#{0}", fill.Value)); - } - - set - { - // Get the tcPr (table cell properties) element for this Cell, - // null will be return if no such element exists. - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the shd (table shade) element for this Cell, - * null will be return if no such element exists. - */ - XElement shd = tcPr.Element(XName.Get("shd", DocX.w.NamespaceName)); - if (shd == null) - { - tcPr.SetElementValue(XName.Get("shd", DocX.w.NamespaceName), string.Empty); - shd = tcPr.Element(XName.Get("shd", DocX.w.NamespaceName)); - } - - // The val attribute needs to be set to clear - shd.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), "clear"); - - // The color attribute needs to be set to auto - shd.SetAttributeValue(XName.Get("color", DocX.w.NamespaceName), "auto"); - - // The fill attribute needs to be set to the hex for this Color. - shd.SetAttributeValue(XName.Get("fill", DocX.w.NamespaceName), value.ToHex()); - } - } - - /// - /// Width in pixels. // Added by Joel, refactored by Cathal - /// - public double Width - { - get - { - // Get the tcPr (table cell properties) element for this Cell, - // null will be return if no such element exists. - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - - // If tcPr is null, this cell contains no width information. - // Get the tcW (table cell width) element for this Cell, - // null will be return if no such element exists. - XElement tcW = tcPr?.Element(XName.Get("tcW", DocX.w.NamespaceName)); - - // If tcW is null, this cell contains no width information. - // Get the w attribute of the tcW element. - XAttribute w = tcW?.Attribute(XName.Get("w", DocX.w.NamespaceName)); - - // If w is null, this cell contains no width information. - if (w == null) - return double.NaN; - - // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; - double widthInWordUnits; - if (!double.TryParse(w.Value, out widthInWordUnits)) - { - w.Remove(); - return double.NaN; - } - - // 15 "word units" is equal to one pixel. - return (widthInWordUnits / 15); - } - - set - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the tcW (table cell width) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcW = tcPr.Element(XName.Get("tcW", DocX.w.NamespaceName)); - if (tcW == null) - { - tcPr.SetElementValue(XName.Get("tcW", DocX.w.NamespaceName), string.Empty); - tcW = tcPr.Element(XName.Get("tcW", DocX.w.NamespaceName)); - } - - if (value == -1) - { - // remove cell width; due to set on table prop. - tcW.Remove(); - 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"); - - // 15 "word units" is equal to one pixel. - tcW.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), (value * 15).ToString()); - } - } - - /// - /// LeftMargin in pixels. // Added by lckuiper - /// - /// - /// - /// // Create a new document. - ///using (DocX document = DocX.Create("Test.docx")) - ///{ - /// // Insert table into this document. - /// Table t = document.InsertTable(3, 3); - /// t.Design = TableDesign.TableGrid; - /// - /// // Get the center cell. - /// Cell center = t.Rows[1].Cells[1]; - /// - /// // Insert some text so that we can see the effect of the Margins. - /// center.Paragraphs[0].Append("Center Cell"); - /// - /// // Set the center cells Left, Margin to 10. - /// center.MarginLeft = 25; - /// - /// // Save the document. - /// document.Save(); - ///} - /// - /// - public double MarginLeft - { - get - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - - // If tcPr is null, this cell contains no width information. - if (tcPr == null) - return double.NaN; - - /* - * Get the tcMar - * - */ - XElement tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - - // If tcMar is null, this cell contains no margin information. - // Get the left (LeftMargin) element - XElement tcMarLeft = tcMar?.Element(XName.Get("left", DocX.w.NamespaceName)); - - // If tcMarLeft is null, this cell contains no left margin information. - // Get the w attribute of the tcMarLeft element. - XAttribute w = tcMarLeft?.Attribute(XName.Get("w", DocX.w.NamespaceName)); - - // If w is null, this cell contains no width information. - if (w == null) - return double.NaN; - - // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; - double leftMarginInWordUnits; - if (!double.TryParse(w.Value, out leftMarginInWordUnits)) - { - w.Remove(); - return double.NaN; - } - - // 15 "word units" is equal to one pixel. - return (leftMarginInWordUnits / 15); - } - - set - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the tcMar (table cell margin) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - if (tcMar == null) - { - tcPr.SetElementValue(XName.Get("tcMar", DocX.w.NamespaceName), string.Empty); - tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - } - - /* - * Get the left (table cell left margin) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcMarLeft = tcMar.Element(XName.Get("left", DocX.w.NamespaceName)); - if (tcMarLeft == null) - { - tcMar.SetElementValue(XName.Get("left", DocX.w.NamespaceName), string.Empty); - tcMarLeft = tcMar.Element(XName.Get("left", DocX.w.NamespaceName)); - } - - // 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. - tcMarLeft.SetAttributeValue(XName.Get("type", DocX.w.NamespaceName), "dxa"); - - // 15 "word units" is equal to one pixel. - tcMarLeft.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), (value * 15).ToString()); - } - } - - /// - /// RightMargin in pixels. // Added by lckuiper - /// - /// - /// - /// // Create a new document. - ///using (DocX document = DocX.Create("Test.docx")) - ///{ - /// // Insert table into this document. - /// Table t = document.InsertTable(3, 3); - /// t.Design = TableDesign.TableGrid; - /// - /// // Get the center cell. - /// Cell center = t.Rows[1].Cells[1]; - /// - /// // Insert some text so that we can see the effect of the Margins. - /// center.Paragraphs[0].Append("Center Cell"); - /// - /// // Set the center cells Right, Margin to 10. - /// center.MarginRight = 25; - /// - /// // Save the document. - /// document.Save(); - ///} - /// - /// - public double MarginRight - { - get - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - - // If tcPr is null, this cell contains no width information. - if (tcPr == null) - return double.NaN; - - /* - * Get the tcMar - * - */ - XElement tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - - // If tcMar is null, this cell contains no margin information. - // Get the right (RightMargin) element - XElement tcMarRight = tcMar?.Element(XName.Get("right", DocX.w.NamespaceName)); - - // If tcMarRight is null, this cell contains no right margin information. - // Get the w attribute of the tcMarRight element. - XAttribute w = tcMarRight?.Attribute(XName.Get("w", DocX.w.NamespaceName)); - - // If w is null, this cell contains no width information. - if (w == null) - return double.NaN; - - // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; - double rightMarginInWordUnits; - if (!double.TryParse(w.Value, out rightMarginInWordUnits)) - { - w.Remove(); - return double.NaN; - } - - // 15 "word units" is equal to one pixel. - return (rightMarginInWordUnits / 15); - } - - set - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the tcMar (table cell margin) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - if (tcMar == null) - { - tcPr.SetElementValue(XName.Get("tcMar", DocX.w.NamespaceName), string.Empty); - tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - } - - /* - * Get the right (table cell right margin) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcMarRight = tcMar.Element(XName.Get("right", DocX.w.NamespaceName)); - if (tcMarRight == null) - { - tcMar.SetElementValue(XName.Get("right", DocX.w.NamespaceName), string.Empty); - tcMarRight = tcMar.Element(XName.Get("right", DocX.w.NamespaceName)); - } - - // 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. - tcMarRight.SetAttributeValue(XName.Get("type", DocX.w.NamespaceName), "dxa"); - - // 15 "word units" is equal to one pixel. - tcMarRight.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), (value * 15).ToString()); - } - } - - /// - /// TopMargin in pixels. // Added by lckuiper - /// - /// - /// - /// // Create a new document. - ///using (DocX document = DocX.Create("Test.docx")) - ///{ - /// // Insert table into this document. - /// Table t = document.InsertTable(3, 3); - /// t.Design = TableDesign.TableGrid; - /// - /// // Get the center cell. - /// Cell center = t.Rows[1].Cells[1]; - /// - /// // Insert some text so that we can see the effect of the Margins. - /// center.Paragraphs[0].Append("Center Cell"); - /// - /// // Set the center cells Top, Margin to 10. - /// center.MarginTop = 25; - /// - /// // Save the document. - /// document.Save(); - ///} - /// - /// - public double MarginTop - { - get - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - - // If tcPr is null, this cell contains no width information. - if (tcPr == null) - return double.NaN; - - /* - * Get the tcMar - * - */ - XElement tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - - // If tcMar is null, this cell contains no margin information. - // Get the top (TopMargin) element - XElement tcMarTop = tcMar?.Element(XName.Get("top", DocX.w.NamespaceName)); - - // If tcMarTop is null, this cell contains no top margin information. - // Get the w attribute of the tcMarTop element. - XAttribute w = tcMarTop?.Attribute(XName.Get("w", DocX.w.NamespaceName)); - - // If w is null, this cell contains no width information. - if (w == null) - return double.NaN; - - // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; - double topMarginInWordUnits; - if (!double.TryParse(w.Value, out topMarginInWordUnits)) - { - w.Remove(); - return double.NaN; - } - - // 15 "word units" is equal to one pixel. - return (topMarginInWordUnits / 15); - } - - set - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the tcMar (table cell margin) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - if (tcMar == null) - { - tcPr.SetElementValue(XName.Get("tcMar", DocX.w.NamespaceName), string.Empty); - tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - } - - /* - * Get the top (table cell top margin) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcMarTop = tcMar.Element(XName.Get("top", DocX.w.NamespaceName)); - if (tcMarTop == null) - { - tcMar.SetElementValue(XName.Get("top", DocX.w.NamespaceName), string.Empty); - tcMarTop = tcMar.Element(XName.Get("top", DocX.w.NamespaceName)); - } - - // 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. - tcMarTop.SetAttributeValue(XName.Get("type", DocX.w.NamespaceName), "dxa"); - - // 15 "word units" is equal to one pixel. - tcMarTop.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), (value * 15).ToString()); - } - } - - /// - /// BottomMargin in pixels. // Added by lckuiper - /// - /// - /// - /// // Create a new document. - ///using (DocX document = DocX.Create("Test.docx")) - ///{ - /// // Insert table into this document. - /// Table t = document.InsertTable(3, 3); - /// t.Design = TableDesign.TableGrid; - /// - /// // Get the center cell. - /// Cell center = t.Rows[1].Cells[1]; - /// - /// // Insert some text so that we can see the effect of the Margins. - /// center.Paragraphs[0].Append("Center Cell"); - /// - /// // Set the center cells Top, Margin to 10. - /// center.MarginBottom = 25; - /// - /// // Save the document. - /// document.Save(); - ///} - /// - /// - public double MarginBottom - { - get - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - - // If tcPr is null, this cell contains no width information. - - /* - * Get the tcMar - * - */ - XElement tcMar = tcPr?.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - - // If tcMar is null, this cell contains no margin information. - if (tcMar == null) - return double.NaN; - - // Get the bottom (BottomMargin) element - XElement tcMarBottom = tcMar.Element(XName.Get("bottom", DocX.w.NamespaceName)); - - // If tcMarBottom is null, this cell contains no bottom margin information. - - // Get the w attribute of the tcMarBottom element. - XAttribute w = tcMarBottom?.Attribute(XName.Get("w", DocX.w.NamespaceName)); - - // If w is null, this cell contains no width information. - if (w == null) - return double.NaN; - - // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; - double bottomMarginInWordUnits; - if (!double.TryParse(w.Value, out bottomMarginInWordUnits)) - { - w.Remove(); - return double.NaN; - } - - // 15 "word units" is equal to one pixel. - return (bottomMarginInWordUnits / 15); - } - - set - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the tcMar (table cell margin) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - if (tcMar == null) - { - tcPr.SetElementValue(XName.Get("tcMar", DocX.w.NamespaceName), string.Empty); - tcMar = tcPr.Element(XName.Get("tcMar", DocX.w.NamespaceName)); - } - - /* - * Get the bottom (table cell bottom margin) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcMarBottom = tcMar.Element(XName.Get("bottom", DocX.w.NamespaceName)); - if (tcMarBottom == null) - { - tcMar.SetElementValue(XName.Get("bottom", DocX.w.NamespaceName), string.Empty); - tcMarBottom = tcMar.Element(XName.Get("bottom", DocX.w.NamespaceName)); - } - - // 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. - tcMarBottom.SetAttributeValue(XName.Get("type", DocX.w.NamespaceName), "dxa"); - - // 15 "word units" is equal to one pixel. - tcMarBottom.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), (value * 15).ToString()); - } - } - - /// - /// Set the table cell border - /// Added by lckuiper @ 20101117 - /// - /// - /// - /// // Create a new document. - ///using (DocX document = DocX.Create("Test.docx")) - ///{ - /// // Insert a table into this document. - /// Table t = document.InsertTable(3, 3); - /// - /// // Get the center cell. - /// Cell center = t.Rows[1].Cells[1]; - /// - /// // Create a large blue border. - /// Border b = new Border(BorderStyle.Tcbs_single, BorderSize.seven, 0, Color.Blue); - /// - /// // Set the center cells Top, Bottom, Left and Right Borders to b. - /// center.SetBorder(TableCellBorderType.Top, b); - /// center.SetBorder(TableCellBorderType.Bottom, b); - /// center.SetBorder(TableCellBorderType.Left, b); - /// center.SetBorder(TableCellBorderType.Right, b); - /// - /// // Save the document. - /// document.Save(); - ///} - /// - /// - /// Table Cell border to set - /// Border object to set the table cell border - public void SetBorder(TableCellBorderType borderType, Border border) - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the tblBorders (table cell borders) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcBorders = tcPr.Element(XName.Get("tcBorders", DocX.w.NamespaceName)); - if (tcBorders == null) - { - tcPr.SetElementValue(XName.Get("tcBorders", DocX.w.NamespaceName), string.Empty); - tcBorders = tcPr.Element(XName.Get("tcBorders", DocX.w.NamespaceName)); - } - - /* - * Get the 'borderType' (table cell border) element for this Cell, - * null will be return if no such element exists. - */ - string tcbordertype; - switch (borderType) - { - case TableCellBorderType.TopLeftToBottomRight: - tcbordertype = "tl2br"; - break; - case TableCellBorderType.TopRightToBottomLeft: - tcbordertype = "tr2bl"; - break; - default: - // enum to string - tcbordertype = borderType.ToString(); - // only lower the first char of string (because of insideH and insideV) - tcbordertype = tcbordertype.Substring(0, 1).ToLower() + tcbordertype.Substring(1); - break; - } - - XElement tcBorderType = tcBorders.Element(XName.Get(borderType.ToString(), DocX.w.NamespaceName)); - if (tcBorderType == null) - { - tcBorders.SetElementValue(XName.Get(tcbordertype, DocX.w.NamespaceName), string.Empty); - tcBorderType = tcBorders.Element(XName.Get(tcbordertype, 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 - tcBorderType.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), borderstyle); - - 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 - tcBorderType.SetAttributeValue(XName.Get("sz", DocX.w.NamespaceName), (size).ToString()); - - // The space attribute is used for the cell spacing (probably '0') - tcBorderType.SetAttributeValue(XName.Get("space", DocX.w.NamespaceName), (border.Space).ToString()); - - // The color attribute is used for the border color - tcBorderType.SetAttributeValue(XName.Get("color", DocX.w.NamespaceName), border.Color.ToHex()); - } - - - /// - /// Get a table cell border - /// Added by lckuiper @ 20101117 - /// - /// The table cell border to get - public Border GetBorder(TableCellBorderType borderType) - { - // instance with default border values - var b = new Border(); - - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - // uses default border style - } - - /* - * Get the tcBorders (table cell borders) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcBorders = tcPr.Element(XName.Get("tcBorders", DocX.w.NamespaceName)); - if (tcBorders == null) - { - // uses default border style - } - - /* - * Get the 'borderType' (cell border) element for this Cell, - * null will be return if no such element exists. - */ - var tcbordertype = borderType.ToString(); - - switch (tcbordertype) - { - case "TopLeftToBottomRight": - tcbordertype = "tl2br"; - break; - case "TopRightToBottomLeft": - tcbordertype = "tr2bl"; - break; - default: - // only lower the first char of string (because of insideH and insideV) - tcbordertype = tcbordertype.Substring(0, 1).ToLower() + tcbordertype.Substring(1); - break; - } - - XElement tcBorderType = tcBorders.Element(XName.Get(tcbordertype, DocX.w.NamespaceName)); - if (tcBorderType == null) - { - // uses default border style - } - - // The val attribute is used for the border style - XAttribute val = tcBorderType.Attribute(XName.Get("val", DocX.w.NamespaceName)); - // If val is null, this cell contains no border information. - if (val == null) - { - // uses default border style - } - else - { - try - { - string bordertype = "Tcbs_" + val.Value; - b.Tcbs = (BorderStyle)Enum.Parse(typeof(BorderStyle), bordertype); - } - - catch - { - val.Remove(); - // uses default border style - } - } - - // The sz attribute is used for the border size - XAttribute sz = tcBorderType.Attribute(XName.Get("sz", DocX.w.NamespaceName)); - // If sz is null, this border contains no size information. - if (sz == null) - { - // uses default border style - } - else - { - // If sz is not an int, something is wrong with this attributes value, so remove it - int numerical_size; - if (!int.TryParse(sz.Value, out numerical_size)) - sz.Remove(); - else - { - switch (numerical_size) - { - case 2: b.Size = BorderSize.one; break; - case 4: b.Size = BorderSize.two; break; - case 6: b.Size = BorderSize.three; break; - case 8: b.Size = BorderSize.four; break; - case 12: b.Size = BorderSize.five; break; - case 18: b.Size = BorderSize.six; break; - case 24: b.Size = BorderSize.seven; break; - case 36: b.Size = BorderSize.eight; break; - case 48: b.Size = BorderSize.nine; break; - default: b.Size = BorderSize.one; break; - } - } - } - - // The space attribute is used for the border spacing (probably '0') - XAttribute space = tcBorderType.Attribute(XName.Get("space", DocX.w.NamespaceName)); - // If space is null, this border contains no space information. - if (space == null) - { - // uses default border style - } - else - { - // If space is not an int, something is wrong with this attributes value, so remove it - int borderspace; - if (!int.TryParse(space.Value, out borderspace)) - { - space.Remove(); - // uses default border style - } - else - { - b.Space = borderspace; - } - } - - // The color attribute is used for the border color - XAttribute color = tcBorderType.Attribute(XName.Get("color", DocX.w.NamespaceName)); - if (color == null) - { - // uses default border style - } - else - { - // If color is not a Color, something is wrong with this attributes value, so remove it - try - { - b.Color = ColorTranslator.FromHtml(string.Format("#{0}", color.Value)); - } - catch - { - color.Remove(); - // uses default border style - } - } - return b; - } - - /// - /// Gets or Sets the fill color of this Cell. - /// - /// - /// - /// // Create a new document. - /// using (DocX document = DocX.Create("Test.docx")) - /// { - /// // Insert a table into this document. - /// Table t = document.InsertTable(3, 3); - /// - /// // Fill the first cell as Blue. - /// t.Rows[0].Cells[0].FillColor = Color.Blue; - /// // Fill the middle cell as Red. - /// t.Rows[1].Cells[1].FillColor = Color.Red; - /// // Fill the last cell as Green. - /// t.Rows[2].Cells[2].FillColor = Color.Green; - /// - /// // Save the document. - /// document.Save(); - /// } - /// - /// - public Color FillColor - { - get - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - XElement shd = tcPr?.Element(XName.Get("shd", DocX.w.NamespaceName)); - XAttribute fill = shd?.Attribute(XName.Get("fill", DocX.w.NamespaceName)); - if (fill == null) - return Color.Empty; - int argb = Int32.Parse(fill.Value.Replace("#", ""), NumberStyles.HexNumber); - return Color.FromArgb(argb); - } - - set - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the tcW (table cell width) element for this Cell, - * null will be return if no such element exists. - */ - XElement shd = tcPr.Element(XName.Get("shd", DocX.w.NamespaceName)); - if (shd == null) - { - tcPr.SetElementValue(XName.Get("shd", DocX.w.NamespaceName), string.Empty); - shd = tcPr.Element(XName.Get("shd", DocX.w.NamespaceName)); - } - - shd.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), "clear"); - shd.SetAttributeValue(XName.Get("color", DocX.w.NamespaceName), "auto"); - shd.SetAttributeValue(XName.Get("fill", DocX.w.NamespaceName), value.ToHex()); - } - } - - 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; - } - - public TextDirection TextDirection - { - get - { - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - - // If tcPr is null, this cell contains no width information. - XElement textDirection = tcPr?.Element(XName.Get("textDirection", DocX.w.NamespaceName)); - XAttribute val = textDirection?.Attribute(XName.Get("val", DocX.w.NamespaceName)); - if (val == null) - return TextDirection.right; - - // If val is not a VerticalAlign enum, something is wrong with this attributes value, so remove it and return VerticalAlignment.Center; - try - { - return (TextDirection)Enum.Parse(typeof(TextDirection), val.Value, true); - } - catch - { - val.Remove(); - return TextDirection.right; - } - } - set - { - /* - * Get the tcPr (table cell properties) element for this Cell, - * null will be return if no such element exists. - */ - XElement tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - if (tcPr == null) - { - Xml.SetElementValue(XName.Get("tcPr", DocX.w.NamespaceName), string.Empty); - tcPr = Xml.Element(XName.Get("tcPr", DocX.w.NamespaceName)); - } - - /* - * Get the vAlign (table cell vertical alignment) element for this Cell, - * null will be return if no such element exists. - */ - XElement textDirection = tcPr.Element(XName.Get("textDirection", DocX.w.NamespaceName)); - if (textDirection == null) - { - tcPr.SetElementValue(XName.Get("textDirection", DocX.w.NamespaceName), string.Empty); - textDirection = tcPr.Element(XName.Get("textDirection", DocX.w.NamespaceName)); - } - - // Set the VerticalAlignment in 'val' - textDirection.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), value.ToString()); - - } - } - } - - - public class TableLook - { - public bool FirstRow { get; set; } - public bool LastRow { get; set; } - public bool FirstColumn { get; set; } - public bool LastColumn { get; set; } - public bool NoHorizontalBanding { get; set; } - public bool NoVerticalBanding { get; set; } - } - -} diff --git a/DocX/TableOfContents.cs b/DocX/TableOfContents.cs deleted file mode 100644 index 57737144..00000000 --- a/DocX/TableOfContents.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Xml; -using System.Xml.Linq; - -namespace Novacode -{ - /// - /// Represents a table of contents in the document - /// - public class TableOfContents : DocXElement - { - #region TocBaseValues - - private const string HeaderStyle = "TOCHeading"; - private const int RightTabPos = 9350; - #endregion - - private TableOfContents(DocX document, XElement xml, string headerStyle) : base(document, xml) - { - AssureUpdateField(document); - AssureStyles(document, headerStyle); - } - - internal static TableOfContents CreateTableOfContents(DocX document, string title, TableOfContentsSwitches switches, string headerStyle = null, int lastIncludeLevel = 3, int? rightTabPos = null) - { - var reader = XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocXmlBase, headerStyle ?? HeaderStyle, title, rightTabPos ?? RightTabPos, BuildSwitchString(switches, lastIncludeLevel)))); - var xml = XElement.Load(reader); - return new TableOfContents(document, xml, headerStyle); - } - - private void AssureUpdateField(DocX document) - { - if (document.settings.Descendants().Any(x => x.Name.Equals(DocX.w + "updateFields"))) return; - - var element = new XElement(XName.Get("updateFields", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", true)); - document.settings.Root.Add(element); - } - - private void AssureStyles(DocX document, string headerStyle) - { - if (!HasStyle(document, headerStyle, "paragraph")) - { - var reader = XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocHeadingStyleBase, headerStyle ?? HeaderStyle))); - var xml = XElement.Load(reader); - document.styles.Root.Add(xml); - } - if (!HasStyle(document, "TOC1", "paragraph")) - { - var reader = XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocElementStyleBase, "TOC1", "toc 1"))); - var xml = XElement.Load(reader); - document.styles.Root.Add(xml); - } - if (!HasStyle(document, "TOC2", "paragraph")) - { - var reader = XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocElementStyleBase, "TOC2", "toc 2"))); - var xml = XElement.Load(reader); - document.styles.Root.Add(xml); - } - if (!HasStyle(document, "TOC3", "paragraph")) - { - var reader = XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocElementStyleBase, "TOC3", "toc 3"))); - var xml = XElement.Load(reader); - document.styles.Root.Add(xml); - } - if (!HasStyle(document, "TOC4", "paragraph")) - { - var reader = XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocElementStyleBase, "TOC4", "toc 4"))); - var xml = XElement.Load(reader); - document.styles.Root.Add(xml); - } - if (!HasStyle(document, "Hyperlink", "character")) - { - var reader = XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocHyperLinkStyleBase))); - var xml = XElement.Load(reader); - document.styles.Root.Add(xml); - } - } - - private bool HasStyle(DocX document, string value, string type) - { - return document.styles.Descendants().Any(x => x.Name.Equals(DocX.w + "style")&& (x.Attribute(DocX.w + "type") == null || x.Attribute(DocX.w + "type").Value.Equals(type)) && x.Attribute(DocX.w + "styleId") != null && x.Attribute(DocX.w + "styleId").Value.Equals(value)); - } - - private static string BuildSwitchString(TableOfContentsSwitches switches, int lastIncludeLevel) - { - var allSwitches = Enum.GetValues(typeof (TableOfContentsSwitches)).Cast(); - var switchString = "TOC"; - foreach (var s in allSwitches.Where(s => s != TableOfContentsSwitches.None && switches.HasFlag(s))) - { - switchString += " " + s.EnumDescription(); - if (s == TableOfContentsSwitches.O) - { - switchString += string.Format(" '{0}-{1}'", 1, lastIncludeLevel); - } - } - - return switchString; - } - - } -} \ No newline at end of file diff --git a/DocX/_BaseClasses.cs b/DocX/_BaseClasses.cs deleted file mode 100644 index b0e67c59..00000000 --- a/DocX/_BaseClasses.cs +++ /dev/null @@ -1,310 +0,0 @@ -using System; -using System.IO.Packaging; -using System.Linq; -using System.Xml.Linq; - -namespace Novacode -{ - /// - /// All DocX types are derived from DocXElement. - /// This class contains properties which every element of a DocX must contain. - /// - public abstract class DocXElement - { - internal PackagePart mainPart; - public PackagePart PackagePart { get { return mainPart; } set { mainPart = value; } } - - /// - /// This is the actual Xml that gives this element substance. - /// For example, a Paragraphs Xml might look something like the following - ///

- /// - /// Hello World! - /// - ///

- ///
- - public XElement Xml { get; set; } - /// - /// This is a reference to the DocX object that this element belongs to. - /// Every DocX element is connected to a document. - /// - internal DocX Document { get; set; } - /// - /// Store both the document and xml so that they can be accessed by derived types. - /// - /// The document that this element belongs to. - /// The Xml that gives this element substance - public DocXElement(DocX document, XElement xml) - { - this.Document = document; - this.Xml = xml; - } - } - - /// - /// This class provides functions for inserting new DocXElements before or after the current DocXElement. - /// Only certain DocXElements can support these functions without creating invalid documents, at the moment these are Paragraphs and Table. - /// - public abstract class InsertBeforeOrAfter : DocXElement - { - public InsertBeforeOrAfter(DocX document, XElement xml) : base(document, xml) { } - - public virtual void InsertPageBreakBeforeSelf() - { - XElement p = new XElement - ( - XName.Get("p", DocX.w.NamespaceName), - new XElement - ( - XName.Get("r", DocX.w.NamespaceName), - new XElement - ( - XName.Get("br", DocX.w.NamespaceName), - new XAttribute(XName.Get("type", DocX.w.NamespaceName), "page") - ) - ) - ); - - Xml.AddBeforeSelf(p); - } - - public virtual void InsertPageBreakAfterSelf() - { - XElement p = new XElement - ( - XName.Get("p", DocX.w.NamespaceName), - new XElement - ( - XName.Get("r", DocX.w.NamespaceName), - new XElement - ( - XName.Get("br", DocX.w.NamespaceName), - new XAttribute(XName.Get("type", DocX.w.NamespaceName), "page") - ) - ) - ); - - Xml.AddAfterSelf(p); - } - - public virtual Paragraph InsertParagraphBeforeSelf(Paragraph p) - { - Xml.AddBeforeSelf(p.Xml); - XElement newlyInserted = Xml.ElementsBeforeSelf().First(); - - p.Xml = newlyInserted; - - return p; - } - - public virtual Paragraph InsertParagraphAfterSelf(Paragraph p) - { - Xml.AddAfterSelf(p.Xml); - XElement newlyInserted = Xml.ElementsAfterSelf().First(); - - //Dmitchern - if (this as Paragraph != null) - { - return new Paragraph(Document, newlyInserted, (this as Paragraph).endIndex); - } - - p.Xml = newlyInserted; //IMPORTANT: I think we have return new paragraph in any case, but I dont know what to put as startIndex parameter into Paragraph constructor - return p; - } - - public virtual Paragraph InsertParagraphBeforeSelf(string text) - { - return InsertParagraphBeforeSelf(text, false, new Formatting()); - } - - public virtual Paragraph InsertParagraphAfterSelf(string text) - { - return InsertParagraphAfterSelf(text, false, new Formatting()); - } - - public virtual Paragraph InsertParagraphBeforeSelf(string text, bool trackChanges) - { - return InsertParagraphBeforeSelf(text, trackChanges, new Formatting()); - } - - public virtual Paragraph InsertParagraphAfterSelf(string text, bool trackChanges) - { - return InsertParagraphAfterSelf(text, trackChanges, new Formatting()); - } - - public virtual Paragraph InsertParagraphBeforeSelf(string text, bool trackChanges, Formatting formatting) - { - XElement newParagraph = new XElement - ( - XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName)), HelperFunctions.FormatInput(text, formatting.Xml) - ); - - if (trackChanges) - newParagraph = Paragraph.CreateEdit(EditType.ins, DateTime.Now, newParagraph); - - Xml.AddBeforeSelf(newParagraph); - XElement newlyInserted = Xml.ElementsBeforeSelf().Last(); - - return new Paragraph(Document, newlyInserted, -1); - } - - public virtual Paragraph InsertParagraphAfterSelf(string text, bool trackChanges, Formatting formatting) - { - XElement newParagraph = new XElement - ( - XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName)), HelperFunctions.FormatInput(text, formatting.Xml) - ); - - if (trackChanges) - newParagraph = Paragraph.CreateEdit(EditType.ins, DateTime.Now, newParagraph); - - Xml.AddAfterSelf(newParagraph); - XElement newlyInserted = Xml.ElementsAfterSelf().First(); - - Paragraph p = new Paragraph(Document, newlyInserted, -1); - - return p; - } - - public virtual Table InsertTableAfterSelf(int rowCount, int columnCount) - { - XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount); - Xml.AddAfterSelf(newTable); - XElement newlyInserted = Xml.ElementsAfterSelf().First(); - - return new Table(Document, newlyInserted) { mainPart = mainPart }; - } - - public virtual Table InsertTableAfterSelf(Table t) - { - Xml.AddAfterSelf(t.Xml); - XElement newlyInserted = Xml.ElementsAfterSelf().First(); - //Dmitchern - return new Table(Document, newlyInserted) { mainPart = mainPart }; //return new table, dont affect parameter table - } - - public virtual Table InsertTableBeforeSelf(int rowCount, int columnCount) - { - XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount); - Xml.AddBeforeSelf(newTable); - XElement newlyInserted = Xml.ElementsBeforeSelf().Last(); - - return new Table(Document, newlyInserted) { mainPart = mainPart }; - } - - public virtual Table InsertTableBeforeSelf(Table t) - { - Xml.AddBeforeSelf(t.Xml); - XElement newlyInserted = Xml.ElementsBeforeSelf().Last(); - - //Dmitchern - return new Table(Document, newlyInserted) { mainPart=mainPart}; //return new table, dont affect parameter table - } - } - - public static class XmlTemplateBases - { - #region TocXml - public const string TocXmlBase = @" - - - - - \ - - - - - - - - - - - - - - - - - {1} - - - - - - - - - - - - - - - - - {3} - - - - - - - - - - - - - - - - - - "; - public const string TocHeadingStyleBase = @" - - - - - - - - - - - - - - - - "; - public const string TocElementStyleBase = @" - - - - - - - - - - - - "; - public const string TocHyperLinkStyleBase = @" - - - - - - - - - - "; - #endregion - } -} diff --git a/DocX/_Extensions.cs b/DocX/_Extensions.cs deleted file mode 100644 index 7d7d429d..00000000 --- a/DocX/_Extensions.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Drawing; -using System.Xml.Linq; - -namespace Novacode -{ - internal static class Extensions - { - internal static string ToHex(this Color source) - { - byte red = source.R; - byte green = source.G; - byte blue = source.B; - - string redHex = red.ToString("X"); - if (redHex.Length < 2) - redHex = "0" + redHex; - - string blueHex = blue.ToString("X"); - if (blueHex.Length < 2) - blueHex = "0" + blueHex; - - string greenHex = green.ToString("X"); - if (greenHex.Length < 2) - greenHex = "0" + greenHex; - - return string.Format("{0}{1}{2}", redHex, greenHex, blueHex); - } - - public static void Flatten(this XElement e, XName name, List flat) - { - // Add this element (without its children) to the flat list. - XElement clone = CloneElement(e); - clone.Elements().Remove(); - - // Filter elements using XName. - if (clone.Name == name) - flat.Add(clone); - - // Process the children. - if (e.HasElements) - foreach (XElement elem in e.Elements(name)) // Filter elements using XName - elem.Flatten(name, flat); - } - - static XElement CloneElement(XElement element) - { - return new XElement(element.Name, - element.Attributes(), - element.Nodes().Select(n => - { - XElement e = n as XElement; - if (e != null) - return CloneElement(e); - return n; - } - ) - ); - } - - public static string GetAttribute(this XElement el, XName name, string defaultValue = "") - { - var attr = el.Attribute(name); - if (attr != null) - return attr.Value; - return defaultValue; - } - - /// - /// Sets margin for all the pages in a Dox document in Inches. (Written by Shashwat Tripathi) - /// - /// - /// Margin from the Top. Leave -1 for no change - /// Margin from the Bottom. Leave -1 for no change - /// Margin from the Right. Leave -1 for no change - /// Margin from the Left. Leave -1 for no change - public static void SetMargin(this DocX document, float top, float bottom, float right, float left) - { - XNamespace ab = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; - var tempElement = document.PageLayout.Xml.Descendants(ab + "pgMar"); - - foreach (var item in tempElement) - { - if (left != -1) - item.SetAttributeValue(ab + "left", (1440 * left) / 1); - if (right != -1) - item.SetAttributeValue(ab + "right", (1440 * right) / 1); - if (top != -1) - item.SetAttributeValue(ab + "top", (1440 * top) / 1); - if (bottom != -1) - item.SetAttributeValue(ab + "bottom", (1440 * bottom) / 1); - } - } - } - -} diff --git a/Documentation/Documentation.shfbproj b/Documentation/Documentation.shfbproj deleted file mode 100644 index b7b01ee5..00000000 --- a/Documentation/Documentation.shfbproj +++ /dev/null @@ -1,88 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {1eb1ee8f-9978-425b-a742-533dcceb4811} - 2015.6.5.0 - - Documentation - Documentation - Documentation - - Help\ - Documentation - en-US - HtmlHelp1 - False - .NET Framework 3.5 - True - False - False - True - Standard - Blank - False - VS2013 - False - Guid - DocX - A Sandcastle Documented Class Library - coffey.cathal%40gmail.com - coffey.cathal%40gmail.com - AboveNamespaces - - - - SAK - SAK - SAK - SAK - %temp%\ - - - - - - - - - - - OnlyWarningsAndErrors - 1.0.0.0 - 2 - False - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Documentation/Documentation.shfbproj.vspscc b/Documentation/Documentation.shfbproj.vspscc deleted file mode 100644 index feffdeca..00000000 --- a/Documentation/Documentation.shfbproj.vspscc +++ /dev/null @@ -1,10 +0,0 @@ -"" -{ -"FILE_VERSION" = "9237" -"ENLISTMENT_CHOICE" = "NEVER" -"PROJECT_FILE_RELATIVE_PATH" = "" -"NUMBER_OF_EXCLUDED_FILES" = "0" -"ORIGINAL_PROJECT_FILE_PATH" = "" -"NUMBER_OF_NESTED_PROJECTS" = "0" -"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" -} diff --git a/Examples/Examples.csproj b/Examples/Examples.csproj deleted file mode 100644 index 526dda53..00000000 --- a/Examples/Examples.csproj +++ /dev/null @@ -1,97 +0,0 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {F3022BB7-0E40-4C80-A495-37FEAF3671AB} - Exe - Properties - Examples - Examples - v4.6 - - - 512 - SAK - SAK - SAK - SAK - - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - AnyCPU - bin\Debug\ - false - - - AnyCPU - bin\Release\ - false - true - false - - - - - - - - - - - - - - - - - - - - Always - - - Always - - - Always - - - - - {e863d072-aa8b-4108-b5f1-785241b37f67} - DocX - - - - - \ No newline at end of file diff --git a/Examples/Examples.csproj.vspscc b/Examples/Examples.csproj.vspscc deleted file mode 100644 index feffdeca..00000000 --- a/Examples/Examples.csproj.vspscc +++ /dev/null @@ -1,10 +0,0 @@ -"" -{ -"FILE_VERSION" = "9237" -"ENLISTMENT_CHOICE" = "NEVER" -"PROJECT_FILE_RELATIVE_PATH" = "" -"NUMBER_OF_EXCLUDED_FILES" = "0" -"ORIGINAL_PROJECT_FILE_PATH" = "" -"NUMBER_OF_NESTED_PROJECTS" = "0" -"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" -} diff --git a/Examples/Program.cs b/Examples/Program.cs index 2743c2c8..3f3f4d7b 100644 --- a/Examples/Program.cs +++ b/Examples/Program.cs @@ -1,2023 +1,141 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using System.Xml.Linq; -using Novacode; -using WindowsBitmap = System.Drawing.Bitmap; -using WindowsBrushes = System.Drawing.Brushes; -using WindowsColor = System.Drawing.Color; -using WindowsFont = System.Drawing.Font; -using WindowsFontFamily = System.Drawing.FontFamily; -using WindowsGraphics = System.Drawing.Graphics; -using WindowsImageFormat = System.Drawing.Imaging.ImageFormat; - -namespace Examples -{ - class Program - { - private static Border BlankBorder = new Border(BorderStyle.Tcbs_none, 0, 0, WindowsColor.White); - - static void Main(string[] args) - { - Setup(); - Examples(); - } - - static void Examples() - { - // Easy - Console.WriteLine("\nRunning Easy Examples"); - HelloWorld(); - HelloWorldKeepLinesTogether(); - HelloWorldKeepWithNext(); - HelloWorldAdvancedFormatting(); - HelloWorldProtectedDocument(); - HelloWorldAddPictureToWord(); - HelloWorldInsertHorizontalLine(); - RightToLeft(); - Indentation(); - HeadersAndFooters(); - HyperlinksImagesTables(); - AddList(); - Equations(); - Bookmarks(); - BookmarksReplaceTextOfBookmarkKeepingFormat(); - BarChart(); - PieChart(); - LineChart(); - Chart3D(); - DocumentMargins(); - CreateTableWithTextDirection(); - CreateTableRowsFromTemplate(); - AddToc(); - AddTocByReference(); - - // Intermediate - Console.WriteLine("\nRunning Intermediate Examples"); - CreateInvoice(); - HyperlinksImagesTablesWithLists(); - HeadersAndFootersWithImagesAndTables(); - HeadersAndFootersWithImagesAndTablesUsingInsertPicture(); - DocumentsWithListsFontChange(); - DocumentHeading(); - LargeTable(); - TableWithSpecifiedWidths(); - //Contents(); - - // Advanced - Console.WriteLine("\nRunning Advanced Examples"); - ProgrammaticallyManipulateImbeddedImage(); - ReplaceTextParallel(); - - Console.WriteLine("\nPress any key to exit."); - Console.ReadKey(); - } - - private static void Setup() - { - if (!Directory.Exists("docs")) - { - Directory.CreateDirectory("docs"); - } - } - - #region Charts - - private class ChartData - { - public String Mounth { get; set; } - public Double Money { get; set; } - - public static List CreateCompanyList1() - { - List company1 = new List(); - company1.Add(new ChartData() { Mounth = "January", Money = 100 }); - company1.Add(new ChartData() { Mounth = "February", Money = 120 }); - company1.Add(new ChartData() { Mounth = "March", Money = 140 }); - return company1; - } - - public static List CreateCompanyList2() - { - List company2 = new List(); - company2.Add(new ChartData() { Mounth = "January", Money = 80 }); - company2.Add(new ChartData() { Mounth = "February", Money = 160 }); - company2.Add(new ChartData() { Mounth = "March", Money = 130 }); - return company2; - } - } - - private static void BarChart() - { - Console.WriteLine("\tBarChart()"); - // Create new document. - using (DocX document = DocX.Create(@"docs\BarChart.docx")) - { - // Create chart. - BarChart c = new BarChart(); - c.BarDirection = BarDirection.Column; - c.BarGrouping = BarGrouping.Standard; - c.GapWidth = 400; - c.AddLegend(ChartLegendPosition.Bottom, false); - - // Create data. - List company1 = ChartData.CreateCompanyList1(); - List company2 = ChartData.CreateCompanyList2(); - - // Create and add series - Series s1 = new Series("Microsoft"); - s1.Color = WindowsColor.GreenYellow; - s1.Bind(company1, "Mounth", "Money"); - c.AddSeries(s1); - Series s2 = new Series("Apple"); - s2.Bind(company2, "Mounth", "Money"); - c.AddSeries(s2); - - // Insert chart into document - document.InsertParagraph("Diagram").FontSize(20); - document.InsertChart(c); - document.Save(); - } - Console.WriteLine("\tCreated: docs\\BarChart.docx\n"); - } - - private static void PieChart() - { - Console.WriteLine("\tPieChart()"); - // Create new document. - using (DocX document = DocX.Create(@"docs\PieChart.docx")) - { - // Create chart. - PieChart c = new PieChart(); - c.AddLegend(ChartLegendPosition.Bottom, false); - - // Create data. - List company2 = ChartData.CreateCompanyList2(); - - // Create and add series - Series s = new Series("Apple"); - s.Bind(company2, "Mounth", "Money"); - c.AddSeries(s); - - // Insert chart into document - document.InsertParagraph("Diagram").FontSize(20); - document.InsertChart(c); - document.Save(); - } - Console.WriteLine("\tCreated: docs\\PieChart.docx\n"); - } - - private static void LineChart() - { - Console.WriteLine("\tLineChart()"); - // Create new document. - using (DocX document = DocX.Create(@"docs\LineChart.docx")) - { - // Create chart. - LineChart c = new LineChart(); - c.AddLegend(ChartLegendPosition.Bottom, false); - - // Create data. - List company1 = ChartData.CreateCompanyList1(); - List company2 = ChartData.CreateCompanyList2(); - - // Create and add series - Series s1 = new Series("Microsoft"); - s1.Color = WindowsColor.GreenYellow; - s1.Bind(company1, "Mounth", "Money"); - c.AddSeries(s1); - Series s2 = new Series("Apple"); - s2.Bind(company2, "Mounth", "Money"); - c.AddSeries(s2); - - // Insert chart into document - document.InsertParagraph("Diagram").FontSize(20); - document.InsertChart(c); - document.Save(); - } - Console.WriteLine("\tCreated: docs\\LineChart.docx\n"); - } - - private static void Chart3D() - { - Console.WriteLine("\tChart3D()"); - // Create new document. - using (DocX document = DocX.Create(@"docs\3DChart.docx")) - { - // Create chart. - BarChart c = new BarChart(); - c.View3D = true; - - // Create data. - List company1 = ChartData.CreateCompanyList1(); - - // Create and add series - Series s = new Series("Microsoft"); - s.Color = WindowsColor.GreenYellow; - s.Bind(company1, "Mounth", "Money"); - c.AddSeries(s); - - // Insert chart into document - document.InsertParagraph("3D Diagram").FontSize(20); - document.InsertChart(c); - document.Save(); - } - Console.WriteLine("\tCreated: docs\\3DChart.docx\n"); - } - - #endregion - - /// - /// Load a document and set content controls. - /// - private static void Contents() - { - Console.WriteLine("\tContent()"); - - // Load a document. - using (DocX document = DocX.Load(@"docs\Content.docx")) - { - foreach (var c in document.Contents) - { - Console.WriteLine(String.Format("Name : {0}, Tag : {1}", c.Name, c.Tag)); - } - - (from d in document.Contents - where d.Name == "Name" - select d).First().SetText("NewerText"); - - document.SaveAs(@"docs\ContentSetSingle.docx"); - - XElement el = new XElement("Root", - new XElement("Name", "Claudia"), - new XElement("Address", "17 Liberty St"), - new XElement("Total", "123.45") - - ); - - XDocument doc = new XDocument(el); - document.SetContent(el); - document.SaveAs(@"docs\ContentSetWithElement.docx"); - - - doc.Save(@"docs\elements.xml"); - - document.SetContent(@"docs\elements.xml"); - document.SaveAs(@"docs\ContentSetWithPath.docx"); - - - } - } - /// - /// Create a document wit(h two equations. - /// - private static void Equations() - { - Console.WriteLine("\tEquations()"); - - // Create a new document. - using (DocX document = DocX.Create(@"docs\Equations.docx")) - { - // Insert first Equation in this document. - Paragraph pEquation1 = document.InsertEquation("x = y+z"); - - // Insert second Equation in this document and add formatting. - Paragraph pEquation2 = document.InsertEquation("x = (y+z)/t").FontSize(18).Color(WindowsColor.Blue); - - // Save this document to disk. - document.Save(); - Console.WriteLine("\tCreated: docs\\Equations.docx\n"); - } - } - public static void DocumentHeading() - { - Console.WriteLine("\tDocumentHeading()"); - using (DocX document = DocX.Create(@"docs\DocumentHeading.docx")) - { - - foreach (HeadingType heading in (HeadingType[])Enum.GetValues(typeof(HeadingType))) - { - string text = string.Format("{0} - The quick brown fox jumps over the lazy dog", heading.EnumDescription()); - - Paragraph p = document.InsertParagraph(); - p.AppendLine(text).Heading(heading); - } - - - document.Save(); - Console.WriteLine("\tCreated: docs\\DocumentHeading.docx\n"); - } - } - - /// - /// Loads a document having a table with a given line as template. - /// It avoids extra manipulation regarding style - /// - private static void CreateTableRowsFromTemplate() - { - Console.WriteLine("\tCreateTableFromTemplate()"); - - using (DocX docX = DocX.Load(@"docs\DocumentWithTemplateTable.docx")) - { - //look for one specific table here - Table orderTable = docX.Tables.First(t => t.TableCaption == "ORDER_TABLE"); - if (orderTable != null) - { - //Row 0 and 1 are Headers - //Row 2 is pattern - if (orderTable.RowCount >= 2) - { - //get the Pattern row for duplication - Row orderRowPattern = orderTable.Rows[2]; - //Add 5 lines of product - for (int i = 0; i < 5; i++) - { - //InsertRow performs a copy, so we get markup in new line ready for replacements - Row newOrderRow = orderTable.InsertRow(orderRowPattern, 2 + i); - newOrderRow.ReplaceText("%PRODUCT_NAME%", "Product_" + i); - newOrderRow.ReplaceText("%PRODUCT_PRICE1%", "$ " + i * new Random().Next(1, 50)); - newOrderRow.ReplaceText("%PRODUCT_PRICE2%", "$ " + i * new Random().Next(1, 50)); - } - - //pattern row is at the end now, can be removed from table - orderRowPattern.Remove(); - - } - docX.SaveAs(@"docs\CreateTableFromTemplate.docx"); - - } - else - { - Console.WriteLine("\tError, couldn't find table with caption ORDER_TABLE in document"); - } - - - } - Console.WriteLine("\tCreated: docs\\CreateTableFromTemplate.docx"); - } - - private static void Bookmarks() - { - Console.WriteLine("\tBookmarks()"); - - using (var document = DocX.Create(@"docs\Bookmarks.docx")) - { - var paragraph = document.InsertBookmark("firstBookmark"); - - var paragraph2 = document.InsertParagraph("This is a paragraph which contains a "); - paragraph2.AppendBookmark("secondBookmark"); - paragraph2.Append("bookmark"); - - paragraph2.InsertAtBookmark("handy ", "secondBookmark"); - - document.Save(); - Console.WriteLine("\tCreated: docs\\Bookmarks.docx\n"); - - } - } - /// - /// Loads a document 'DocumentWithBookmarks.docx' and changes text inside bookmark keeping formatting the same. - /// This code creates the file 'BookmarksReplaceTextOfBookmarkKeepingFormat.docx'. - /// - private static void BookmarksReplaceTextOfBookmarkKeepingFormat() - { - Console.WriteLine("\tBookmarksReplaceTextOfBookmarkKeepingFormat()"); - - using (DocX docX = DocX.Load(@"docs\DocumentWithBookmarks.docx")) - { - foreach (Bookmark bookmark in docX.Bookmarks) - Console.WriteLine("\t\tFound bookmark {0}", bookmark.Name); - - // Replace bookmars content - docX.Bookmarks["bmkNoContent"].SetText("Here there was a bookmark"); - docX.Bookmarks["bmkContent"].SetText("Here there was a bookmark with a previous content"); - docX.Bookmarks["bmkFormattedContent"].SetText("Here there was a formatted bookmark"); - - docX.SaveAs(@"docs\BookmarksReplaceTextOfBookmarkKeepingFormat.docx"); - } - Console.WriteLine("\tCreated: docs\\BookmarksReplaceTextOfBookmarkKeepingFormat.docx"); - } - - /// - /// Create a document with a Paragraph whos first line is indented. - /// - private static void Indentation() - { - Console.WriteLine("\tIndentation()"); - - // Create a new document. - using (DocX document = DocX.Create(@"docs\Indentation.docx")) - { - // Create a new Paragraph. - Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3"); - - // Indent only the first line of the Paragraph. - p.IndentationFirstLine = 1.0f; - - - // Save all changes made to this document. - document.Save(); - Console.WriteLine("\tCreated: docs\\Indentation.docx\n"); - } - } - - /// - /// Create a document that with RightToLeft text flow. - /// - private static void RightToLeft() - { - Console.WriteLine("\tRightToLeft()"); - - // Create a new document. - using (DocX document = DocX.Create(@"docs\RightToLeft.docx")) - { - // Create a new Paragraph with the text "Hello World". - Paragraph p = document.InsertParagraph("Hello World."); - - // Make this Paragraph flow right to left. Default is left to right. - p.Direction = Direction.RightToLeft; - - // You don't need to manually set the text direction foreach Paragraph, you can just call this function. - document.SetDirection(Direction.RightToLeft); - - // Save all changes made to this document. - document.Save(); - Console.WriteLine("\tCreated: docs\\RightToLeft.docx\n"); - } - } - - /// - /// Creates a document with a Hyperlink, an Image and a Table. - /// - private static void HyperlinksImagesTables() - { - Console.WriteLine("\tHyperlinksImagesTables()"); - - // Create a document. - using (DocX document = DocX.Create(@"docs\HyperlinksImagesTables.docx")) - { - // Add a hyperlink into the document. - Hyperlink link = document.AddHyperlink("link", new Uri("http://www.google.com")); - - // Add a Table into the document. - Table table = document.AddTable(2, 2); - table.Design = TableDesign.ColorfulGridAccent2; - table.Alignment = Alignment.center; - table.Rows[0].Cells[0].Paragraphs[0].Append("1"); - table.Rows[0].Cells[1].Paragraphs[0].Append("2"); - table.Rows[1].Cells[0].Paragraphs[0].Append("3"); - table.Rows[1].Cells[1].Paragraphs[0].Append("4"); - - Row newRow = table.InsertRow(table.Rows[1]); - newRow.ReplaceText("4", "5"); - - // Add an image into the document. - RelativeDirectory rd = new RelativeDirectory(); // prepares the files for testing - rd.Up(2); - Image image = document.AddImage(rd.Path + @"\images\logo_template.png"); - - // Create a picture (A custom view of an Image). - Picture picture = image.CreatePicture(); - picture.Rotation = 10; - picture.SetPictureShape(BasicShapes.cube); - - // Insert a new Paragraph into the document. - Paragraph title = document.InsertParagraph().Append("Test").FontSize(20).Font(new Font("Comic Sans MS")); - title.Alignment = Alignment.center; - - // Insert a new Paragraph into the document. - Paragraph p1 = document.InsertParagraph(); - - // Append content to the Paragraph - p1.AppendLine("This line contains a ").Append("bold").Bold().Append(" word."); - p1.AppendLine("Here is a cool ").AppendHyperlink(link).Append("."); - p1.AppendLine(); - p1.AppendLine("Check out this picture ").AppendPicture(picture).Append(" its funky don't you think?"); - p1.AppendLine(); - p1.AppendLine("Can you check this Table of figures for me?"); - p1.AppendLine(); - - // Insert the Table after Paragraph 1. - p1.InsertTableAfterSelf(table); - - // Insert a new Paragraph into the document. - Paragraph p2 = document.InsertParagraph(); - - // Append content to the Paragraph. - p2.AppendLine("Is it correct?"); - - // Save this document. - document.Save(); - - Console.WriteLine("\tCreated: docs\\HyperlinksImagesTables.docx\n"); - } - } - private static void HyperlinksImagesTablesWithLists() - { - Console.WriteLine("\tHyperlinksImagesTablesWithLists()"); - - // Create a document. - using (DocX document = DocX.Create(@"docs\HyperlinksImagesTablesWithLists.docx")) - { - // Add a hyperlink into the document. - Hyperlink link = document.AddHyperlink("link", new Uri("http://www.google.com")); - - // created numbered lists - var numberedList = document.AddList("First List Item.", 0, ListItemType.Numbered, 1); - document.AddListItem(numberedList, "First sub list item", 1); - document.AddListItem(numberedList, "Second List Item."); - document.AddListItem(numberedList, "Third list item."); - document.AddListItem(numberedList, "Nested item.", 1); - document.AddListItem(numberedList, "Second nested item.", 1); - - // created bulleted lists - - var bulletedList = document.AddList("First Bulleted Item.", 0, ListItemType.Bulleted); - document.AddListItem(bulletedList, "Second bullet item"); - document.AddListItem(bulletedList, "Sub bullet item", 1); - document.AddListItem(bulletedList, "Second sub bullet item", 1); - document.AddListItem(bulletedList, "Third bullet item"); - - - // Add a Table into the document. - Table table = document.AddTable(2, 2); - table.Design = TableDesign.ColorfulGridAccent2; - table.Alignment = Alignment.center; - table.Rows[0].Cells[0].Paragraphs[0].Append("1"); - table.Rows[0].Cells[1].Paragraphs[0].Append("2"); - table.Rows[1].Cells[0].Paragraphs[0].Append("3"); - table.Rows[1].Cells[1].Paragraphs[0].Append("4"); - - Row newRow = table.InsertRow(table.Rows[1]); - newRow.ReplaceText("4", "5"); - - // Add an image into the document. - RelativeDirectory rd = new RelativeDirectory(); // prepares the files for testing - rd.Up(2); - Image image = document.AddImage(rd.Path + @"\images\logo_template.png"); - - // Create a picture (A custom view of an Image). - Picture picture = image.CreatePicture(); - picture.Rotation = 10; - picture.SetPictureShape(BasicShapes.cube); - - // Insert a new Paragraph into the document. - Paragraph title = document.InsertParagraph().Append("Test").FontSize(20).Font(new Font("Comic Sans MS")); - title.Alignment = Alignment.center; - - - - // Insert a new Paragraph into the document. - Paragraph p1 = document.InsertParagraph(); - - // Append content to the Paragraph - p1.AppendLine("This line contains a ").Append("bold").Bold().Append(" word."); - p1.AppendLine("Here is a cool ").AppendHyperlink(link).Append("."); - p1.AppendLine(); - p1.AppendLine("Check out this picture ").AppendPicture(picture).Append(" its funky don't you think?"); - p1.AppendLine(); - p1.AppendLine("Can you check this Table of figures for me?"); - p1.AppendLine(); - - // Insert the Table after Paragraph 1. - p1.InsertTableAfterSelf(table); - - // Insert a new Paragraph into the document. - Paragraph p2 = document.InsertParagraph(); - - // Append content to the Paragraph. - p2.AppendLine("Is it correct?"); - p2.AppendLine(); - p2.AppendLine("Adding bullet list below: "); - - document.InsertList(bulletedList); - - // Adding another paragraph to add table and bullet list after it - Paragraph p3 = document.InsertParagraph(); - p3.AppendLine(); - p3.AppendLine("Adding another table..."); - - // Adding another table - Table table1 = document.AddTable(2, 2); - table1.Design = TableDesign.ColorfulGridAccent2; - table1.Alignment = Alignment.center; - table1.Rows[0].Cells[0].Paragraphs[0].Append("1"); - table1.Rows[0].Cells[1].Paragraphs[0].Append("2"); - table1.Rows[1].Cells[0].Paragraphs[0].Append("3"); - table1.Rows[1].Cells[1].Paragraphs[0].Append("4"); - - Paragraph p4 = document.InsertParagraph(); - p4.InsertTableBeforeSelf(table1); - - p4.AppendLine(); - - - // Insert numbered list after table - Paragraph p5 = document.InsertParagraph(); - p5.AppendLine("Adding numbered list below: "); - p5.AppendLine(); - document.InsertList(numberedList); - - - - - // Save this document. - document.Save(); - - Console.WriteLine("\tCreated: docs\\HyperlinksImagesTablesWithLists.docx\n"); - } - } - - private static void DocumentMargins() - { - Console.WriteLine("\tDocumentMargins()"); - - // Create a document. - using (DocX document = DocX.Create(@"docs\DocumentMargins.docx")) - { - - // Create a float var that contains doc Margins properties. - float leftMargin = document.MarginLeft; - float rightMargin = document.MarginRight; - float topMargin = document.MarginTop; - float bottomMargin = document.MarginBottom; - // Modify using your own vars. - leftMargin = 95F; - rightMargin = 45F; - topMargin = 50F; - bottomMargin = 180F; - - // Or simply work the margins by setting the property directly. - document.MarginLeft = leftMargin; - document.MarginRight = rightMargin; - document.MarginTop = topMargin; - document.MarginBottom = bottomMargin; - - // created bulleted lists - - var bulletedList = document.AddList("First Bulleted Item.", 0, ListItemType.Bulleted); - document.AddListItem(bulletedList, "Second bullet item"); - document.AddListItem(bulletedList, "Sub bullet item", 1); - document.AddListItem(bulletedList, "Second sub bullet item", 1); - document.AddListItem(bulletedList, "Third bullet item"); - - - document.InsertList(bulletedList); - - // Save this document. - document.Save(); - - Console.WriteLine("\tCreated: docs\\DocumentMargins.docx\n"); - } - } - - private static void DocumentsWithListsFontChange() - { - Console.WriteLine("\tDocumentsWithListsFontChange()"); - - // Create a document. - using (DocX document = DocX.Create(@"docs\DocumentsWithListsFontChange.docx")) - { - foreach (var oneFontFamily in WindowsFontFamily.Families) - { - var fontFamily = new Font(oneFontFamily.Name); - var fontSize = 15.0; - - // created numbered lists - var numberedList = document.AddList("First List Item.", 0, ListItemType.Numbered, 1); - document.AddListItem(numberedList, "First sub list item", 1); - document.AddListItem(numberedList, "Second List Item."); - document.AddListItem(numberedList, "Third list item."); - document.AddListItem(numberedList, "Nested item.", 1); - document.AddListItem(numberedList, "Second nested item.", 1); - - // created bulleted lists - - var bulletedList = document.AddList("First Bulleted Item.", 0, ListItemType.Bulleted); - document.AddListItem(bulletedList, "Second bullet item"); - document.AddListItem(bulletedList, "Sub bullet item", 1); - document.AddListItem(bulletedList, "Second sub bullet item", 1); - document.AddListItem(bulletedList, "Third bullet item"); - - document.InsertList(bulletedList); - document.InsertList(numberedList, fontFamily, fontSize); - } - - // Save this document. - document.Save(); - - Console.WriteLine("\tCreated: docs\\DocumentsWithListsFontChange.docx\n"); - } - } - - private static void AddList() - { - Console.WriteLine("\tAddList()"); - - using (var document = DocX.Create(@"docs\Lists.docx")) - { - var numberedList = document.AddList("First List Item.", 0, ListItemType.Numbered); - //Add a numbered list starting at 2 - document.AddListItem(numberedList, "Second List Item."); - document.AddListItem(numberedList, "Third list item."); - document.AddListItem(numberedList, "First sub list item", 1); - - document.AddListItem(numberedList, "Nested item.", 2); - document.AddListItem(numberedList, "Fourth nested item."); - - var bulletedList = document.AddList("First Bulleted Item.", 0, ListItemType.Bulleted); - document.AddListItem(bulletedList, "Second bullet item"); - document.AddListItem(bulletedList, "Sub bullet item", 1); - document.AddListItem(bulletedList, "Second sub bullet item", 2); - document.AddListItem(bulletedList, "Third bullet item"); - - document.InsertList(numberedList); - document.InsertList(bulletedList); - document.Save(); - Console.WriteLine("\tCreated: docs\\Lists.docx"); - } - } - - private static void HeadersAndFooters() - { - Console.WriteLine("\tHeadersAndFooters()"); - - // Create a new document. - using (DocX document = DocX.Create(@"docs\HeadersAndFooters.docx")) - { - // Add Headers and Footers to this document. - document.AddHeaders(); - document.AddFooters(); - - // Force the first page to have a different Header and Footer. - document.DifferentFirstPage = true; - - // Force odd & even pages to have different Headers and Footers. - document.DifferentOddAndEvenPages = true; - - // Get the first, odd and even Headers for this document. - Header header_first = document.Headers.first; - Header header_odd = document.Headers.odd; - Header header_even = document.Headers.even; - - // Get the first, odd and even Footer for this document. - Footer footer_first = document.Footers.first; - Footer footer_odd = document.Footers.odd; - Footer footer_even = document.Footers.even; - - // Insert a Paragraph into the first Header. - Paragraph p0 = header_first.InsertParagraph(); - p0.Append("Hello First Header.").Bold(); - - // Insert a Paragraph into the odd Header. - Paragraph p1 = header_odd.InsertParagraph(); - p1.Append("Hello Odd Header.").Bold(); - - // Insert a Paragraph into the even Header. - Paragraph p2 = header_even.InsertParagraph(); - p2.Append("Hello Even Header.").Bold(); - - // Insert a Paragraph into the first Footer. - Paragraph p3 = footer_first.InsertParagraph(); - p3.Append("Hello First Footer.").Bold(); - - // Insert a Paragraph into the odd Footer. - Paragraph p4 = footer_odd.InsertParagraph(); - p4.Append("Hello Odd Footer.").Bold(); - - // Insert a Paragraph into the even Header. - Paragraph p5 = footer_even.InsertParagraph(); - p5.Append("Hello Even Footer.").Bold(); - - // Insert a Paragraph into the document. - Paragraph p6 = document.InsertParagraph(); - p6.AppendLine("Hello First page."); - - // Create a second page to show that the first page has its own header and footer. - p6.InsertPageBreakAfterSelf(); - - // Insert a Paragraph after the page break. - Paragraph p7 = document.InsertParagraph(); - p7.AppendLine("Hello Second page."); - - // Create a third page to show that even and odd pages have different headers and footers. - p7.InsertPageBreakAfterSelf(); - - // Insert a Paragraph after the page break. - Paragraph p8 = document.InsertParagraph(); - p8.AppendLine("Hello Third page."); - - //Insert a next page break, which is a section break combined with a page break - document.InsertSectionPageBreak(); - - //Insert a paragraph after the "Next" page break - Paragraph p9 = document.InsertParagraph(); - p9.Append("Next page section break."); - - //Insert a continuous section break - document.InsertSection(); - - //Create a paragraph in the new section - var p10 = document.InsertParagraph(); - p10.Append("Continuous section paragraph."); - - // Save all changes to this document. - document.Save(); - - Console.WriteLine("\tCreated: docs\\HeadersAndFooters.docx\n"); - }// Release this document from memory. - } - private static void HeadersAndFootersWithImagesAndTables() - { - Console.WriteLine("\tHeadersAndFootersWithImagesAndTables()"); - - // Create a new document. - using (DocX document = DocX.Create(@"docs\HeadersAndFootersWithImagesAndTables.docx")) - { - // Add a template logo image to this document. - RelativeDirectory rd = new RelativeDirectory(); // prepares the files for testing - rd.Up(2); - Image logo = document.AddImage(rd.Path + @"\images\logo_the_happy_builder.png"); - - // Add Headers and Footers to this document. - document.AddHeaders(); - document.AddFooters(); - - // Force the first page to have a different Header and Footer. - document.DifferentFirstPage = true; - - // Force odd & even pages to have different Headers and Footers. - document.DifferentOddAndEvenPages = true; - - // Get the first, odd and even Headers for this document. - Header header_first = document.Headers.first; - Header header_odd = document.Headers.odd; - Header header_even = document.Headers.even; - - // Get the first, odd and even Footer for this document. - Footer footer_first = document.Footers.first; - Footer footer_odd = document.Footers.odd; - Footer footer_even = document.Footers.even; - - // Insert a Paragraph into the first Header. - Paragraph p0 = header_first.InsertParagraph(); - p0.Append("Hello First Header.").Bold(); - - - - // Insert a Paragraph into the odd Header. - Paragraph p1 = header_odd.InsertParagraph(); - p1.Append("Hello Odd Header.").Bold(); - - - // Insert a Paragraph into the even Header. - Paragraph p2 = header_even.InsertParagraph(); - p2.Append("Hello Even Header.").Bold(); - - // Insert a Paragraph into the first Footer. - Paragraph p3 = footer_first.InsertParagraph(); - p3.Append("Hello First Footer.").Bold(); - - // Insert a Paragraph into the odd Footer. - Paragraph p4 = footer_odd.InsertParagraph(); - p4.Append("Hello Odd Footer.").Bold(); - - // Insert a Paragraph into the even Header. - Paragraph p5 = footer_even.InsertParagraph(); - p5.Append("Hello Even Footer.").Bold(); - - // Insert a Paragraph into the document. - Paragraph p6 = document.InsertParagraph(); - p6.AppendLine("Hello First page."); - - // Create a second page to show that the first page has its own header and footer. - p6.InsertPageBreakAfterSelf(); +/*************************************************************************************** - // Insert a Paragraph after the page break. - Paragraph p7 = document.InsertParagraph(); - p7.AppendLine("Hello Second page."); + DocX – DocX is the community edition of Xceed Words for .NET - // Create a third page to show that even and odd pages have different headers and footers. - p7.InsertPageBreakAfterSelf(); + Copyright (C) 2009-2017 Xceed Software Inc. - // Insert a Paragraph after the page break. - Paragraph p8 = document.InsertParagraph(); - p8.AppendLine("Hello Third page."); + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license - //Insert a next page break, which is a section break combined with a page break - document.InsertSectionPageBreak(); + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ - //Insert a paragraph after the "Next" page break - Paragraph p9 = document.InsertParagraph(); - p9.Append("Next page section break."); - - //Insert a continuous section break - document.InsertSection(); - - //Create a paragraph in the new section - var p10 = document.InsertParagraph(); - p10.Append("Continuous section paragraph."); - - - // Inserting logo into footer and header into Tables - - #region Company Logo in Header in Table - // Insert Table into First Header - Create a new Table with 2 columns and 1 rows. - Table header_first_table = header_first.InsertTable(1, 2); - header_first_table.Design = TableDesign.TableGrid; - header_first_table.AutoFit = AutoFit.Window; - // Get the upper right Paragraph in the layout_table. - Paragraph upperRightParagraph = header_first.Tables[0].Rows[0].Cells[1].Paragraphs[0]; - // Insert this template logo into the upper right Paragraph of Table. - upperRightParagraph.AppendPicture(logo.CreatePicture()); - upperRightParagraph.Alignment = Alignment.right; - - // Get the upper left Paragraph in the layout_table. - Paragraph upperLeftParagraphFirstTable = header_first.Tables[0].Rows[0].Cells[0].Paragraphs[0]; - upperLeftParagraphFirstTable.Append("Company Name - DocX Corporation"); - #endregion - - - #region Company Logo in Header in Invisible Table - // Insert Table into First Header - Create a new Table with 2 columns and 1 rows. - Table header_second_table = header_odd.InsertTable(1, 2); - header_second_table.Design = TableDesign.None; - header_second_table.AutoFit = AutoFit.Window; - // Get the upper right Paragraph in the layout_table. - Paragraph upperRightParagraphSecondTable = header_second_table.Rows[0].Cells[1].Paragraphs[0]; - // Insert this template logo into the upper right Paragraph of Table. - upperRightParagraphSecondTable.AppendPicture(logo.CreatePicture()); - upperRightParagraphSecondTable.Alignment = Alignment.right; - - // Get the upper left Paragraph in the layout_table. - Paragraph upperLeftParagraphSecondTable = header_second_table.Rows[0].Cells[0].Paragraphs[0]; - upperLeftParagraphSecondTable.Append("Company Name - DocX Corporation"); - #endregion - - #region Company Logo in Footer in Table - // Insert Table into First Header - Create a new Table with 2 columns and 1 rows. - Table footer_first_table = footer_first.InsertTable(1, 2); - footer_first_table.Design = TableDesign.TableGrid; - footer_first_table.AutoFit = AutoFit.Window; - // Get the upper right Paragraph in the layout_table. - Paragraph upperRightParagraphFooterParagraph = footer_first.Tables[0].Rows[0].Cells[1].Paragraphs[0]; - // Insert this template logo into the upper right Paragraph of Table. - upperRightParagraphFooterParagraph.AppendPicture(logo.CreatePicture()); - upperRightParagraphFooterParagraph.Alignment = Alignment.right; - - // Get the upper left Paragraph in the layout_table. - Paragraph upperLeftParagraphFirstTableFooter = footer_first.Tables[0].Rows[0].Cells[0].Paragraphs[0]; - upperLeftParagraphFirstTableFooter.Append("Company Name - DocX Corporation"); - #endregion - - - - #region Company Logo in Header in Invisible Table - // Insert Table into First Header - Create a new Table with 2 columns and 1 rows. - Table footer_second_table = footer_odd.InsertTable(1, 2); - footer_second_table.Design = TableDesign.None; - footer_second_table.AutoFit = AutoFit.Window; - // Get the upper right Paragraph in the layout_table. - Paragraph upperRightParagraphSecondTableFooter = footer_second_table.Rows[0].Cells[1].Paragraphs[0]; - // Insert this template logo into the upper right Paragraph of Table. - upperRightParagraphSecondTableFooter.AppendPicture(logo.CreatePicture()); - upperRightParagraphSecondTableFooter.Alignment = Alignment.right; - - // Get the upper left Paragraph in the layout_table. - Paragraph upperLeftParagraphSecondTableFooter = footer_second_table.Rows[0].Cells[0].Paragraphs[0]; - upperLeftParagraphSecondTableFooter.Append("Company Name - DocX Corporation"); - #endregion - - // Save all changes to this document. - document.Save(); - - Console.WriteLine("\tCreated: docs\\HeadersAndFootersWithImagesAndTables.docx\n"); - }// Release this document from memory. - } - private static void HeadersAndFootersWithImagesAndTablesUsingInsertPicture() - { - Console.WriteLine("\tHeadersAndFootersWithImagesAndTablesUsingInsertPicture()"); - - // Create a new document. - using (DocX document = DocX.Create(@"docs\HeadersAndFootersWithImagesAndTablesUsingInsertPicture.docx")) - { - // Add a template logo image to this document. - RelativeDirectory rd = new RelativeDirectory(); // prepares the files for testing - rd.Up(2); - Image logo = document.AddImage(rd.Path + @"\images\logo_the_happy_builder.png"); - - // Add Headers and Footers to this document. - document.AddHeaders(); - document.AddFooters(); - - // Force the first page to have a different Header and Footer. - document.DifferentFirstPage = true; - - // Force odd & even pages to have different Headers and Footers. - document.DifferentOddAndEvenPages = true; - - // Get the first, odd and even Headers for this document. - Header header_first = document.Headers.first; - Header header_odd = document.Headers.odd; - Header header_even = document.Headers.even; - - // Get the first, odd and even Footer for this document. - Footer footer_first = document.Footers.first; - Footer footer_odd = document.Footers.odd; - Footer footer_even = document.Footers.even; - - // Insert a Paragraph into the first Header. - Paragraph p0 = header_first.InsertParagraph(); - p0.Append("Hello First Header.").Bold(); - - - - // Insert a Paragraph into the odd Header. - Paragraph p1 = header_odd.InsertParagraph(); - p1.Append("Hello Odd Header.").Bold(); - - - // Insert a Paragraph into the even Header. - Paragraph p2 = header_even.InsertParagraph(); - p2.Append("Hello Even Header.").Bold(); - - // Insert a Paragraph into the first Footer. - Paragraph p3 = footer_first.InsertParagraph(); - p3.Append("Hello First Footer.").Bold(); - - // Insert a Paragraph into the odd Footer. - Paragraph p4 = footer_odd.InsertParagraph(); - p4.Append("Hello Odd Footer.").Bold(); - - // Insert a Paragraph into the even Header. - Paragraph p5 = footer_even.InsertParagraph(); - p5.Append("Hello Even Footer.").Bold(); - - // Insert a Paragraph into the document. - Paragraph p6 = document.InsertParagraph(); - p6.AppendLine("Hello First page."); - - // Create a second page to show that the first page has its own header and footer. - p6.InsertPageBreakAfterSelf(); - - // Insert a Paragraph after the page break. - Paragraph p7 = document.InsertParagraph(); - p7.AppendLine("Hello Second page."); - - // Create a third page to show that even and odd pages have different headers and footers. - p7.InsertPageBreakAfterSelf(); - - // Insert a Paragraph after the page break. - Paragraph p8 = document.InsertParagraph(); - p8.AppendLine("Hello Third page."); - - //Insert a next page break, which is a section break combined with a page break - document.InsertSectionPageBreak(); - - //Insert a paragraph after the "Next" page break - Paragraph p9 = document.InsertParagraph(); - p9.Append("Next page section break."); - - //Insert a continuous section break - document.InsertSection(); - - //Create a paragraph in the new section - var p10 = document.InsertParagraph(); - p10.Append("Continuous section paragraph."); - - - // Inserting logo into footer and header into Tables - - #region Company Logo in Header in Table - // Insert Table into First Header - Create a new Table with 2 columns and 1 rows. - Table header_first_table = header_first.InsertTable(1, 2); - header_first_table.Design = TableDesign.TableGrid; - header_first_table.AutoFit = AutoFit.Window; - // Get the upper right Paragraph in the layout_table. - Paragraph upperRightParagraph = header_first.Tables[0].Rows[0].Cells[1].Paragraphs[0]; - // Insert this template logo into the upper right Paragraph of Table. - upperRightParagraph.InsertPicture(logo.CreatePicture()); - upperRightParagraph.Alignment = Alignment.right; - - // Get the upper left Paragraph in the layout_table. - Paragraph upperLeftParagraphFirstTable = header_first.Tables[0].Rows[0].Cells[0].Paragraphs[0]; - upperLeftParagraphFirstTable.Append("Company Name - DocX Corporation"); - #endregion - - - #region Company Logo in Header in Invisible Table - // Insert Table into First Header - Create a new Table with 2 columns and 1 rows. - Table header_second_table = header_odd.InsertTable(1, 2); - header_second_table.Design = TableDesign.None; - header_second_table.AutoFit = AutoFit.Window; - // Get the upper right Paragraph in the layout_table. - Paragraph upperRightParagraphSecondTable = header_second_table.Rows[0].Cells[1].Paragraphs[0]; - // Insert this template logo into the upper right Paragraph of Table. - upperRightParagraphSecondTable.InsertPicture(logo.CreatePicture()); - upperRightParagraphSecondTable.Alignment = Alignment.right; - - // Get the upper left Paragraph in the layout_table. - Paragraph upperLeftParagraphSecondTable = header_second_table.Rows[0].Cells[0].Paragraphs[0]; - upperLeftParagraphSecondTable.Append("Company Name - DocX Corporation"); - #endregion - - #region Company Logo in Footer in Table - // Insert Table into First Header - Create a new Table with 2 columns and 1 rows. - Table footer_first_table = footer_first.InsertTable(1, 2); - footer_first_table.Design = TableDesign.TableGrid; - footer_first_table.AutoFit = AutoFit.Window; - // Get the upper right Paragraph in the layout_table. - Paragraph upperRightParagraphFooterParagraph = footer_first.Tables[0].Rows[0].Cells[1].Paragraphs[0]; - // Insert this template logo into the upper right Paragraph of Table. - upperRightParagraphFooterParagraph.InsertPicture(logo.CreatePicture()); - upperRightParagraphFooterParagraph.Alignment = Alignment.right; - - // Get the upper left Paragraph in the layout_table. - Paragraph upperLeftParagraphFirstTableFooter = footer_first.Tables[0].Rows[0].Cells[0].Paragraphs[0]; - upperLeftParagraphFirstTableFooter.Append("Company Name - DocX Corporation"); - #endregion - - - - #region Company Logo in Header in Invisible Table - // Insert Table into First Header - Create a new Table with 2 columns and 1 rows. - Table footer_second_table = footer_odd.InsertTable(1, 2); - footer_second_table.Design = TableDesign.None; - footer_second_table.AutoFit = AutoFit.Window; - // Get the upper right Paragraph in the layout_table. - Paragraph upperRightParagraphSecondTableFooter = footer_second_table.Rows[0].Cells[1].Paragraphs[0]; - // Insert this template logo into the upper right Paragraph of Table. - upperRightParagraphSecondTableFooter.InsertPicture(logo.CreatePicture()); - upperRightParagraphSecondTableFooter.Alignment = Alignment.right; - - // Get the upper left Paragraph in the layout_table. - Paragraph upperLeftParagraphSecondTableFooter = footer_second_table.Rows[0].Cells[0].Paragraphs[0]; - upperLeftParagraphSecondTableFooter.Append("Company Name - DocX Corporation"); - #endregion - - // Save all changes to this document. - document.Save(); - - Console.WriteLine("\tCreated: docs\\HeadersAndFootersWithImagesAndTablesUsingInsertPicture.docx\n"); - }// Release this document from memory. - } - - private static void CreateInvoice() - { - Console.WriteLine("\tCreateInvoice()"); - DocX g_document; - - try - { - // Store a global reference to the loaded document. - g_document = DocX.Load(@"docs\InvoiceTemplate.docx"); - - /* - * The template 'InvoiceTemplate.docx' does exist, - * so lets use it to create an invoice for a factitious company - * called "The Happy Builder" and store a global reference it. - */ - g_document = CreateInvoiceFromTemplate(DocX.Load(@"docs\InvoiceTemplate.docx")); - - // Save all changes made to this template as Invoice_The_Happy_Builder.docx (We don't want to replace InvoiceTemplate.docx). - g_document.SaveAs(@"docs\Invoice_The_Happy_Builder.docx"); - Console.WriteLine("\tCreated: docs\\Invoice_The_Happy_Builder.docx\n"); - } - - // The template 'InvoiceTemplate.docx' does not exist, so create it. - catch (FileNotFoundException) - { - // Create and store a global reference to the template 'InvoiceTemplate.docx'. - g_document = CreateInvoiceTemplate(); - - // Save the template 'InvoiceTemplate.docx'. - g_document.Save(); - Console.WriteLine("\tCreated: docs\\InvoiceTemplate.docx"); - - // The template exists now so re-call CreateInvoice(). - CreateInvoice(); - } - } - private static void CreateTableWithTextDirection() - { - Console.WriteLine("\tCreateTableWithTextDirection()"); - - // Create a document. - using (DocX document = DocX.Create(@"docs\\CeateTableWithTextDirection.docx")) - { - // Add a Table to this document. - Table t = document.AddTable(2, 3); - // Specify some properties for this Table. - t.Alignment = Alignment.center; - t.Design = TableDesign.MediumGrid1Accent2; - // Add content to this Table. - t.Rows[0].Cells[0].Paragraphs.First().Append("A"); - t.Rows[0].Cells[0].TextDirection = TextDirection.btLr; - t.Rows[0].Cells[1].Paragraphs.First().Append("B"); - t.Rows[0].Cells[1].TextDirection = TextDirection.btLr; - t.Rows[0].Cells[2].Paragraphs.First().Append("C"); - t.Rows[0].Cells[2].TextDirection = TextDirection.btLr; - t.Rows[1].Cells[0].Paragraphs.First().Append("D"); - t.Rows[1].Cells[1].Paragraphs.First().Append("E"); - t.Rows[1].Cells[2].Paragraphs.First().Append("F"); - // Insert the Table into the document. - document.InsertTable(t); - document.Save(); - }// Release this document from memory. - Console.WriteLine("\tCreated: docs\\CreateTableWithTextDirection.docx"); - } - - // Create an invoice for a factitious company called "The Happy Builder". - private static DocX CreateInvoiceFromTemplate(DocX template) - { - #region Logo - // A quick glance at the template shows us that the logo Paragraph is in row zero cell 1. - Paragraph logo_paragraph = template.Tables[0].Rows[0].Cells[1].Paragraphs[0]; - // Remove the template Picture that is in this Paragraph. - logo_paragraph.Pictures[0].Remove(); - - // Add the Happy Builders logo to this document. - RelativeDirectory rd = new RelativeDirectory(); // prepares the files for testing - rd.Up(2); - Image logo = template.AddImage(rd.Path + @"\images\logo_the_happy_builder.png"); - - // Insert the Happy Builders logo into this Paragraph. - logo_paragraph.InsertPicture(logo.CreatePicture()); - #endregion - - #region Set CustomProperty values - // Set the value of the custom property 'company_name'. - template.AddCustomProperty(new CustomProperty("company_name", "The Happy Builder")); - - // Set the value of the custom property 'company_slogan'. - template.AddCustomProperty(new CustomProperty("company_slogan", "No job too small")); - - // Set the value of the custom properties 'hired_company_address_line_one', 'hired_company_address_line_two' and 'hired_company_address_line_three'. - template.AddCustomProperty(new CustomProperty("hired_company_address_line_one", "The Crooked House,")); - template.AddCustomProperty(new CustomProperty("hired_company_address_line_two", "Dublin,")); - template.AddCustomProperty(new CustomProperty("hired_company_address_line_three", "12345")); - - // Set the value of the custom property 'invoice_date'. - template.AddCustomProperty(new CustomProperty("invoice_date", DateTime.Today.Date.ToString("d"))); - - // Set the value of the custom property 'invoice_number'. - template.AddCustomProperty(new CustomProperty("invoice_number", 1)); - - // Set the value of the custom property 'hired_company_details_line_one' and 'hired_company_details_line_two'. - template.AddCustomProperty(new CustomProperty("hired_company_details_line_one", "Business Street, Dublin, 12345")); - template.AddCustomProperty(new CustomProperty("hired_company_details_line_two", "Phone: 012-345-6789, Fax: 012-345-6789, e-mail: support@thehappybuilder.com")); - #endregion - - /* - * InvoiceTemplate.docx contains a blank Table, - * we want to replace this with a new Table that - * contains all of our invoice data. - */ - Table t = template.Tables[1]; - Table invoice_table = CreateAndInsertInvoiceTableAfter(t, ref template); - t.Remove(); - - // Return the template now that it has been modified to hold all of our custom data. - return template; - } - - // Create an invoice template. - private static DocX CreateInvoiceTemplate() - { - // Create a new document. - DocX document = DocX.Create(@"docs\InvoiceTemplate.docx"); - - // Create a table for layout purposes (This table will be invisible). - Table layout_table = document.InsertTable(2, 2); - layout_table.Design = TableDesign.TableNormal; - layout_table.AutoFit = AutoFit.Window; - - // Dark formatting - Formatting dark_formatting = new Formatting(); - dark_formatting.Bold = true; - dark_formatting.Size = 12; - dark_formatting.FontColor = WindowsColor.FromArgb(31, 73, 125); - - // Light formatting - Formatting light_formatting = new Formatting(); - light_formatting.Italic = true; - light_formatting.Size = 11; - light_formatting.FontColor = WindowsColor.FromArgb(79, 129, 189); - - #region Company Name - // Get the upper left Paragraph in the layout_table. - Paragraph upper_left_paragraph = layout_table.Rows[0].Cells[0].Paragraphs[0]; - - // Create a custom property called company_name - CustomProperty company_name = new CustomProperty("company_name", "Company Name"); - - // Insert a field of type doc property (This will display the custom property 'company_name') - layout_table.Rows[0].Cells[0].Paragraphs[0].InsertDocProperty(company_name, f: dark_formatting); - - // Force the next text insert to be on a new line. - upper_left_paragraph.InsertText("\n", false); - #endregion - - #region Company Slogan - // Create a custom property called company_slogan - CustomProperty company_slogan = new CustomProperty("company_slogan", "Company slogan goes here."); - - // Insert a field of type doc property (This will display the custom property 'company_slogan') - upper_left_paragraph.InsertDocProperty(company_slogan, f: light_formatting); - #endregion - - #region Company Logo - // Get the upper right Paragraph in the layout_table. - Paragraph upper_right_paragraph = layout_table.Rows[0].Cells[1].Paragraphs[0]; - - // Add a template logo image to this document. - RelativeDirectory rd = new RelativeDirectory(); // prepares the files for testing - rd.Up(2); - Image logo = document.AddImage(rd.Path + @"\images\logo_template.png"); - - // Insert this template logo into the upper right Paragraph. - upper_right_paragraph.InsertPicture(logo.CreatePicture()); - - upper_right_paragraph.Alignment = Alignment.right; - #endregion - - // Custom properties cannot contain newlines, so the company address must be split into 3 custom properties. - #region Hired Company Address - // Create a custom property called company_address_line_one - CustomProperty hired_company_address_line_one = new CustomProperty("hired_company_address_line_one", "Street Address,"); - - // Get the lower left Paragraph in the layout_table. - Paragraph lower_left_paragraph = layout_table.Rows[1].Cells[0].Paragraphs[0]; - lower_left_paragraph.InsertText("TO:\n", false, dark_formatting); - - // Insert a field of type doc property (This will display the custom property 'hired_company_address_line_one') - lower_left_paragraph.InsertDocProperty(hired_company_address_line_one, f: light_formatting); - - // Force the next text insert to be on a new line. - lower_left_paragraph.InsertText("\n", false); - - // Create a custom property called company_address_line_two - CustomProperty hired_company_address_line_two = new CustomProperty("hired_company_address_line_two", "City,"); - - // Insert a field of type doc property (This will display the custom property 'hired_company_address_line_two') - lower_left_paragraph.InsertDocProperty(hired_company_address_line_two, f: light_formatting); - - // Force the next text insert to be on a new line. - lower_left_paragraph.InsertText("\n", false); - - // Create a custom property called company_address_line_two - CustomProperty hired_company_address_line_three = new CustomProperty("hired_company_address_line_three", "Zip Code"); - - // Insert a field of type doc property (This will display the custom property 'hired_company_address_line_three') - lower_left_paragraph.InsertDocProperty(hired_company_address_line_three, f: light_formatting); - #endregion - - #region Date & Invoice number - // Get the lower right Paragraph from the layout table. - Paragraph lower_right_paragraph = layout_table.Rows[1].Cells[1].Paragraphs[0]; - - CustomProperty invoice_date = new CustomProperty("invoice_date", DateTime.Today.Date.ToString("d")); - lower_right_paragraph.InsertText("Date: ", false, dark_formatting); - lower_right_paragraph.InsertDocProperty(invoice_date, f: light_formatting); - - CustomProperty invoice_number = new CustomProperty("invoice_number", 1); - lower_right_paragraph.InsertText("\nInvoice: ", false, dark_formatting); - lower_right_paragraph.InsertText("#", false, light_formatting); - lower_right_paragraph.InsertDocProperty(invoice_number, f: light_formatting); - - lower_right_paragraph.Alignment = Alignment.right; - #endregion - - // Insert an empty Paragraph between two Tables, so that they do not touch. - document.InsertParagraph(string.Empty, false); - - // This table will hold all of the invoice data. - Table invoice_table = document.InsertTable(4, 4); - invoice_table.Design = TableDesign.LightShadingAccent1; - invoice_table.Alignment = Alignment.center; - - // A nice thank you Paragraph. - Paragraph thankyou = document.InsertParagraph("\nThank you for your business, we hope to work with you again soon.", false, dark_formatting); - thankyou.Alignment = Alignment.center; - - #region Hired company details - CustomProperty hired_company_details_line_one = new CustomProperty("hired_company_details_line_one", "Street Address, City, ZIP Code"); - CustomProperty hired_company_details_line_two = new CustomProperty("hired_company_details_line_two", "Phone: 000-000-0000, Fax: 000-000-0000, e-mail: support@companyname.com"); - - Paragraph companyDetails = document.InsertParagraph(string.Empty, false); - companyDetails.InsertDocProperty(hired_company_details_line_one, f: light_formatting); - companyDetails.InsertText("\n", false); - companyDetails.InsertDocProperty(hired_company_details_line_two, f: light_formatting); - companyDetails.Alignment = Alignment.center; - #endregion - - // Return the document now that it has been created. - return document; - } - - private static Table CreateAndInsertInvoiceTableAfter(Table t, ref DocX document) - { - // Grab data from somewhere (Most likely a database) - DataTable data = GetDataFromDatabase(); - - /* - * The trick to replacing one Table with another, - * is to insert the new Table after the old one, - * and then remove the old one. - */ - Table invoice_table = t.InsertTableAfterSelf(data.Rows.Count + 1, data.Columns.Count); - invoice_table.Design = TableDesign.LightShadingAccent1; - - #region Table title - Formatting table_title = new Formatting(); - table_title.Bold = true; - - invoice_table.Rows[0].Cells[0].Paragraphs[0].InsertText("Description", false, table_title); - invoice_table.Rows[0].Cells[0].Paragraphs[0].Alignment = Alignment.center; - invoice_table.Rows[0].Cells[1].Paragraphs[0].InsertText("Hours", false, table_title); - invoice_table.Rows[0].Cells[1].Paragraphs[0].Alignment = Alignment.center; - invoice_table.Rows[0].Cells[2].Paragraphs[0].InsertText("Rate", false, table_title); - invoice_table.Rows[0].Cells[2].Paragraphs[0].Alignment = Alignment.center; - invoice_table.Rows[0].Cells[3].Paragraphs[0].InsertText("Amount", false, table_title); - invoice_table.Rows[0].Cells[3].Paragraphs[0].Alignment = Alignment.center; - #endregion - - // Loop through the rows in the Table and insert data from the data source. - for (int row = 1; row < invoice_table.RowCount; row++) - { - for (int cell = 0; cell < invoice_table.Rows[row].Cells.Count; cell++) - { - Paragraph cell_paragraph = invoice_table.Rows[row].Cells[cell].Paragraphs[0]; - cell_paragraph.InsertText(data.Rows[row - 1].ItemArray[cell].ToString(), false); - } - } - - // We want to fill in the total by suming the values from the amount column. - Row total = invoice_table.InsertRow(); - total.Cells[0].Paragraphs[0].InsertText("Total:", false); - Paragraph total_paragraph = total.Cells[invoice_table.ColumnCount - 1].Paragraphs[0]; - - /* - * Lots of people are scared of LINQ, - * so I will walk you through this line by line. - * - * invoice_table.Rows is an IEnumerable (i.e a collection of rows), with LINQ you can query collections. - * .Where(condition) is a filter that you want to apply to the items of this collection. - * My condition is that the index of the row must be greater than 0 and less than RowCount. - * .Select(something) lets you select something from each item in the filtered collection. - * I am selecting the Text value from each row, for example €100, then I am remove the €, - * and then I am parsing the remaining string as a double. This will return a collection of doubles, - * the final thing I do is call .Sum() on this collection which return one double the sum of all the doubles, - * this is the total. - */ - double totalCost = - ( - invoice_table.Rows - .Where((row, index) => index > 0 && index < invoice_table.RowCount - 1) - .Select(row => double.Parse(row.Cells[row.Cells.Count() - 1].Paragraphs[0].Text.Remove(0, 1))) - ).Sum(); - - // Insert the total calculated above using LINQ into the total Paragraph. - total_paragraph.InsertText(string.Format("€{0}", totalCost), false); - - // Let the tables columns expand to fit its contents. - invoice_table.AutoFit = AutoFit.Contents; - - // Center the Table - invoice_table.Alignment = Alignment.center; - - // Return the invloce table now that it has been created. - return invoice_table; - } - - // You need to rewrite this function to grab data from your data source. - private static DataTable GetDataFromDatabase() - { - DataTable table = new DataTable(); - table.Columns.AddRange(new DataColumn[] { new DataColumn("Description"), new DataColumn("Hours"), new DataColumn("Rate"), new DataColumn("Amount") }); - - table.Rows.Add - ( - "Install wooden doors (Kitchen, Sitting room, Dining room & Bedrooms)", - "5", - "€25", - string.Format("€{0}", 5 * 25) - ); - - table.Rows.Add - ( - "Fit stairs", - "20", - "€30", - string.Format("€{0}", 20 * 30) - ); - - table.Rows.Add - ( - "Replace Sitting room window", - "6", - "€50", - string.Format("€{0}", 6 * 50) - ); - - table.Rows.Add - ( - "Build garden shed", - "10", - "€10", - string.Format("€{0}", 10 * 10) - ); - - table.Rows.Add - ( - "Fit new lock on back door", - "0.5", - "€30", - string.Format("€{0}", 0.5 * 30) - ); - - table.Rows.Add - ( - "Tile Kitchen floor", - "24", - "€25", - string.Format("€{0}", 24 * 25) - ); - - return table; - } - - /// - /// Creates a simple document with the text Hello World. - /// - static void HelloWorld() - { - Console.WriteLine("\tHelloWorld()"); - - // Create a new document. - using (DocX document = DocX.Create(@"docs\HelloWorld.docx")) - { - // Insert a Paragraph into this document. - Paragraph p = document.InsertParagraph(); - - // Append some text and add formatting. - p.Append("Hello World!^011Hello World!") - .Font(new Font("Times New Roman")) - .FontSize(32) - .Color(WindowsColor.Blue) - .Bold(); - - - - // Save this document to disk. - document.Save(); - Console.WriteLine("\tCreated: docs\\HelloWorld.docx\n"); - } - } - - static void HelloWorldInsertHorizontalLine() - { - Console.WriteLine("\tHelloWorldInsertHorizontalLine()"); - - // Create a new document. - using (DocX document = DocX.Create(@"docs\HelloWorldInsertHorizontalLine.docx")) - { - // Insert a Paragraph into this document. - Paragraph p = document.InsertParagraph(); - - // Append some text and add formatting. - p.Append("Hello World!^011Hello World!") - .Font(new Font("Times New Roman")) - .FontSize(32) - .Color(WindowsColor.Blue) - .Bold(); - p.InsertHorizontalLine("double", 6, 1, "auto"); - - Paragraph p1 = document.InsertParagraph(); - p1.InsertHorizontalLine("double", 6, 1, "red"); - Paragraph p2 = document.InsertParagraph(); - p2.InsertHorizontalLine("single", 6, 1, "red"); - Paragraph p3 = document.InsertParagraph(); - p3.InsertHorizontalLine("triple", 6, 1, "blue"); - Paragraph p4 = document.InsertParagraph(); - p4.InsertHorizontalLine("double", 3, 10, "red"); - - - // Save this document to disk. - document.Save(); - Console.WriteLine("\tCreated: docs\\HelloWorldInsertHorizontalLine.docx\n"); - } - } - - static void HelloWorldProtectedDocument() - { - Console.WriteLine("\tHelloWorldPasswordProtected()"); - - // Create a new document. - using (DocX document = DocX.Create(@"docs\HelloWorldPasswordProtected.docx")) - { - // Insert a Paragraph into this document. - Paragraph p = document.InsertParagraph(); - - // Append some text and add formatting. - p.Append("Hello World!^011Hello World!") - .Font(new Font("Times New Roman")) - .FontSize(32) - .Color(WindowsColor.Blue) - .Bold(); - - - // Save this document to disk with different options - // Protected with password for Read Only - EditRestrictions erReadOnly = EditRestrictions.readOnly; - document.AddProtection(erReadOnly, "SomePassword"); - document.SaveAs(@"docs\\HelloWorldPasswordProtectedReadOnly.docx"); - Console.WriteLine("\tCreated: docs\\HelloWorldPasswordProtectedReadOnly.docx\n"); - - // Protected with password for Comments - EditRestrictions erComments = EditRestrictions.comments; - document.AddProtection(erComments, "SomePassword"); - document.SaveAs(@"docs\\HelloWorldPasswordProtectedCommentsOnly.docx"); - Console.WriteLine("\tCreated: docs\\HelloWorldPasswordProtectedCommentsOnly.docx\n"); - - // Protected with password for Forms - EditRestrictions erForms = EditRestrictions.forms; - document.AddProtection(erForms, "SomePassword"); - document.SaveAs(@"docs\\HelloWorldPasswordProtectedFormsOnly.docx"); - Console.WriteLine("\tCreated: docs\\HelloWorldPasswordProtectedFormsOnly.docx\n"); - - // Protected with password for Tracked Changes - EditRestrictions erTrackedChanges = EditRestrictions.trackedChanges; - document.AddProtection(erTrackedChanges, "SomePassword"); - document.SaveAs(@"docs\\HelloWorldPasswordProtectedTrackedChangesOnly.docx"); - Console.WriteLine("\tCreated: docs\\HelloWorldPasswordProtectedTrackedChangesOnly.docx\n"); - - // But it's also possible to add restrictions without protecting it with password. - - // Protected with password for Read Only - document.AddProtection(erReadOnly); - document.SaveAs(@"docs\\HelloWorldWithoutPasswordReadOnly.docx"); - Console.WriteLine("\tCreated: docs\\HelloWorldWithoutPasswordReadOnly.docx\n"); - - // Protected with password for Comments - document.AddProtection(erComments); - document.SaveAs(@"docs\\HelloWorldWithoutPasswordCommentsOnly.docx"); - Console.WriteLine("\tCreated: docs\\HelloWorldWithoutPasswordCommentsOnly.docx\n"); - - // Protected with password for Forms - document.AddProtection(erForms); - document.SaveAs(@"docs\\HelloWorldWithoutPasswordFormsOnly.docx"); - Console.WriteLine("\tCreated: docs\\HelloWorldWithoutPasswordFormsOnly.docx\n"); - - // Protected with password for Tracked Changes - document.AddProtection(erTrackedChanges); - document.SaveAs(@"docs\\HelloWorldWithoutPasswordTrackedChangesOnly.docx"); - Console.WriteLine("\tCreated: docs\\HelloWorldWithoutPasswordTrackedChangesOnly.docx\n"); - } - } - - static void HelloWorldAdvancedFormatting() - { - Console.WriteLine("\tHelloWorldAdvancedFormatting()"); - // Create a document. - using (DocX document = DocX.Create(@"docs\HelloWorldAdvancedFormatting.docx")) - { - // Insert a new Paragraphs. - Paragraph p = document.InsertParagraph(); - - p.Append("I am ").Append("bold").Bold() - .Append(" and I am ") - .Append("italic").Italic().Append(".") - .AppendLine("I am ") - .Append("Arial Black") - .Font(new Font("Arial Black")) - .Append(" and I am not.") - .AppendLine("I am ") - .Append("BLUE").Color(WindowsColor.Blue) - .Append(" and I am") - .Append("Red").Color(WindowsColor.Red).Append("."); - - // Save this document. - document.Save(); - Console.WriteLine("\tCreated: docs\\HelloWorldAdvancedFormatting.docx\n"); - }// Release this document from memory. - } - - /// - /// Loads a document 'Input.docx' and writes the text 'Hello World' into the first imbedded Image. - /// This code creates the file 'Output.docx'. - /// - static void ProgrammaticallyManipulateImbeddedImage() - { - Console.WriteLine("\tProgrammaticallyManipulateImbeddedImage()"); - const string str = "Hello World"; - - // Open the document Input.docx. - using (DocX document = DocX.Load(@"docs\Input.docx")) - { - // Make sure this document has at least one Image. - if (document.Images.Count() > 0) - { - Image img = document.Images[0]; - - // Write "Hello World" into this Image. - var b = new WindowsBitmap(img.GetStream(FileMode.Open, FileAccess.ReadWrite)); - - /* - * Get the Graphics object for this Bitmap. - * The Graphics object provides functions for drawing. - */ - var g = WindowsGraphics.FromImage(b); - - // Draw the string "Hello World". - g.DrawString - ( - str, - new WindowsFont("Tahoma", 20), - WindowsBrushes.Blue, - 0.0f, 0.0f - ); - - // Save this Bitmap back into the document using a Create\Write stream. - b.Save(img.GetStream(FileMode.Create, FileAccess.Write), WindowsImageFormat.Png); - } - else - Console.WriteLine("The provided document contains no Images."); - - // Save this document as Output.docx. - document.SaveAs(@"docs\Output.docx"); - Console.WriteLine("\tCreated: docs\\Output.docx\n"); - } - } - - /// - /// For each of the documents in the folder 'docs\', - /// Replace the string a with the string b, - /// Do this in Parrallel accross many CPU cores. - /// - static void ReplaceTextParallel() - { - Console.WriteLine("\tReplaceTextParallel()\n"); - const string a = "apple"; - const string b = "pear"; - - // Directory containing many .docx documents. - DirectoryInfo di = new DirectoryInfo(@"docs\"); - - // Loop through each document in this specified direction. - Parallel.ForEach - ( - di.GetFiles(), - currentFile => - { - // Load the document. - using (DocX document = DocX.Load(currentFile.FullName)) - { - // Replace text in this document. - document.ReplaceText(a, b); - - // Save changes made to this document. - document.Save(); - } // Release this document from memory. - } - ); - Console.WriteLine("\tCreated: None\n"); - } - - static void AddToc() - { - Console.WriteLine("\tAddToc()"); - - using (var document = DocX.Create(@"docs\Toc.docx")) - { - document.InsertTableOfContents("I can haz table of contentz", TableOfContentsSwitches.O | TableOfContentsSwitches.U | TableOfContentsSwitches.Z | TableOfContentsSwitches.H, "Heading2"); - var h1 = document.InsertParagraph("Heading 1"); - h1.StyleName = "Heading1"; - document.InsertParagraph("Some very interesting content here"); - var h2 = document.InsertParagraph("Heading 2"); - document.InsertSectionPageBreak(); - h2.StyleName = "Heading1"; - document.InsertParagraph("Some very interesting content here as well"); - var h3 = document.InsertParagraph("Heading 2.1"); - h3.StyleName = "Heading2"; - document.InsertParagraph("Not so very interesting...."); - - document.Save(); - } - } - - static void AddTocByReference() - { - Console.WriteLine("\tAddTocByReference()"); - - using (var document = DocX.Create(@"docs\TocByReference.docx")) - { - var h1 = document.InsertParagraph("Heading 1"); - h1.StyleName = "Heading1"; - document.InsertParagraph("Some very interesting content here"); - var h2 = document.InsertParagraph("Heading 2"); - document.InsertSectionPageBreak(); - h2.StyleName = "Heading1"; - document.InsertParagraph("Some very interesting content here as well"); - var h3 = document.InsertParagraph("Heading 2.1"); - h3.StyleName = "Heading2"; - document.InsertParagraph("Not so very interesting...."); - - document.InsertTableOfContents(h2, "I can haz table of contentz", TableOfContentsSwitches.O | TableOfContentsSwitches.U | TableOfContentsSwitches.Z | TableOfContentsSwitches.H, "Heading2"); - - document.Save(); - } - } - - static void HelloWorldKeepWithNext() - { - // Create a Paragraph that will stay on the same page as the paragraph that comes next - Console.WriteLine("\tHelloWorldKeepWithNext()"); - // Create a new document. - using (DocX document = DocX.Create("docs\\HelloWorldKeepWithNext.docx")) - - { - // Create a new Paragraph with the text "Hello World". - Paragraph p = document.InsertParagraph("Hello World."); - p.KeepWithNext(); - document.InsertParagraph("Previous paragraph will appear on the same page as this paragraph"); - - // Save all changes made to this document. - document.Save(); - Console.WriteLine("\tCreated: docs\\HelloWorldKeepWithNext.docx\n"); - } - } - static void HelloWorldKeepLinesTogether() - { - // Create a Paragraph that will stay on the same page as the paragraph that comes next - Console.WriteLine("\tHelloWorldKeepLinesTogether()"); - // Create a new document. - using (DocX document = DocX.Create("docs\\HelloWorldKeepLinesTogether.docx")) - { - // Create a new Paragraph with the text "Hello World". - Paragraph p = document.InsertParagraph("All lines of this paragraph will appear on the same page...\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6..."); - p.KeepLinesTogether(); - // Save all changes made to this document. - document.Save(); - Console.WriteLine("\tCreated: docs\\HelloWorldKeepLinesTogether.docx\n"); - } - } + *************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Threading; - static void LargeTable() - { - Console.WriteLine("\tLargeTable()"); - var _directoryWithFiles = "docs\\"; - using (var output = File.Open(_directoryWithFiles + "LargeTable.docx", FileMode.Create)) - { - using (var doc = DocX.Create(output)) - { - var tbl = doc.InsertTable(1, 18); +namespace Xceed.Words.NET.Examples +{ + public class Program + { + internal const string SampleDirectory = @"..\..\Samples\"; - var wholeWidth = doc.PageWidth - doc.MarginLeft - doc.MarginRight; - var colWidth = wholeWidth / tbl.ColumnCount; - var colWidths = new int[tbl.ColumnCount]; - tbl.AutoFit = AutoFit.Contents; - var r = tbl.Rows[0]; - var cx = 0; - foreach (var cell in r.Cells) - { - cell.Paragraphs.First().Append("Col " + cx); - //cell.Width = colWidth; - cell.MarginBottom = 0; - cell.MarginLeft = 0; - cell.MarginRight = 0; - cell.MarginTop = 0; + private static void Main( string[] args ) + { - cx++; - } - tbl.SetBorder(TableBorderType.Bottom, BlankBorder); - tbl.SetBorder(TableBorderType.Left, BlankBorder); - tbl.SetBorder(TableBorderType.Right, BlankBorder); - tbl.SetBorder(TableBorderType.Top, BlankBorder); - tbl.SetBorder(TableBorderType.InsideV, BlankBorder); - tbl.SetBorder(TableBorderType.InsideH, BlankBorder); + Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo( "en-US" ); - doc.Save(); - } - } - Console.WriteLine("\tCreated: docs\\LargeTable.docx\n"); - } + //Paragraphs + ParagraphSample.SimpleFormattedParagraphs(); + ParagraphSample.ForceParagraphOnSinglePage(); + ParagraphSample.ForceMultiParagraphsOnSinglePage(); + ParagraphSample.TextActions(); + ParagraphSample.Heading(); + //Document + DocumentSample.AddCustomProperties(); + DocumentSample.ReplaceText(); + DocumentSample.ApplyTemplate(); + DocumentSample.AppendDocument(); - static void TableWithSpecifiedWidths() - { - Console.WriteLine("\tTableSpecifiedWidths()"); - var _directoryWithFiles = "docs\\"; - using (var output = File.Open(_directoryWithFiles + "TableSpecifiedWidths.docx", FileMode.Create)) - { - using (var doc = DocX.Create(output)) - { - var widths = new float[] { 200f, 100f, 300f }; - var tbl = doc.InsertTable(1, widths.Length); - tbl.SetWidths(widths); - var wholeWidth = doc.PageWidth - doc.MarginLeft - doc.MarginRight; - tbl.AutoFit = AutoFit.Contents; - var r = tbl.Rows[0]; - var cx = 0; - foreach (var cell in r.Cells) - { - cell.Paragraphs.First().Append("Col " + cx); - //cell.Width = colWidth; - cell.MarginBottom = 0; - cell.MarginLeft = 0; - cell.MarginRight = 0; - cell.MarginTop = 0; + //Images + ImageSample.AddPicture(); + ImageSample.CopyPicture(); + ImageSample.ModifyImage(); - cx++; - } - //add new rows - for (var x = 0; x < 5; x++) - { - r = tbl.InsertRow(); - cx = 0; - foreach (var cell in r.Cells) - { - cell.Paragraphs.First().Append("Col " + cx); - //cell.Width = colWidth; - cell.MarginBottom = 0; - cell.MarginLeft = 0; - cell.MarginRight = 0; - cell.MarginTop = 0; + //Indentation/Direction/Margins + MarginSample.SetDirection(); + MarginSample.Indentation(); + MarginSample.Margins(); - cx++; - } - } - tbl.SetBorder(TableBorderType.Bottom, BlankBorder); - tbl.SetBorder(TableBorderType.Left, BlankBorder); - tbl.SetBorder(TableBorderType.Right, BlankBorder); - tbl.SetBorder(TableBorderType.Top, BlankBorder); - tbl.SetBorder(TableBorderType.InsideV, BlankBorder); - tbl.SetBorder(TableBorderType.InsideH, BlankBorder); + //Header/Footers + HeaderFooterSample.HeadersFooters(); - doc.Save(); - } - } - Console.WriteLine("\tCreated: docs\\TableSpecifiedWidths.docx\n"); + //Tables + TableSample.InsertRowAndImageTable(); + TableSample.TextDirectionTable(); + TableSample.CreateRowsFromTemplate(); + TableSample.ColumnsWidth(); + TableSample.MergeCells(); - } + //Hyperlink + HyperlinkSample.Hyperlinks(); - /// - /// Create a document with two pictures. One picture is inserted normal way, the other one with rotation - /// - static void HelloWorldAddPictureToWord() - { - Console.WriteLine("\tHelloWorldAddPictureToWord()"); + //Section + SectionSample.InsertSections(); - // Create a document. - using (DocX document = DocX.Create(@"docs\HelloWorldAddPictureToWord.docx")) - { - // Add an image into the document. - RelativeDirectory rd = new RelativeDirectory(); // prepares the files for testing - rd.Up(2); - Image image = document.AddImage(rd.Path + @"\images\logo_template.png"); + //Lists + ListSample.AddList(); - // Create a picture (A custom view of an Image). - Picture picture = image.CreatePicture(); - picture.Rotation = 10; - picture.SetPictureShape(BasicShapes.cube); + //Equations + EquationSample.InsertEquation(); - // Insert a new Paragraph into the document. - Paragraph title = document.InsertParagraph().Append("This is a test for a picture").FontSize(20).Font(new Font("Comic Sans MS")); - title.Alignment = Alignment.center; + //Bookmarks + BookmarkSample.InsertBookmarks(); + BookmarkSample.ReplaceText(); - // Insert a new Paragraph into the document. - Paragraph p1 = document.InsertParagraph(); + //Charts + ChartSample.BarChart(); + ChartSample.LineChart(); + ChartSample.PieChart(); + ChartSample.Chart3D(); - // Append content to the Paragraph - p1.AppendLine("Just below there should be a picture ").Append("picture").Bold().Append(" inserted in a non-conventional way."); - p1.AppendLine(); - p1.AppendLine("Check out this picture ").AppendPicture(picture).Append(" its funky don't you think?"); - p1.AppendLine(); + //Tale of Content + TableOfContentSample.InsertTableOfContent(); + TableOfContentSample.InsertTableOfContentWithReference(); - // Insert a new Paragraph into the document. - Paragraph p2 = document.InsertParagraph(); - // Append content to the Paragraph. + //Lines + LineSample.InsertHorizontalLine(); - p2.AppendLine("Is it correct?"); - p2.AppendLine(); + //Protection + ProtectionSample.AddPasswordProtection(); + ProtectionSample.AddProtection(); - // Lets add another picture (without the fancy stuff) - Picture pictureNormal = image.CreatePicture(); + //Parallel + ParallelSample.DoParallelActions(); - Paragraph p3 = document.InsertParagraph(); - p3.AppendLine("Lets add another picture (without the fancy rotation stuff)"); - p3.AppendLine(); - p3.AppendPicture(pictureNormal); + //Others + MiscellaneousSample.CreateRecipe(); + MiscellaneousSample.CompanyReport(); + MiscellaneousSample.CreateInvoice(); - // Save this document. - document.Save(); - Console.WriteLine("\tCreated: docs\\HelloWorldAddPictureToWord.docx\n"); - } - } + Console.WriteLine( "\nPress any key to exit." ); + Console.ReadKey(); + } + #region Charts + private class ChartData + { + public String Mounth + { + get; set; + } + public Double Money + { + get; set; + } + + public static List CreateCompanyList1() + { + List company1 = new List(); + company1.Add( new ChartData() { Mounth = "January", Money = 100 } ); + company1.Add( new ChartData() { Mounth = "February", Money = 120 } ); + company1.Add( new ChartData() { Mounth = "March", Money = 140 } ); + return company1; + } + + public static List CreateCompanyList2() + { + List company2 = new List(); + company2.Add( new ChartData() { Mounth = "January", Money = 80 } ); + company2.Add( new ChartData() { Mounth = "February", Money = 160 } ); + company2.Add( new ChartData() { Mounth = "March", Money = 130 } ); + return company2; + } } + + #endregion + } } diff --git a/Examples/Properties/AssemblyInfo.cs b/Examples/Properties/AssemblyInfo.cs index 4da500ed..425591fa 100644 --- a/Examples/Properties/AssemblyInfo.cs +++ b/Examples/Properties/AssemblyInfo.cs @@ -1,36 +1,28 @@ -using System.Reflection; +using System; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Examples")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Examples")] -[assembly: AssemblyCopyright("Copyright © 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] +[assembly: AssemblyTitle( "Xceed Words for .NET - Examples" )] +[assembly: AssemblyDescription( "This assembly contains the Examples for Xceed Words for .NET." )] + +[assembly: AssemblyCompany( "Xceed Software Inc." )] +[assembly: AssemblyProduct( "Xceed Words for .NET" )] +[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2009-2017" )] +[assembly: AssemblyCulture( "" )] + // 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 // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("b18a3992-244e-430f-8ba2-cc3dd17971e6")] +#pragma warning disable 1699 +[assembly: AssemblyDelaySign( false )] +[assembly: AssemblyKeyFile( @"..\..\..\sn.snk" )] +[assembly: AssemblyKeyName( "" )] +#pragma warning restore 1699 -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Examples/RelativeDirectory.cs b/Examples/RelativeDirectory.cs deleted file mode 100644 index 0bb56d20..00000000 --- a/Examples/RelativeDirectory.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.IO; - -namespace Examples -{ - class RelativeDirectory - { - // Author D. Bolton see http://cplus.about.com (c) 2010 - private DirectoryInfo _dirInfo; - - public string Dir - { - get - { - return _dirInfo.Name; - } - } - - public string Path - { - get { return _dirInfo.FullName; } - set - { - try - { - DirectoryInfo newDir = new DirectoryInfo(value); - _dirInfo = newDir; - } - catch - { - // silent - } - } - } - public RelativeDirectory() - { - _dirInfo = new DirectoryInfo(Environment.CurrentDirectory); - } - - public RelativeDirectory(string absoluteDir) - { - _dirInfo = new DirectoryInfo(absoluteDir); - } - - public Boolean Up(int numLevels) - { - for (int i = 0; i < numLevels; i++) - { - DirectoryInfo tempDir = _dirInfo.Parent; - if (tempDir != null) - _dirInfo = tempDir; - else - return false; - } - return true; - } - - public Boolean Up() - - { - return Up(1); - } - - public Boolean Down(string match) - { - DirectoryInfo[] dirs = _dirInfo.GetDirectories(match + '*'); - _dirInfo = dirs[0]; - return true; - } - - } - -} diff --git a/Examples/Samples/Bookmark/BookmarkSample.cs b/Examples/Samples/Bookmark/BookmarkSample.cs new file mode 100644 index 00000000..ed9e1987 --- /dev/null +++ b/Examples/Samples/Bookmark/BookmarkSample.cs @@ -0,0 +1,115 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System; +using System.IO; +using System.Linq; + +namespace Xceed.Words.NET.Examples +{ + public class BookmarkSample + { + #region Private Members + + private const string BookmarkSampleResourcesDirectory = Program.SampleDirectory + @"Bookmark\Resources\"; + private const string BookmarkSampleOutputDirectory = Program.SampleDirectory + @"Bookmark\Output\"; + + #endregion + + #region Constructors + + static BookmarkSample() + { + if( !Directory.Exists( BookmarkSample.BookmarkSampleOutputDirectory ) ) + { + Directory.CreateDirectory( BookmarkSample.BookmarkSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Insert a bookmark in a document and a paragraph(and replace the displayed bookmark). + /// + public static void InsertBookmarks() + { + Console.WriteLine( "\tInsertBookmarks()" ); + + // Create a document + using( DocX document = DocX.Create( BookmarkSample.BookmarkSampleOutputDirectory + @"InsertBookmarks.docx" ) ) + { + // Add a title + document.InsertParagraph( "Insert Bookmarks" ).FontSize( 15d ).SpacingAfter( 40d ).Alignment = Alignment.center; + + // Insert a bookmark in the document. + document.InsertBookmark( "Bookmark1" ); + + // Add a paragraph + var p = document.InsertParagraph( "This document contains a bookmark named \"" ); + p.Append( document.Bookmarks.First().Name ); + p.Append( "\" just before this line." ); + p.SpacingAfter( 50d ); + + var _bookmarkName = "Bookmark2"; + var _displayedBookmarkName = "special"; + + // Add another paragraph. + var p2 = document.InsertParagraph( "This paragraph contains a " ); + // Add a bookmark into the paragraph. + p2.AppendBookmark( _bookmarkName ); + p2.Append( " bookmark named \"" ); + p2.Append( document.Bookmarks.Last().Name ); + p2.Append( "\" but displayed as \"" + _displayedBookmarkName + "\"." ); + + // Set a string to be displayed as the Bookmark in the second paragraph. + p2.InsertAtBookmark( _displayedBookmarkName, _bookmarkName ); + + document.Save(); + Console.WriteLine( "\tCreated: InsertBookmarks.docx\n" ); + } + } + + /// + /// Load a document with bookmarks and replace the bookmark's text. + /// + public static void ReplaceText() + { + Console.WriteLine( "\tReplaceBookmarkText()" ); + + // Load a document + using( DocX document = DocX.Load( BookmarkSample.BookmarkSampleResourcesDirectory + @"DocumentWithBookmarks.docx" ) ) + { + // Get the regular bookmark from the document and replace its Text. + var regularBookmark = document.Bookmarks[ "regBookmark" ]; + if( regularBookmark != null ) + { + regularBookmark.SetText( "Regular Bookmark has been changed" ); + } + + // Get the formatted bookmark from the document and replace its Text. + var formattedBookmark = document.Bookmarks[ "formattedBookmark" ]; + if( formattedBookmark != null ) + { + formattedBookmark.SetText( "Formatted Bookmark has been changed" ); + } + + document.SaveAs( BookmarkSample.BookmarkSampleOutputDirectory + @"ReplaceBookmarkText.docx" ); + Console.WriteLine( "\tCreated: ReplaceBookmarkText.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/Bookmark/Resources/DocumentWithBookmarks.docx b/Examples/Samples/Bookmark/Resources/DocumentWithBookmarks.docx new file mode 100644 index 00000000..bb9a96dc Binary files /dev/null and b/Examples/Samples/Bookmark/Resources/DocumentWithBookmarks.docx differ diff --git a/Examples/Samples/Chart/ChartData.cs b/Examples/Samples/Chart/ChartData.cs new file mode 100644 index 00000000..06b47f68 --- /dev/null +++ b/Examples/Samples/Chart/ChartData.cs @@ -0,0 +1,61 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System.Collections.Generic; + +namespace Xceed.Words.NET.Examples +{ + internal class ChartData + { + public string Category + { + get; + set; + } + public double Expenses + { + get; + set; + } + + public static List CreateCanadaExpenses() + { + var canada = new List(); + canada.Add( new ChartData() { Category = "Food", Expenses = 100 } ); + canada.Add( new ChartData() { Category = "Housing", Expenses = 120 } ); + canada.Add( new ChartData() { Category = "Transportation", Expenses = 140 } ); + canada.Add( new ChartData() { Category = "Health Care", Expenses = 150 } ); + return canada; + } + + public static List CreateUSAExpenses() + { + var usa = new List(); + usa.Add( new ChartData() { Category = "Food", Expenses = 200 } ); + usa.Add( new ChartData() { Category = "Housing", Expenses = 150 } ); + usa.Add( new ChartData() { Category = "Transportation", Expenses = 110 } ); + usa.Add( new ChartData() { Category = "Health Care", Expenses = 100 } ); + return usa; + } + + public static List CreateBrazilExpenses() + { + var brazil = new List(); + brazil.Add( new ChartData() { Category = "Food", Expenses = 125 } ); + brazil.Add( new ChartData() { Category = "Housing", Expenses = 80 } ); + brazil.Add( new ChartData() { Category = "Transportation", Expenses = 110 } ); + brazil.Add( new ChartData() { Category = "Health Care", Expenses = 60 } ); + return brazil; + } + } +} diff --git a/Examples/Samples/Chart/ChartSample.cs b/Examples/Samples/Chart/ChartSample.cs new file mode 100644 index 00000000..cddae136 --- /dev/null +++ b/Examples/Samples/Chart/ChartSample.cs @@ -0,0 +1,207 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System; +using System.Drawing; +using System.IO; + +namespace Xceed.Words.NET.Examples +{ + public class ChartSample + { + #region Private Members + + private const string ChartSampleOutputDirectory = Program.SampleDirectory + @"Chart\Output\"; + + #endregion + + #region Constructors + + static ChartSample() + { + if( !Directory.Exists( ChartSample.ChartSampleOutputDirectory ) ) + { + Directory.CreateDirectory( ChartSample.ChartSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Add a Bar chart to a document. + /// + public static void BarChart() + { + Console.WriteLine( "\tBarChart()" ); + + // Creates a document + using( DocX document = DocX.Create( ChartSample.ChartSampleOutputDirectory + @"BarChart.docx" ) ) + { + // Add a title + document.InsertParagraph( "Bar Chart" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Create a bar chart. + var c = new BarChart(); + c.AddLegend( ChartLegendPosition.Left, false ); + c.BarDirection = BarDirection.Bar; + c.BarGrouping = BarGrouping.Standard; + c.GapWidth = 200; + + // Create the data. + var canada = ChartData.CreateCanadaExpenses(); + var usa = ChartData.CreateUSAExpenses(); + var brazil = ChartData.CreateBrazilExpenses(); + + // Create and add series + var s1 = new Series( "Brazil" ); + s1.Color = Color.GreenYellow; + s1.Bind( brazil, "Category", "Expenses" ); + c.AddSeries( s1 ); + + var s2 = new Series( "USA" ); + s2.Color = Color.LightBlue; + s2.Bind( usa, "Category", "Expenses" ); + c.AddSeries( s2 ); + + var s3 = new Series( "Canada" ); + s3.Color = Color.Gray; + s3.Bind( canada, "Category", "Expenses" ); + c.AddSeries( s3 ); + + // Insert the chart into the document. + document.InsertParagraph( "Expenses(M$) for selected categories per country" ).FontSize( 15 ).SpacingAfter( 10d ); + document.InsertChart( c ); + + document.Save(); + Console.WriteLine( "\tCreated: BarChart.docx\n" ); + } + } + + /// + /// Add a Line chart to a document. + /// + public static void LineChart() + { + Console.WriteLine( "\tLineChartt()" ); + + // Creates a document + using( DocX document = DocX.Create( ChartSample.ChartSampleOutputDirectory + @"LineChart.docx" ) ) + { + // Add a title + document.InsertParagraph( "Line Chart" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Create a line chart. + var c = new LineChart(); + c.AddLegend( ChartLegendPosition.Left, false ); + + // Create the data. + var canada = ChartData.CreateCanadaExpenses(); + var usa = ChartData.CreateUSAExpenses(); + var brazil = ChartData.CreateBrazilExpenses(); + + // Create and add series + var s1 = new Series( "Brazil" ); + s1.Bind( brazil, "Category", "Expenses" ); + c.AddSeries( s1 ); + + var s2 = new Series( "USA" ); + s2.Bind( usa, "Category", "Expenses" ); + c.AddSeries( s2 ); + + var s3 = new Series( "Canada" ); + s3.Bind( canada, "Category", "Expenses" ); + c.AddSeries( s3 ); + + // Insert chart into document + document.InsertParagraph( "Expenses(M$) for selected categories per country" ).FontSize( 15 ).SpacingAfter( 10d ); + document.InsertChart( c ); + + document.Save(); + Console.WriteLine( "\tCreated: LineChart.docx\n" ); + } + } + + /// + /// Add a Pie chart to a document. + /// + public static void PieChart() + { + Console.WriteLine( "\tPieChart()" ); + + // Creates a document + using( DocX document = DocX.Create( ChartSample.ChartSampleOutputDirectory + @"PieChart.docx" ) ) + { + // Add a title + document.InsertParagraph( "Pie Chart" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Create a pie chart. + var c = new PieChart(); + c.AddLegend( ChartLegendPosition.Left, false ); + + // Create the data. + var brazil = ChartData.CreateBrazilExpenses(); + + // Create and add series + var s1 = new Series( "Canada" ); + s1.Bind( brazil, "Category", "Expenses" ); + c.AddSeries( s1 ); + + // Insert chart into document + document.InsertParagraph( "Expenses(M$) for selected categories of Canada" ).FontSize( 15 ).SpacingAfter( 10d ); + document.InsertChart( c ); + + document.Save(); + Console.WriteLine( "\tCreated: PieChart.docx\n" ); + } + } + + /// + /// Add a 3D bar chart to a document. + /// + /// + public static void Chart3D() + { + Console.WriteLine( "\tChart3D)" ); + + // Creates a document + using( DocX document = DocX.Create( ChartSample.ChartSampleOutputDirectory + @"3DChart.docx" ) ) + { + // Add a title + document.InsertParagraph( "3D Chart" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Create a 3D Bar chart. + var c = new BarChart(); + c.View3D = true; + + // Create the data. + var brazil = ChartData.CreateBrazilExpenses(); + + // Create and add series + var s1 = new Series( "Brazil" ); + s1.Color = Color.GreenYellow; + s1.Bind( brazil, "Category", "Expenses" ); + c.AddSeries( s1 ); + + // Insert chart into document + document.InsertParagraph( "Expenses(M$) for selected categories of Brazil" ).FontSize( 15 ).SpacingAfter( 10d ); + document.InsertChart( c ); + + document.Save(); + Console.WriteLine( "\tCreated: 3DChart.docx\n" ); + } + } + #endregion + } +} diff --git a/Examples/Samples/Document/DocumentSample.cs b/Examples/Samples/Document/DocumentSample.cs new file mode 100644 index 00000000..52b7e2de --- /dev/null +++ b/Examples/Samples/Document/DocumentSample.cs @@ -0,0 +1,178 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; + +namespace Xceed.Words.NET.Examples +{ + public class DocumentSample + { + #region Private Members + + private static Dictionary _replacePatterns = new Dictionary() + { + { "OPPONENT", "Pittsburgh Penguins" }, + { "GAME_TIME", "19h30" }, + { "GAME_NUMBER", "161" }, + { "DATE", "October 18 2016" }, + }; + + private const string DocumentSampleResourcesDirectory = Program.SampleDirectory + @"Document\Resources\"; + private const string DocumentSampleOutputDirectory = Program.SampleDirectory + @"Document\Output\"; + + #endregion + + #region Constructors + + static DocumentSample() + { + if( !Directory.Exists( DocumentSample.DocumentSampleOutputDirectory ) ) + { + Directory.CreateDirectory( DocumentSample.DocumentSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Load a document and replace texts following a replace pattern. + /// + public static void ReplaceText() + { + Console.WriteLine( "\tReplaceText()" ); + + // Load a document. + using( DocX document = DocX.Load( DocumentSample.DocumentSampleResourcesDirectory + @"ReplaceText.docx" ) ) + { + // Check if all the replace patterns are used in the loaded document. + if( document.FindUniqueByPattern( @"<[\w \=]{4,}>", RegexOptions.IgnoreCase ).Count == _replacePatterns.Count ) + { + // Do the replacement + for( int i = 0; i < _replacePatterns.Count; ++i ) + { + document.ReplaceText( "<(.*?)>", DocumentSample.ReplaceFunc, false, RegexOptions.IgnoreCase, null, new Formatting() ); + } + + // Save this document to disk. + document.SaveAs( DocumentSample.DocumentSampleOutputDirectory + @"ReplacedText.docx" ); + Console.WriteLine( "\tCreated: ReplacedText.docx\n" ); + } + } + } + + /// + /// Add custom properties to a document. + /// + public static void AddCustomProperties() + { + Console.WriteLine( "\tAddCustomProperties()" ); + + // Create a new document. + using( DocX document = DocX.Create( DocumentSample.DocumentSampleOutputDirectory + @"AddCustomProperties.docx" ) ) + { + // Add a title + document.InsertParagraph( "Adding Custom Properties to a document" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + //Add custom properties to document. + document.AddCustomProperty( new CustomProperty( "CompanyName", "Xceed Software inc." ) ); + document.AddCustomProperty( new CustomProperty( "Product", "Xceed Words for .NET" ) ); + document.AddCustomProperty( new CustomProperty( "Address", "10 Boul. de Mortagne" ) ); + document.AddCustomProperty( new CustomProperty( "Date", DateTime.Now ) ); + + // Add a paragraph displaying the number of custom properties. + var p = document.InsertParagraph( "This document contains " ).Append( document.CustomProperties.Count.ToString() ).Append(" Custom Properties :"); + p.SpacingAfter( 30 ); + + // Display each propertie's name and value. + foreach( var prop in document.CustomProperties ) + { + document.InsertParagraph( prop.Value.Name ).Append( " = " ).Append( prop.Value.Value.ToString() ).AppendLine(); + } + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: AddCustomProperties.docx\n" ); + } + } + + /// + /// Add a template to a document. + /// + public static void ApplyTemplate() + { + Console.WriteLine( "\tApplyTemplate()" ); + + // Create a new document. + using( DocX document = DocX.Create( DocumentSample.DocumentSampleOutputDirectory + @"ApplyTemplate.docx" ) ) + { + // The path to a template document, + var templatePath = DocumentSample.DocumentSampleResourcesDirectory + @"Template.docx"; + + // Apply a template to the document based on a path. + document.ApplyTemplate( templatePath ); + + // Add a paragraph at the end of the template. + document.InsertParagraph( "This paragraph is not part of the template." ).FontSize( 15d ).UnderlineStyle(UnderlineStyle.singleLine).SpacingBefore(50d); + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: ApplyTemplate.docx\n" ); + } + } + + /// + /// Insert a document at the end of another document. + /// + public static void AppendDocument() + { + Console.WriteLine( "\tAppendDocument()" ); + + // Load the first document. + using( DocX document1 = DocX.Load( DocumentSample.DocumentSampleResourcesDirectory + @"First.docx" ) ) + { + // Load the second document. + using( DocX document2 = DocX.Load( DocumentSample.DocumentSampleResourcesDirectory + @"Second.docx" ) ) + { + // Insert a document at the end of another document. + // When true, document is added at the end. When false, document is added at beginning. + document1.InsertDocument( document2, true ); + + // Save this document to disk. + document1.SaveAs( DocumentSample.DocumentSampleOutputDirectory + @"AppendDocument.docx" ); + Console.WriteLine( "\tCreated: AppendDocument.docx\n" ); + } + } + } + + #endregion + + #region Private Methods + + private static string ReplaceFunc( string findStr ) + { + if( _replacePatterns.ContainsKey( findStr ) ) + { + return _replacePatterns[ findStr ]; + } + return findStr; + } + + #endregion + } +} diff --git a/Examples/Samples/Document/Resources/First.docx b/Examples/Samples/Document/Resources/First.docx new file mode 100644 index 00000000..141acd71 Binary files /dev/null and b/Examples/Samples/Document/Resources/First.docx differ diff --git a/Examples/Samples/Document/Resources/ReplaceText.docx b/Examples/Samples/Document/Resources/ReplaceText.docx new file mode 100644 index 00000000..31fe9ab2 Binary files /dev/null and b/Examples/Samples/Document/Resources/ReplaceText.docx differ diff --git a/Examples/Samples/Document/Resources/Second.docx b/Examples/Samples/Document/Resources/Second.docx new file mode 100644 index 00000000..f81042ec Binary files /dev/null and b/Examples/Samples/Document/Resources/Second.docx differ diff --git a/Examples/Samples/Document/Resources/Template.docx b/Examples/Samples/Document/Resources/Template.docx new file mode 100644 index 00000000..09f8d7f5 Binary files /dev/null and b/Examples/Samples/Document/Resources/Template.docx differ diff --git a/Examples/Samples/Equation/EquationSample.cs b/Examples/Samples/Equation/EquationSample.cs new file mode 100644 index 00000000..14c317f5 --- /dev/null +++ b/Examples/Samples/Equation/EquationSample.cs @@ -0,0 +1,71 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ + +using System; +using System.Drawing; +using System.IO; + +namespace Xceed.Words.NET.Examples +{ + public class EquationSample + { + #region Private Members + + private const string EquationSampleOutputDirectory = Program.SampleDirectory + @"Equation\Output\"; + + #endregion + + #region Constructors + + static EquationSample() + { + if( !Directory.Exists( EquationSample.EquationSampleOutputDirectory ) ) + { + Directory.CreateDirectory( EquationSample.EquationSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Create a document and add Equations in it. + /// + public static void InsertEquation() + { + Console.WriteLine( "\tEquationSample()" ); + + // Create a document. + using( DocX document = DocX.Create( EquationSample.EquationSampleOutputDirectory + @"EquationSample.docx" ) ) + { + // Add a title + document.InsertParagraph( "Inserting Equations" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + document.InsertParagraph( "A Linear equation : " ); + // Insert first Equation in this document. + document.InsertEquation( "y = mx + b" ).SpacingAfter( 30d ); + + document.InsertParagraph( "A Quadratic equation : " ); + // Insert second Equation in this document and add formatting. + document.InsertEquation( "x = ( -b \u00B1 \u221A(b\u00B2 - 4ac))/2a" ).FontSize( 18 ).Color( Color.Blue ); + + document.Save(); + Console.WriteLine( "\tCreated: EquationSample.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/HeaderFooter/HeaderFooterSample.cs b/Examples/Samples/HeaderFooter/HeaderFooterSample.cs new file mode 100644 index 00000000..fe67e5b0 --- /dev/null +++ b/Examples/Samples/HeaderFooter/HeaderFooterSample.cs @@ -0,0 +1,112 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ + +using System; +using System.IO; + +namespace Xceed.Words.NET.Examples +{ + public class HeaderFooterSample + { + #region Private Members + + private const string HeaderFooterSampleOutputDirectory = Program.SampleDirectory + @"HeaderFooter\Output\"; + + #endregion + + #region Constructors + + static HeaderFooterSample() + { + if( !Directory.Exists( HeaderFooterSample.HeaderFooterSampleOutputDirectory ) ) + { + Directory.CreateDirectory( HeaderFooterSample.HeaderFooterSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Add three different types of headers and footers to a document. + /// + public static void HeadersFooters() + { + Console.WriteLine( "\tHeadersFooters()" ); + + // Create a document. + using( DocX document = DocX.Create( HeaderFooterSample.HeaderFooterSampleOutputDirectory + @"HeadersFooters.docx" ) ) + { + // Insert a Paragraph in the first page of the document. + var p1 = document.InsertParagraph("This is the ").Append( "first").Bold().Append(" page Content."); + p1.SpacingBefore( 70d ); + p1.InsertPageBreakAfterSelf(); + + // Insert a Paragraph in the second page of the document. + var p2 = document.InsertParagraph( "This is the " ).Append( "second" ).Bold().Append( " page Content." ); + p2.InsertPageBreakAfterSelf(); + + // Insert a Paragraph in the third page of the document. + var p3 = document.InsertParagraph( "This is the " ).Append( "third" ).Bold().Append( " page Content." ); + p3.InsertPageBreakAfterSelf(); + + // Insert a Paragraph in the third page of the document. + var p4 = document.InsertParagraph( "This is the " ).Append( "fourth" ).Bold().Append( " page Content." ); + + // Add Headers and Footers to the document. + document.AddHeaders(); + document.AddFooters(); + + // Force the first page to have a different Header and Footer. + document.DifferentFirstPage = true; + + // Force odd & even pages to have different Headers and Footers. + document.DifferentOddAndEvenPages = true; + + // Insert a Paragraph into the first Header. + document.Headers.First.InsertParagraph("This is the ").Append("first").Bold().Append(" page header"); + + // Insert a Paragraph into the first Footer. + document.Footers.First.InsertParagraph( "This is the " ).Append( "first" ).Bold().Append( " page footer" ); + + // Insert a Paragraph into the even Header. + document.Headers.Even.InsertParagraph( "This is an " ).Append( "even" ).Bold().Append( " page header" ); + + // Insert a Paragraph into the even Footer. + document.Footers.Even.InsertParagraph( "This is an " ).Append( "even" ).Bold().Append( " page footer" ); + + // Insert a Paragraph into the odd Header. + document.Headers.Odd.InsertParagraph( "This is an " ).Append( "odd" ).Bold().Append( " page header" ); + + // Insert a Paragraph into the odd Footer. + document.Footers.Odd.InsertParagraph( "This is an " ).Append( "odd" ).Bold().Append( " page footer" ); + + // Add the page number in the first Footer. + document.Footers.First.InsertParagraph("Page #").AppendPageNumber( PageNumberFormat.normal ); + + // Add the page number in the even Footers. + document.Footers.Even.InsertParagraph( "Page #" ).AppendPageNumber( PageNumberFormat.normal ); + + // Add the page number in the odd Footers. + document.Footers.Odd.InsertParagraph( "Page #" ).AppendPageNumber( PageNumberFormat.normal ); + + document.Save(); + Console.WriteLine( "\tCreated: HeadersFooters.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/Hyperlink/HyperlinkSample.cs b/Examples/Samples/Hyperlink/HyperlinkSample.cs new file mode 100644 index 00000000..5d8069ec --- /dev/null +++ b/Examples/Samples/Hyperlink/HyperlinkSample.cs @@ -0,0 +1,99 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System; +using System.Drawing; +using System.IO; +using System.Linq; + +namespace Xceed.Words.NET.Examples +{ + public class HyperlinkSample + { + #region Private Members + + private const string HyperlinkSampleOutputDirectory = Program.SampleDirectory + @"Hyperlink\Output\"; + + #endregion + + #region Constructors + + static HyperlinkSample() + { + if( !Directory.Exists( HyperlinkSample.HyperlinkSampleOutputDirectory ) ) + { + Directory.CreateDirectory( HyperlinkSample.HyperlinkSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Insert/Add/Remove hyperlinks from paragraphs. + /// + public static void Hyperlinks() + { + Console.WriteLine( "\tHyperlinks()" ); + + // Create a document + using( DocX document = DocX.Create( HyperlinkSample.HyperlinkSampleOutputDirectory + @"Hyperlinks.docx" ) ) + { + // Add a title + document.InsertParagraph( "Insert/Remove Hyperlinks" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add an Hyperlink into this document. + var h = document.AddHyperlink( "google", new Uri( "http://www.google.com" ) ); + + // Add a paragraph. + var p = document.InsertParagraph( "The hyperlink has been inserted in this paragraph." ); + // insert an hyperlink at specific index in this paragraph. + p.InsertHyperlink( h, 4 ); + p.SpacingAfter( 40d ); + + // Get the first hyperlink in the document. + var hyperlink = document.Hyperlinks.FirstOrDefault(); + if( hyperlink != null ) + { + // Modify its text and Uri. + hyperlink.Text = "xceed"; + hyperlink.Uri = new Uri( "http://www.xceed.com/" ); + } + + // Add an Hyperlink to this document. + var h2 = document.AddHyperlink( "xceed", new Uri( "http://www.xceed.com/" ) ); + // Add a paragraph. + var p2 = document.InsertParagraph( "A formatted hyperlink has been added at the end of this paragraph: " ); + // Append an hyperlink to a paragraph. + p2.AppendHyperlink( h2 ).Color( Color.Blue ).UnderlineStyle( UnderlineStyle.singleLine ); + p2.Append( "." ).SpacingAfter( 40d ); + + // Add an Hyperlink to this document. + var h3 = document.AddHyperlink( "microsoft", new Uri( "http://www.microsoft.com" ) ); + // Add a paragraph + var p3 = document.InsertParagraph( "The hyperlink from this paragraph has been removed. " ); + // Append an hyperlink to a paragraph. + p3.AppendHyperlink( h3 ).Color( Color.Green ).UnderlineStyle( UnderlineStyle.singleLine ).Italic(); + + // Remove the first hyperlink of paragraph 3. + p3.RemoveHyperlink( 0 ); + + document.Save(); + Console.WriteLine( "\tCreated: Hyperlinks.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/Image/ImageSample.cs b/Examples/Samples/Image/ImageSample.cs new file mode 100644 index 00000000..82e6019c --- /dev/null +++ b/Examples/Samples/Image/ImageSample.cs @@ -0,0 +1,163 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ + +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; + +namespace Xceed.Words.NET.Examples +{ + public class ImageSample + { + #region Private Members + + private const string ImageSampleResourcesDirectory = Program.SampleDirectory + @"Image\Resources\"; + private const string ImageSampleOutputDirectory = Program.SampleDirectory + @"Image\Output\"; + + #endregion + + #region Constructors + + static ImageSample() + { + if( !Directory.Exists( ImageSample.ImageSampleOutputDirectory ) ) + { + Directory.CreateDirectory( ImageSample.ImageSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Add a picture loaded from disk or stream to a document. + /// + public static void AddPicture() + { + Console.WriteLine( "\tAddPicture()" ); + + // Create a document. + using( DocX document = DocX.Create( ImageSample.ImageSampleOutputDirectory + @"AddPicture.docx" ) ) + { + // Add a title + document.InsertParagraph( "Adding Pictures" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add a simple image from disk. + var image = document.AddImage( ImageSample.ImageSampleResourcesDirectory + @"balloon.jpg" ); + var picture = image.CreatePicture( 150, 150 ); + var p = document.InsertParagraph( "Here is a simple picture added from disk:" ); + p.AppendPicture( picture ); + p.SpacingAfter( 30 ); + + // Add a rotated image from disk. + var rotatedPicture = image.CreatePicture( 150, 150 ); + rotatedPicture.Rotation = 25; + + var p2 = document.InsertParagraph( "Here is the same picture added from disk, but rotated:" ); + p2.AppendPicture( rotatedPicture ); + p2.SpacingAfter( 30 ); + + // Add a simple image from a stream + var streamImage = document.AddImage( new FileStream( ImageSample.ImageSampleResourcesDirectory + @"balloon.jpg", FileMode.Open, FileAccess.Read ) ); + var pictureStream = streamImage.CreatePicture( 150, 150 ); + var p3 = document.InsertParagraph( "Here is the same picture added from a stream:" ); + p3.AppendPicture( pictureStream ); + + document.Save(); + Console.WriteLine( "\tCreated: AddPicture.docx\n" ); + } + } + + /// + /// Copy a picture from a paragraph. + /// + public static void CopyPicture() + { + Console.WriteLine( "\tCopyPicture()" ); + + // Create a document. + using( DocX document = DocX.Create( ImageSample.ImageSampleOutputDirectory + @"CopyPicture.docx" ) ) + { + // Add a title + document.InsertParagraph( "Copying Pictures" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add a paragraph containing an image. + var image = document.AddImage( ImageSample.ImageSampleResourcesDirectory + @"balloon.jpg" ); + var picture = image.CreatePicture( 100, 100 ); + var p = document.InsertParagraph( "This is the first paragraph. " ); + p.AppendPicture( picture ); + p.AppendLine("It contains an image added from disk."); + p.SpacingAfter( 50 ); + + // Add a second paragraph containing no image. + var p2 = document.InsertParagraph( "This is the second paragraph. " ); + p2.AppendLine( "It contains a copy of the image located in the first paragraph." ).AppendLine(); + + // Extract the first Picture from the first Paragraph. + var firstPicture = p.Pictures.FirstOrDefault(); + if( firstPicture != null ) + { + // copy it at the end of the second paragraph. + p2.AppendPicture( firstPicture ); + } + + document.Save(); + Console.WriteLine( "\tCreated: CopyPicture.docx\n" ); + } + } + + /// + /// Modify an image from a document by writing text into it. + /// + public static void ModifyImage() + { + Console.WriteLine( "\tModifyImage()" ); + + // Open the document Input.docx. + using( DocX document = DocX.Load( ImageSample.ImageSampleResourcesDirectory + @"Input.docx" ) ) + { + // Add a title + document.InsertParagraph( 0, "Modifying Image by adding text/circle into the following image", false ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Get the first image in the document. + var image = document.Images.FirstOrDefault(); + if( image != null ) + { + // Create a bitmap from the image. + var bitmap = new Bitmap( image.GetStream( FileMode.Open, FileAccess.ReadWrite ) ); + // Get the graphic from the bitmap to be able to draw in it. + var graphic = Graphics.FromImage( bitmap ); + if( graphic != null ) + { + // Draw a string with a specific font, font size and color at (0,10) from top left of the image. + graphic.DrawString( "@copyright", new System.Drawing.Font( "Arial Bold", 12 ), Brushes.Red, new PointF( 0f, 10f ) ); + // Draw a blue circle of 10x10 at (30, 5) from the top left of the image. + graphic.FillEllipse( Brushes.Blue, 30, 5, 10, 10 ); + + // Save this Bitmap back into the document using a Create\Write stream. + bitmap.Save( image.GetStream( FileMode.Create, FileAccess.Write ), ImageFormat.Png ); + } + } + + document.SaveAs( ImageSample.ImageSampleOutputDirectory + @"ModifyImage.docx" ); + Console.WriteLine( "\tCreated: ModifyImage.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/Image/Resources/Input.docx b/Examples/Samples/Image/Resources/Input.docx new file mode 100644 index 00000000..ca5271cc Binary files /dev/null and b/Examples/Samples/Image/Resources/Input.docx differ diff --git a/Examples/Samples/Image/Resources/balloon.jpg b/Examples/Samples/Image/Resources/balloon.jpg new file mode 100644 index 00000000..17a6b828 Binary files /dev/null and b/Examples/Samples/Image/Resources/balloon.jpg differ diff --git a/Examples/Samples/Line/LineSample.cs b/Examples/Samples/Line/LineSample.cs new file mode 100644 index 00000000..bd24de15 --- /dev/null +++ b/Examples/Samples/Line/LineSample.cs @@ -0,0 +1,91 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System; +using System.Drawing; +using System.IO; + +namespace Xceed.Words.NET.Examples +{ + public class LineSample + { + #region Private Members + + private const string LineSampleOutputDirectory = Program.SampleDirectory + @"Line\Output\"; + + #endregion + + #region Constructors + + static LineSample() + { + if( !Directory.Exists( LineSample.LineSampleOutputDirectory ) ) + { + Directory.CreateDirectory( LineSample.LineSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Create a document and add different lines under paragraphs. + /// + public static void InsertHorizontalLine() + { + Console.WriteLine( "\tInsertHorizontalLine()" ); + + using( var document = DocX.Create( LineSample.LineSampleOutputDirectory + @"InsertHorizontalLine.docx" ) ) + { + // Add a title + document.InsertParagraph( "Adding bottom Horizontal lines" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add a paragraph with a single line. + var p = document.InsertParagraph(); + p.Append( "This is a paragraph with a single line." ).Font( new Font( "Arial" ) ).FontSize( 20 ); + p.InsertHorizontalLine( "single", 6, 1, "auto" ); + p.SpacingAfter( 20 ); + + // Add a paragraph with a double green line. + var p2 = document.InsertParagraph(); + p2.Append( "This is a paragraph with a double colored line." ).Font( new Font( "Arial" ) ).FontSize( 20 ); + p2.InsertHorizontalLine( "double", 6, 1, "green" ); + p2.SpacingAfter( 20 ); + + // Add a paragraph with a triple red line. + var p3 = document.InsertParagraph(); + p3.Append( "This is a paragraph with a triple colored line." ).Font( new Font( "Arial" ) ).FontSize( 20 ); + p3.InsertHorizontalLine( "triple", 6, 1, "red" ); + p3.SpacingAfter( 20 ); + + // Add a paragraph with a single spaced line. + var p4 = document.InsertParagraph(); + p4.Append( "This is a paragraph with a spaced line." ).Font( new Font( "Arial" ) ).FontSize( 20 ); + p4.InsertHorizontalLine( "single", 6, 12, "auto" ); + p4.SpacingAfter( 20 ); + + // Add a paragraph with a single large line. + var p5 = document.InsertParagraph(); + p5.Append( "This is a paragraph with a large line." ).Font( new Font( "Arial" ) ).FontSize( 20 ); + p5.InsertHorizontalLine( "single", 25, 1, "auto" ); + p5.SpacingAfter( 20 ); + + document.Save(); + Console.WriteLine( "\tCreated: InsertHorizontalLine.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/List/ListSample.cs b/Examples/Samples/List/ListSample.cs new file mode 100644 index 00000000..6feb0803 --- /dev/null +++ b/Examples/Samples/List/ListSample.cs @@ -0,0 +1,106 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ + +using System; +using System.Drawing; +using System.IO; + +namespace Xceed.Words.NET.Examples +{ + public class ListSample + { + #region Private Members + + private const string ListSampleOutputDirectory = Program.SampleDirectory + @"List\Output\"; + + #endregion + + #region Constructors + + static ListSample() + { + if( !Directory.Exists( ListSample.ListSampleOutputDirectory ) ) + { + Directory.CreateDirectory( ListSample.ListSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Create a numbered and a bulleted lists with different listItem's levels. + /// + public static void AddList() + { + Console.WriteLine( "\tAddList()" ); + + // Create a document. + using( DocX document = DocX.Create( ListSample.ListSampleOutputDirectory + @"AddList.docx" ) ) + { + // Add a title + document.InsertParagraph( "Adding lists into a document" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add a numbered list where the first ListItem is starting with number 1. + var numberedList = document.AddList( "Berries", 0, ListItemType.Numbered, 1 ); + // Add Sub-items(level 1) to the preceding ListItem. + document.AddListItem( numberedList, "Strawberries", 1 ); + document.AddListItem( numberedList, "Blueberries", 1 ); + document.AddListItem( numberedList, "Raspberries", 1 ); + // Add an item (level 0) + document.AddListItem( numberedList, "Banana" ); + // Add an item (level 0) + document.AddListItem( numberedList, "Apple" ); + // Add Sub-items(level 1) to the preceding ListItem. + document.AddListItem( numberedList, "Red", 1 ); + document.AddListItem( numberedList, "Green", 1 ); + document.AddListItem( numberedList, "Yellow", 1 ); + + // Add a bulleted list with its first item. + var bulletedList = document.AddList( "Canada", 0, ListItemType.Bulleted); + // Add Sub-items(level 1) to the preceding ListItem. + document.AddListItem( bulletedList, "Toronto", 1 ); + document.AddListItem( bulletedList, "Montreal", 1 ); + // Add an item (level 0) + document.AddListItem( bulletedList, "Brazil" ); + // Add an item (level 0) + document.AddListItem( bulletedList, "USA" ); + // Add Sub-items(level 1) to the preceding ListItem. + document.AddListItem( bulletedList, "New York", 1 ); + // Add Sub-items(level 2) to the preceding ListItem. + document.AddListItem( bulletedList, "Brooklyn", 2 ); + document.AddListItem( bulletedList, "Manhattan", 2 ); + document.AddListItem( bulletedList, "Los Angeles", 1 ); + document.AddListItem( bulletedList, "Miami", 1 ); + // Add an item (level 0) + document.AddListItem( bulletedList, "France" ); + // Add Sub-items(level 1) to the preceding ListItem. + document.AddListItem( bulletedList, "Paris", 1 ); + + // Insert the lists into the document. + document.InsertParagraph( "This is a Numbered List:\n" ); + document.InsertList( numberedList ); + document.InsertParagraph().SpacingAfter( 40d ); + document.InsertParagraph( "This is a Bulleted List:\n" ); + document.InsertList( bulletedList, new Font("Cooper Black"), 15 ); + + document.Save(); + Console.WriteLine( "\tCreated: AddList.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/Margin/MarginSample.cs b/Examples/Samples/Margin/MarginSample.cs new file mode 100644 index 00000000..5f153861 --- /dev/null +++ b/Examples/Samples/Margin/MarginSample.cs @@ -0,0 +1,149 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ + +using System; +using System.IO; + +namespace Xceed.Words.NET.Examples +{ + public class MarginSample + { + #region Private Members + + private const string MarginSampleOutputDirectory = Program.SampleDirectory + @"Margin\Output\"; + + #endregion + + #region Constructors + + static MarginSample() + { + if( !Directory.Exists( MarginSample.MarginSampleOutputDirectory ) ) + { + Directory.CreateDirectory( MarginSample.MarginSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Modify the direction of text in a paragraph or document. + /// + public static void SetDirection() + { + Console.WriteLine( "\tSetDirection()" ); + + // Create a document. + using( DocX document = DocX.Create( MarginSample.MarginSampleOutputDirectory + @"SetDirection.docx" ) ) + { + // Add a title. + document.InsertParagraph( "Modify direction of paragraphs" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add first paragraph. + var p = document.InsertParagraph("This is the first paragraph."); + p.SpacingAfter( 30 ); + + // Add second paragraph. + var p2 = document.InsertParagraph( "This is the second paragraph." ); + p2.SpacingAfter( 30 ); + // Make this Paragraph flow right to left. Default is left to right. + p2.Direction = Direction.RightToLeft; + + // Add third paragraph. + var p3 = document.InsertParagraph( "This is the third paragraph." ); + p3.SpacingAfter( 30 ); + + // Add fourth paragraph. + var p4 = document.InsertParagraph( "This is the fourth paragraph." ); + p4.SpacingAfter( 30 ); + + // To modify the direction of each paragraph in a document, just set the direction on the document. + document.SetDirection( Direction.RightToLeft ); + + document.Save(); + Console.WriteLine( "\tCreated: SetDirection.docx\n" ); + } + } + + /// + /// Add indentations on paragraphs. + /// + public static void Indentation() + { + Console.WriteLine( "\tIndentation()" ); + + // Create a document. + using( DocX document = DocX.Create( MarginSample.MarginSampleOutputDirectory + @"Indentation.docx" ) ) + { + // Add a title. + document.InsertParagraph( "Paragraph indentation" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Set a smaller page width. + document.PageWidth = 250f; + + // Add the first paragraph. + var p = document.InsertParagraph( "This is the first paragraph. It doesn't contain any indentation." ); + p.SpacingAfter( 30 ); + + // Add the second paragraph. + var p2 = document.InsertParagraph( "This is the second paragraph. It contains an indentation on the first line." ); + // Indent only the first line of the Paragraph. + p2.IndentationFirstLine = 1.0f; + p2.SpacingAfter( 30 ); + + // Add the third paragraph. + var p3 = document.InsertParagraph( "This is the third paragraph. It contains an indentation on all the lines except the first one." ); + // Indent all the lines of the Paragraph, except the first. + p3.IndentationHanging = 1.0f; + + document.Save(); + Console.WriteLine( "\tCreated: Indentation.docx\n" ); + } + } + + /// + /// Add margins for a document. + /// + public static void Margins() + { + Console.WriteLine( "\tMargins()" ); + + // Create a document. + using( DocX document = DocX.Create( MarginSample.MarginSampleOutputDirectory + @"Margins.docx" ) ) + { + // Add a title. + document.InsertParagraph( "Document margins" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Set the page width to be smaller. + document.PageWidth = 350f; + + // Set the document margins. + document.MarginLeft = 85f; + document.MarginRight = 85f; + document.MarginTop = 0f; + document.MarginBottom = 50f; + + // Add a paragraph. It will be affected by the document margins. + var p = document.InsertParagraph("This is a paragraph from a document with a left margin of 85, a right margin of 85, a top margin of 0 and a bottom margin of 50."); + + document.Save(); + Console.WriteLine( "\tCreated: Margins.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/Miscellaneous/MiscellaneousSample.cs b/Examples/Samples/Miscellaneous/MiscellaneousSample.cs new file mode 100644 index 00000000..ebf9fbdc --- /dev/null +++ b/Examples/Samples/Miscellaneous/MiscellaneousSample.cs @@ -0,0 +1,375 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; + +namespace Xceed.Words.NET.Examples +{ + public class MiscellaneousSample + { + #region Private Members + + private const string MiscellaneousSampleResourcesDirectory = Program.SampleDirectory + @"Miscellaneous\Resources\"; + private const string MiscellaneousSampleOutputDirectory = Program.SampleDirectory + @"Miscellaneous\Output\"; + + #endregion + + #region Constructors + + static MiscellaneousSample() + { + if( !Directory.Exists( MiscellaneousSample.MiscellaneousSampleOutputDirectory ) ) + { + Directory.CreateDirectory( MiscellaneousSample.MiscellaneousSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Create a file and add a picture, a table, an hyperlink, paragraphs, a bulleted list and a numbered list. + /// + public static void CreateRecipe() + { + Console.WriteLine( "\tCreateRecipe()" ); + + // Create a new document. + using( DocX document = DocX.Create( MiscellaneousSample.MiscellaneousSampleOutputDirectory + @"CreateRecipe.docx" ) ) + { + // Create a rotated picture from existing image. + var image = document.AddImage( MiscellaneousSample.MiscellaneousSampleResourcesDirectory + @"cupcake.png" ); + var picture = image.CreatePicture(); + picture.Rotation = 20; + + // Create an hyperlink. + var hyperlink = document.AddHyperlink( "Food.com", new Uri( "http://www.food.com/recipe/simple-vanilla-cupcakes-178370" ) ); + + // Create a bulleted list for the ingredients. + var bulletsList = document.AddList( "2 cups of flour", 0, ListItemType.Bulleted ); + document.AddListItem( bulletsList, "3⁄4 cup of sugar" ); + document.AddListItem( bulletsList, "1⁄2 cup of butter" ); + document.AddListItem( bulletsList, "2 eggs" ); + document.AddListItem( bulletsList, "1 cup of milk" ); + document.AddListItem( bulletsList, "2 teaspoons of baking powder" ); + document.AddListItem( bulletsList, "1⁄2 teaspoon of salt" ); + document.AddListItem( bulletsList, "1 teaspoon of vanilla essence" ); + + // Create a table for text and the picture. + var table = document.AddTable( 1, 2 ); + table.Design = TableDesign.LightListAccent3; + table.AutoFit = AutoFit.Window; + table.Rows[ 0 ].Cells[ 0 ].Paragraphs[ 0 ].AppendLine().AppendLine().Append( "Simple Vanilla Cupcakes Recipe" ).FontSize( 20 ).Font( new Font( "Comic Sans MS" ) ); + table.Rows[ 0 ].Cells[ 1 ].Paragraphs[ 0 ].AppendPicture( picture ); + + // Create a numbered list for the directions. + var recipeList = document.AddList( "Preheat oven to 375F and fill muffin cups with papers.", 0, ListItemType.Numbered, 1 ); + document.AddListItem( recipeList, "Mix butter and sugar until light and fluffy." ); + document.AddListItem( recipeList, "Beat in the eggs, one at a time.", 1 ); + document.AddListItem( recipeList, "Add the flour, baking powder and salt, alternate with milk and beat well." ); + document.AddListItem( recipeList, "Add in vanilla.", 1 ); + document.AddListItem( recipeList, "Divide in the pans and bake for 18 minutes." ); + document.AddListItem( recipeList, "Let cool 5 minutes an eat.", 1 ); + + // Insert the data in page. + document.InsertTable( table ); + var paragraph = document.InsertParagraph(); + paragraph.AppendLine(); + paragraph.AppendLine(); + paragraph.AppendLine( "Ingredients" ).FontSize( 15 ).Bold().Color(Color.BlueViolet); + document.InsertList( bulletsList ); + var paragraph2 = document.InsertParagraph(); + paragraph2.AppendLine(); + paragraph2.AppendLine( "Directions" ).FontSize( 15 ).Bold().Color( Color.BlueViolet ); + document.InsertList( recipeList ); + var paragraph3 = document.InsertParagraph(); + paragraph3.AppendLine(); + paragraph3.AppendLine( "Reference: " ).AppendHyperlink( hyperlink ).Color( Color.Blue ).UnderlineColor( Color.Blue ).Append( "." ); + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: CreateRecipe.docx\n" ); + } + } + + /// + /// Create a document and add headers/footers with tables and pictures, paragraphs and charts. + /// + public static void CompanyReport() + { + Console.WriteLine( "\tCompanyReport()" ); + + // Create a new document. + using( DocX document = DocX.Create( MiscellaneousSample.MiscellaneousSampleOutputDirectory + @"CompanyReport.docx" ) ) + { + // Add headers and footers. + document.AddHeaders(); + document.AddFooters(); + + // Define the pages header's picture in a Table. Odd and even pages will have the same headers. + var oddHeader = document.Headers.Odd; + var headerFirstTable = oddHeader.InsertTable( 1, 2 ); + headerFirstTable.Design = TableDesign.ColorfulGrid; + headerFirstTable.AutoFit = AutoFit.Window; + var upperLeftParagraph = oddHeader.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs[ 0 ]; + var logo = document.AddImage( MiscellaneousSample.MiscellaneousSampleResourcesDirectory + @"Phone.png" ); + upperLeftParagraph.AppendPicture( logo.CreatePicture( 30, 100 ) ); + upperLeftParagraph.Alignment = Alignment.left; + + // Define the pages header's text in a Table. Odd and even pages will have the same footers. + var upperRightParagraph = oddHeader.Tables[ 0 ].Rows[ 0 ].Cells[ 1 ].Paragraphs[ 0 ]; + upperRightParagraph.Append( "Toms Telecom Annual report" ).Color( Color.White ); + upperRightParagraph.SpacingBefore( 5d ); + upperRightParagraph.Alignment = Alignment.right; + + // Define the pages footer's picture in a Table. + var oddFooter = document.Footers.Odd; + var footerFirstTable = oddFooter.InsertTable( 1, 2 ); + footerFirstTable.Design = TableDesign.ColorfulGrid; + footerFirstTable.AutoFit = AutoFit.Window; + var lowerRightParagraph = oddFooter.Tables[ 0 ].Rows[ 0 ].Cells[ 1 ].Paragraphs[ 0 ]; + lowerRightParagraph.AppendPicture( logo.CreatePicture( 30, 100 ) ); + lowerRightParagraph.Alignment = Alignment.right; + + // Define the pages footer's text in a Table + var lowerLeftParagraph = oddFooter.Tables[ 0 ].Rows[ 0 ].Cells[ 0 ].Paragraphs[ 0 ]; + lowerLeftParagraph.Append( "Toms Telecom 2016" ).Color( Color.White ); + lowerLeftParagraph.SpacingBefore( 5d ); + + // Define Data in first page : a Paragraph. + var paragraph = document.InsertParagraph(); + paragraph.AppendLine( "Toms Telecom Annual report\n2016" ).Bold().FontSize( 35 ).SpacingBefore( 150d ); + paragraph.Alignment = Alignment.center; + paragraph.InsertPageBreakAfterSelf(); + + // Define Data in second page : a Bar Chart. + document.InsertParagraph("").SpacingAfter( 150d ); + var barChart = new BarChart(); + var sales = CompanyData.CreateSales(); + var salesSeries = new Series( "Sales Per Month" ); + salesSeries.Color = Color.GreenYellow; + salesSeries.Bind( sales, "Month", "Sales" ); + barChart.AddSeries( salesSeries ); + document.InsertChart( barChart ); + document.InsertParagraph("Sales were 11% greater in 2016 compared to 2015, with the usual drop during spring time.").SpacingBefore(35d).InsertPageBreakAfterSelf(); + + // Define Data in third page : a Line Chart. + document.InsertParagraph( "" ).SpacingAfter( 150d ); + var lineChart = new LineChart(); + var calls = CompanyData.CreateCallNumber(); + var callSeries = new Series( "Call Number Per Month" ); + callSeries.Bind( calls, "Month", "Calls" ); + lineChart.AddSeries( callSeries ); + document.InsertChart( lineChart ); + document.InsertParagraph( "The number of calls received was much lower in 2016 compared to 2015, by 31%. Winter is still the busiest time of year." ).SpacingBefore( 35d ); + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: CompanyReport.docx\n" ); + } + } + + + /// + /// Load a document containing a templated invoice with Custom properties, tables, paragraphs and a picture. + /// Set the values of those Custom properties, modify the picture, and fill the details table. + /// + public static void CreateInvoice() + { + Console.WriteLine( "\tCreateInvoice()" ); + + // Load the templated invoice. + var templateDoc = DocX.Load( MiscellaneousSample.MiscellaneousSampleResourcesDirectory + @"TemplateInvoice.docx" ); + if( templateDoc != null ) + { + // Create the invoice from the templated invoice. + var invoice = MiscellaneousSample.CreateInvoiceFromTemplate( templateDoc ); + + invoice.SaveAs( MiscellaneousSample.MiscellaneousSampleOutputDirectory + @"CreateInvoice.docx" ); + Console.WriteLine( "\tCreated: CreateInvoice.docx\n" ); + } + } + #endregion + + #region Private Methods + + private static DocX CreateInvoiceFromTemplate( DocX templateDoc ) + { + // Fill in the document custom properties. + templateDoc.AddCustomProperty( new CustomProperty( "InvoiceNumber", 1355 ) ); + templateDoc.AddCustomProperty( new CustomProperty( "InvoiceDate", new DateTime( 2016, 10, 15 ).ToShortDateString() ) ); + templateDoc.AddCustomProperty( new CustomProperty( "CompanyName", "Toms Telecoms" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "CompanySlogan", "Always with you" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "ClientName", "James Doh" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "ClientStreetName", "123 Main street" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "ClientCity", "Springfield, Ohio" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "ClientZipCode", "54789" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "ClientPhone", "438-585-9636" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "ClientMail", "abc@gmail.com" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "CompanyStreetName", "1458 Thompson Road" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "CompanyCity", "Los Angeles, California" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "CompanyZipCode", "90210" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "CompanyPhone", "1-965-434-5786" ) ); + templateDoc.AddCustomProperty( new CustomProperty( "CompanySupport", "support@tomstelecoms.com" ) ); + + // Remove the default logo and add the new one. + var paragraphWithDefaultLogo = MiscellaneousSample.GetParagraphContainingPicture( templateDoc ); + if( paragraphWithDefaultLogo != null ) + { + paragraphWithDefaultLogo.Pictures.First().Remove(); + var newLogo = templateDoc.AddImage( MiscellaneousSample.MiscellaneousSampleResourcesDirectory + @"Phone.png" ); + paragraphWithDefaultLogo.AppendPicture( newLogo.CreatePicture( 60, 180 ) ); + } + + // Fill the details table. + MiscellaneousSample.FillDetailsTable( ref templateDoc ); + + return templateDoc; + } + + private static Paragraph GetParagraphContainingPicture( DocX doc ) + { + foreach( var p in doc.Paragraphs ) + { + var picture = p.Pictures.FirstOrDefault(); + if( picture != null ) + { + return p; + } + } + + return null; + } + + private static void FillDetailsTable( ref DocX templateDoc ) + { + // The datas that will fill the details table. + var datas = MiscellaneousSample.GetDetailsData(); + + // T he table from the templated invoice. + var detailsTable = templateDoc.Tables.LastOrDefault(); + if( detailsTable == null ) + return; + + // Remove all rows of the details table, except the header one. + while( detailsTable.Rows.Count > 1 ) + { + detailsTable.RemoveRow(); + } + + // Loop through each data rows and use them to add new rows in the detailsTable. + foreach( DataRow data in datas.Rows ) + { + var newRow = detailsTable.InsertRow(); + newRow.Cells.First().InsertParagraph( data.ItemArray.First().ToString() ); + newRow.Cells.Last().InsertParagraph( data.ItemArray.Last().ToString() ); + } + + // Calculate the total amount. + var amountStrings = detailsTable.Rows.Select( r => r.Cells.Last().Paragraphs.Last().Text.Remove(0,1) ).ToList(); + amountStrings.RemoveAt( 0 ); // remove the header + var totalAmount = amountStrings.Select( s => double.Parse( s ) ).Sum(); + + // Add a Total row in the details table. + var totalRow = detailsTable.InsertRow(); + totalRow.Cells.First().InsertParagraph( "TOTAL:" ); + totalRow.Cells.Last().InsertParagraph( string.Format( "${0}", totalAmount ) ); + } + + private static DataTable GetDetailsData() + { + // Create Data to fill the invoice details table. + var dataTable = new DataTable(); + dataTable.Columns.AddRange( new DataColumn[] { new DataColumn( "Description" ), new DataColumn( "Amount" ) } ); + + dataTable.Rows.Add( "Explorer 8698HD Terminal", "$149.95" ); + dataTable.Rows.Add( "MultiSwitch TV Connector", "$24.95" ); + dataTable.Rows.Add( "50 feets cable wires", "$22.49" ); + dataTable.Rows.Add( "Transit A449 Phone Modem", "$59.95" ); + dataTable.Rows.Add( "Toms Wi-Fi router", "$79.95" ); + dataTable.Rows.Add( "Toms Protect2000 Antivirus software", "$39.95" ); + dataTable.Rows.Add( "Installation (3h30)", "$154.49" ); + + return dataTable; + } + + #endregion + + #region Private Classes + + private class CompanyData + { + public string Month + { + get; + set; + } + + public int Sales + { + get; + set; + } + + public int Calls + { + get; + set; + } + + internal static List CreateSales() + { + var sales = new List(); + sales.Add( new CompanyData() { Month = "Jan", Sales = 2500 } ); + sales.Add( new CompanyData() { Month = "Fev", Sales = 3000 } ); + sales.Add( new CompanyData() { Month = "Mar", Sales = 2850 } ); + sales.Add( new CompanyData() { Month = "Apr", Sales = 1050 } ); + sales.Add( new CompanyData() { Month = "May", Sales = 1200 } ); + sales.Add( new CompanyData() { Month = "Jun", Sales = 2900 } ); + sales.Add( new CompanyData() { Month = "Jul", Sales = 3450 } ); + sales.Add( new CompanyData() { Month = "Aug", Sales = 3800 } ); + sales.Add( new CompanyData() { Month = "Sep", Sales = 2900 } ); + sales.Add( new CompanyData() { Month = "Oct", Sales = 2600 } ); + sales.Add( new CompanyData() { Month = "Nov", Sales = 3000 } ); + sales.Add( new CompanyData() { Month = "Dec", Sales = 2500 } ); + return sales; + } + + internal static List CreateCallNumber() + { + var calls = new List(); + calls.Add( new CompanyData() { Month = "Jan", Calls = 1200 } ); + calls.Add( new CompanyData() { Month = "Fev", Calls = 1400 } ); + calls.Add( new CompanyData() { Month = "Mar", Calls = 400 } ); + calls.Add( new CompanyData() { Month = "Apr", Calls = 50 } ); + calls.Add( new CompanyData() { Month = "May", Calls = 220 } ); + calls.Add( new CompanyData() { Month = "Jun", Calls = 400 } ); + calls.Add( new CompanyData() { Month = "Jul", Calls = 880 } ); + calls.Add( new CompanyData() { Month = "Aug", Calls = 220 } ); + calls.Add( new CompanyData() { Month = "Sep", Calls = 550 } ); + calls.Add( new CompanyData() { Month = "Oct", Calls = 790 } ); + calls.Add( new CompanyData() { Month = "Nov", Calls = 990 } ); + calls.Add( new CompanyData() { Month = "Dec", Calls = 1300 } ); + return calls; + } + } + + #endregion + } +} diff --git a/Examples/Samples/Miscellaneous/Resources/Phone.png b/Examples/Samples/Miscellaneous/Resources/Phone.png new file mode 100644 index 00000000..6c9d950e Binary files /dev/null and b/Examples/Samples/Miscellaneous/Resources/Phone.png differ diff --git a/Examples/Samples/Miscellaneous/Resources/TemplateInvoice.docx b/Examples/Samples/Miscellaneous/Resources/TemplateInvoice.docx new file mode 100644 index 00000000..c0538fc6 Binary files /dev/null and b/Examples/Samples/Miscellaneous/Resources/TemplateInvoice.docx differ diff --git a/Examples/Samples/Miscellaneous/Resources/cupcake.png b/Examples/Samples/Miscellaneous/Resources/cupcake.png new file mode 100644 index 00000000..c89e261c Binary files /dev/null and b/Examples/Samples/Miscellaneous/Resources/cupcake.png differ diff --git a/Examples/Samples/Paragraph/ParagraphSample.cs b/Examples/Samples/Paragraph/ParagraphSample.cs new file mode 100644 index 00000000..51c5a74b --- /dev/null +++ b/Examples/Samples/Paragraph/ParagraphSample.cs @@ -0,0 +1,259 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text.RegularExpressions; + +namespace Xceed.Words.NET.Examples +{ + public class ParagraphSample + { + #region Private Members + + private static Dictionary _replacePatterns = new Dictionary() + { + { "COST", "$13.95" }, + }; + + private const string ParagraphSampleOutputDirectory = Program.SampleDirectory + @"Paragraph\Output\"; + + #endregion + + #region Constructors + + static ParagraphSample() + { + if( !Directory.Exists( ParagraphSample.ParagraphSampleOutputDirectory ) ) + { + Directory.CreateDirectory( ParagraphSample.ParagraphSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Create a document with formatted paragraphs. + /// + public static void SimpleFormattedParagraphs() + { + Console.WriteLine( "\tSimpleFormattedParagraphs()" ); + + // Create a new document. + using( DocX document = DocX.Create( ParagraphSample.ParagraphSampleOutputDirectory + @"SimpleFormattedParagraphs.docx" ) ) + { + // Add a title + document.InsertParagraph( "Formatted paragraphs" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Insert a Paragraph into this document. + var p = document.InsertParagraph(); + + // Append some text and add formatting. + p.Append( "This is a simple formatted red bold paragraph" ) + .Font( new Font( "Arial" ) ) + .FontSize( 25 ) + .Color( Color.Red ) + .Bold() + .Append( " containing a blue italic text." ).Font( new Font( "Times New Roman" ) ).Color( Color.Blue ).Italic() + .SpacingAfter( 40 ); + + // Insert another Paragraph into this document. + var p2 = document.InsertParagraph(); + + // Append some text and add formatting. + p2.Append( "This is a formatted paragraph using spacing," ) + .Font( new Font( "Courier New" ) ) + .FontSize( 10 ) + .Italic() + .Spacing( 5 ) + .Append( "highlight" ).Highlight( Highlight.yellow ).UnderlineColor( Color.Blue ).CapsStyle( CapsStyle.caps ) + .Append( " and strike through." ).StrikeThrough( StrikeThrough.strike ); + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: SimpleFormattedParagraphs.docx\n" ); + } + } + + /// + /// Create a document and add a paragraph with all its lines on a single page. + /// + public static void ForceParagraphOnSinglePage() + { + Console.WriteLine( "\tForceParagraphOnSinglePage()" ); + + // Create a new document. + using( DocX document = DocX.Create( ParagraphSample.ParagraphSampleOutputDirectory + @"ForceParagraphOnSinglePage.docx" ) ) + { + // Add a title + document.InsertParagraph( "Prevent paragraph split" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Create a Paragraph that will appear on 1st page. + var p = document.InsertParagraph( "This is a paragraph on first page.\nLine2\nLine3\nLine4\nLine5\nLine6\nLine7\nLine8\nLine9\nLine10\nLine11\nLine12\nLine13\nLine14\nLine15\nLine16\nLine17\nLine18\nLine19\nLine20\nLine21\nLine22\nLine23\nLine24\nLine25\n" ); + p.FontSize(15).SpacingAfter( 30 ); + + // Create a Paragraph where all its lines will appear on a same page. + var p2 = document.InsertParagraph( "This is a paragraph where all its lines are on the same page. The paragraph does not split on 2 pages.\nLine2\nLine3\nLine4\nLine5\nLine6\nLine7\nLine8\nLine9\nLine10" ); + p2.SpacingAfter( 30 ); + + // Indicate that all the paragraph's lines will be on the same page + p2.KeepLinesTogether(); + + // Create a Paragraph that will appear on 2nd page. + var p3 = document.InsertParagraph( "This is a paragraph on second page.\nLine2\nLine3\nLine4\nLine5\nLine6\nLine7\nLine8\nLine9\nLine10" ); + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: ForceParagraphOnSinglePage.docx\n" ); + } + } + + /// + /// Create a document and add a paragraph with all its lines on the same page as the next paragraph. + /// + public static void ForceMultiParagraphsOnSinglePage() + { + Console.WriteLine( "\tForceMultiParagraphsOnSinglePage()" ); + + // Create a new document. + using( DocX document = DocX.Create( ParagraphSample.ParagraphSampleOutputDirectory + @"ForceMultiParagraphsOnSinglePage.docx" ) ) + { + // Add a title. + document.InsertParagraph( "Keeps Paragraphs on same page" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Create a Paragraph that will appear on 1st page. + var p = document.InsertParagraph( "This is a paragraph on first page.\nLine2\nLine3\nLine4\nLine5\nLine6\nLine7\nLine8\nLine9\nLine10\nLine11\nLine12\nLine13\nLine14\nLine15\nLine16\nLine17\nLine18\nLine19\nLine20\nLine21\nLine22\n" ); + p.FontSize( 15 ).SpacingAfter( 30 ); + + // Create a Paragraph where all its lines will appear on a same page as the next paragraph. + var p2 = document.InsertParagraph( "This is a paragraph where all its lines are on the same page as the next paragraph.\nLine2\nLine3\nLine4\nLine5\nLine6\nLine7\nLine8\nLine9\nLine10" ); + p2.SpacingAfter( 30 ); + + // Indicate that this paragraph will be on the same page as the next paragraph. + p2.KeepWithNextParagraph(); + + // Create a Paragraph that will appear on 2nd page. + var p3 = document.InsertParagraph( "This is a paragraph on second page.\nLine2\nLine3\nLine4\nLine5\nLine6\nLine7\nLine8\nLine9\nLine10" ); + + // Indicate that all this paragraph's lines will be on the same page. + p3.KeepLinesTogether(); + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: ForceMultiParagraphsOnSinglePage.docx\n" ); + } + } + + /// + /// Create a document and insert, remove and replace texts. + /// + public static void TextActions() + { + Console.WriteLine( "\tTextActions()" ); + + // Create a new document. + using( DocX document = DocX.Create( ParagraphSample.ParagraphSampleOutputDirectory + @"TextActions.docx" ) ) + { + // Add a title + document.InsertParagraph( "Insert, remove and replace text" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Create a paragraph and insert text. + var p1 = document.InsertParagraph( "In this paragraph we insert a comma, a colon and " ); + // Add a comma at index 17. + p1.InsertText( 17, "," ); + // Add a colon at index of character 'd'. + p1.InsertText( p1.Text.IndexOf( "d" ) + 1, ": " ); + // Add "a name" at the end of p1.Text. + p1.InsertText( p1.Text.Length, "a name." ); + + p1.SpacingAfter( 30 ); + + // Create a paragraph and insert text. + var p2 = document.InsertParagraph( "In this paragraph, we remove a mistaken word and a comma." ); + // Remove the word "mistaken". + p2.RemoveText( 31, 9 ); + // Remove the comma sign. + p2.RemoveText( p2.Text.IndexOf( "," ), 1 ); + + p2.SpacingAfter( 30 ); + + // Create a paragraph and insert text. + var p3 = document.InsertParagraph( "In this paragraph, we replace an complex word with an easier one and spaces with hyphens." ); + // Replace the "complex" word with "easy" word. + p3.ReplaceText( "complex", "easy" ); + // Replace the spaces with tabs + p3.ReplaceText( " ", "--" ); + + p3.SpacingAfter( 30 ); + + // Create a paragraph and insert text. + var p4 = document.InsertParagraph( "In this paragraph, we replace a word by using a handler: ." ); + // Replace "" with "$13.95" using an handler + p4.ReplaceText( "<(.*?)>", ReplaceTextHandler, false, RegexOptions.IgnoreCase, null, new Formatting() ); + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: TextActions.docx\n" ); + } + } + + /// + /// Set different Heading type for a Paragraph. + /// + public static void Heading() + { + Console.WriteLine( "\tHeading()" ); + + // Create a document. + using( DocX document = DocX.Create( ParagraphSample.ParagraphSampleOutputDirectory + @"Heading.docx" ) ) + { + // Add a title. + document.InsertParagraph( "Heading types" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + var headingTypes = Enum.GetValues( typeof( HeadingType ) ); + + foreach( HeadingType heading in headingTypes ) + { + // Set a text containing the current Heading type. + var text = string.Format( "This Paragraph is using \"{0}\" heading type.", heading.EnumDescription() ); + // Add a paragraph. + var p = document.InsertParagraph().AppendLine( text ); + // Set the paragraph's heading type. + p.Heading( heading ); + } + + document.Save(); + Console.WriteLine( "\tCreated: Heading.docx\n" ); + } + } + + #endregion + + #region Private Methods + + private static string ReplaceTextHandler( string findStr ) + { + if( _replacePatterns.ContainsKey( findStr ) ) + { + return _replacePatterns[ findStr ]; + } + return findStr; + } + + #endregion + } +} diff --git a/Examples/Samples/Parallel/ParallelSample.cs b/Examples/Samples/Parallel/ParallelSample.cs new file mode 100644 index 00000000..470160b9 --- /dev/null +++ b/Examples/Samples/Parallel/ParallelSample.cs @@ -0,0 +1,91 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System; +using System.IO; +using System.Threading.Tasks; +using System.Linq; + +namespace Xceed.Words.NET.Examples +{ + public class ParallelSample + { + #region Private Members + + private const string ParallelSampleResourcesDirectory = Program.SampleDirectory + @"Parallel\Resources\"; + private const string ParallelSampleOutputDirectory = Program.SampleDirectory + @"Parallel\Output\"; + + #endregion + + #region Constructors + + static ParallelSample() + { + if( !Directory.Exists( ParallelSample.ParallelSampleOutputDirectory ) ) + { + Directory.CreateDirectory( ParallelSample.ParallelSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// For each of the documents in the folder 'Parallel\Resources\', + /// Replace the string "Apple" with the string "Potato" and replace the "Apple" image by a "Potato" image. + /// Do this in Parrallel accross many CPU cores. + /// + public static void DoParallelActions() + { + Console.WriteLine( "\tDoParallelActions()" ); + + // Get the docx files from the Resources directory. + var inputDir = new DirectoryInfo( ParallelSample.ParallelSampleResourcesDirectory ); + var inputFiles = inputDir.GetFiles( "*.docx" ); + + // Loop through each document and do actions on them. + Parallel.ForEach( inputFiles, f => ParallelSample.Action( f ) ); + } + + private static void Action( FileInfo file ) + { + // Load the document. + using( DocX document = DocX.Load( file.FullName ) ) + { + // Replace texts in this document. + document.ReplaceText( "Apples", "Potatoes" ); + document.ReplaceText( "An Apple", "A Potato" ); + + // create the new image + var newImage = document.AddImage( ParallelSample.ParallelSampleResourcesDirectory + @"potato.jpg" ); + + // Look in each paragraph and remove its first image to replace it with the new one. + foreach( var p in document.Paragraphs ) + { + var oldPicture = p.Pictures.FirstOrDefault(); + if( oldPicture != null ) + { + oldPicture.Remove(); + p.AppendPicture( newImage.CreatePicture( 150, 150 ) ); + } + } + + document.SaveAs( ParallelSample.ParallelSampleOutputDirectory + "Output" + file.Name ); + Console.WriteLine( "\tCreated: Output" + file.Name + ".docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/Parallel/Resources/Doc1.docx b/Examples/Samples/Parallel/Resources/Doc1.docx new file mode 100644 index 00000000..f71e4259 Binary files /dev/null and b/Examples/Samples/Parallel/Resources/Doc1.docx differ diff --git a/Examples/Samples/Parallel/Resources/Doc2.docx b/Examples/Samples/Parallel/Resources/Doc2.docx new file mode 100644 index 00000000..34428213 Binary files /dev/null and b/Examples/Samples/Parallel/Resources/Doc2.docx differ diff --git a/Examples/Samples/Parallel/Resources/Doc3.docx b/Examples/Samples/Parallel/Resources/Doc3.docx new file mode 100644 index 00000000..988a79eb Binary files /dev/null and b/Examples/Samples/Parallel/Resources/Doc3.docx differ diff --git a/Examples/Samples/Parallel/Resources/potato.jpg b/Examples/Samples/Parallel/Resources/potato.jpg new file mode 100644 index 00000000..00b425bc Binary files /dev/null and b/Examples/Samples/Parallel/Resources/potato.jpg differ diff --git a/Examples/Samples/Protection/ProtectionSample.cs b/Examples/Samples/Protection/ProtectionSample.cs new file mode 100644 index 00000000..c7edd571 --- /dev/null +++ b/Examples/Samples/Protection/ProtectionSample.cs @@ -0,0 +1,107 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System; +using System.Drawing; +using System.IO; + +namespace Xceed.Words.NET.Examples +{ + public class ProtectionSample + { + #region Private Members + + private const string ProtectionSampleOutputDirectory = Program.SampleDirectory + @"Protection\Output\"; + + #endregion + + #region Constructors + + static ProtectionSample() + { + if( !Directory.Exists( ProtectionSample.ProtectionSampleOutputDirectory ) ) + { + Directory.CreateDirectory( ProtectionSample.ProtectionSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Create a read only document that can be edited by entering a valid password. + /// + public static void AddPasswordProtection() + { + Console.WriteLine( "\tAddPasswordProtection()" ); + + // Create a new document. + using( DocX document = DocX.Create( ProtectionSample.ProtectionSampleOutputDirectory + @"AddPasswordProtection.docx" ) ) + { + // Add a title + document.InsertParagraph( "Document protection using password" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Insert a Paragraph into this document. + var p = document.InsertParagraph(); + + // Append some text and add formatting. + p.Append( "This document is protected and can only be edited by stopping its protection with a valid password(\"xceed\")." ) + .Font( new Font( "Arial" ) ) + .FontSize( 25 ) + .Color( Color.Blue ) + .Bold(); + + // Set the document as read only and add a password to unlock it. + document.AddPasswordProtection( EditRestrictions.readOnly, "xceed" ); + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: AddPasswordProtection.docx\n" ); + } + } + + /// + /// Create a read only document that can be edited by stopping the protection. + /// + public static void AddProtection() + { + Console.WriteLine( "\tAddProtection()" ); + + // Create a new document. + using( DocX document = DocX.Create( ProtectionSample.ProtectionSampleOutputDirectory + @"AddProtection.docx" ) ) + { + // Add a title. + document.InsertParagraph( "Document protection not using password" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Insert a Paragraph into this document. + var p = document.InsertParagraph(); + + // Append some text and add formatting. + p.Append( "This document is protected and can only be edited by stopping its protection." ) + .Font( new Font( "Arial" ) ) + .FontSize( 25 ) + .Color( Color.Red ) + .Bold(); + + document.AddProtection( EditRestrictions.readOnly ); + + // Save this document to disk. + document.Save(); + Console.WriteLine( "\tCreated: AddProtection.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/Section/SectionSample.cs b/Examples/Samples/Section/SectionSample.cs new file mode 100644 index 00000000..d658271b --- /dev/null +++ b/Examples/Samples/Section/SectionSample.cs @@ -0,0 +1,88 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ + +using System; +using System.IO; +using System.Linq; + +namespace Xceed.Words.NET.Examples +{ + public class SectionSample + { + #region Private Members + + private const string SectionSampleOutputDirectory = Program.SampleDirectory + @"Section\Output\"; + + #endregion + + #region Constructors + + static SectionSample() + { + if( !Directory.Exists( SectionSample.SectionSampleOutputDirectory ) ) + { + Directory.CreateDirectory( SectionSample.SectionSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Create a document and insert Sections into it. + /// + public static void InsertSections() + { + Console.WriteLine( "\tInsertSections()" ); + + // Create a document. + using( DocX document = DocX.Create( SectionSample.SectionSampleOutputDirectory + @"InsertSections.docx" ) ) + { + // Add a title + document.InsertParagraph( "Inserting sections" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add 2 paragraphs + document.InsertParagraph( "This is the first paragraph." ); + document.InsertParagraph( "This is the second paragraph." ); + // Add a paragraph and a section break. + document.InsertSection(); + // Add a new paragraph + document.InsertParagraph( "This is the third paragraph, in a new section." ); + // Add a paragraph and a page break. + document.InsertSectionPageBreak(); + document.InsertParagraph( "This is the fourth paragraph, in a new section." ); + + var sections = document.GetSections(); + + // Add a paragraph to display the result of sections. + var p = document.InsertParagraph( "This document contains " ).Append( sections.Count.ToString() ).Append( " Sections.\n" ); + p.SpacingBefore( 40d ); + // Display the paragraphs count per section from this document. + for( int i = 0; i < sections.Count; ++i ) + { + var section = sections[ i ]; + var paragraphs = section.SectionParagraphs; + var nonEmptyParagraphs = paragraphs.Where( x => !string.IsNullOrEmpty( x.Text ) ); + p.Append( "Section " ).Append( (i + 1).ToString() ).Append( " has " ).Append( nonEmptyParagraphs.Count().ToString() ).Append( " non-empty paragraphs.\n" ); + } + + document.Save(); + Console.WriteLine( "\tCreated: InsertSections.docx\n" ); + } + } + + #endregion + } +} diff --git a/Examples/Samples/Table/Resources/DocumentWithTemplateTable.docx b/Examples/Samples/Table/Resources/DocumentWithTemplateTable.docx new file mode 100644 index 00000000..552c1ebc Binary files /dev/null and b/Examples/Samples/Table/Resources/DocumentWithTemplateTable.docx differ diff --git a/Examples/Samples/Table/Resources/logo_xceed.png b/Examples/Samples/Table/Resources/logo_xceed.png new file mode 100644 index 00000000..d21b65ec Binary files /dev/null and b/Examples/Samples/Table/Resources/logo_xceed.png differ diff --git a/Examples/Samples/Table/TableSample.cs b/Examples/Samples/Table/TableSample.cs new file mode 100644 index 00000000..b98b5f3a --- /dev/null +++ b/Examples/Samples/Table/TableSample.cs @@ -0,0 +1,338 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ + +using System; +using System.Drawing; +using System.IO; +using System.Linq; + +namespace Xceed.Words.NET.Examples +{ + public class TableSample + { + #region Private Members + + private static Random rand = new Random(); + + private const string TableSampleResourcesDirectory = Program.SampleDirectory + @"Table\Resources\"; + private const string TableSampleOutputDirectory = Program.SampleDirectory + @"Table\Output\"; + + #endregion + + #region Constructors + + static TableSample() + { + if( !Directory.Exists( TableSample.TableSampleOutputDirectory ) ) + { + Directory.CreateDirectory( TableSample.TableSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Create a table, insert rows, image and replace text. + /// + public static void InsertRowAndImageTable() + { + Console.WriteLine( "\tInsertRowAndImageTable()" ); + + // Create a document. + using( DocX document = DocX.Create( TableSample.TableSampleOutputDirectory + @"InsertRowAndImageTable.docx" ) ) + { + // Add a title + document.InsertParagraph( "Inserting table" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add a Table into the document and sets its values. + var t = document.AddTable( 5, 2 ); + t.Design = TableDesign.ColorfulListAccent1; + t.Alignment = Alignment.center; + t.Rows[ 0 ].Cells[ 0 ].Paragraphs[ 0 ].Append( "Mike" ); + t.Rows[ 0 ].Cells[ 1 ].Paragraphs[ 0 ].Append( "65" ); + t.Rows[ 1 ].Cells[ 0 ].Paragraphs[ 0 ].Append( "Kevin" ); + t.Rows[ 1 ].Cells[ 1 ].Paragraphs[ 0 ].Append( "62" ); + t.Rows[ 2 ].Cells[ 0 ].Paragraphs[ 0 ].Append( "Carl" ); + t.Rows[ 2 ].Cells[ 1 ].Paragraphs[ 0 ].Append( "60" ); + t.Rows[ 3 ].Cells[ 0 ].Paragraphs[ 0 ].Append( "Michael" ); + t.Rows[ 3 ].Cells[ 1 ].Paragraphs[ 0 ].Append( "59" ); + t.Rows[ 4 ].Cells[ 0 ].Paragraphs[ 0 ].Append( "Shawn" ); + t.Rows[ 4 ].Cells[ 1 ].Paragraphs[ 0 ].Append( "57" ); + + // Add a row at the end of the table and sets its values. + var r = t.InsertRow(); + r.Cells[ 0 ].Paragraphs[ 0 ].Append( "Mario" ); + r.Cells[ 1 ].Paragraphs[ 0 ].Append( "54" ); + + // Add a row at the end of the table which is a copy of another row, and sets its values. + var newPlayer = t.InsertRow( t.Rows[ 2 ] ); + newPlayer.ReplaceText( "Carl", "Max" ); + newPlayer.ReplaceText( "60", "50" ); + + // Add an image into the document. + var image = document.AddImage( TableSample.TableSampleResourcesDirectory + @"logo_xceed.png" ); + // Create a picture from image. + var picture = image.CreatePicture( 25, 100 ); + + // Calculate totals points from second column in table. + var totalPts = 0; + foreach( var row in t.Rows ) + { + totalPts += int.Parse( row.Cells[ 1 ].Paragraphs[ 0 ].Text ); + } + + // Add a row at the end of the table and sets its values. + var totalRow = t.InsertRow(); + totalRow.Cells[ 0 ].Paragraphs[ 0 ].Append( "Total for " ).AppendPicture( picture ); + totalRow.Cells[ 1 ].Paragraphs[ 0 ].Append( totalPts.ToString() ); + totalRow.Cells[ 1 ].VerticalAlignment = VerticalAlignment.Center; + + // Insert a new Paragraph into the document. + var p = document.InsertParagraph( "Xceed Top Players Points:" ); + p.SpacingAfter( 40d ); + + // Insert the Table after the Paragraph. + p.InsertTableAfterSelf( t ); + + document.Save(); + Console.WriteLine( "\tCreated: InsertRowAndImageTable.docx\n" ); + } + } + + /// + /// Create a table and set the text direction of each cell. + /// + public static void TextDirectionTable() + { + Console.WriteLine( "\tTextDirectionTable()" ); + + // Create a document. + using( DocX document = DocX.Create( TableSample.TableSampleOutputDirectory + @"TextDirectionTable.docx" ) ) + { + // Add a title + document.InsertParagraph( "Text Direction of Table's cells" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Create a table. + var table = document.AddTable( 2, 3 ); + table.Design = TableDesign.ColorfulList; + + // Set the table's values. + table.Rows[ 0 ].Cells[ 0 ].Paragraphs[ 0 ].Append( "First" ); + table.Rows[ 0 ].Cells[ 0 ].TextDirection = TextDirection.btLr; + table.Rows[ 0 ].Cells[ 0 ].Paragraphs[ 0 ].Spacing( 5d ); + table.Rows[ 0 ].Cells[ 1 ].Paragraphs[ 0 ].Append( "Second" ); + table.Rows[ 0 ].Cells[ 1 ].TextDirection = TextDirection.right; + table.Rows[ 0 ].Cells[ 2 ].Paragraphs[ 0 ].Append( "Third" ); + table.Rows[ 0 ].Cells[ 2 ].Paragraphs[ 0 ].Spacing( 5d ); + table.Rows[ 0 ].Cells[ 2 ].TextDirection = TextDirection.btLr; + table.Rows[ 1 ].Cells[ 0 ].Paragraphs[ 0 ].Append( "Fourth" ); + table.Rows[ 1 ].Cells[ 0 ].TextDirection = TextDirection.btLr; + table.Rows[ 1 ].Cells[ 0 ].Paragraphs[ 0 ].Spacing( 5d ); + table.Rows[ 1 ].Cells[ 1 ].Paragraphs[ 0 ].Append( "Fifth" ); + table.Rows[ 1 ].Cells[ 2 ].Paragraphs[ 0 ].Append( "Sixth" ).Color( Color.White ); + table.Rows[ 1 ].Cells[ 2 ].TextDirection = TextDirection.btLr; + // Last cell have a green background + table.Rows[ 1 ].Cells[ 2 ].FillColor = Color.Green; + table.Rows[ 1 ].Cells[ 2 ].Paragraphs[ 0 ].Spacing( 5d ); + + // Set the table's column width. + table.SetWidths( new float[] { 200, 300, 100 } ); + + // Add the table into the document. + document.InsertTable( table ); + + document.Save(); + Console.WriteLine( "\tCreated: TextDirectionTable.docx\n" ); + } + } + + /// + /// Load a document, gets its table and replace the default row with updated copies of it. + /// + public static void CreateRowsFromTemplate() + { + Console.WriteLine( "\tCreateRowsFromTemplate()" ); + + // Load a document + using( DocX document = DocX.Load( TableSample.TableSampleResourcesDirectory + @"DocumentWithTemplateTable.docx" ) ) + { + // get the table with caption "GROCERY_LIST" from the document. + var groceryListTable = document.Tables.FirstOrDefault( t => t.TableCaption == "GROCERY_LIST" ); + if( groceryListTable == null ) + { + Console.WriteLine( "\tError, couldn't find table with caption GROCERY_LIST in current document." ); + } + else + { + if( groceryListTable.RowCount > 1 ) + { + // Get the row pattern of the second row. + var rowPattern = groceryListTable.Rows[ 1 ]; + + // Add items (rows) to the grocery list. + TableSample.AddItemToTable( groceryListTable, rowPattern, "Banana" ); + TableSample.AddItemToTable( groceryListTable, rowPattern, "Strawberry" ); + TableSample.AddItemToTable( groceryListTable, rowPattern, "Chicken" ); + TableSample.AddItemToTable( groceryListTable, rowPattern, "Bread" ); + TableSample.AddItemToTable( groceryListTable, rowPattern, "Eggs" ); + TableSample.AddItemToTable( groceryListTable, rowPattern, "Salad" ); + + // Remove the pattern row. + rowPattern.Remove(); + } + } + + document.SaveAs( TableSample.TableSampleOutputDirectory + @"CreateTableFromTemplate.docx" ); + Console.WriteLine( "\tCreated: CreateTableFromTemplate.docx\n" ); + } + } + + /// + /// Add a Table in a document where its columns will have a specific width. In addition, + /// the left margin of the row cells will be removed for all rows except the first. + /// Finally, a blank border will be set for the table's top and bottom borders. + /// + public static void ColumnsWidth() + { + Console.WriteLine( "\tColumnsWidth()" ); + + // Create a document + using( DocX document = DocX.Create( TableSample.TableSampleOutputDirectory + @"ColumnsWidth.docx" ) ) + { + // Add a title + document.InsertParagraph( "Columns width" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Insert a title paragraph. + var p = document.InsertParagraph( "In the following table, the cell's left margin has been removed for rows 2-5 as well as the top/bottom table's borders." ).Bold(); + p.Alignment = Alignment.center; + p.SpacingAfter( 40d ); + + // Add a table in a document of 1 row and 3 columns. + var columnWidths = new float[] { 100f, 300f, 200f }; + var t = document.InsertTable( 1, columnWidths.Length ); + + // Set the table's column width and background + t.SetWidths( columnWidths ); + t.Design = TableDesign.TableGrid; + t.AutoFit = AutoFit.Contents; + + var row = t.Rows.First(); + + // Fill in the columns of the first row in the table. + for( int i = 0; i < row.Cells.Count; ++i ) + { + row.Cells[i].Paragraphs.First().Append( "Data " + i ); + } + + // Add rows in the table. + for( int i = 0; i < 5; i++ ) + { + var newRow = t.InsertRow(); + + // Fill in the columns of the new rows. + for( int j = 0; j < newRow.Cells.Count; ++j ) + { + var newCell = newRow.Cells[ j ]; + newCell.Paragraphs.First().Append( "Data " + i ); + // Remove the left margin of the new cells. + newCell.MarginLeft = 0; + } + } + + // Set a blank border for the table's top/bottom borders. + var blankBorder = new Border( BorderStyle.Tcbs_none, 0, 0, Color.White ); + t.SetBorder( TableBorderType.Bottom, blankBorder ); + t.SetBorder( TableBorderType.Top, blankBorder ); + + document.Save(); + Console.WriteLine( "\tCreated: ColumnsWidth.docx\n" ); + } + } + + /// + /// Add a table and merged some cells. Individual cells can also be removed by shifting their right neighbors to the left. + /// + public static void MergeCells() + { + Console.WriteLine( "\tMergeCells()" ); + + // Create a document. + using( DocX document = DocX.Create( TableSample.TableSampleOutputDirectory + @"MergeCells.docx" ) ) + { + // Add a title. + document.InsertParagraph( "Merge and delete cells" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add A table . + var t = document.AddTable( 3, 2 ); + t.Design = TableDesign.TableGrid; + + var t1 = document.InsertTable( t ); + + // Add 4 columns in the table. + t1.InsertColumn( t1.ColumnCount, true ); + t1.InsertColumn( t1.ColumnCount, true ); + t1.InsertColumn( t1.ColumnCount, true ); + t1.InsertColumn( t1.ColumnCount, true ); + + // Merged Cells 1 to 4 in first row of the table. + t1.Rows[ 0 ].MergeCells( 1, 4 ); + + // Merged the last 2 Cells in the second row of the table. + var columnCount = t1.Rows[ 1 ].ColumnCount; + t1.Rows[ 1 ].MergeCells( columnCount - 2, columnCount - 1 ); + + // Add text in each cell of the table. + foreach( var r in t1.Rows ) + { + for( int i = 0; i < r.Cells.Count; ++i ) + { + var c = r.Cells[ i ]; + c.Paragraphs[ 0 ].InsertText( "Column " + i ); + c.Paragraphs[ 0 ].Alignment = Alignment.center; + } + } + + // Delete the second cell from the third row and shift the cells on its right by 1 to the left. + t1.DeleteAndShiftCellsLeft( 2, 1 ); + + document.Save(); + Console.WriteLine( "\tCreated: MergeCells.docx\n" ); + } + } + + #endregion + + #region Private Methods + + private static void AddItemToTable( Table table, Row rowPattern, string productName ) + { + // Gets a random unit price and quantity. + var unitPrice = Math.Round( rand.NextDouble(), 2 ); + var unitQuantity = rand.Next( 1, 10 ); + + // Insert a copy of the rowPattern at the last index in the table. + var newItem = table.InsertRow( rowPattern, table.RowCount - 1 ); + + // Replace the default values of the newly inserted row. + newItem.ReplaceText( "%PRODUCT_NAME%", productName ); + newItem.ReplaceText( "%PRODUCT_UNITPRICE%", "$ " + unitPrice.ToString( "N2" ) ); + newItem.ReplaceText( "%PRODUCT_QUANTITY%", unitQuantity.ToString() ); + newItem.ReplaceText( "%PRODUCT_TOTALPRICE%", "$ " + ( unitPrice * unitQuantity ).ToString( "N2" ) ); + } + + #endregion + } +} diff --git a/Examples/Samples/TableOfContent/TableOfContentSample.cs b/Examples/Samples/TableOfContent/TableOfContentSample.cs new file mode 100644 index 00000000..074a67ff --- /dev/null +++ b/Examples/Samples/TableOfContent/TableOfContentSample.cs @@ -0,0 +1,152 @@ +/*************************************************************************************** + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2017 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + *************************************************************************************/ +using System; +using System.IO; + +namespace Xceed.Words.NET.Examples +{ + public class TableOfContentSample + { + #region Private Members + + private const string TableOfContentSampleOutputDirectory = Program.SampleDirectory + @"TableOfContent\Output\"; + + #endregion + + #region Constructors + + static TableOfContentSample() + { + if( !Directory.Exists( TableOfContentSample.TableOfContentSampleOutputDirectory ) ) + { + Directory.CreateDirectory( TableOfContentSample.TableOfContentSampleOutputDirectory ); + } + } + + #endregion + + #region Public Methods + + /// + /// Add a Table of content to a document. + /// + public static void InsertTableOfContent() + { + Console.WriteLine( "\tInsertTableOfContent()" ); + + // Creates a document + using( DocX document = DocX.Create( TableOfContentSample.TableOfContentSampleOutputDirectory + @"InsertTableOfContent.docx" ) ) + { + // Add a title + document.InsertParagraph( "Insert Table of content" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Insert a table of content with a page break. + document.InsertTableOfContents( "Teams", TableOfContentsSwitches.O | TableOfContentsSwitches.U | TableOfContentsSwitches.Z | TableOfContentsSwitches.H ); + document.InsertSectionPageBreak(); + + // Create a paragraph and fill it in method AddTeams(). + var p = document.InsertParagraph(); + var rosters = TableOfContentSample.AddTeams( p ); + document.InsertParagraph( rosters ); + + document.Save(); + Console.WriteLine( "\tCreated: InsertTableOfContent.docx\n" ); + } + } + + /// + /// Add a Table of content to a document by inserting it just before a reference paragraph. + /// + public static void InsertTableOfContentWithReference() + { + Console.WriteLine( "\tInsertTableOfContentWithReference()" ); + + // Create a document. + using( DocX document = DocX.Create( TableOfContentSample.TableOfContentSampleOutputDirectory + @"InsertTableOfContentWithReference.docx" ) ) + { + // Add a title. + document.InsertParagraph( "Insert Table of content with reference" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center; + + // Add an intro paragraph. + var intro = document.InsertParagraph( "This page will show the team rosters of the American League East Division." ); + intro.SpacingAfter( 150d ); + + // Create a paragraph and fill it in method AddTeams(). + var p = document.InsertParagraph(); + var rosters = TableOfContentSample.AddTeams( p ); + document.InsertParagraph( rosters ); + + // Insert a table of content with a page break just before the paragraph p. + document.InsertTableOfContents( p, + "Teams", + TableOfContentsSwitches.O | TableOfContentsSwitches.U | TableOfContentsSwitches.Z | TableOfContentsSwitches.H, + "Heading4" ); + + document.Save(); + Console.WriteLine( "\tCreated: InsertTableOfContentWithReference.docx\n" ); + } + } + + #endregion + + #region Private Methods + + private static Paragraph AddTeams( Paragraph paragraph ) + { + // Add a title paragraph. + var title = paragraph.InsertParagraphAfterSelf( "Team Rosters" ).Bold().FontSize( 20 ).SpacingAfter( 50d ); + title.Alignment = Alignment.center; + + // Add the content paragraphs and set a style for the Table of Content to recognize them. + var p = title.InsertParagraphAfterSelf( "Boston Red Sox" ).Bold().FontSize( 15 ).SpacingAfter( 25d ); + p.StyleName = "Heading1"; + var p1 = p.InsertParagraphAfterSelf( "Tom Smith, P" ) + .AppendLine( "Mike Fitzgerald, C" ) + .AppendLine( "Tom Clancy, 1B" ) + .AppendLine( "Kevin Garnet, OF" ).SpacingAfter( 300d ); + + var p2 = p1.InsertParagraphAfterSelf( "Tampa Rays" ).Bold().FontSize( 15 ).SpacingAfter( 25d ); + p2.StyleName = "Heading1"; + var p3 = p2.InsertParagraphAfterSelf( "Josh Hernandez, P" ) + .AppendLine( "Jacob Trouba, C" ) + .AppendLine( "Jesus Sanchez, 1B" ) + .AppendLine( "Jose Ria, OF" ).SpacingAfter( 300d ); + + var p4 = p3.InsertParagraphAfterSelf( "New York Yankees" ).Bold().FontSize( 15 ).SpacingAfter( 25d ); + p4.StyleName = "Heading1"; + var p5 = p4.InsertParagraphAfterSelf( "Derek Jones, P" ) + .AppendLine( "Jose Riva, C" ) + .AppendLine( "Bryan Smith, 1B" ) + .AppendLine( "Carl Shattern, OF" ).SpacingAfter( 300d ); + + var p6 = p5.InsertParagraphAfterSelf( "Baltimore Orioles" ).Bold().FontSize( 15 ).SpacingAfter( 25d ); + p6.StyleName = "Heading1"; + var p7 = p6.InsertParagraphAfterSelf( "Simon Delgar, P" ) + .AppendLine( "Johnny Helpan, C" ) + .AppendLine( "Miguel Danregados, 1B" ) + .AppendLine( "Joe West, OF" ).SpacingAfter( 300d ); + + var p8 = p7.InsertParagraphAfterSelf( "Toronto Blue Jays" ).Bold().FontSize( 15 ).SpacingAfter( 25d ); + p8.StyleName = "Heading1"; + var p9 = p8.InsertParagraphAfterSelf( "Samir Endoya, P" ) + .AppendLine( "Steve Martin, C" ) + .AppendLine( "Erik Young, 1B" ) + .AppendLine( "Steve Martinek, OF" ); + + return paragraph; + } + + #endregion + } +} diff --git a/Examples/Xceed.Words.NET.Examples.csproj b/Examples/Xceed.Words.NET.Examples.csproj new file mode 100644 index 00000000..53b92472 --- /dev/null +++ b/Examples/Xceed.Words.NET.Examples.csproj @@ -0,0 +1,105 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB} + Exe + Properties + Examples + Examples + v4.0 + + + 512 + + + x86 + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + + + x86 + none + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e863d072-aa8b-4108-b5f1-785241b37f67} + Xceed.Words.NET + + + + + + \ No newline at end of file diff --git a/Examples/app.config b/Examples/app.config index 2e71eabc..cb2586be 100644 --- a/Examples/app.config +++ b/Examples/app.config @@ -1,3 +1,3 @@ - + diff --git a/Examples/docs/DocumentWithBookmarks.docx b/Examples/docs/DocumentWithBookmarks.docx deleted file mode 100644 index 9c51b68c..00000000 Binary files a/Examples/docs/DocumentWithBookmarks.docx and /dev/null differ diff --git a/Examples/docs/DocumentWithTemplateTable.docx b/Examples/docs/DocumentWithTemplateTable.docx deleted file mode 100644 index 6b18bd70..00000000 Binary files a/Examples/docs/DocumentWithTemplateTable.docx and /dev/null differ diff --git a/Examples/docs/Input.docx b/Examples/docs/Input.docx deleted file mode 100644 index 9d9607bd..00000000 Binary files a/Examples/docs/Input.docx and /dev/null differ diff --git a/Examples/images/logo_template.png b/Examples/images/logo_template.png deleted file mode 100644 index 8509516d..00000000 Binary files a/Examples/images/logo_template.png and /dev/null differ diff --git a/Examples/images/logo_the_happy_builder.png b/Examples/images/logo_the_happy_builder.png deleted file mode 100644 index fe72fcaf..00000000 Binary files a/Examples/images/logo_the_happy_builder.png and /dev/null differ diff --git a/Examples/packages.config b/Examples/packages.config deleted file mode 100644 index 07c929c9..00000000 --- a/Examples/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Examples/sn.snk b/Examples/sn.snk new file mode 100644 index 00000000..1bdc9120 Binary files /dev/null and b/Examples/sn.snk differ diff --git a/UnitTests/AppendBookmark.cs b/UnitTests/AppendBookmark.cs deleted file mode 100644 index a55b3092..00000000 --- a/UnitTests/AppendBookmark.cs +++ /dev/null @@ -1,50 +0,0 @@ -using NUnit.Framework; -using Novacode; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace UnitTests -{ - [TestFixture] - public class AppendBookmark - { - [Test] - public void Bookmark_should_be_appended() - { - using (var doc = DocX.Create("")) - { - var paragraph = doc.InsertParagraph("A paragraph"); - paragraph.AppendBookmark("bookmark"); - var bookmarks = paragraph.GetBookmarks(); - Assert.AreEqual(1, bookmarks.Count()); - } - } - - [Test] - public void Bookmark_should_be_named_correctly() - { - using (var doc = DocX.Create("")) - { - var paragraph = doc.InsertParagraph("A paragraph"); - paragraph.AppendBookmark("bookmark"); - var bookmarks = paragraph.GetBookmarks(); - Assert.AreEqual("bookmark", bookmarks.First().Name); - } - } - - [Test] - public void Bookmark_should_reference_paragraph() - { - using (var doc = DocX.Create("")) - { - var paragraph = doc.InsertParagraph("A paragraph"); - paragraph.AppendBookmark("bookmark"); - var bookmarks = paragraph.GetBookmarks(); - Assert.AreEqual(paragraph, bookmarks.First().Paragraph); - } - } - - } -} diff --git a/UnitTests/DocXUnitTests.cs b/UnitTests/DocXUnitTests.cs deleted file mode 100644 index e5f563ce..00000000 --- a/UnitTests/DocXUnitTests.cs +++ /dev/null @@ -1,3300 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using System.Xml; -using System.Xml.Linq; -using Novacode; -using NUnit.Framework; -using DocXFormatting = Novacode.Formatting; -using WindowsColor = System.Drawing.Color; - -namespace UnitTests -{ - /// - /// Summary description for DocXUnitTest - /// - [TestFixture] - public class DocXUnitTests - { - private readonly string _directoryDocuments; - private readonly string _directoryWithFiles; - private static readonly Border BlankBorder = new Border(BorderStyle.Tcbs_none, 0, 0, WindowsColor.White); - - const string package_part_document = "/word/document.xml"; - - public DocXUnitTests() - { - _directoryDocuments = Path.Combine(Path.GetTempPath(), "DocXTests", "documents"); - Setup(_directoryDocuments); // prepare temp documents directory - - _directoryWithFiles = TestHelper.DirectoryWithFiles; - } - private static void Setup(string path) - { - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - } - [Test] - public void LargeTable() - { - using (var output = File.Open(Path.Combine(_directoryWithFiles, "LargeTable.docx"), FileMode.Create)) - { - using (var doc = DocX.Create(output)) - { - var tbl = doc.InsertTable(1, 18); - - var wholeWidth = doc.PageWidth - doc.MarginLeft - doc.MarginRight; - var colWidth = wholeWidth / tbl.ColumnCount; - var colWidths = new int[tbl.ColumnCount]; - tbl.AutoFit = AutoFit.Contents; - var r = tbl.Rows[0]; - var cx = 0; - foreach (var cell in r.Cells) - { - cell.Paragraphs.First().Append("Col " + cx); - cell.MarginBottom = 0; - cell.MarginLeft = 0; - cell.MarginRight = 0; - cell.MarginTop = 0; - - cx++; - } - tbl.SetBorder(TableBorderType.Bottom, BlankBorder); - tbl.SetBorder(TableBorderType.Left, BlankBorder); - tbl.SetBorder(TableBorderType.Right, BlankBorder); - tbl.SetBorder(TableBorderType.Top, BlankBorder); - tbl.SetBorder(TableBorderType.InsideV, BlankBorder); - tbl.SetBorder(TableBorderType.InsideH, BlankBorder); - - doc.Save(); - } - } - } - - [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 == 9658 ); - } - - // Delete the tempory file. - File.Delete( temporaryFilePath ); - } - - [Test] - public void TableWithSpecifiedWidths() - { - using (var output = File.Open(Path.Combine(_directoryWithFiles, "TableSpecifiedWidths.docx"), FileMode.Create)) - { - using (var doc = DocX.Create(output)) - { - var widths = new float[] { 200f, 100f, 300f }; - var tbl = doc.InsertTable(1, widths.Length); - tbl.SetWidths(widths); - var wholeWidth = doc.PageWidth - doc.MarginLeft - doc.MarginRight; - tbl.AutoFit = AutoFit.Contents; - var r = tbl.Rows[0]; - var cx = 0; - foreach (var cell in r.Cells) - { - cell.Paragraphs.First().Append("Col " + cx); - cell.MarginBottom = 0; - cell.MarginLeft = 0; - cell.MarginRight = 0; - cell.MarginTop = 0; - - cx++; - } - //add new rows - for (var x = 0; x < 5; x++) - { - r = tbl.InsertRow(); - cx = 0; - foreach (var cell in r.Cells) - { - cell.Paragraphs.First().Append("Col " + cx); - cell.MarginBottom = 0; - cell.MarginLeft = 0; - cell.MarginRight = 0; - cell.MarginTop = 0; - - cx++; - } - } - tbl.SetBorder(TableBorderType.Bottom, BlankBorder); - tbl.SetBorder(TableBorderType.Left, BlankBorder); - tbl.SetBorder(TableBorderType.Right, BlankBorder); - tbl.SetBorder(TableBorderType.Top, BlankBorder); - tbl.SetBorder(TableBorderType.InsideV, BlankBorder); - tbl.SetBorder(TableBorderType.InsideH, BlankBorder); - - doc.Save(); - } - } - } - - [Test] - public void Test_InvalidCharacter() - { - using( var output = File.Open( Path.Combine( _directoryWithFiles, "InvalidCharacters.docx" ), FileMode.Create ) ) - { - using( var doc = DocX.Create( output ) ) - { - doc.InsertParagraph( "\b" ); - Exception ex = null; - try - { - doc.Save(); - } - catch( Exception e ) - { - ex = e; - } - Assert.IsTrue( ex == null ); - } - } - } - - /// - /// TextRemove should not remove empty paragraphs in case the paragraph is alone in the cell. - /// In the rest cases empty paragraph may be removed. - /// - [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" ) ); - } - } - } - - [Test] - public void Test_Clone_Table_Twice() - { - 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 ); - - Table tab1 = doc.Tables[ 0 ]; - doc.InsertParagraph( "" ); - Table tab2 = doc.InsertTable( tab1 ); - Assert.IsTrue( doc.Tables.Count == 2 ); - doc.InsertParagraph( "" ); - Table tab3 = doc.InsertTable( tab2 ); - Assert.IsTrue( doc.Tables.Count == 3 ); - - doc.SaveAs( Path.Combine( _directoryWithFiles, "TwoClonedTables.docx" ) ); - } - } - } - - public string ReplaceFunc(string findStr) - { - var testPatterns = new Dictionary - { - {"COURT NAME","Fred Frump"}, - {"Case Number","cr-md-2011-1234567"} - }; - - if (testPatterns.ContainsKey(findStr)) - { - return testPatterns[findStr]; - } - return findStr; - } - - [Test] - public void RegexTest() - { - var findPattern = "<(.*?)>"; - var sample = " text"; - var matchCollection = Regex.Matches(sample, findPattern, RegexOptions.IgnoreCase); - } - - [Test] - public void Test_Pattern_Replacement() - { - var testPatterns = new Dictionary - { - {"COURT NAME","Fred Frump"}, - {"Case Number","cr-md-2011-1234567"} - }; - - using (DocX replaceDoc = DocX.Load(Path.Combine(_directoryWithFiles, "ReplaceTests.docx"))) - { - foreach (var t in replaceDoc.Tables) - { // each table has 1 row and 3 columns - Assert.IsTrue(t.Rows[0].Cells.Count == 3); - Assert.IsTrue(t.ColumnCount == 3); - Assert.IsTrue(t.Rows.Count == 1); - Assert.IsTrue(t.RowCount == 1); - } - - // Make sure the origional strings are in the document. - Assert.IsTrue(replaceDoc.FindAll("").Count == 2); - Assert.IsTrue(replaceDoc.FindAll("").Count == 2); - - // There are only two patterns, even though each pattern is used more than once - Assert.IsTrue(replaceDoc.FindUniqueByPattern(@"<[\w \=]{4,}>", RegexOptions.IgnoreCase).Count == 2); - - // Make sure the new strings are not in the document. - Assert.IsTrue(replaceDoc.FindAll("Fred Frump").Count == 0); - Assert.IsTrue(replaceDoc.FindAll("cr-md-2011-1234567").Count == 0); - - // Do the replacing - foreach (var p in testPatterns) - { - replaceDoc.ReplaceText("<(.*?)>", ReplaceFunc, false, RegexOptions.IgnoreCase); - //replaceDoc.ReplaceText("<" + p.Key + ">", p.Value, false, RegexOptions.IgnoreCase); - } - - // Make sure the origional string are no longer in the document. - Assert.IsTrue(replaceDoc.FindAll("").Count == 0); - Assert.IsTrue(replaceDoc.FindAll("").Count == 0); - - // Make sure the new strings are now in the document. - Assert.IsTrue(replaceDoc.FindAll("FRED FRUMP").Count == 2); - Assert.IsTrue(replaceDoc.FindAll("cr-md-2011-1234567").Count == 2); - - // Make sure the replacement worked. - Assert.IsTrue(replaceDoc.Text == "\t\t\t\t\t\t\t\t\t\t\t\t\t\tThese two tables should look identical:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSTATE OF IOWA,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tPlaintiff,\t\t\t\t\t\t\t\t\t\t\t\t\t\tvs.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFRED FRUMP,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tDefendant.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tCase No.: cr-md-2011-1234567\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tORDER SETTING ASIDE DEFAULT JUDGMENT\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSTATE OF IOWA,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tPlaintiff,\t\t\t\t\t\t\t\t\t\t\t\t\t\tvs.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFRED FRUMP,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tDefendant.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tCase No.: cr-md-2011-1234567\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tORDER SETTING ASIDE DEFAULT JUDGMENT\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); - } - - } - - [Test] - public void Test_CustomProperty_Add() - { - // Load a document. - using (DocX document = DocX.Create("CustomProperty_Add.docx")) - { - Assert.IsTrue(document.CustomProperties.Count == 0); - - document.AddCustomProperty(new CustomProperty("fname", "cathal")); - - Assert.IsTrue(document.CustomProperties.Count == 1); - Assert.IsTrue(document.CustomProperties.ContainsKey("fname")); - Assert.IsTrue((string)document.CustomProperties["fname"].Value == "cathal"); - - document.AddCustomProperty(new CustomProperty("age", 24)); - - Assert.IsTrue(document.CustomProperties.Count == 2); - Assert.IsTrue(document.CustomProperties.ContainsKey("age")); - Assert.IsTrue((int)document.CustomProperties["age"].Value == 24); - - document.AddCustomProperty(new CustomProperty("male", true)); - - Assert.IsTrue(document.CustomProperties.Count == 3); - Assert.IsTrue(document.CustomProperties.ContainsKey("male")); - Assert.IsTrue((bool)document.CustomProperties["male"].Value); - - document.AddCustomProperty(new CustomProperty("newyear2012", new DateTime(2012, 1, 1))); - - Assert.IsTrue(document.CustomProperties.Count == 4); - Assert.IsTrue(document.CustomProperties.ContainsKey("newyear2012")); - Assert.IsTrue((DateTime)document.CustomProperties["newyear2012"].Value == new DateTime(2012, 1, 1)); - - document.AddCustomProperty(new CustomProperty("fav_num", 3.141592)); - - Assert.IsTrue(document.CustomProperties.Count == 5); - Assert.IsTrue(document.CustomProperties.ContainsKey("fav_num")); - Assert.IsTrue((double)document.CustomProperties["fav_num"].Value == 3.141592); - } - } - - [Test] - public void Test_EverybodyHasAHome_Loaded() - { - // Load a document. - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "EverybodyHasAHome.docx"))) - { - // Main document tests. - string document_xml_file = document.mainPart.Uri.OriginalString; - Assert.IsTrue(document.Paragraphs[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - Assert.IsTrue(document.Tables[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - Assert.IsTrue(document.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - Assert.IsTrue(document.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - Assert.IsTrue(document.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - - // header first - Header header_first = document.Headers.first; - string header_first_xml_file = header_first.mainPart.Uri.OriginalString; - - Assert.IsTrue(header_first.Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - Assert.IsTrue(header_first.Tables[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - Assert.IsTrue(header_first.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - Assert.IsTrue(header_first.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - Assert.IsTrue(header_first.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - - // header odd - Header header_odd = document.Headers.odd; - string header_odd_xml_file = header_odd.mainPart.Uri.OriginalString; - - Assert.IsTrue(header_odd.mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Tables[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - - // header even - Header header_even = document.Headers.even; - string header_even_xml_file = header_even.mainPart.Uri.OriginalString; - - Assert.IsTrue(header_even.mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Tables[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - - // footer first - Footer footer_first = document.Footers.first; - string footer_first_xml_file = footer_first.mainPart.Uri.OriginalString; - - Assert.IsTrue(footer_first.mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Tables[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - - // footer odd - Footer footer_odd = document.Footers.odd; - string footer_odd_xml_file = footer_odd.mainPart.Uri.OriginalString; - - Assert.IsTrue(footer_odd.mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Tables[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - - // footer even - Footer footer_even = document.Footers.even; - string footer_even_xml_file = footer_even.mainPart.Uri.OriginalString; - - Assert.IsTrue(footer_even.mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Tables[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - } - } - - [Test] - public void Test_Insert_Picture_ParagraphBeforeSelf() - { - // Create test document. - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Test.docx"))) - { - // Add an Image to this document. - Image img = document.AddImage(Path.Combine(_directoryWithFiles, "purple.png")); - - // Create a Picture from this Image. - Picture pic = img.CreatePicture(); - Assert.IsNotNull(pic); - - // Main document. - Paragraph p0 = document.InsertParagraph("Hello"); - Paragraph p1 = p0.InsertParagraphBeforeSelf("again"); - p1.InsertPicture(pic, 3); - - // Save this document. - document.Save(); - } - } - - [Test] - public void Test_Insert_Picture_ParagraphAfterSelf() - { - // Create test document. - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Test.docx"))) - { - // Add an Image to this document. - Image img = document.AddImage(Path.Combine(_directoryWithFiles, "purple.png")); - - // Create a Picture from this Image. - Picture pic = img.CreatePicture(); - Assert.IsNotNull(pic); - - // Main document. - Paragraph p0 = document.InsertParagraph("Hello"); - Paragraph p1 = p0.InsertParagraphAfterSelf("again"); - p1.InsertPicture(pic, 3); - - // Save this document. - document.Save(); - } - } - - [Test] - public void Test_EverybodyHasAHome_Created() - { - // Create a new document. - using (DocX document = DocX.Create("Test.docx")) - { - // Create a Table. - Table t = document.AddTable(3, 3); - t.Design = TableDesign.TableGrid; - - // Insert a Paragraph and a Table into the main document. - document.InsertParagraph(); - document.InsertTable(t); - - // Insert a Paragraph and a Table into every Header. - document.AddHeaders(); - document.Headers.odd.InsertParagraph(); - document.Headers.odd.InsertTable(t); - document.Headers.even.InsertParagraph(); - document.Headers.even.InsertTable(t); - document.Headers.first.InsertParagraph(); - document.Headers.first.InsertTable(t); - - // Insert a Paragraph and a Table into every Footer. - document.AddFooters(); - document.Footers.odd.InsertParagraph(); - document.Footers.odd.InsertTable(t); - document.Footers.even.InsertParagraph(); - document.Footers.even.InsertTable(t); - document.Footers.first.InsertParagraph(); - document.Footers.first.InsertTable(t); - - // Main document tests. - string document_xml_file = document.mainPart.Uri.OriginalString; - Assert.IsTrue(document.Paragraphs[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - Assert.IsTrue(document.Tables[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - Assert.IsTrue(document.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - Assert.IsTrue(document.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - Assert.IsTrue(document.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(document_xml_file)); - - // header first - Header header_first = document.Headers.first; - string header_first_xml_file = header_first.mainPart.Uri.OriginalString; - - Assert.IsTrue(header_first.Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - Assert.IsTrue(header_first.Tables[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - Assert.IsTrue(header_first.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - Assert.IsTrue(header_first.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - Assert.IsTrue(header_first.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_first_xml_file)); - - // header odd - Header header_odd = document.Headers.odd; - string header_odd_xml_file = header_odd.mainPart.Uri.OriginalString; - - Assert.IsTrue(header_odd.mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Tables[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - Assert.IsTrue(header_odd.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_odd_xml_file)); - - // header even - Header header_even = document.Headers.even; - string header_even_xml_file = header_even.mainPart.Uri.OriginalString; - - Assert.IsTrue(header_even.mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Tables[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - Assert.IsTrue(header_even.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(header_even_xml_file)); - - // footer first - Footer footer_first = document.Footers.first; - string footer_first_xml_file = footer_first.mainPart.Uri.OriginalString; - - Assert.IsTrue(footer_first.mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Tables[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - Assert.IsTrue(footer_first.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_first_xml_file)); - - // footer odd - Footer footer_odd = document.Footers.odd; - string footer_odd_xml_file = footer_odd.mainPart.Uri.OriginalString; - - Assert.IsTrue(footer_odd.mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Tables[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - Assert.IsTrue(footer_odd.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_odd_xml_file)); - - // footer even - Footer footer_even = document.Footers.even; - string footer_even_xml_file = footer_even.mainPart.Uri.OriginalString; - - Assert.IsTrue(footer_even.mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Tables[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Tables[0].Rows[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Tables[0].Rows[0].Cells[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - Assert.IsTrue(footer_even.Tables[0].Rows[0].Cells[0].Paragraphs[0].mainPart.Uri.OriginalString.Equals(footer_even_xml_file)); - } - } - - [Test] - public void Test_Document_AddImage_FromDisk() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "test_add_images.docx"))) - { - // Add a png to into this document - Image png = document.AddImage(Path.Combine(_directoryWithFiles, "purple.png")); - Assert.IsTrue(document.Images.Count == 1); - Assert.IsTrue(Path.GetExtension(png.pr.TargetUri.OriginalString) == ".png"); - - // Add a tiff into to this document - Image tif = document.AddImage(Path.Combine(_directoryWithFiles, "yellow.tif")); - Assert.IsTrue(document.Images.Count == 2); - Assert.IsTrue(Path.GetExtension(tif.pr.TargetUri.OriginalString) == ".tif"); - - // Add a gif into to this document - Image gif = document.AddImage(Path.Combine(_directoryWithFiles, "orange.gif")); - Assert.IsTrue(document.Images.Count == 3); - Assert.IsTrue(Path.GetExtension(gif.pr.TargetUri.OriginalString) == ".gif"); - - // Add a jpg into to this document - Image jpg = document.AddImage(Path.Combine(_directoryWithFiles, "green.jpg")); - Assert.IsTrue(document.Images.Count == 4); - Assert.IsTrue(Path.GetExtension(jpg.pr.TargetUri.OriginalString) == ".jpg"); - - // Add a bitmap to this document - Image bitmap = document.AddImage(Path.Combine(_directoryWithFiles, "red.bmp")); - Assert.IsTrue(document.Images.Count == 5); - // Word does not allow bmp make sure it was inserted as a png. - Assert.IsTrue(Path.GetExtension(bitmap.pr.TargetUri.OriginalString) == ".png"); - } - } - - [Test] - public void Test_Document_AddImage_FromStream() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "test_add_images.docx"))) - { - // DocX will always insert Images that come from Streams as jpeg. - - // Add a png to into this document - Image png = document.AddImage(new FileStream(Path.Combine(_directoryWithFiles, "purple.png"), FileMode.Open)); - Assert.IsTrue(document.Images.Count == 1); - Assert.IsTrue(Path.GetExtension(png.pr.TargetUri.OriginalString) == ".jpeg"); - - // Add a tiff into to this document - Image tif = document.AddImage(new FileStream(Path.Combine(_directoryWithFiles, "yellow.tif"), FileMode.Open)); - Assert.IsTrue(document.Images.Count == 2); - Assert.IsTrue(Path.GetExtension(tif.pr.TargetUri.OriginalString) == ".jpeg"); - - // Add a gif into to this document - Image gif = document.AddImage(new FileStream(Path.Combine(_directoryWithFiles, "orange.gif"), FileMode.Open)); - Assert.IsTrue(document.Images.Count == 3); - Assert.IsTrue(Path.GetExtension(gif.pr.TargetUri.OriginalString) == ".jpeg"); - - // Add a jpg into to this document - Image jpg = document.AddImage(new FileStream(Path.Combine(_directoryWithFiles, "green.jpg"), FileMode.Open)); - Assert.IsTrue(document.Images.Count == 4); - Assert.IsTrue(Path.GetExtension(jpg.pr.TargetUri.OriginalString) == ".jpeg"); - - // Add a bitmap to this document - Image bitmap = document.AddImage(new FileStream(Path.Combine(_directoryWithFiles, "red.bmp"), FileMode.Open)); - Assert.IsTrue(document.Images.Count == 5); - // Word does not allow bmp make sure it was inserted as a png. - Assert.IsTrue(Path.GetExtension(bitmap.pr.TargetUri.OriginalString) == ".jpeg"); - } - } - - [Test] - public void Test_Tables() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "Tables.docx"))) - { - // There is only one Paragraph at the document level. - Assert.IsTrue(document.Paragraphs.Count() == 13); - - // There is only one Table in this document. - Assert.IsTrue(document.Tables.Count() == 1); - - // Extract the only Table. - Table t0 = document.Tables[0]; - - // This table has 12 Paragraphs. - Assert.IsTrue(t0.Paragraphs.Count() == 12); - } - } - - [Test] - public void Test_Images() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "Images.docx"))) - { - // Extract Images from Document. - List document_images = document.Images; - - // Make sure there are 3 Images in this document. - Assert.IsTrue(document_images.Count() == 3); - - // Extract the headers from this document. - Headers headers = document.Headers; - Header header_first = headers.first; - Header header_odd = headers.odd; - Header header_even = headers.even; - - #region Header_First - // Extract Images from the first Header. - List header_first_images = header_first.Images; - - // Make sure there is 1 Image in the first header. - Assert.IsTrue(header_first_images.Count() == 1); - #endregion - - #region Header_Odd - // Extract Images from the odd Header. - List header_odd_images = header_odd.Images; - - // Make sure there is 1 Image in the first header. - Assert.IsTrue(header_odd_images.Count() == 1); - #endregion - - #region Header_Even - // Extract Images from the odd Header. - List header_even_images = header_even.Images; - - // Make sure there is 1 Image in the first header. - Assert.IsTrue(header_even_images.Count() == 1); - #endregion - } - } - - [Test] - public void Test_Insert_Picture() - { - // Load test document. - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Test.docx"))) - { - // Add Headers and Footers into this document. - document.AddHeaders(); - document.AddFooters(); - document.DifferentFirstPage = true; - document.DifferentOddAndEvenPages = true; - - // Add an Image to this document. - Image img = document.AddImage(Path.Combine(_directoryWithFiles, "purple.png")); - - // Create a Picture from this Image. - Picture pic = img.CreatePicture(); - - // Main document. - Paragraph p0 = document.InsertParagraph("Hello"); - p0.InsertPicture(pic, 3); - - // Header first. - Paragraph p1 = document.Headers.first.InsertParagraph("----"); - p1.InsertPicture(pic, 2); - - // Header odd. - Paragraph p2 = document.Headers.odd.InsertParagraph("----"); - p2.InsertPicture(pic, 2); - - // Header even. - Paragraph p3 = document.Headers.even.InsertParagraph("----"); - p3.InsertPicture(pic, 2); - - // Footer first. - Paragraph p4 = document.Footers.first.InsertParagraph("----"); - p4.InsertPicture(pic, 2); - - // Footer odd. - Paragraph p5 = document.Footers.odd.InsertParagraph("----"); - p5.InsertPicture(pic, 2); - - // Footer even. - Paragraph p6 = document.Footers.even.InsertParagraph("----"); - p6.InsertPicture(pic, 2); - - // Save this document. - document.Save(); - } - } - - /// - /// This test fills two tables with hyperlinks. - /// - [Test] - public void Test_Insert_Hyperlink_In_Tables() - { - 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 > 0 ); - Table tab1 = doc.Tables[ 0 ]; - Assert.IsTrue( tab1.RowCount > 0 ); - Assert.IsTrue( tab1.Rows[0].ColumnCount > 0 ); - doc.InsertParagraph( "" ); - Table tab2 = doc.InsertTable( tab1 ); - Assert.IsTrue( tab2.RowCount > 0 ); - - Row row1 = tab1.Rows[ 0 ]; - Row row2 = tab2.Rows[ 0 ]; - - // 10 times insert hyperlinks in both tables in tic-tak order - for( int index = 0; index < 10; index++ ) - { - Row newRow1 = tab1.InsertRow( row1 ); - Row newRow2 = tab2.InsertRow( row2 ); - - Hyperlink h1 = doc.AddHyperlink( - string.Format( "Table {0}, Row {1}. Google searches for {0} {1}", 1, index + 1 ), - new Uri( string.Format( "https://www.google.com/search?q=Table{0}Row{1}", 1, index + 1 ) ) ); - newRow1.Cells[ 0 ].Paragraphs[ 0 ].InsertHyperlink( h1 ); - - Hyperlink h2 = doc.AddHyperlink( - string.Format( "Table {0}, Row {1}. Google searches for {0} {1}", 2, index + 1 ), - new Uri( string.Format( "https://www.google.com/search?q=Table{0}Row{1}", 2, index + 1 ) ) ); - newRow2.Cells[ 0 ].Paragraphs[ 0 ].InsertHyperlink( h2 ); - - } - //Make sure links are ok and in right order - for( int index = 0; index < doc.Hyperlinks.Count; index++ ) - { - Hyperlink h = doc.Hyperlinks[ index ]; - string text = string.Format( "Table {0}, Row {1}. Google searches for {0} {1}", ( index / 10 ) + 1, ( index ) % 10 + 1 ); - string uri = string.Format( "https://www.google.com/search?q=Table{0}Row{1}", ( index / 10 ) + 1, ( index ) % 10 + 1 ); - Assert.IsTrue( string.Compare( h.Text, text ) == 0 ); - Assert.IsTrue( h.Uri != null ); - Assert.IsTrue( string.Compare( h.Uri.ToString(), uri ) == 0 ); - } - doc.SaveAs( Path.Combine( _directoryDocuments, "Test_Insert_Hyperlink_In_Tables.docx" ) ); - } - } - } - - /// - /// This test makes 2 file. The first uses InsertHyperlink. The second uses AppendHyperlink. - /// The both hyperlink collections should be equal to each other. - /// We need be sure the bug in InsertHyperlink is fixed (id attribute in hyperlink was empty and order of inserteed hyperlinks was broken). - /// - [Test] - public void Test_Compare_InsertHyperlink_And_AppendHyperLinks() - { - string fileName1 = Path.Combine( _directoryDocuments, "Test_InsertHyperLinks.docx" ); - string fileName2 = Path.Combine( _directoryDocuments, "Test_AppendHyperlinks.docx" ); - using( DocX document1 = DocX.Create( fileName1 ) ) - { - using( DocX document2 = DocX.Create( fileName2 ) ) - { - for( int index = 0; index < 10; index++ ) - { - Hyperlink h = document1.AddHyperlink( - string.Format( "Google searches for {0}", index + 1 ), - new Uri( string.Format( "https://www.google.com/search?q={0}", index + 1 ) ) ); - document1.InsertParagraph( "" ).InsertHyperlink( h ); - } - document1.Save(); - - for( int index = 0; index < 10; index++ ) - { - Hyperlink h = document2.AddHyperlink( - string.Format( "Google searches for {0}", index + 1 ), - new Uri( string.Format( "https://www.google.com/search?q={0}", index + 1 ) ) ); - document2.InsertParagraph( "" ).AppendHyperlink( h ); - } - document2.Save(); - - Assert.IsTrue( document1.Hyperlinks.Count == document2.Hyperlinks.Count ); - for( int index = 0; index < document1.Hyperlinks.Count; index++ ) - { - Hyperlink h1 = document1.Hyperlinks[ index ]; - Hyperlink h2 = document2.Hyperlinks[ index ]; - Assert.IsTrue( string.Compare( h1.Text, h2.Text ) == 0 ); - Assert.IsTrue( string.Compare( h1.Uri.ToString(), h2.Uri.ToString() ) == 0 ); - } - } - } - } - - [Test] - public void Test_Insert_Hyperlink() - { - // Load test document. - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Test.docx"))) - { - // Add Headers and Footers into this document. - document.AddHeaders(); - document.AddFooters(); - document.DifferentFirstPage = true; - document.DifferentOddAndEvenPages = true; - - // Add a Hyperlink into this document. - Hyperlink h = document.AddHyperlink("google", new Uri("http://www.google.com")); - - // Main document. - Paragraph p0 = document.InsertParagraph("Hello"); - p0.InsertHyperlink(h, 3); - - // Header first. - Paragraph p1 = document.Headers.first.InsertParagraph("----"); - p1.InsertHyperlink(h, 3); - - // Header odd. - Paragraph p2 = document.Headers.odd.InsertParagraph("----"); - p2.InsertHyperlink(h, 3); - - // Header even. - Paragraph p3 = document.Headers.even.InsertParagraph("----"); - p3.InsertHyperlink(h, 3); - - // Footer first. - Paragraph p4 = document.Footers.first.InsertParagraph("----"); - p4.InsertHyperlink(h, 3); - - // Footer odd. - Paragraph p5 = document.Footers.odd.InsertParagraph("----"); - p5.InsertHyperlink(h, 3); - - // Footer even. - Paragraph p6 = document.Footers.even.InsertParagraph("----"); - p6.InsertHyperlink(h, 3); - - // Save this document. - document.Save(); - } - } - - [Test] - public void Test_Get_Set_Hyperlink() - { - // Load test document. - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "Hyperlinks.docx"))) - { - // Hyperlinks in the document. - Assert.IsTrue(document.Hyperlinks.Count == 3); - Assert.IsTrue(document.Hyperlinks[0].Text == "page1"); - Assert.IsTrue(document.Hyperlinks[0].Uri.AbsoluteUri == "http://www.page1.com/"); - Assert.IsTrue(document.Hyperlinks[1].Text == "page2"); - Assert.IsTrue(document.Hyperlinks[1].Uri.AbsoluteUri == "http://www.page2.com/"); - Assert.IsTrue(document.Hyperlinks[2].Text == "page3"); - Assert.IsTrue(document.Hyperlinks[2].Uri.AbsoluteUri == "http://www.page3.com/"); - - // Change the Hyperlinks and check that it has in fact changed. - document.Hyperlinks[0].Text = "somethingnew"; - document.Hyperlinks[0].Uri = new Uri("http://www.google.com/"); - Assert.IsTrue(document.Hyperlinks[0].Text == "somethingnew"); - Assert.IsTrue(document.Hyperlinks[0].Uri.AbsoluteUri == "http://www.google.com/"); - document.Hyperlinks[1].Text = "somethingnew"; - document.Hyperlinks[1].Uri = new Uri("http://www.google.com/"); - Assert.IsTrue(document.Hyperlinks[1].Text == "somethingnew"); - Assert.IsTrue(document.Hyperlinks[1].Uri.AbsoluteUri == "http://www.google.com/"); - document.Hyperlinks[2].Text = "somethingnew"; - document.Hyperlinks[2].Uri = new Uri("http://www.google.com/"); - Assert.IsTrue(document.Hyperlinks[2].Text == "somethingnew"); - Assert.IsTrue(document.Hyperlinks[2].Uri.AbsoluteUri == "http://www.google.com/"); - - Assert.IsTrue(document.Headers.first.Hyperlinks.Count == 1); - Assert.IsTrue(document.Headers.first.Hyperlinks[0].Text == "header-first"); - Assert.IsTrue(document.Headers.first.Hyperlinks[0].Uri.AbsoluteUri == "http://www.header-first.com/"); - - // Change the Hyperlinks and check that it has in fact changed. - document.Headers.first.Hyperlinks[0].Text = "somethingnew"; - document.Headers.first.Hyperlinks[0].Uri = new Uri("http://www.google.com/"); - Assert.IsTrue(document.Headers.first.Hyperlinks[0].Text == "somethingnew"); - Assert.IsTrue(document.Headers.first.Hyperlinks[0].Uri.AbsoluteUri == "http://www.google.com/"); - - Assert.IsTrue(document.Headers.odd.Hyperlinks.Count == 1); - Assert.IsTrue(document.Headers.odd.Hyperlinks[0].Text == "header-odd"); - Assert.IsTrue(document.Headers.odd.Hyperlinks[0].Uri.AbsoluteUri == "http://www.header-odd.com/"); - - // Change the Hyperlinks and check that it has in fact changed. - document.Headers.odd.Hyperlinks[0].Text = "somethingnew"; - document.Headers.odd.Hyperlinks[0].Uri = new Uri("http://www.google.com/"); - Assert.IsTrue(document.Headers.odd.Hyperlinks[0].Text == "somethingnew"); - Assert.IsTrue(document.Headers.odd.Hyperlinks[0].Uri.AbsoluteUri == "http://www.google.com/"); - - Assert.IsTrue(document.Headers.even.Hyperlinks.Count == 1); - Assert.IsTrue(document.Headers.even.Hyperlinks[0].Text == "header-even"); - Assert.IsTrue(document.Headers.even.Hyperlinks[0].Uri.AbsoluteUri == "http://www.header-even.com/"); - - // Change the Hyperlinks and check that it has in fact changed. - document.Headers.even.Hyperlinks[0].Text = "somethingnew"; - document.Headers.even.Hyperlinks[0].Uri = new Uri("http://www.google.com/"); - Assert.IsTrue(document.Headers.even.Hyperlinks[0].Text == "somethingnew"); - Assert.IsTrue(document.Headers.even.Hyperlinks[0].Uri.AbsoluteUri == "http://www.google.com/"); - - Assert.IsTrue(document.Footers.first.Hyperlinks.Count == 1); - Assert.IsTrue(document.Footers.first.Hyperlinks[0].Text == "footer-first"); - Assert.IsTrue(document.Footers.first.Hyperlinks[0].Uri.AbsoluteUri == "http://www.footer-first.com/"); - - // Change the Hyperlinks and check that it has in fact changed. - document.Footers.first.Hyperlinks[0].Text = "somethingnew"; - document.Footers.first.Hyperlinks[0].Uri = new Uri("http://www.google.com/"); - Assert.IsTrue(document.Footers.first.Hyperlinks[0].Text == "somethingnew"); - Assert.IsTrue(document.Footers.first.Hyperlinks[0].Uri.AbsoluteUri == "http://www.google.com/"); - - Assert.IsTrue(document.Footers.odd.Hyperlinks.Count == 1); - Assert.IsTrue(document.Footers.odd.Hyperlinks[0].Text == "footer-odd"); - Assert.IsTrue(document.Footers.odd.Hyperlinks[0].Uri.AbsoluteUri == "http://www.footer-odd.com/"); - - // Change the Hyperlinks and check that it has in fact changed. - document.Footers.odd.Hyperlinks[0].Text = "somethingnew"; - document.Footers.odd.Hyperlinks[0].Uri = new Uri("http://www.google.com/"); - Assert.IsTrue(document.Footers.odd.Hyperlinks[0].Text == "somethingnew"); - Assert.IsTrue(document.Footers.odd.Hyperlinks[0].Uri.AbsoluteUri == "http://www.google.com/"); - - Assert.IsTrue(document.Footers.even.Hyperlinks.Count == 1); - Assert.IsTrue(document.Footers.even.Hyperlinks[0].Text == "footer-even"); - Assert.IsTrue(document.Footers.even.Hyperlinks[0].Uri.AbsoluteUri == "http://www.footer-even.com/"); - - // Change the Hyperlinks and check that it has in fact changed. - document.Footers.even.Hyperlinks[0].Text = "somethingnew"; - document.Footers.even.Hyperlinks[0].Uri = new Uri("http://www.google.com/"); - Assert.IsTrue(document.Footers.even.Hyperlinks[0].Text == "somethingnew"); - Assert.IsTrue(document.Footers.even.Hyperlinks[0].Uri.AbsoluteUri == "http://www.google.com/"); - } - } - - [Test] - public void Test_Append_Hyperlink() - { - // Load test document. - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Test.docx"))) - { - // Add Headers and Footers into this document. - document.AddHeaders(); - document.AddFooters(); - document.DifferentFirstPage = true; - document.DifferentOddAndEvenPages = true; - - // Add a Hyperlink to this document. - Hyperlink h = document.AddHyperlink("google", new Uri("http://www.google.com")); - - // Main document. - Paragraph p0 = document.InsertParagraph("----"); - p0.AppendHyperlink(h); - Assert.IsTrue(p0.Text == "----google"); - - // Header first. - Paragraph p1 = document.Headers.first.InsertParagraph("----"); - p1.AppendHyperlink(h); - Assert.IsTrue(p1.Text == "----google"); - - // Header odd. - Paragraph p2 = document.Headers.odd.InsertParagraph("----"); - p2.AppendHyperlink(h); - Assert.IsTrue(p2.Text == "----google"); - - // Header even. - Paragraph p3 = document.Headers.even.InsertParagraph("----"); - p3.AppendHyperlink(h); - Assert.IsTrue(p3.Text == "----google"); - - // Footer first. - Paragraph p4 = document.Footers.first.InsertParagraph("----"); - p4.AppendHyperlink(h); - Assert.IsTrue(p4.Text == "----google"); - - // Footer odd. - Paragraph p5 = document.Footers.odd.InsertParagraph("----"); - p5.AppendHyperlink(h); - Assert.IsTrue(p5.Text == "----google"); - - // Footer even. - Paragraph p6 = document.Footers.even.InsertParagraph("----"); - p6.AppendHyperlink(h); - Assert.IsTrue(p6.Text == "----google"); - - // Save the document. - document.Save(); - } - } - - [Test] - public void Test_Append_Picture() - { - // Create test document. - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Test.docx"))) - { - // Add Headers and Footers into this document. - document.AddHeaders(); - document.AddFooters(); - document.DifferentFirstPage = true; - document.DifferentOddAndEvenPages = true; - - // Add an Image to this document. - Image img = document.AddImage(Path.Combine(_directoryWithFiles, "purple.png")); - - // Create a Picture from this Image. - Picture pic = img.CreatePicture(); - - // Main document. - Paragraph p0 = document.InsertParagraph(); - p0.AppendPicture(pic); - - // Header first. - Paragraph p1 = document.Headers.first.InsertParagraph(); - p1.AppendPicture(pic); - - // Header odd. - Paragraph p2 = document.Headers.odd.InsertParagraph(); - p2.AppendPicture(pic); - - // Header even. - Paragraph p3 = document.Headers.even.InsertParagraph(); - p3.AppendPicture(pic); - - // Footer first. - Paragraph p4 = document.Footers.first.InsertParagraph(); - p4.AppendPicture(pic); - - // Footer odd. - Paragraph p5 = document.Footers.odd.InsertParagraph(); - p5.AppendPicture(pic); - - // Footer even. - Paragraph p6 = document.Footers.even.InsertParagraph(); - p6.AppendPicture(pic); - - // Save the document. - document.Save(); - } - } - - [Test] - public void Test_Move_Picture_Load() - { - // Load test document. - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "MovePicture.docx"))) - { - // Extract the first Picture from the first Paragraph. - Picture picture = document.Paragraphs.First().Pictures.First(); - - // Move it into the first Header. - Header header_first = document.Headers.first; - header_first.Paragraphs.First().AppendPicture(picture); - - // Move it into the even Header. - Header header_even = document.Headers.even; - header_even.Paragraphs.First().AppendPicture(picture); - - // Move it into the odd Header. - Header header_odd = document.Headers.odd; - header_odd.Paragraphs.First().AppendPicture(picture); - - // Move it into the first Footer. - Footer footer_first = document.Footers.first; - footer_first.Paragraphs.First().AppendPicture(picture); - - // Move it into the even Footer. - Footer footer_even = document.Footers.even; - footer_even.Paragraphs.First().AppendPicture(picture); - - // Move it into the odd Footer. - Footer footer_odd = document.Footers.odd; - footer_odd.Paragraphs.First().AppendPicture(picture); - - // Save this as MovedPicture.docx - document.SaveAs(Path.Combine(_directoryDocuments, "MovedPicture.docx")); - } - } - - [Test] - public void Test_Paragraph_InsertHyperlink() - { - // Create a new document - using (DocX document = DocX.Create("Test.docx")) - { - // Add a Hyperlink to this document. - Hyperlink h = document.AddHyperlink("link", new Uri("http://www.google.com")); - - // Simple - Paragraph p1 = document.InsertParagraph("AC"); - p1.InsertHyperlink(h); Assert.IsTrue(p1.Text == "linkAC"); - p1.InsertHyperlink(h, p1.Text.Length); Assert.IsTrue(p1.Text == "linkAClink"); - p1.InsertHyperlink(h, p1.Text.IndexOf("C", StringComparison.Ordinal)); Assert.IsTrue(p1.Text == "linkAlinkClink"); - - // Difficult - Paragraph p2 = document.InsertParagraph("\tA\tC\t"); - p2.InsertHyperlink(h); Assert.IsTrue(p2.Text == "link\tA\tC\t"); - p2.InsertHyperlink(h, p2.Text.Length); Assert.IsTrue(p2.Text == "link\tA\tC\tlink"); - p2.InsertHyperlink(h, p2.Text.IndexOf("C", StringComparison.Ordinal)); Assert.IsTrue(p2.Text == "link\tA\tlinkC\tlink"); - - // Contrived - // Add a contrived Hyperlink to this document. - Hyperlink h2 = document.AddHyperlink("\tlink\t", new Uri("http://www.google.com")); - Paragraph p3 = document.InsertParagraph("\tA\tC\t"); - p3.InsertHyperlink(h2); Assert.IsTrue(p3.Text == "\tlink\t\tA\tC\t"); - p3.InsertHyperlink(h2, p3.Text.Length); Assert.IsTrue(p3.Text == "\tlink\t\tA\tC\t\tlink\t"); - p3.InsertHyperlink(h2, p3.Text.IndexOf("C", StringComparison.Ordinal)); Assert.IsTrue(p3.Text == "\tlink\t\tA\t\tlink\tC\t\tlink\t"); - } - } - - [Test] - public void Test_Paragraph_RemoveHyperlink() - { - // Create a new document - using (DocX document = DocX.Create("Test.docx")) - { - // Add a Hyperlink to this document. - Hyperlink h = document.AddHyperlink("link", new Uri("http://www.google.com")); - - // Simple - Paragraph p1 = document.InsertParagraph("AC"); - p1.InsertHyperlink(h); Assert.IsTrue(p1.Text == "linkAC"); - p1.InsertHyperlink(h, p1.Text.Length); Assert.IsTrue(p1.Text == "linkAClink"); - p1.InsertHyperlink(h, p1.Text.IndexOf("C", StringComparison.Ordinal)); Assert.IsTrue(p1.Text == "linkAlinkClink"); - - // Try and remove a Hyperlink using a negative index. - // This should throw an exception. - try - { - p1.RemoveHyperlink(-1); - Assert.Fail(); - } - catch (ArgumentException) { } - catch (Exception) { Assert.Fail(); } - - // Try and remove a Hyperlink at an index greater than the last. - // This should throw an exception. - try - { - p1.RemoveHyperlink(3); - Assert.Fail(); - } - catch (ArgumentException) { } - catch (Exception) { Assert.Fail(); } - - p1.RemoveHyperlink(0); Assert.IsTrue(p1.Text == "AlinkClink"); - p1.RemoveHyperlink(1); Assert.IsTrue(p1.Text == "AlinkC"); - p1.RemoveHyperlink(0); Assert.IsTrue(p1.Text == "AC"); - } - } - - [Test] - public void Test_Paragraph_ReplaceText() - { - // Create a new document - using (DocX document = DocX.Create("Test.docx")) - { - // Simple - Paragraph p1 = document.InsertParagraph("Apple Pear Apple Apple Pear Apple"); - p1.ReplaceText("Apple", "Orange"); Assert.IsTrue(p1.Text == "Orange Pear Orange Orange Pear Orange"); - p1.ReplaceText("Pear", "Apple"); Assert.IsTrue(p1.Text == "Orange Apple Orange Orange Apple Orange"); - p1.ReplaceText("Orange", "Pear"); Assert.IsTrue(p1.Text == "Pear Apple Pear Pear Apple Pear"); - - // Try and replace text that dosen't exist in the Paragraph. - string old = p1.Text; - p1.ReplaceText("foo", "bar"); Assert.IsTrue(p1.Text.Equals(old)); - - // Difficult - Paragraph p2 = document.InsertParagraph("Apple Pear Apple Apple Pear Apple"); - p2.ReplaceText(" ", "\t"); Assert.IsTrue(p2.Text == "Apple\tPear\tApple\tApple\tPear\tApple"); - p2.ReplaceText("\tApple\tApple", ""); Assert.IsTrue(p2.Text == "Apple\tPear\tPear\tApple"); - p2.ReplaceText("Apple\tPear\t", ""); Assert.IsTrue(p2.Text == "Pear\tApple"); - p2.ReplaceText("Pear\tApple", ""); Assert.IsTrue(p2.Text == ""); - } - } - - [Test] - public void Test_Paragraph_ReplaceTextInGivenFormat() - { - // Load a document. - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "VariousTextFormatting.docx"))) - { - // Removing red text highlighted with yellow - var formatting = new DocXFormatting(); - formatting.FontColor = WindowsColor.Blue; - // IMPORTANT: default constructor of Formatting sets up language property - set it to NULL to be language independent - var desiredFormat = new DocXFormatting() { Language = null, FontColor = WindowsColor.FromArgb(255, 0, 0), Highlight = Highlight.yellow }; - var replaced = string.Empty; - foreach (var p in document.Paragraphs) - { - if (p.Text == "Text highlighted with yellow") - { - p.ReplaceText("Text highlighted with yellow", "New text highlighted with yellow", false, RegexOptions.None, null, desiredFormat, MatchFormattingOptions.ExactMatch); - replaced += p.Text; - } - } - - Assert.AreEqual("New text highlighted with yellow", replaced); - - // Removing red text with no other formatting (ExactMatch) - desiredFormat = new DocXFormatting() { Language = null, FontColor = WindowsColor.FromArgb(255, 0, 0) }; - var count = 0; - - foreach (var p in document.Paragraphs) - { - p.ReplaceText("Text", "Replaced text", false, RegexOptions.None, null, desiredFormat, MatchFormattingOptions.ExactMatch); - - if (p.Text.StartsWith("Replaced text")) - { - ++count; - } - } - - Assert.AreEqual(1, count); - - // Removing just red text with any other formatting (SubsetMatch) - desiredFormat = new DocXFormatting() { Language = null, FontColor = WindowsColor.FromArgb(255, 0, 0) }; - count = 0; - foreach (var p in document.Paragraphs) - { - p.ReplaceText("Text", "Replaced text", false, RegexOptions.None, null, desiredFormat); - if (p.Text.StartsWith("Replaced text")) - { - ++count; - } - } - - Assert.AreEqual(2, count); - } - } - - [Test] - public void Test_Paragraph_RemoveText() - { - // Create a new document - using (DocX document = DocX.Create("Test.docx")) - { - // Simple - //

- // HellWorld - //

- Paragraph p1 = document.InsertParagraph("HelloWorld"); - p1.RemoveText(0, 1); Assert.IsTrue(p1.Text == "elloWorld"); - p1.RemoveText(p1.Text.Length - 1, 1); Assert.IsTrue(p1.Text == "elloWorl"); - p1.RemoveText(p1.Text.IndexOf("o", StringComparison.Ordinal), 1); Assert.IsTrue(p1.Text == "ellWorl"); - - // Try and remove text at an index greater than the last. - // This should throw an exception. - try - { - p1.RemoveText(p1.Text.Length, 1); - Assert.Fail(); - } - catch (ArgumentOutOfRangeException) { } - catch (Exception) { Assert.Fail(); } - - // Try and remove text at a negative index. - // This should throw an exception. - try - { - p1.RemoveText(-1, 1); - Assert.Fail(); - } - catch (ArgumentOutOfRangeException) { } - catch (Exception) { Assert.Fail(); } - - // Difficult - //

- // A - // B - // C - //

- Paragraph p2 = document.InsertParagraph("A\tB\tC"); - p2.RemoveText(0, 1); Assert.IsTrue(p2.Text == "\tB\tC"); - p2.RemoveText(p2.Text.Length - 1, 1); Assert.IsTrue(p2.Text == "\tB\t"); - p2.RemoveText(p2.Text.IndexOf("B", StringComparison.Ordinal), 1); Assert.IsTrue(p2.Text == "\t\t"); - p2.RemoveText(0, 1); Assert.IsTrue(p2.Text == "\t"); - p2.RemoveText(0, 1); Assert.IsTrue(p2.Text == ""); - - // Contrived 1 - //

- // - // A - // B - // C - // - //

- Paragraph p3 = document.InsertParagraph(""); - p3.Xml = XElement.Parse - ( - @" - - - - A - B - C - - " - ); - - p3.RemoveText(0, 1); Assert.IsTrue(p3.Text == "BC"); - p3.RemoveText(p3.Text.Length - 1, 1); Assert.IsTrue(p3.Text == "B"); - p3.RemoveText(0, 1); Assert.IsTrue(p3.Text == ""); - - // Contrived 2 - //

- // - // A - // B - // C - // - //

- Paragraph p4 = document.InsertParagraph(""); - p4.Xml = XElement.Parse - ( - @" - - - - - A - - - - - - B - - - " - ); - - p4.RemoveText(0, 1); Assert.IsTrue(p4.Text == "A\t\tB\t"); - p4.RemoveText(1, 1); Assert.IsTrue(p4.Text == "A\tB\t"); - p4.RemoveText(p4.Text.Length - 1, 1); Assert.IsTrue(p4.Text == "A\tB"); - 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 == ""); - - // 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] - public void Test_Document_RemoveTextInGivenFormat() - { - // Load a document. - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "VariousTextFormatting.docx"))) - { - var formatting = new DocXFormatting(); - formatting.FontColor = WindowsColor.Blue; - // IMPORTANT: default constructor of Formatting sets up language property - set it to NULL to be language independent - formatting.Language = null; - var deletedCount = document.RemoveTextInGivenFormat(formatting); - Assert.AreEqual(2, deletedCount); - - deletedCount = document.RemoveTextInGivenFormat(new DocXFormatting() { Highlight = Highlight.yellow, Language = null }); - Assert.AreEqual(2, deletedCount); - - deletedCount = document.RemoveTextInGivenFormat(new DocXFormatting() { Highlight = Highlight.blue, Language = null, FontColor = WindowsColor.FromArgb(0, 255, 0) }); - Assert.AreEqual(1, deletedCount); - - deletedCount = document.RemoveTextInGivenFormat(new DocXFormatting() { Language = null, FontColor = WindowsColor.FromArgb(123, 123, 123) }, MatchFormattingOptions.ExactMatch); - Assert.AreEqual(2, deletedCount); - } - } - - [Test] - public void Test_Paragraph_InsertText() - { - // Create a new document - using (DocX document = DocX.Create("Test.docx")) - { - // Simple - //

- // HelloWorld - //

- Paragraph p1 = document.InsertParagraph("HelloWorld"); - p1.InsertText(0, "-"); Assert.IsTrue(p1.Text == "-HelloWorld"); - p1.InsertText(p1.Text.Length, "-"); Assert.IsTrue(p1.Text == "-HelloWorld-"); - p1.InsertText(p1.Text.IndexOf("W", StringComparison.Ordinal), "-"); Assert.IsTrue(p1.Text == "-Hello-World-"); - - // Try and insert text at an index greater than the last + 1. - // This should throw an exception. - try - { - p1.InsertText(p1.Text.Length + 1, "-"); - Assert.Fail(); - } - catch (ArgumentOutOfRangeException) { } - catch (Exception) { Assert.Fail(); } - - // Try and insert text at a negative index. - // This should throw an exception. - try - { - p1.InsertText(-1, "-"); - Assert.Fail(); - } - catch (ArgumentOutOfRangeException) { } - catch (Exception) { Assert.Fail(); } - - // Difficult - //

- // A - // B - // C - //

- Paragraph p2 = document.InsertParagraph("A\tB\tC"); - p2.InsertText(0, "-"); Assert.IsTrue(p2.Text == "-A\tB\tC"); - p2.InsertText(p2.Text.Length, "-"); Assert.IsTrue(p2.Text == "-A\tB\tC-"); - p2.InsertText(p2.Text.IndexOf("B", StringComparison.Ordinal), "-"); Assert.IsTrue(p2.Text == "-A\t-B\tC-"); - p2.InsertText(p2.Text.IndexOf("C", StringComparison.Ordinal), "-"); Assert.IsTrue(p2.Text == "-A\t-B\t-C-"); - - // Contrived 1 - //

- // - // A - // B - // C - // - //

- Paragraph p3 = document.InsertParagraph(""); - p3.Xml = XElement.Parse - ( - @" - - - - A - B - C - - " - ); - - p3.InsertText(0, "-"); Assert.IsTrue(p3.Text == "-ABC"); - p3.InsertText(p3.Text.Length, "-"); Assert.IsTrue(p3.Text == "-ABC-"); - p3.InsertText(p3.Text.IndexOf("B", StringComparison.Ordinal), "-"); Assert.IsTrue(p3.Text == "-A-BC-"); - p3.InsertText(p3.Text.IndexOf("C", StringComparison.Ordinal), "-"); Assert.IsTrue(p3.Text == "-A-B-C-"); - - // Contrived 2 - //

- // - // A - // B - // C - // - //

- Paragraph p4 = document.InsertParagraph(""); - p4.Xml = XElement.Parse - ( - @" - - - - A - B - C - - " - ); - - p4.InsertText(0, "\t"); Assert.IsTrue(p4.Text == "\tABC"); - p4.InsertText(p4.Text.Length, "\t"); Assert.IsTrue(p4.Text == "\tABC\t"); - p4.InsertText(p4.Text.IndexOf("B", StringComparison.Ordinal), "\t"); Assert.IsTrue(p4.Text == "\tA\tBC\t"); - p4.InsertText(p4.Text.IndexOf("C", StringComparison.Ordinal), "\t"); Assert.IsTrue(p4.Text == "\tA\tB\tC\t"); - } - } - - [Test] - public void Test_Document_Paragraphs() - { - string temporaryFilePath = Path.Combine(_directoryDocuments, "temp.docx"); - - // Load the document 'Paragraphs.docx' - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "Paragraphs.docx"))) - { - // Extract the Paragraphs from this document. - ReadOnlyCollection paragraphs = document.Paragraphs; - - // There should be 3 Paragraphs in this document. - Assert.IsTrue(paragraphs.Count() == 3); - - // Extract the 3 Paragraphs. - Paragraph p1 = paragraphs[0]; - Paragraph p2 = paragraphs[1]; - Paragraph p3 = paragraphs[2]; - - // Extract their Text properties. - string p1_text = p1.Text; - string p2_text = p2.Text; - string p3_text = p3.Text; - - // Test their Text properties against absolutes. - Assert.IsTrue(p1_text == "Paragraph 1"); - Assert.IsTrue(p2_text == "Paragraph 2"); - Assert.IsTrue(p3_text == "Paragraph 3"); - - // Its important that each Paragraph knows the PackagePart it belongs to. - foreach (var paragraph in document.Paragraphs) - { - Assert.IsTrue(paragraph.PackagePart.Uri.ToString() == package_part_document); - } - - // Test the saving of the document. - document.SaveAs(temporaryFilePath); - } - - // Delete the tempory file. - File.Delete(temporaryFilePath); - } - - [Test] - public void Test_Table_mainPart_bug9526() - { - using (DocX document = DocX.Create("test.docx")) - { - Hyperlink h = document.AddHyperlink("follow me", new Uri("http://www.google.com")); - Table t = document.AddTable(2, 3); - int cc = t.ColumnCount; - - Paragraph p = t.Rows[0].Cells[0].Paragraphs[0]; - p.AppendHyperlink(h); - } - } - - [Test] - public void Test_Table_RemoveColumnWithMergedCells() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Tables3.docx"))) - { - //Add A table - Table t = document.AddTable(2, 3); - t.Design = TableDesign.TableGrid; - - Table t1 = document.InsertTable(t); - t1.Rows[0].MergeCells(1, 2); - t1.RemoveColumn(); - document.Save(); - } - } - - [Test] - public void Test_Table_MergedRowCellsMergedWithColumnMergedCells() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Tables3.docx"))) - { - //Add A table - Table t = document.AddTable(3, 3); - t.Design = TableDesign.TableGrid; - - Table t1 = document.InsertTable(t); - t1.Rows[0].MergeCells(0, 1); - t1.Rows[1].MergeCells(0, 1); - t1.MergeCellsInColumn(0, 0, 1); - document.Save(); - } - } - - [Test] - public void Test_Table_RemoveRowWithMergedCells() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Tables3.docx"))) - { - //Add A table - Table t = document.AddTable(3, 4); - t.Design = TableDesign.TableGrid; - - Table t1 = document.InsertTable(t); - t1.Rows[0].MergeCells(1, 2); - t1.RemoveRow(); - t1.MergeCellsInColumn(0, 0, 1); - t1.InsertRow(); - t1.RemoveRow(1); - document.Save(); - } - } - - [Test] - public void Test_Table_InsertRow() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Tables3.docx"))) - { - //Add A table - Table t = document.AddTable(2, 3); - t.Design = TableDesign.TableGrid; - - Table t1 = document.InsertTable(t); - t1.MergeCellsInColumn(1, 0, 1); - t1.InsertRow(); - t1.Rows[2].MergeCells(1, 3); - t1.InsertRow(3); - document.Save(); - } - } - - [Test] - public void Test_Table_AddColumnWithCellDeleted() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Tables3.docx"))) - { - //Add A table - Table t = document.AddTable(2, 3); - t.Design = TableDesign.TableGrid; - - Table t1 = document.InsertTable(t); - - t1.DeleteAndShiftCellsLeft(0, 1); - // 4 columns - t1.InsertColumn(); - t1.DeleteAndShiftCellsLeft(0, 1); - // 5 columns - t1.InsertColumn(); - t1.DeleteAndShiftCellsLeft(0, 1); - - document.Save(); - } - } - - [Test] - public void Test_Table_DeleteCellInRow() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Tables3.docx"))) - { - //Add A table - Table t = document.AddTable(2, 2); - t.Design = TableDesign.TableGrid; - - Table t1 = document.InsertTable(t); - - t1.DeleteAndShiftCellsLeft(0, 1); - document.Save(); - document.Save(); - } - } - - [Test] - public void Test_Table_InsertColumnWithMergedCells() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Tables3.docx"))) - { - //Add A table - Table t = document.AddTable(2, 2); - t.Design = TableDesign.TableGrid; - - Table t1 = document.InsertTable(t); - - t1.InsertColumn(2, true); - t1.InsertColumn(2, true); - t1.InsertColumn(2, true); - t1.InsertColumn(2, true); - t1.Rows[0].MergeCells(1, 4); - - Assert.AreEqual(t1.Rows[1].Cells.Count, 6); - Assert.AreEqual(t1.ColumnCount, 6); - - foreach (Row r in t1.Rows) - { - foreach (Cell c in r.Cells) - { - c.Paragraphs[0].InsertText("Hello"); - } - } - t1.InsertColumn(6, false); - t1.InsertColumn(); - t1.InsertColumn(3, true); - t1.InsertColumn(6, true); - t1.InsertColumn(6, true); - t1.InsertColumn(5, true); - document.Save(); - } - } - - [Test] - public void Test_Table_InsertRowAndColumn() - { - // Create a table - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "Tables2.docx"))) - { - // Add a Table to a document. - Table t = document.AddTable(2, 2); - t.Design = TableDesign.TableGrid; - - t.Rows[0].Cells[0].Paragraphs[0].InsertText("X"); - t.Rows[0].Cells[1].Paragraphs[0].InsertText("X"); - t.Rows[1].Cells[0].Paragraphs[0].InsertText("X"); - t.Rows[1].Cells[1].Paragraphs[0].InsertText("X"); - - // Insert the Table into the main section of the document. - Table t1 = document.InsertTable(t); - // ... and add a column and a row - t1.InsertRow(1); - t1.InsertColumn(1, true); - - // Save the document. - document.Save(); - } - - // Check table - using (DocX document = DocX.Load(Path.Combine(_directoryDocuments, "Tables2.docx"))) - { - // Get a table from a document - Table t = document.Tables[0]; - - // Check that the table is equal this: - // X - X - // - - - - // X - X - Assert.AreEqual("X", t.Rows[0].Cells[0].Paragraphs[0].Text); - Assert.AreEqual("X", t.Rows[2].Cells[0].Paragraphs[0].Text); - Assert.AreEqual("X", t.Rows[0].Cells[2].Paragraphs[0].Text); - Assert.AreEqual("X", t.Rows[2].Cells[2].Paragraphs[0].Text); - Assert.IsTrue(String.IsNullOrEmpty(t.Rows[1].Cells[0].Paragraphs[0].Text)); - Assert.IsTrue(String.IsNullOrEmpty(t.Rows[1].Cells[1].Paragraphs[0].Text)); - Assert.IsTrue(String.IsNullOrEmpty(t.Rows[1].Cells[2].Paragraphs[0].Text)); - Assert.IsTrue(String.IsNullOrEmpty(t.Rows[0].Cells[1].Paragraphs[0].Text)); - Assert.IsTrue(String.IsNullOrEmpty(t.Rows[2].Cells[1].Paragraphs[0].Text)); - } - } - - [Test] - public void Test_Table_SetTableDesignNone() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "TablesDesign.docx"))) - { - //Add A table - Table t = document.AddTable(2, 3); - Table t1 = document.InsertTable(t); - t1.Design = TableDesign.None; - // requires FIX for .None/.Custom set in a row - // t1.Design = TableDesign.None; - // t1.Design = TableDesign.Custom; - t1.Design = TableDesign.Custom; - t1.Design = TableDesign.ColorfulGrid; - t1.Design = TableDesign.ColorfulGrid; - t1.MergeCellsInColumn(1, 0, 1); - t1.InsertRow(); - t1.Rows[2].MergeCells(1, 3); - t1.InsertRow(3); - document.Save(); - } - } - - [Test] - public void Test_Document_ApplyTemplate() - { - using (MemoryStream documentStream = new MemoryStream()) - { - using (DocX document = DocX.Create(documentStream)) - { - document.ApplyTemplate(Path.Combine(_directoryWithFiles, "Template.dotx")); - document.Save(); - - Header firstHeader = document.Headers.first; - Header oddHeader = document.Headers.odd; - Header evenHeader = document.Headers.even; - - Footer firstFooter = document.Footers.first; - Footer oddFooter = document.Footers.odd; - Footer evenFooter = document.Footers.even; - - Assert.IsTrue(firstHeader.Paragraphs.Count == 1, "More than one paragraph in header."); - Assert.IsTrue(firstHeader.Paragraphs[0].Text.Equals("First page header"), "Header isn't retrieved from template."); - - Assert.IsTrue(oddHeader.Paragraphs.Count == 1, "More than one paragraph in header."); - Assert.IsTrue(oddHeader.Paragraphs[0].Text.Equals("Odd page header"), "Header isn't retrieved from template."); - - Assert.IsTrue(evenHeader.Paragraphs.Count == 1, "More than one paragraph in header."); - Assert.IsTrue(evenHeader.Paragraphs[0].Text.Equals("Even page header"), "Header isn't retrieved from template."); - - Assert.IsTrue(firstFooter.Paragraphs.Count == 1, "More than one paragraph in footer."); - Assert.IsTrue(firstFooter.Paragraphs[0].Text.Equals("First page footer"), "Footer isn't retrieved from template."); - - Assert.IsTrue(oddFooter.Paragraphs.Count == 1, "More than one paragraph in footer."); - Assert.IsTrue(oddFooter.Paragraphs[0].Text.Equals("Odd page footer"), "Footer isn't retrieved from template."); - - Assert.IsTrue(evenFooter.Paragraphs.Count == 1, "More than one paragraph in footer."); - Assert.IsTrue(evenFooter.Paragraphs[0].Text.Equals("Even page footer"), "Footer isn't retrieved from template."); - - Paragraph firstParagraph = document.Paragraphs[0]; - Assert.IsTrue(firstParagraph.StyleName.Equals("DocXSample"), "First paragraph isn't of style from template."); - } - } - } - [Test] - public void When_opening_a_template_no_error_should_be_thrown() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "Template.dotx"))) - { - Assert.IsTrue(document.Paragraphs.Count > 0); - } - } - [Test] - public void Saving_and_loading_a_template_should_work() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "test template.dotx"), DocumentTypes.Template)) - { - document.InsertParagraph("hello, this is a paragraph"); - document.Save(); - } - using (DocX document = DocX.Load(Path.Combine(_directoryDocuments, "test template.dotx"))) - { - Assert.IsTrue(document.Paragraphs.Count > 0); - } - - } - [Test] - public void Test_ParentContainer_When_Creating_Doc() - { - using (DocX document = DocX.Create("Test.docx")) - { - document.AddHeaders(); - Paragraph p1 = document.Headers.first.InsertParagraph("Test"); - - Assert.IsTrue(p1.ParentContainer == ContainerType.Header); - } - } - - [Test] - public void Test_Section_Count_When_Creating_Doc() - { - //This adds a section break - so insert paragraphs, and follow it up by a section break/paragraph - using (DocX document = DocX.Create("TestSectionCount.docx")) - { - document.InsertSection(); - - var sections = document.GetSections(); - - Assert.AreEqual(sections.Count(), 2); - } - - } - - [Test] - public void Test_Sections_And_Paragraphs_When_Creating_Doc() - { - //This adds a section break - so insert paragraphs, and follow it up by a section break/paragraph - using (DocX document = DocX.Create("TestSectionAndParagraph.docx")) - { - //Add 2 paras and a break - document.InsertParagraph("First Para"); - document.InsertParagraph("Second Para"); - document.InsertSection(); - document.InsertParagraph("This is default para"); - - var sections = document.GetSections(); - - Assert.AreEqual(sections.Count(), 2); - } - - - } - - [Test] - public void Test_ParentContainer_When_Reading_Doc() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "Tables.docx"))) - { - ReadOnlyCollection paragraphs = document.Paragraphs; - - Paragraph p1 = paragraphs[0]; - - Assert.IsTrue(p1.ParentContainer == ContainerType.Cell); - } - - } - - [Test] - public void Test_Section_Count_When_Reading_Doc() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "testdoc_SectionsWithSectionBreaks.docx"))) - { - var sections = document.GetSections(); - - Assert.AreEqual(sections.Count(), 4); - } - - } - - [Test] - public void Test_Section_Paragraph_Count_Match_When_Reading_Doc() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "testdoc_SectionsWithSectionBreaksMultiParagraph.docx"))) - { - - var sections = document.GetSections(); - - Assert.AreEqual(sections[0].SectionParagraphs.Count, 2); - Assert.AreEqual(sections[1].SectionParagraphs.Count, 1); - Assert.AreEqual(sections[2].SectionParagraphs.Count, 2); - Assert.AreEqual(sections[3].SectionParagraphs.Count, 1); - } - } - - [Test] - public void Test_Section_Paragraph_Content_Match_When_Reading_Doc() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "testdoc_SectionsWithSectionBreaks.docx"))) - { - - var sections = document.GetSections(); - - Assert.IsTrue(sections[0].SectionParagraphs[0].Text.Contains("Section 1")); - Assert.IsTrue(sections[1].SectionParagraphs[0].Text.Contains("Section 2")); - Assert.IsTrue(sections[2].SectionParagraphs[0].Text.Contains("Section 3")); - Assert.IsTrue(sections[3].SectionParagraphs[0].Text.Contains("Section 4")); - - } - } - - [Test] - public void Test_Ordered_List_When_Reading_Doc() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "testdoc_OrderedList.docx"))) - { - - var sections = document.GetSections(); - - Assert.IsTrue(sections[0].SectionParagraphs[0].IsListItem); - Assert.IsTrue(sections[0].SectionParagraphs[1].IsListItem); - Assert.IsTrue(sections[0].SectionParagraphs[2].IsListItem); - - Assert.AreEqual(sections[0].SectionParagraphs[0].ListItemType, ListItemType.Numbered); - Assert.AreEqual(sections[0].SectionParagraphs[1].ListItemType, ListItemType.Numbered); - Assert.AreEqual(sections[0].SectionParagraphs[2].ListItemType, ListItemType.Numbered); - } - } - - [Test] - public void Test_Unordered_List_When_Reading_Doc() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "testdoc_UnorderedList.docx"))) - { - - var sections = document.GetSections(); - - Assert.IsTrue(sections[0].SectionParagraphs[0].IsListItem); - Assert.IsTrue(sections[0].SectionParagraphs[1].IsListItem); - Assert.IsTrue(sections[0].SectionParagraphs[2].IsListItem); - - Assert.AreEqual(sections[0].SectionParagraphs[0].ListItemType, ListItemType.Bulleted); - Assert.AreEqual(sections[0].SectionParagraphs[1].ListItemType, ListItemType.Bulleted); - Assert.AreEqual(sections[0].SectionParagraphs[2].ListItemType, ListItemType.Bulleted); - } - } - - [Test] - public void Test_Ordered_Unordered_Lists_When_Reading_Doc() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "testdoc_OrderedUnorderedLists.docx"))) - { - - var sections = document.GetSections(); - - Assert.IsTrue(sections[0].SectionParagraphs[0].IsListItem); - Assert.IsTrue(sections[0].SectionParagraphs[1].IsListItem); - Assert.IsTrue(sections[0].SectionParagraphs[2].IsListItem); - - Assert.AreEqual(sections[0].SectionParagraphs[0].ListItemType, ListItemType.Numbered); - Assert.AreEqual(sections[0].SectionParagraphs[1].ListItemType, ListItemType.Numbered); - Assert.AreEqual(sections[0].SectionParagraphs[2].ListItemType, ListItemType.Numbered); - - Assert.IsTrue(sections[0].SectionParagraphs[3].IsListItem); - Assert.IsTrue(sections[0].SectionParagraphs[4].IsListItem); - Assert.IsTrue(sections[0].SectionParagraphs[5].IsListItem); - - Assert.AreEqual(sections[0].SectionParagraphs[3].ListItemType, ListItemType.Bulleted); - Assert.AreEqual(sections[0].SectionParagraphs[4].ListItemType, ListItemType.Bulleted); - Assert.AreEqual(sections[0].SectionParagraphs[5].ListItemType, ListItemType.Bulleted); - - } - } - - [Test] - public void WhenCreatingAnOrderedListTheListXmlShouldHaveNumberedListItemType() - { - - using (DocX document = DocX.Create("TestListXmlNumbered.docx")) - { - const int level = 0; - XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; - var list = document.AddList("First Item"); - document.InsertList(list); - - var listNumPropNode = document.mainDoc.Descendants().First(s => s.Name.LocalName == "numPr"); - - var numId = listNumPropNode.Descendants().First(s => s.Name.LocalName == "numId"); - var abstractNum = list.GetAbstractNum(int.Parse(numId.GetAttribute(w + "val"))); - var lvl = abstractNum.Descendants().First(d => d.Name.LocalName == "lvl" && d.GetAttribute(w + "ilvl").Equals(level.ToString())); - var numFormat = lvl.Descendants().First(d => d.Name.LocalName == "numFmt"); - - Assert.AreEqual(numFormat.GetAttribute(w + "val").ToLower(), "decimal"); - } - - } - - [Test] - public void WhenCreatingAnUnOrderedListTheListXmlShouldHaveBulletListItemType() - { - - using (DocX document = DocX.Create("TestListXmlBullet.docx")) - { - var list = document.AddList("First Item", 0, ListItemType.Bulleted); - document.InsertList(list); - - var listNumPropNode = document.mainDoc.Descendants().First(s => s.Name.LocalName == "numPr"); - - var numId = listNumPropNode.Descendants().First(s => s.Name.LocalName == "numId"); - - Assert.AreEqual(numId.Attribute(DocX.w + "val").Value, "1"); - } - } - - [Test] - public void WhenCreatingAListWithTextTheListXmlShouldHaveTheCorrectRunItemText() - { - using (DocX document = DocX.Create("TestListCreate.docx")) - { - const string listText = "RunText"; - var list = document.AddList(listText, 0, ListItemType.Bulleted); - document.InsertList(list); - - var listNumPropNode = document.mainDoc.Descendants().First(s => s.Name.LocalName == "numPr"); - - var runTextNode = document.mainDoc.Descendants().First(s => s.Name.LocalName == "t"); - - Assert.IsNotNull(listNumPropNode); - Assert.AreEqual(list.Items.First().runs.First().Value, runTextNode.Value); - Assert.AreEqual(listText, runTextNode.Value); - } - } - - [Test] - public void WhenCreatingAnOrderedListTheListShouldHaveNumberedListItemType() - { - - using (DocX document = DocX.Create("TestListCreateOrderedList.docx")) - { - var list = document.AddList("First Item"); - - Assert.AreEqual(list.ListType, ListItemType.Numbered); - } - - } - - [Test] - public void WhenCreatingAnUnOrderedListTheListShouldHaveBulletListItemType() - { - - using (DocX document = DocX.Create("TestListCreateUnorderedList.docx")) - { - var list = document.AddList("First Item", 0, ListItemType.Bulleted); - - Assert.AreEqual(list.ListType, ListItemType.Bulleted); - } - - } - - [Test] - public void WhenCreatingAListWithTextTheListShouldHaveTheCorrectRunItemText() - { - - using (DocX document = DocX.Create("TestListCreateRunText.docx")) - { - var list = document.AddList("RunText", 0, ListItemType.Bulleted); - document.InsertList(list); - - Assert.AreEqual(list.Items.First().runs.First().Value, "RunText"); - } - } - - [Test] - public void WhenCreatingAListTheListStyleShouldExistOrBeCreated() - { - - using (DocX document = DocX.Create("TestListStyle.docx")) - { - var style = document.AddStylesForList(); - - XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; - - bool listStyleExists = - ( - from s in style.Element(w + "styles").Elements() - let styleId = s.Attribute(XName.Get("styleId", w.NamespaceName)) - where (styleId != null && styleId.Value == "ListParagraph") - select s - ).Any(); - - Assert.IsTrue(listStyleExists); - - } - } - - [Test] - public void ANewListItemShouldCreateAnAbstractNumberingEntry() - { - using (DocX document = DocX.Create("TestNumbering.docx")) - { - var numbering = document.numbering.Descendants().Where(d => d.Name.LocalName == "abstractNum"); - Assert.IsFalse(numbering.Any()); - - document.AddList("List Text"); - - numbering = document.numbering.Descendants().Where(d => d.Name.LocalName == "abstractNum"); - Assert.IsTrue(numbering.Any()); - } - } - - [Test] - public void ANewListItemShouldCreateANewNumEntry() - { - using (DocX document = DocX.Create("TestNumEntry.docx")) - { - var numbering = document.numbering.Descendants().Where(d => d.Name.LocalName == "num"); - Assert.IsFalse(numbering.Any()); - - document.AddList("List Text"); - - numbering = document.numbering.Descendants().Where(d => d.Name.LocalName == "num"); - Assert.IsTrue(numbering.Any()); - } - } - - [Test] - public void CreateNewNumberingNumIdShouldAddNumberingDataToTheDocument() - { - using (DocX document = DocX.Create("TestCreateNumbering.docx")) - { - var numbering = document.numbering.Descendants().Where(d => d.Name.LocalName == "num"); - Assert.IsFalse(numbering.Any()); - var list = document.AddList("", 0, ListItemType.Bulleted); - document.InsertList(list); - - numbering = document.numbering.Descendants().Where(d => d.Name.LocalName == "num"); - Assert.IsTrue(numbering.Any()); - } - } - - [Test] - public void CreateNewNumberingNumIdShouldAddNumberingAbstractDataToTheDocument() - { - using (DocX document = DocX.Create("TestCreateNumberingAbstract.docx")) - { - var numbering = document.numbering.Descendants().Where(d => d.Name.LocalName == "abstractNum"); - Assert.IsFalse(numbering.Any()); - var list = document.AddList("", 0, ListItemType.Bulleted); - document.InsertList(list); - - numbering = document.numbering.Descendants().Where(d => d.Name.LocalName == "abstractNum"); - Assert.IsTrue(numbering.Any()); - } - } - - [Test] - public void IfPreviousElementIsAListThenAddingANewListContinuesThePreviousList() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "TestAddListToPreviousList.docx"))) - { - var list = document.AddList("List Text"); - document.AddListItem(list, "List Text2"); - document.InsertList(list); - - var lvlNodes = document.mainDoc.Descendants().Where(s => s.Name.LocalName == "ilvl").ToList(); - var numIdNodes = document.mainDoc.Descendants().Where(s => s.Name.LocalName == "numId").ToList(); - - Assert.AreEqual(lvlNodes.Count(), 2); - Assert.AreEqual(numIdNodes.Count(), 2); - - var prevLvlNode = lvlNodes[0]; - var newLvlNode = lvlNodes[1]; - - Assert.AreEqual(prevLvlNode.Attribute(DocX.w + "val").Value, newLvlNode.Attribute(DocX.w + "val").Value); - - var prevNumIdNode = numIdNodes[0]; - var newNumIdNode = numIdNodes[1]; - - Assert.AreEqual(prevNumIdNode.Attribute(DocX.w + "val").Value, newNumIdNode.Attribute(DocX.w + "val").Value); - document.Save(); - } - - } - - [Test] - public void WhenADocumentHasListsTheListPropertyReturnsTheCorrectNumberOfLists() - { - - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "testdoc_OrderedUnorderedLists.docx"))) - { - var lists = document.Lists; - - Assert.AreEqual(lists.Count, 2); - - } - } - - [Test] - public void WhenADocumentIsCreatedWithAListItemThatHasASpecifiedStartNumber() - { - using (DocX document = DocX.Create("CreateListItemFromDifferentStartValue.docx")) - { - var list = document.AddList("Test", 0, ListItemType.Numbered, 5); - document.AddListItem(list, "NewElement"); - - var numbering = document.numbering.Descendants().Where(d => d.Name.LocalName == "abstractNum"); - var level = numbering.Descendants().First(el => el.Name.LocalName == "lvl"); - var start = level.Descendants().First(el => el.Name.LocalName == "start"); - Assert.AreEqual(start.GetAttribute(DocX.w + "val"), 5.ToString()); - } - } - - [Test] - public void WhenANumberedAndBulletedListIsCreatedThereShouldBeTwoNumberingXmls() - { - using (DocX document = DocX.Create("NumberAndBulletListInOne.docx")) - { - var numberList = document.AddList("Test"); - document.AddListItem(numberList, "Second Numbered Item"); - - var bulletedList = document.AddList("Bullet", 0, ListItemType.Bulleted); - document.AddListItem(bulletedList, "Second bullet item"); - - document.InsertList(numberList); - document.InsertList(bulletedList); - - var abstractNums = document.numbering.Descendants().Where(d => d.Name.LocalName == "abstractNum"); - Assert.AreEqual(abstractNums.Count(), 2); - - } - } - - [Test] - public void WhenICreateAnEmptyListAndAddEntriesToIt() - { - using (DocX document = DocX.Create("CreateEmptyListAndAddItemsToIt.docx")) - { - var list = document.AddList(); - Assert.AreEqual(list.Items.Count, 0); - - document.AddListItem(list, "Test item 1."); - document.AddListItem(list, "Test item 2."); - Assert.AreEqual(list.Items.Count, 2); - } - } - - [Test] - public void WhenICreateAHeaderItShouldHaveAStyle() - { - using (var document = DocX.Create(Path.Combine(_directoryDocuments, "CreateHeaderElement.docx"))) - { - document.InsertParagraph("Header Text 1").StyleName = "Header1"; - Assert.IsNotNull(document.styles.Root.Descendants().FirstOrDefault(d => d.GetAttribute(DocX.w + "styleId").ToLowerInvariant() == "heading1")); - document.Save(); - } - } - - [Test] - public void ParagraphAppendHyperLink_ParagraphIsListItem_ShouldNotThrow() - { - using (var document = DocX.Create(Path.Combine(_directoryDocuments, "HyperlinkList.docx"))) - { - var list = document.AddList("Item 1"); - document.AddListItem(list, "Item 2"); - document.AddListItem(list, "Item 3"); - - Uri uri; - Uri.TryCreate("http://www.google.com", UriKind.RelativeOrAbsolute, out uri); - var hLink = document.AddHyperlink("Google", uri); - var item2 = list.Items[1]; - - item2.InsertText("\nMore text\n"); - item2.AppendHyperlink(hLink); - - item2.InsertText("\nEven more text"); - - document.InsertList(list); - document.Save(); - } - } - - - [Test] - public void WhileReadingWhenTextIsBoldItalicUnderlineItShouldReadTheProperFormatting() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "FontFormat.docx"))) - { - var underlinedTextFormatting = document.Paragraphs[0].MagicText[0].formatting; - var boldTextFormatting = document.Paragraphs[0].MagicText[2].formatting; - var italicTextFormatting = document.Paragraphs[0].MagicText[4].formatting; - var boldItalicUnderlineTextFormatting = document.Paragraphs[0].MagicText[6].formatting; - - Assert.IsTrue(boldTextFormatting.Bold.HasValue && boldTextFormatting.Bold.Value); - Assert.IsTrue(italicTextFormatting.Italic.HasValue && italicTextFormatting.Italic.Value); - Assert.AreEqual(underlinedTextFormatting.UnderlineStyle, UnderlineStyle.singleLine); - Assert.IsTrue(boldItalicUnderlineTextFormatting.Bold.HasValue && boldItalicUnderlineTextFormatting.Bold.Value); - Assert.IsTrue(boldItalicUnderlineTextFormatting.Italic.HasValue && boldItalicUnderlineTextFormatting.Italic.Value); - Assert.AreEqual(boldItalicUnderlineTextFormatting.UnderlineStyle, UnderlineStyle.singleLine); - } - } - - - [Test] - public void WhileWritingWhenTextIsBoldItalicUnderlineItShouldReadTheProperFormatting() - { - using (DocX document = DocX.Create("FontFormatWrite.docx")) - { - - Paragraph p = document.InsertParagraph(); - p.Append("This is bold.").Bold().Append("This is underlined.").UnderlineStyle(UnderlineStyle.singleLine). - Append("This is italic.").Italic().Append("This is boldItalicUnderlined").Italic().Bold().UnderlineStyle(UnderlineStyle.singleLine); - - var boldTextFormatting = document.Paragraphs[0].MagicText[0].formatting; - var underlinedTextFormatting = document.Paragraphs[0].MagicText[1].formatting; - var italicTextFormatting = document.Paragraphs[0].MagicText[2].formatting; - var boldItalicUnderlineTextFormatting = document.Paragraphs[0].MagicText[3].formatting; - - Assert.IsTrue(boldTextFormatting.Bold.HasValue && boldTextFormatting.Bold.Value); - Assert.IsTrue(italicTextFormatting.Italic.HasValue && italicTextFormatting.Italic.Value); - Assert.AreEqual(underlinedTextFormatting.UnderlineStyle, UnderlineStyle.singleLine); - Assert.IsTrue(boldItalicUnderlineTextFormatting.Bold.HasValue && boldItalicUnderlineTextFormatting.Bold.Value); - Assert.IsTrue(boldItalicUnderlineTextFormatting.Italic.HasValue && boldItalicUnderlineTextFormatting.Italic.Value); - Assert.AreEqual(boldItalicUnderlineTextFormatting.UnderlineStyle, UnderlineStyle.singleLine); - } - } - - [Test] - public void InsertingANextPageBreakShouldAddADocumentSection() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "SectionPageBreak.docx"))) - { - document.InsertSectionPageBreak(); - - var sections = document.GetSections(); - Assert.AreEqual(sections.Count, 2); - document.Save(); - } - } - - [Test] - public void InsertANextPageBreakWithParagraphTextsShouldAddProperParagraphsToProperSections() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "SectionPageBreakWithParagraphs.docx"))) - { - document.InsertParagraph("First paragraph."); - document.InsertParagraph("Second paragraph."); - document.InsertSectionPageBreak(); - document.InsertParagraph("Third paragraph."); - document.InsertParagraph("Fourth paragraph."); - - var sections = document.GetSections(); - Assert.AreEqual(sections.Count, 2); - - Assert.AreEqual(sections[0].SectionParagraphs.Count(p => !string.IsNullOrWhiteSpace(p.Text)), 2); - Assert.AreEqual(sections[1].SectionParagraphs.Count(p => !string.IsNullOrWhiteSpace(p.Text)), 2); - document.Save(); - } - } - - [Test] - public void WhenAFontFamilyIsSpecifiedForAParagraphItShouldSetTheFontOfTheParagraphTextToTheFontFamily() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, "FontTest.docx"))) - { - Paragraph p = document.InsertParagraph(); - - var fontFamily = new Font("Symbol"); - - p.Append("Hello World").Font(fontFamily); - - Assert.AreEqual(p.MagicText[0].formatting.FontFamily.Name, fontFamily.Name); - - document.Save(); - } - } - - [Test] - public void Test_Paragraph_RemoveTextManyLetters() - { - using (DocX document = DocX.Create(@"HelloWorldRemovingManyLetters.docx")) - { - - Paragraph p3 = document.InsertParagraph(""); - p3.Xml = XElement.Parse( - @" - - - - - Based on the previous screening criteria, you qualify to participate in this particular survey. At the completion of the survey, you will be notified that your responses have been received and honoraria information will be captured for future payment. Thank you in advance for taking the time to participate with us. ^f('xMinutes').get() == 'xx' ? """" : "" - - - - - - This survey should take - - - "" + f('xMinutes').get() + "" - - - - - - minutes. - - - ""^Participants completing this survey will receive the honorarium designated in the invitation you have received. <BR><BR>If you leave the survey prior to finishing it, you may return to your last question by visiting the same link provided in your email invitation (please be certain to use the same email that you used a moment ago to register for this study). If you have any questions or concerns about this study, please contact us at <a href=""mailto:blabla@blabla.com?Subject=^f('sName')^ PD:^f('pdID')^"">blabla@blabla.com</a>. Thank you. - - "); - - int l1 = p3.Text.Length; //960 - p3.RemoveText(318, 99); - int l2 = p3.Text.Length; //should be 861 - Assert.AreEqual(l1 - 99, l2); - } - } - - [Test] - public void Test_Table_RemoveParagraphs() - { - var memoryStream = new MemoryStream(); - var document = DocX.Create(memoryStream); - // Add a Table into the document. - Table table = document.AddTable(1, 4); // 1 row, 4 cells - table.Design = TableDesign.TableGrid; - table.Alignment = Alignment.center; - // Edit row - var row = table.Rows[0]; - - // Fill 1st paragraph - row.Cells[0].Paragraphs.ElementAt(0).Append("Paragraph 1"); - // Fill 2nd paragraph - var secondParagraph = row.Cells[0].InsertParagraph("Paragraph 2"); - - // Check number of paragraphs - Assert.AreEqual(2, row.Cells[0].Paragraphs.Count()); - - // Remove 1st paragraph - var deleted = row.Cells[0].RemoveParagraphAt(0); - Assert.IsTrue(deleted); - // Check number of paragraphs - Assert.AreEqual(1, row.Cells[0].Paragraphs.Count()); - - // Remove 3rd (nonexisting) paragraph - deleted = row.Cells[0].RemoveParagraphAt(3); - Assert.IsFalse(deleted); - //check number of paragraphs - Assert.AreEqual(1, row.Cells[0].Paragraphs.Count()); - - // Remove secondParagraph (this time the only one) paragraph - deleted = row.Cells[0].RemoveParagraph(secondParagraph); - Assert.IsTrue(deleted); - Assert.AreEqual(0, row.Cells[0].Paragraphs.Count()); - - // Remove last paragraph once again - this time this paragraph does not exists - deleted = row.Cells[0].RemoveParagraph(secondParagraph); - Assert.IsFalse(deleted); - Assert.AreEqual(0, row.Cells[0].Paragraphs.Count()); - } - [Test] - public void GenerateHeadingTestDocument() - { - using (DocX document = DocX.Create(Path.Combine(_directoryDocuments, @"Document Header Test.docx"))) - { - - foreach (HeadingType heading in (HeadingType[])Enum.GetValues(typeof(HeadingType))) - { - string text = string.Format("{0} - The quick brown fox jumps over the lazy dog", heading.EnumDescription()); - - Paragraph p = document.InsertParagraph(); - p.AppendLine(text).Heading(heading); - } - - - document.Save(); - } - } - - - - [Test] - public void CreateTableOfContents_WithTitleAndSwitches_SetsExpectedXml() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const int rightPos = 9350; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - var toc = TableOfContents.CreateTableOfContents(document, title, switches); - - const string switchString = @"TOC \h \o '1-3' \u \z"; - var expectedString = string.Format(XmlTemplateBases.TocXmlBase, "TOCHeading", title, rightPos, switchString); - var expectedReader = XmlReader.Create(new StringReader(expectedString)); - var expected = XElement.Load(expectedReader); - - Assert.IsTrue(XNode.DeepEquals(expected, toc.Xml)); - } - } - - [Test] - public void CreateTableOfContents_WithTitleSwitchesHeaderStyleLastIncludeLevelRightTabPos_SetsExpectedXml() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const int rightPos = 1337; - const string style = "TestStyle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - var toc = TableOfContents.CreateTableOfContents(document, title, switches, style, 6, rightPos); - - const string switchString = @"TOC \h \o '1-6' \u \z"; - var expectedString = string.Format(XmlTemplateBases.TocXmlBase, style, title, rightPos, switchString); - - var expectedReader = XmlReader.Create(new StringReader(expectedString)); - var expected = XElement.Load(expectedReader); - - Assert.IsTrue(XNode.DeepEquals(expected, toc.Xml)); - } - } - - [Test] - public void CreateTableOfContents_WhenCalled_AddsUpdateFieldsWithValueTrueToSettings() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - TableOfContents.CreateTableOfContents(document, title, switches); - - var updateField = document.settings.Descendants().FirstOrDefault(x => x.Name == DocX.w + "updateFields"); - Assert.IsNotNull(updateField); - Assert.AreEqual("true", updateField.Attribute(DocX.w + "val").Value); - } - } - - [Test] - public void CreateTableOfContents_WhenCalledSettingsAlreadyHasUpdateFields_DoesNotAddUpdateFields() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - var element = new XElement(XName.Get("updateFields", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", true)); - document.settings.Root.Add(element); - const string title = "TestTitle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - TableOfContents.CreateTableOfContents(document, title, switches); - - var updateFields = document.settings.Descendants().Single(x => x.Name == DocX.w + "updateFields"); - Assert.AreSame(element, updateFields); - } - } - - [Test] - public void CreteTableOfContents_TocHeadingStyleIsNotPresent_AddsTocHeaderStyle() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const string headerStyle = "TestStyle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - TableOfContents.CreateTableOfContents(document, title, switches, headerStyle); - - var expectedString = string.Format(XmlTemplateBases.TocHeadingStyleBase, headerStyle); - - var expectedReader = XmlReader.Create(new StringReader(expectedString)); - var expected = XElement.Load(expectedReader); - - var actual = document.styles.Root.Descendants().FirstOrDefault(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals(headerStyle)); - - Assert.IsTrue(XNode.DeepEquals(expected, actual)); - } - } - - [Test] - public void CreteTableOfContents_Toc1StyleIsNotPresent_AddsToc1Style() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - TableOfContents.CreateTableOfContents(document, title, switches); - - var expectedString = string.Format(XmlTemplateBases.TocElementStyleBase, "TOC1", "toc 1"); - - var expectedReader = XmlReader.Create(new StringReader(expectedString)); - var expected = XElement.Load(expectedReader); - - var actual = document.styles.Root.Descendants().FirstOrDefault(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals("TOC1")); - - Assert.IsTrue(XNode.DeepEquals(expected, actual)); - } - } - - [Test] - public void CreteTableOfContents_Toc2StyleIsNotPresent_AddsToc2Style() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - TableOfContents.CreateTableOfContents(document, title, switches); - - var expectedString = string.Format(XmlTemplateBases.TocElementStyleBase, "TOC2", "toc 2"); - - var expectedReader = XmlReader.Create(new StringReader(expectedString)); - var expected = XElement.Load(expectedReader); - - var actual = document.styles.Root.Descendants().FirstOrDefault(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals("TOC2")); - - Assert.IsTrue(XNode.DeepEquals(expected, actual)); - } - } - - [Test] - public void CreteTableOfContents_Toc3StyleIsNotPresent_AddsToc3tyle() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - TableOfContents.CreateTableOfContents(document, title, switches); - - var expectedString = string.Format(XmlTemplateBases.TocElementStyleBase, "TOC3", "toc 3"); - - var expectedReader = XmlReader.Create(new StringReader(expectedString)); - var expected = XElement.Load(expectedReader); - - var actual = document.styles.Root.Descendants().FirstOrDefault(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals("TOC3")); - - Assert.IsTrue(XNode.DeepEquals(expected, actual)); - } - } - - [Test] - public void CreteTableOfContents_Toc4StyleIsNotPresent_AddsToc4Style() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - TableOfContents.CreateTableOfContents(document, title, switches); - - var expectedString = string.Format(XmlTemplateBases.TocElementStyleBase, "TOC4", "toc 4"); - - var expectedReader = XmlReader.Create(new StringReader(expectedString)); - var expected = XElement.Load(expectedReader); - - var actual = document.styles.Root.Descendants().FirstOrDefault(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals("TOC4")); - - Assert.IsTrue(XNode.DeepEquals(expected, actual)); - } - } - - [Test] - public void CreteTableOfContents_HyperlinkStyleIsNotPresent_AddsHyperlinkStyle() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - TableOfContents.CreateTableOfContents(document, title, switches); - - var expectedString = XmlTemplateBases.TocHyperLinkStyleBase; - - var expectedReader = XmlReader.Create(new StringReader(expectedString)); - var expected = XElement.Load(expectedReader); - - var actual = document.styles.Root.Descendants().FirstOrDefault(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("character") && - x.Attribute(DocX.w + "styleId").Value.Equals("Hyperlink")); - - Assert.IsTrue(XNode.DeepEquals(expected, actual)); - } - } - - [Test] - public void CreteTableOfContents_TocHeadingStyleIsPresent_DoesNotAddTocHeaderStyle() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const string headerStyle = "TestStyle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - var xElement = XElement.Load(XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocHeadingStyleBase, headerStyle)))); - document.styles.Root.Add(xElement); - - TableOfContents.CreateTableOfContents(document, title, switches, headerStyle); - - var actual = document.styles.Root.Descendants().Single(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals(headerStyle)); - - Assert.AreSame(xElement, actual); - } - } - - [Test] - public void CreteTableOfContents_Toc1StyleIsPresent_DoesNotAddToc1Style() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const string headerStyle = "TestStyle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - var xElement = XElement.Load(XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocElementStyleBase, "TOC1", "toc 1")))); - document.styles.Root.Add(xElement); - - TableOfContents.CreateTableOfContents(document, title, switches, headerStyle); - - var actual = document.styles.Root.Descendants().Single(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals("TOC1")); - - Assert.AreSame(xElement, actual); - } - } - - [Test] - public void CreteTableOfContents_Toc2StyleIsPresent_DoesNotAddToc2Style() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const string headerStyle = "TestStyle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - var xElement = XElement.Load(XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocElementStyleBase, "TOC2", "toc 2")))); - document.styles.Root.Add(xElement); - - TableOfContents.CreateTableOfContents(document, title, switches, headerStyle); - - var actual = document.styles.Root.Descendants().Single(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals("TOC2")); - - Assert.AreSame(xElement, actual); - } - } - - [Test] - public void CreteTableOfContents_Toc3StyleIsPresent_DoesNotAddToc3Style() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const string headerStyle = "TestStyle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - var xElement = XElement.Load(XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocElementStyleBase, "TOC3", "toc 3")))); - document.styles.Root.Add(xElement); - - TableOfContents.CreateTableOfContents(document, title, switches, headerStyle); - - var actual = document.styles.Root.Descendants().Single(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals("TOC3")); - - Assert.AreSame(xElement, actual); - } - } - - [Test] - public void CreteTableOfContents_Toc4StyleIsPresent_DoesNotAddToc4Style() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const string headerStyle = "TestStyle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - var xElement = XElement.Load(XmlReader.Create(new StringReader(string.Format(XmlTemplateBases.TocElementStyleBase, "TOC4", "toc 4")))); - document.styles.Root.Add(xElement); - - TableOfContents.CreateTableOfContents(document, title, switches, headerStyle); - - var actual = document.styles.Root.Descendants().Single(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("paragraph") && - x.Attribute(DocX.w + "styleId").Value.Equals("TOC4")); - - Assert.AreSame(xElement, actual); - } - } - - [Test] - public void CreteTableOfContents_HyperlinkStyleIsPresent_DoesNotAddHyperlinkStyle() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string title = "TestTitle"; - const TableOfContentsSwitches switches = - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U; - - var xElement = XElement.Load(XmlReader.Create(new StringReader(XmlTemplateBases.TocHyperLinkStyleBase))); - document.styles.Root.Add(xElement); - - TableOfContents.CreateTableOfContents(document, title, switches); - - var actual = document.styles.Root.Descendants().Single(x => - x.Name.Equals(DocX.w + "style") && - x.Attribute(DocX.w + "type").Value.Equals("character") && - x.Attribute(DocX.w + "styleId").Value.Equals("Hyperlink")); - - Assert.AreSame(xElement, actual); - } - } - - [Test] - public void InsertDefaultTableOfContents_WhenCalled_AddsTocToDocument() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - document.InsertDefaultTableOfContents(); - - var toc = TableOfContents.CreateTableOfContents(document, "Table of contents", - TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | - TableOfContentsSwitches.U); - - Assert.IsTrue(document.Xml.Descendants().FirstOrDefault(x => XNode.DeepEquals(toc.Xml, x)) != null); - } - } - - [Test] - public void InsertTableOfContents_WhenCalledWithTitleSwitchesHeaderStyleMaxIncludeLevelAndRightTabPos_AddsTocToDocument() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string tableOfContentsTitle = "Table of contents"; - const TableOfContentsSwitches tableOfContentsSwitches = TableOfContentsSwitches.O | TableOfContentsSwitches.A; - const string headerStyle = "HeaderStyle"; - const int lastIncludeLevel = 4; - const int rightTabPos = 1337; - - document.InsertTableOfContents(tableOfContentsTitle, tableOfContentsSwitches, headerStyle, lastIncludeLevel, rightTabPos); - - var toc = TableOfContents.CreateTableOfContents(document, tableOfContentsTitle, tableOfContentsSwitches, headerStyle, lastIncludeLevel, rightTabPos); - - Assert.IsTrue(document.Xml.Descendants().FirstOrDefault(x => XNode.DeepEquals(toc.Xml, x)) != null); - } - } - - [Test] - public void InsertTableOfContents_WhenCalledWithReferenceTitleSwitchesHeaderStyleMaxIncludeLevelAndRightTabPos_AddsTocToDocumentAtExpectedLocation() - { - using (var document = DocX.Create("TableOfContents Test.docx")) - { - const string tableOfContentsTitle = "Table of contents"; - const TableOfContentsSwitches tableOfContentsSwitches = TableOfContentsSwitches.O | TableOfContentsSwitches.A; - const string headerStyle = "HeaderStyle"; - const int lastIncludeLevel = 4; - const int rightTabPos = 1337; - - document.InsertParagraph("Paragraph1"); - var p2 = document.InsertParagraph("Paragraph2"); - var p3 = document.InsertParagraph("Paragraph3"); - - document.InsertTableOfContents(p3, tableOfContentsTitle, tableOfContentsSwitches, headerStyle, lastIncludeLevel, rightTabPos); - - var toc = TableOfContents.CreateTableOfContents(document, tableOfContentsTitle, tableOfContentsSwitches, headerStyle, lastIncludeLevel, rightTabPos); - - var tocElement = document.Xml.Descendants().FirstOrDefault(x => XNode.DeepEquals(toc.Xml, x)); - - Assert.IsTrue(p2.Xml.IsBefore(tocElement)); - Assert.IsTrue(tocElement.IsAfter(p2.Xml)); - Assert.IsTrue(tocElement.IsBefore(p3.Xml)); - Assert.IsTrue(p3.Xml.IsAfter(tocElement)); - } - } - - [Test] - public void ValidateBookmark_WhenCalledWithNameOfNonMatchingBookmark_ReturnsFalse() - { - using (var document = DocX.Create("Bookmark validate.docx")) - { - var p = document.InsertParagraph("No bookmark here"); - - Assert.IsFalse(p.ValidateBookmark("Team Rubberduck")); - } - } - - [Test] - public void ValidateBookmark_WhenCalledWithNameOfMatchingBookmark_ReturnsTrue() - { - using (var document = DocX.Create("Bookmark validate.docx")) - { - var p = document.InsertParagraph("Here's a bookmark!"); - const string bookmarkName = "Team Rubberduck"; - - p.AppendBookmark(bookmarkName); - - Assert.IsTrue(p.ValidateBookmark("Team Rubberduck")); - } - } - - [Test] - public void ValidateBookmarks_WhenCalledWithMatchingBookmarkNameInHeader_ReturnsEmpty() - { - using (var document = DocX.Create("Bookmark validate.docx")) - { - document.AddHeaders(); - var p = document.Headers.first.InsertParagraph("Here's a bookmark!"); - const string bookmarkName = "Team Rubberduck"; - - p.AppendBookmark(bookmarkName); - - Assert.IsTrue(document.ValidateBookmarks("Team Rubberduck").Length == 0); - } - } - - [Test] - public void ValidateBookmarks_WhenCalledWithMatchingBookmarkNameInMainDocument_ReturnsEmpty() - { - using (var document = DocX.Create("Bookmark validate.docx")) - { - var p = document.InsertParagraph("Here's a bookmark!"); - const string bookmarkName = "Team Rubberduck"; - - p.AppendBookmark(bookmarkName); - - Assert.IsTrue(document.ValidateBookmarks("Team Rubberduck").Length == 0); - } - } - - [Test] - public void ValidateBookmarks_WhenCalledWithMatchingBookmarkNameInFooters_ReturnsEmpty() - { - using (var document = DocX.Create("Bookmark validate.docx")) - { - document.AddFooters(); - var p = document.Footers.first.InsertParagraph("Here's a bookmark!"); - const string bookmarkName = "Team Rubberduck"; - - p.AppendBookmark(bookmarkName); - - Assert.IsTrue(document.ValidateBookmarks("Team Rubberduck").Length == 0); - } - } - - [Test] - public void ValidateBookmarks_WhenCalledWithNoMatchingBookmarkNames_ReturnsExpected() - { - using (var document = DocX.Create("Bookmark validate.docx")) - { - document.AddHeaders(); - var p = document.Headers.first.InsertParagraph("Here's a bookmark!"); - - p.AppendBookmark("Not in search"); - - var bookmarkNames = new[] { "Team Rubberduck", "is", "the most", "awesome people" }; - - var result = document.ValidateBookmarks(bookmarkNames); - for (var i = 0; i < bookmarkNames.Length; i++) - { - Assert.AreEqual(bookmarkNames[i], result[i]); - } - } - } - - [Test] - public void CreateTable_WhenCalledSetColumnWidth_ReturnsExpected() - { - using (var document = DocX.Create("Set column width.docx")) - { - var table = document.InsertTable(1, 2); - - table.SetColumnWidth(0, 1000); - table.SetColumnWidth(1, 2000); - - Assert.AreEqual(1000, table.GetColumnWidth(0)); - Assert.AreEqual(2000, table.GetColumnWidth(1)); - } - } - - [Test] - public void UpdateParagraphFontSize_WhenSetFontSize_ReturnsExpected() - { - using (var document = DocX.Create("Update paragraph font size.docx")) - { - var paragraph = document.InsertParagraph().FontSize(9); - - paragraph.FontSize(11); - - string szValue = paragraph.Xml.Descendants(XName.Get("sz", DocX.w.NamespaceName)) - .Attributes(XName.Get("val", DocX.w.NamespaceName)).First().Value; - string szCsValue = paragraph.Xml.Descendants(XName.Get("szCs", DocX.w.NamespaceName)) - .Attributes(XName.Get("val", DocX.w.NamespaceName)).First().Value; - - // the expected value is multiplied by 2 - // and the last font size is 11*2 = 22 - Assert.AreEqual("22", szValue); - Assert.AreEqual("22", szCsValue); - } - } - - [Test] - public void SetTableCellMargin_WhenSetTwoCellMargins_ContainsTwoCellMargins() - { - using (var document = DocX.Create("Set table cell margins.docx")) - { - Table table = document.InsertTable(1, 1); - - table.SetTableCellMargin(TableCellMarginType.left, 20); - table.SetTableCellMargin(TableCellMarginType.right, 40); - - var elements = table.Xml.Descendants(XName.Get("tblCellMar", DocX.w.NamespaceName)).ToList(); - // should contain only one element named tblCellMar - Assert.AreEqual(1, elements.Count); - var element = elements.First(); - // should contain two elements defining the margins - Assert.AreEqual(2, element.Elements().Count()); - - var left = element.Element(XName.Get("left", DocX.w.NamespaceName)); - var right = element.Element(XName.Get("right", DocX.w.NamespaceName)); - - Assert.IsNotNull(left); - Assert.IsNotNull(right); - - Assert.AreEqual("20", left.Attribute(XName.Get("w", DocX.w.NamespaceName)).Value); - Assert.AreEqual("dxa", left.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value); - - Assert.AreEqual("40", right.Attribute(XName.Get("w", DocX.w.NamespaceName)).Value); - Assert.AreEqual("dxa", right.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value); - } - } - - [Test] - public void SetTableCellMargin_WhenReSetCellMargin_ContainsOneCellMargin() - { - using (var document = DocX.Create("Set table cell margin.docx")) - { - Table table = document.InsertTable(1, 1); - - table.SetTableCellMargin(TableCellMarginType.left, 20); - // change the table cell margin - table.SetTableCellMargin(TableCellMarginType.left, 40); - - var elements = table.Xml.Descendants(XName.Get("tblCellMar", DocX.w.NamespaceName)).ToList(); - // should contain only one element named tblCellMar - Assert.AreEqual(1, elements.Count); - var element = elements.First(); - // should contain two elements defining the margins - Assert.AreEqual(1, element.Elements().Count()); - - var left = element.Element(XName.Get("left", DocX.w.NamespaceName)); - - Assert.IsNotNull(left); - - // check that the last value is taken - Assert.AreEqual("40", left.Attribute(XName.Get("w", DocX.w.NamespaceName)).Value); - Assert.AreEqual("dxa", left.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value); - } - } - - [Test] - public void WhileReadingWhenTextIsSuperAndSubscript() - { - using (DocX document = DocX.Load(Path.Combine(_directoryWithFiles, "Super_Subscript.docx"))) - { - var normalText = document.Paragraphs[0].MagicText[0].formatting; - var superscriptText = document.Paragraphs[0].MagicText[3].formatting; - var subscriptText = document.Paragraphs[0].MagicText[5].formatting; - - Assert.IsTrue(normalText.Script.HasValue && normalText.Script == Script.none); - Assert.IsTrue(superscriptText.Script.HasValue && superscriptText.Script == Script.superscript); - Assert.IsTrue(subscriptText.Script.HasValue && subscriptText.Script == Script.subscript); - } - } - } -} diff --git a/UnitTests/InsertAtBookmark.cs b/UnitTests/InsertAtBookmark.cs deleted file mode 100644 index f87ba255..00000000 --- a/UnitTests/InsertAtBookmark.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using Novacode; -using System.Linq; -using System.Collections.Generic; -using NUnit.Framework; - -namespace UnitTests -{ - [TestFixture] - public class InsertAtBookmark - { - [Test] - public void Inserting_at_bookmark_should_add_text_in_paragraph() - { - using (var document = DocX.Create("")) - { - document.InsertParagraph("Hello "); - document.InsertBookmark("bookmark1"); - document.InsertParagraph("!"); - - document.InsertAtBookmark("world", "bookmark1"); - - Assert.AreEqual("Hello world!", document.Text); - - } - } - - [Test] - public void Inserting_at_bookmark_should_add_text_in_header() - { - using (var document = DocX.Create("")) - { - document.AddHeaders(); - var header = document.Headers.even; - header.InsertParagraph("Hello "); - header.InsertBookmark("bookmark1"); - header.InsertParagraph("!"); - - document.InsertAtBookmark("world", "bookmark1"); - - Assert.AreEqual("Hello world!", String.Join("", header.Paragraphs.Select(x=>x.Text))); - - } - } - - [Test] - public void Inserting_at_bookmark_should_add_text_in_footer() - { - using (var document = DocX.Create("")) - { - document.AddHeaders(); - var footer = document.Headers.even; - footer.InsertParagraph("Hello "); - footer.InsertBookmark("bookmark1"); - footer.InsertParagraph("!"); - - document.InsertAtBookmark("world", "bookmark1"); - - Assert.AreEqual("Hello world!", String.Join("", footer.Paragraphs.Select(x => x.Text))); - - } - } - } -} diff --git a/UnitTests/KeyWithoutPassword.snk b/UnitTests/KeyWithoutPassword.snk deleted file mode 100644 index cf3da045..00000000 Binary files a/UnitTests/KeyWithoutPassword.snk and /dev/null differ diff --git a/UnitTests/Properties/AssemblyInfo.cs b/UnitTests/Properties/AssemblyInfo.cs deleted file mode 100644 index 950b8975..00000000 --- a/UnitTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("UnitTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("UnitTests")] -[assembly: AssemblyCopyright("Copyright © 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 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 -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("63e90d26-1aa6-42b1-904d-fd112b6e8d44")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/UnitTests/RelativeDirectory.cs b/UnitTests/RelativeDirectory.cs deleted file mode 100644 index 33e21bdf..00000000 --- a/UnitTests/RelativeDirectory.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.IO; - -namespace UnitTests -{ - class RelativeDirectory - { - // Author D. Bolton see http://cplus.about.com (c) 2010 - private DirectoryInfo _dirInfo; - - public string Dir - { - get - { - return _dirInfo.Name; - } - } - - public string Path - { - get { return _dirInfo.FullName; } - set - { - try - { - DirectoryInfo newDir = new DirectoryInfo(value); - _dirInfo = newDir; - } - catch - { - // silent - } - } - } - public RelativeDirectory() - { - _dirInfo = new DirectoryInfo(Environment.CurrentDirectory); - } - - public RelativeDirectory(string absoluteDir) - { - _dirInfo = new DirectoryInfo(absoluteDir); - } - - public Boolean Up(int numLevels) - { - for (int i = 0; i < numLevels; i++) - { - DirectoryInfo tempDir = _dirInfo.Parent; - if (tempDir != null) - _dirInfo = tempDir; - else - return false; - } - return true; - } - - public Boolean Up() - { - return Up(1); - } - - public Boolean Down(string match) - { - DirectoryInfo[] dirs = _dirInfo.GetDirectories(match + '*'); - _dirInfo = dirs[0]; - return true; - } - - } - -} diff --git a/UnitTests/ReplaceTests.cs b/UnitTests/ReplaceTests.cs deleted file mode 100644 index cf35bd5a..00000000 --- a/UnitTests/ReplaceTests.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; -using NUnit.Framework; -using Novacode; - -namespace UnitTests -{ - [TestFixture] - public class RegExTest - { - private readonly Dictionary _testPatterns = new Dictionary - { - { "COURT NAME", "Fred Frump" }, - { "Case Number", "cr-md-2011-1234567" } - }; - - [Test] - public void ReplaceText_Can_ReplaceViaFunctionHandler() - { - using (var replaceDoc = DocX.Load(Path.Combine(TestHelper.DirectoryWithFiles, "ReplaceTests.docx"))) - { - foreach (var t in replaceDoc.Tables) - { - // each table has 1 row and 3 columns - Assert.IsTrue(t.Rows[0].Cells.Count == 3); - Assert.IsTrue(t.ColumnCount == 3); - Assert.IsTrue(t.Rows.Count == 1); - Assert.IsTrue(t.RowCount == 1); - } - - // Make sure the origional strings are in the document. - Assert.IsTrue(replaceDoc.FindAll("").Count == 2); - Assert.IsTrue(replaceDoc.FindAll("").Count == 2); - - // There are only two patterns, even though each pattern is used more than once - Assert.IsTrue(replaceDoc.FindUniqueByPattern(@"<[\w \=]{4,}>", RegexOptions.IgnoreCase).Count == 2); - - // Make sure the new strings are not in the document. - Assert.IsTrue(replaceDoc.FindAll("Fred Frump").Count == 0); - Assert.IsTrue(replaceDoc.FindAll("cr-md-2011-1234567").Count == 0); - - // Do the replacing - replaceDoc.ReplaceText("<(.*?)>", ReplaceTextHandler, false, RegexOptions.IgnoreCase); - - // Make sure the origional string are no longer in the document. - Assert.IsTrue(replaceDoc.FindAll("").Count == 0); - Assert.IsTrue(replaceDoc.FindAll("").Count == 0); - - // Make sure the new strings are now in the document. - Assert.IsTrue(replaceDoc.FindAll("FRED FRUMP").Count == 2); - Assert.IsTrue(replaceDoc.FindAll("cr-md-2011-1234567").Count == 2); - - // Make sure the replacement worked. - Assert.IsTrue(replaceDoc.Text - == "\t\t\t\t\t\t\t\t\t\t\t\t\t\tThese two tables should look identical:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSTATE OF IOWA,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tPlaintiff,\t\t\t\t\t\t\t\t\t\t\t\t\t\tvs.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFRED FRUMP,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tDefendant.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tCase No.: cr-md-2011-1234567\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tORDER SETTING ASIDE DEFAULT JUDGMENT\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSTATE OF IOWA,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tPlaintiff,\t\t\t\t\t\t\t\t\t\t\t\t\t\tvs.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFRED FRUMP,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tDefendant.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tCase No.: cr-md-2011-1234567\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tORDER SETTING ASIDE DEFAULT JUDGMENT\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"); - } - } - - private string ReplaceTextHandler(string findStr) - { - if (_testPatterns.ContainsKey(findStr)) - { - return _testPatterns[findStr]; - } - return findStr; - } - } -} \ No newline at end of file diff --git a/UnitTests/StrongNameKey.pfx b/UnitTests/StrongNameKey.pfx deleted file mode 100644 index 555325d8..00000000 Binary files a/UnitTests/StrongNameKey.pfx and /dev/null differ diff --git a/UnitTests/TestHelper.cs b/UnitTests/TestHelper.cs deleted file mode 100644 index 9f90b117..00000000 --- a/UnitTests/TestHelper.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.IO; - -namespace UnitTests -{ - public static class TestHelper - { - static TestHelper() - { - string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; - - DirectoryWithFiles = Path.Combine(baseDirectory, "documents"); - } - - public static string DirectoryWithFiles { get; } - } -} \ No newline at end of file diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj deleted file mode 100644 index 37cd28d7..00000000 --- a/UnitTests/UnitTests.csproj +++ /dev/null @@ -1,184 +0,0 @@ - - - - Debug - AnyCPU - - - 2.0 - {3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA} - Library - Properties - UnitTests - UnitTests - v4.6 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - SAK - SAK - SAK - SAK - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - true - - - KeyWithoutPassword.snk - - - - ..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll - True - - - - - 3.5 - - - - - - - - - - - False - - - - - DocXUnitTests.cs - - - DocXUnitTests.cs - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - Designer - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - {e863d072-aa8b-4108-b5f1-785241b37f67} - DocX - - - - - \ No newline at end of file diff --git a/UnitTests/UnitTests.csproj.vspscc b/UnitTests/UnitTests.csproj.vspscc deleted file mode 100644 index feffdeca..00000000 --- a/UnitTests/UnitTests.csproj.vspscc +++ /dev/null @@ -1,10 +0,0 @@ -"" -{ -"FILE_VERSION" = "9237" -"ENLISTMENT_CHOICE" = "NEVER" -"PROJECT_FILE_RELATIVE_PATH" = "" -"NUMBER_OF_EXCLUDED_FILES" = "0" -"ORIGINAL_PROJECT_FILE_PATH" = "" -"NUMBER_OF_NESTED_PROJECTS" = "0" -"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" -} diff --git a/UnitTests/documents/..svnbridge/Template.dotx b/UnitTests/documents/..svnbridge/Template.dotx deleted file mode 100644 index 08149303..00000000 --- a/UnitTests/documents/..svnbridge/Template.dotx +++ /dev/null @@ -1 +0,0 @@ -svn:mime-typeapplication/octet-stream \ No newline at end of file diff --git a/UnitTests/documents/EverybodyHasAHome.docx b/UnitTests/documents/EverybodyHasAHome.docx deleted file mode 100644 index ab5d9bb6..00000000 Binary files a/UnitTests/documents/EverybodyHasAHome.docx and /dev/null differ diff --git a/UnitTests/documents/FontFormat.docx b/UnitTests/documents/FontFormat.docx deleted file mode 100644 index f8b01a27..00000000 Binary files a/UnitTests/documents/FontFormat.docx and /dev/null differ diff --git a/UnitTests/documents/Hyperlinks.docx b/UnitTests/documents/Hyperlinks.docx deleted file mode 100644 index 4e9ee430..00000000 Binary files a/UnitTests/documents/Hyperlinks.docx and /dev/null differ diff --git a/UnitTests/documents/Images.docx b/UnitTests/documents/Images.docx deleted file mode 100644 index 4702609a..00000000 Binary files a/UnitTests/documents/Images.docx and /dev/null differ diff --git a/UnitTests/documents/LargeTable.docx b/UnitTests/documents/LargeTable.docx deleted file mode 100644 index 8a8cb37e..00000000 Binary files a/UnitTests/documents/LargeTable.docx and /dev/null differ diff --git a/UnitTests/documents/MovePicture.docx b/UnitTests/documents/MovePicture.docx deleted file mode 100644 index 38b759b7..00000000 Binary files a/UnitTests/documents/MovePicture.docx and /dev/null differ diff --git a/UnitTests/documents/Paragraphs.docx b/UnitTests/documents/Paragraphs.docx deleted file mode 100644 index 75819b5b..00000000 Binary files a/UnitTests/documents/Paragraphs.docx and /dev/null differ diff --git a/UnitTests/documents/ReplaceTests.docx b/UnitTests/documents/ReplaceTests.docx deleted file mode 100644 index 6640f2c8..00000000 Binary files a/UnitTests/documents/ReplaceTests.docx and /dev/null differ diff --git a/UnitTests/documents/Super_Subscript.docx b/UnitTests/documents/Super_Subscript.docx deleted file mode 100644 index 9877b8d7..00000000 Binary files a/UnitTests/documents/Super_Subscript.docx and /dev/null differ diff --git a/UnitTests/documents/TableSpecifiedHeights.docx b/UnitTests/documents/TableSpecifiedHeights.docx deleted file mode 100644 index 521d3245..00000000 Binary files a/UnitTests/documents/TableSpecifiedHeights.docx and /dev/null differ diff --git a/UnitTests/documents/TableSpecifiedWidths.docx b/UnitTests/documents/TableSpecifiedWidths.docx deleted file mode 100644 index fa5834d8..00000000 Binary files a/UnitTests/documents/TableSpecifiedWidths.docx and /dev/null differ diff --git a/UnitTests/documents/Tables.docx b/UnitTests/documents/Tables.docx deleted file mode 100644 index 226a01f9..00000000 Binary files a/UnitTests/documents/Tables.docx and /dev/null differ diff --git a/UnitTests/documents/Template.dotx b/UnitTests/documents/Template.dotx deleted file mode 100644 index 517c983a..00000000 Binary files a/UnitTests/documents/Template.dotx and /dev/null differ diff --git a/UnitTests/documents/TestParent.docx b/UnitTests/documents/TestParent.docx deleted file mode 100644 index ecdba744..00000000 Binary files a/UnitTests/documents/TestParent.docx and /dev/null differ diff --git a/UnitTests/documents/VariousTextFormatting.docx b/UnitTests/documents/VariousTextFormatting.docx deleted file mode 100644 index b099136d..00000000 Binary files a/UnitTests/documents/VariousTextFormatting.docx and /dev/null differ diff --git a/UnitTests/documents/green.jpg b/UnitTests/documents/green.jpg deleted file mode 100644 index b31a7f11..00000000 Binary files a/UnitTests/documents/green.jpg and /dev/null differ diff --git a/UnitTests/documents/orange.gif b/UnitTests/documents/orange.gif deleted file mode 100644 index 8bf0a750..00000000 Binary files a/UnitTests/documents/orange.gif and /dev/null differ diff --git a/UnitTests/documents/purple.png b/UnitTests/documents/purple.png deleted file mode 100644 index 42c6ba3f..00000000 Binary files a/UnitTests/documents/purple.png and /dev/null differ diff --git a/UnitTests/documents/red.bmp b/UnitTests/documents/red.bmp deleted file mode 100644 index 3582106d..00000000 Binary files a/UnitTests/documents/red.bmp and /dev/null differ diff --git a/UnitTests/documents/testdoc_OrderedList.docx b/UnitTests/documents/testdoc_OrderedList.docx deleted file mode 100644 index a618d9c2..00000000 Binary files a/UnitTests/documents/testdoc_OrderedList.docx and /dev/null differ diff --git a/UnitTests/documents/testdoc_OrderedUnorderedLists.docx b/UnitTests/documents/testdoc_OrderedUnorderedLists.docx deleted file mode 100644 index 98c76c04..00000000 Binary files a/UnitTests/documents/testdoc_OrderedUnorderedLists.docx and /dev/null differ diff --git a/UnitTests/documents/testdoc_SectionsWithHeadingBreaks.docx b/UnitTests/documents/testdoc_SectionsWithHeadingBreaks.docx deleted file mode 100644 index 14d98266..00000000 Binary files a/UnitTests/documents/testdoc_SectionsWithHeadingBreaks.docx and /dev/null differ diff --git a/UnitTests/documents/testdoc_SectionsWithSectionBreaks.docx b/UnitTests/documents/testdoc_SectionsWithSectionBreaks.docx deleted file mode 100644 index 3f1c7c57..00000000 Binary files a/UnitTests/documents/testdoc_SectionsWithSectionBreaks.docx and /dev/null differ diff --git a/UnitTests/documents/testdoc_SectionsWithSectionBreaksMultiParagraph.docx b/UnitTests/documents/testdoc_SectionsWithSectionBreaksMultiParagraph.docx deleted file mode 100644 index c131cdeb..00000000 Binary files a/UnitTests/documents/testdoc_SectionsWithSectionBreaksMultiParagraph.docx and /dev/null differ diff --git a/UnitTests/documents/testdoc_UnorderedList.docx b/UnitTests/documents/testdoc_UnorderedList.docx deleted file mode 100644 index 90faf886..00000000 Binary files a/UnitTests/documents/testdoc_UnorderedList.docx and /dev/null differ diff --git a/UnitTests/documents/yellow.tif b/UnitTests/documents/yellow.tif deleted file mode 100644 index ba7df2d2..00000000 Binary files a/UnitTests/documents/yellow.tif and /dev/null differ diff --git a/UnitTests/packages.config b/UnitTests/packages.config deleted file mode 100644 index d6ca6ee4..00000000 --- a/UnitTests/packages.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/Xceed.Words.NET.sln b/Xceed.Words.NET.sln new file mode 100644 index 00000000..011e45ee --- /dev/null +++ b/Xceed.Words.NET.sln @@ -0,0 +1,64 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xceed.Words.NET.Examples", "Examples\Xceed.Words.NET.Examples.csproj", "{F3022BB7-0E40-4C80-A495-37FEAF3671AB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xceed.Words.NET", "Xceed.Words.NET\Xceed.Words.NET.csproj", "{E863D072-AA8B-4108-B5F1-785241B37F67}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + PerformanceTest|Any CPU = PerformanceTest|Any CPU + PerformanceTest|Mixed Platforms = PerformanceTest|Mixed Platforms + PerformanceTest|x86 = PerformanceTest|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Debug|Any CPU.ActiveCfg = Debug|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Debug|x86.ActiveCfg = Debug|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Debug|x86.Build.0 = Debug|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.PerformanceTest|Any CPU.ActiveCfg = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.PerformanceTest|Any CPU.Build.0 = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.PerformanceTest|Mixed Platforms.ActiveCfg = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.PerformanceTest|Mixed Platforms.Build.0 = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.PerformanceTest|x86.ActiveCfg = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.PerformanceTest|x86.Build.0 = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Release|Any CPU.ActiveCfg = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Release|Mixed Platforms.Build.0 = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Release|x86.ActiveCfg = Release|x86 + {F3022BB7-0E40-4C80-A495-37FEAF3671AB}.Release|x86.Build.0 = Release|x86 + {E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|x86.ActiveCfg = Debug|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|x86.Build.0 = Debug|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.PerformanceTest|Any CPU.ActiveCfg = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.PerformanceTest|Any CPU.Build.0 = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.PerformanceTest|Mixed Platforms.ActiveCfg = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.PerformanceTest|Mixed Platforms.Build.0 = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.PerformanceTest|x86.ActiveCfg = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.PerformanceTest|x86.Build.0 = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Any CPU.Build.0 = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Release|x86.ActiveCfg = Release|Any CPU + {E863D072-AA8B-4108-B5F1-785241B37F67}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = Xceed.Words.NET.vsmdi + EndGlobalSection +EndGlobal diff --git a/Xceed.Words.NET/AssemblyVersionInfo.cs b/Xceed.Words.NET/AssemblyVersionInfo.cs new file mode 100644 index 00000000..eb7d2e05 --- /dev/null +++ b/Xceed.Words.NET/AssemblyVersionInfo.cs @@ -0,0 +1,30 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +#pragma warning disable 0436 +[assembly: System.Reflection.AssemblyVersion( _XceedVersionInfo.Version )] +#pragma warning restore 0436 + +internal static class _XceedVersionInfo +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string BaseVersion = "1.1"; + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string Version = BaseVersion + + ".0.0"; + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string PublicKeyToken = "ba83ff368b7563c6"; + + +} diff --git a/Xceed.Words.NET/AssemblyVersionInfoCommon.cs b/Xceed.Words.NET/AssemblyVersionInfoCommon.cs new file mode 100644 index 00000000..4e6c2d96 --- /dev/null +++ b/Xceed.Words.NET/AssemblyVersionInfoCommon.cs @@ -0,0 +1,20 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +internal static class _XceedVersionInfoCommon +{ +[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string Build = ".*"; + +} diff --git a/Xceed.Words.NET/Properties/AssemblyInfo.cs b/Xceed.Words.NET/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..e7cb8359 --- /dev/null +++ b/Xceed.Words.NET/Properties/AssemblyInfo.cs @@ -0,0 +1,51 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle( "Xceed Words for .NET" )] +[assembly: AssemblyDescription( "This assembly implements the classes for Xceed Words for .NET." )] + +[assembly: AssemblyCompany( "Xceed Software Inc." )] +[assembly: AssemblyProduct( "Xceed Words for .NET" )] +[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2009-2017" )] +[assembly: AssemblyCulture("")] + + +// 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 +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + + +[assembly: InternalsVisibleTo( "UnitTests" + ",PublicKey=" + + "0024000004800000940000000602000000240000525341310004000001000100d59d8147eb2015" + + "ca98a92da860fd766d101271d8c2f545894870fd6183255737d79347bbf5250291ae75651e1150" + + "1b7452ee003b80b936614cdda51db8eb6f8fde913e67d45395b480a992be17bf04744a7fe803ea" + + "131b925dcf84a73d22264352eca7c3fcf9387f3eee1d60ac7974f04866e6c72928dc0609abe341" + + "f92cbfb5")] + + +#pragma warning disable 1699 +[assembly: AssemblyDelaySign( false )] +[assembly: AssemblyKeyFile( @"..\..\sn.snk" )] +[assembly: AssemblyKeyName( "" )] +#pragma warning restore 1699 + diff --git a/DocX/Resources/default_styles.xml.gz b/Xceed.Words.NET/Resources/default_styles.xml.gz similarity index 100% rename from DocX/Resources/default_styles.xml.gz rename to Xceed.Words.NET/Resources/default_styles.xml.gz diff --git a/DocX/Resources/numbering.default_bullet_abstract.xml.gz b/Xceed.Words.NET/Resources/numbering.default_bullet_abstract.xml.gz similarity index 100% rename from DocX/Resources/numbering.default_bullet_abstract.xml.gz rename to Xceed.Words.NET/Resources/numbering.default_bullet_abstract.xml.gz diff --git a/DocX/Resources/numbering.default_decimal_abstract.xml.gz b/Xceed.Words.NET/Resources/numbering.default_decimal_abstract.xml.gz similarity index 100% rename from DocX/Resources/numbering.default_decimal_abstract.xml.gz rename to Xceed.Words.NET/Resources/numbering.default_decimal_abstract.xml.gz diff --git a/DocX/Resources/numbering.xml.gz b/Xceed.Words.NET/Resources/numbering.xml.gz similarity index 100% rename from DocX/Resources/numbering.xml.gz rename to Xceed.Words.NET/Resources/numbering.xml.gz diff --git a/DocX/Resources/styles.xml.gz b/Xceed.Words.NET/Resources/styles.xml.gz similarity index 100% rename from DocX/Resources/styles.xml.gz rename to Xceed.Words.NET/Resources/styles.xml.gz diff --git a/Xceed.Words.NET/Src/Bookmark.cs b/Xceed.Words.NET/Src/Bookmark.cs new file mode 100644 index 00000000..2176b688 --- /dev/null +++ b/Xceed.Words.NET/Src/Bookmark.cs @@ -0,0 +1,49 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +namespace Xceed.Words.NET +{ + public class Bookmark + { + #region Public Properties + + public string Name + { + get; set; + } + public Paragraph Paragraph + { + get; set; + } + + #endregion + + #region Constructors + + public Bookmark() + { + } + + #endregion + + #region Public Methods + + public void SetText( string text ) + { + this.Paragraph.ReplaceAtBookmark( text, this.Name ); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/BookmarkCollection.cs b/Xceed.Words.NET/Src/BookmarkCollection.cs new file mode 100644 index 00000000..646aecf3 --- /dev/null +++ b/Xceed.Words.NET/Src/BookmarkCollection.cs @@ -0,0 +1,34 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System.Collections.Generic; +using System.Linq; + +namespace Xceed.Words.NET +{ + public class BookmarkCollection : List + { + public BookmarkCollection() + { + } + + public Bookmark this[ string name ] + { + get + { + return this.FirstOrDefault( x => x.Name.Equals( name, System.StringComparison.CurrentCultureIgnoreCase ) ); + } + } + } +} diff --git a/Xceed.Words.NET/Src/Border.cs b/Xceed.Words.NET/Src/Border.cs new file mode 100644 index 00000000..6f277edf --- /dev/null +++ b/Xceed.Words.NET/Src/Border.cs @@ -0,0 +1,54 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System.Drawing; + +namespace Xceed.Words.NET +{ + /// + /// Represents a border of a table or table cell + /// + public class Border + { + + #region Public Properties + + public BorderStyle Tcbs { get; set; } + public BorderSize Size { get; set; } + public int Space { get; set; } + public Color Color { get; set; } + + #endregion + + #region Constructors + + public Border() + { + this.Tcbs = BorderStyle.Tcbs_single; + this.Size = BorderSize.one; + this.Space = 0; + this.Color = Color.Black; + } + + public Border( BorderStyle tcbs, BorderSize size, int space, Color color ) + { + this.Tcbs = tcbs; + this.Size = size; + this.Space = space; + this.Color = color; + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/Charts/Axis.cs b/Xceed.Words.NET/Src/Charts/Axis.cs new file mode 100644 index 00000000..27b1fb75 --- /dev/null +++ b/Xceed.Words.NET/Src/Charts/Axis.cs @@ -0,0 +1,150 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + /// + /// Axis base class + /// + public abstract class Axis + { + #region Public Properties + + /// + /// ID of this Axis + /// + public String Id + { + get + { + return Xml.Element( XName.Get( "axId", DocX.c.NamespaceName ) ).Attribute( XName.Get( "val" ) ).Value; + } + } + + /// + /// Return true if this axis is visible + /// + public Boolean IsVisible + { + get + { + return Xml.Element( XName.Get( "delete", DocX.c.NamespaceName ) ).Attribute( XName.Get( "val" ) ).Value == "0"; + } + set + { + if( value ) + Xml.Element( XName.Get( "delete", DocX.c.NamespaceName ) ).Attribute( XName.Get( "val" ) ).Value = "0"; + else + Xml.Element( XName.Get( "delete", DocX.c.NamespaceName ) ).Attribute( XName.Get( "val" ) ).Value = "1"; + } + } + + #endregion + + #region Internal Properties + + /// + /// Axis xml element + /// + internal XElement Xml + { + get; set; + } + + #endregion + + #region Constructors + + internal Axis( XElement xml ) + { + Xml = xml; + } + + public Axis( String id ) + { + } + + #endregion + } + + /// + /// Represents Category Axes + /// + public class CategoryAxis : Axis + { + internal CategoryAxis( XElement xml ) + : base( xml ) + { + } + + public CategoryAxis( String id ) + : base( id ) + { + Xml = XElement.Parse( String.Format( + @" + + + + + + + + + + + + + + + + ", id ) ); + } + } + + /// + /// Represents Values Axes + /// + public class ValueAxis : Axis + { + internal ValueAxis( XElement xml ) + : base( xml ) + { + } + + public ValueAxis( String id ) + : base( id ) + { + Xml = XElement.Parse( String.Format( + @" + + + + + + + + + + + + + + + ", id ) ); + } + } +} diff --git a/Xceed.Words.NET/Src/Charts/BarChart.cs b/Xceed.Words.NET/Src/Charts/BarChart.cs new file mode 100644 index 00000000..e687c79c --- /dev/null +++ b/Xceed.Words.NET/Src/Charts/BarChart.cs @@ -0,0 +1,125 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + /// + /// This element contains the 2-D bar or column series on this chart. + /// 21.2.2.16 barChart (Bar Charts) + /// + public class BarChart : Chart + { + #region Public Properties + + /// + /// Specifies the possible directions for a bar chart. + /// + public BarDirection BarDirection + { + get + { + return XElementHelpers.GetValueToEnum( + ChartXml.Element( XName.Get( "barDir", DocX.c.NamespaceName ) ) ); + } + set + { + XElementHelpers.SetValueFromEnum( + ChartXml.Element( XName.Get( "barDir", DocX.c.NamespaceName ) ), value ); + } + } + + /// + /// Specifies the possible groupings for a bar chart. + /// + public BarGrouping BarGrouping + { + get + { + return XElementHelpers.GetValueToEnum( + ChartXml.Element( XName.Get( "grouping", DocX.c.NamespaceName ) ) ); + } + set + { + XElementHelpers.SetValueFromEnum( + ChartXml.Element( XName.Get( "grouping", DocX.c.NamespaceName ) ), value ); + } + } + + /// + /// Specifies that its contents contain a percentage between 0% and 500%. + /// + public Int32 GapWidth + { + get + { + return Convert.ToInt32( + ChartXml.Element( XName.Get( "gapWidth", DocX.c.NamespaceName ) ).Attribute( XName.Get( "val" ) ).Value ); + } + set + { + if( ( value < 1 ) || ( value > 500 ) ) + throw new ArgumentException( "GapWidth lay between 0% and 500%!" ); + ChartXml.Element( XName.Get( "gapWidth", DocX.c.NamespaceName ) ).Attribute( XName.Get( "val" ) ).Value = value.ToString(); + } + } + + #endregion + + #region Overrides + + protected override XElement CreateChartXml() + { + return XElement.Parse( + @" + + + + " ); + } + + #endregion + + } + + /// + /// Specifies the possible directions for a bar chart. + /// 21.2.3.3 ST_BarDir (Bar Direction) + /// + public enum BarDirection + { + [XmlName( "col" )] + Column, + [XmlName( "bar" )] + Bar + } + + /// + /// Specifies the possible groupings for a bar chart. + /// 21.2.3.4 ST_BarGrouping (Bar Grouping) + /// + public enum BarGrouping + { + [XmlName( "clustered" )] + Clustered, + [XmlName( "percentStacked" )] + PercentStacked, + [XmlName( "stacked" )] + Stacked, + [XmlName( "standard" )] + Standard + } +} diff --git a/Xceed.Words.NET/Src/Charts/Chart.cs b/Xceed.Words.NET/Src/Charts/Chart.cs new file mode 100644 index 00000000..a00594ca --- /dev/null +++ b/Xceed.Words.NET/Src/Charts/Chart.cs @@ -0,0 +1,570 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using System.Collections; +using System.Drawing; +using System.Globalization; + +namespace Xceed.Words.NET +{ + /// + /// Represents every Chart in this document. + /// + public abstract class Chart + { + #region Public Properties + + /// + /// The xml representation of this chart + /// + public XDocument Xml + { + get; private set; + } + + /// + /// Chart's series + /// + public List Series + { + get + { + var series = new List(); + var ser = XName.Get( "ser", DocX.c.NamespaceName ); + int index = 1; + foreach( var element in ChartXml.Elements( ser ) ) + { + element.Add( new XElement( XName.Get("idx", DocX.c.NamespaceName ) ), index.ToString() ); + series.Add( new Series( element ) ); + ++index; + } + return series; + } + } + + /// + /// Return maximum count of series + /// + public virtual Int16 MaxSeriesCount + { + get + { + return Int16.MaxValue; + } + } + + /// + /// Chart's legend. + /// If legend doesn't exist property is null. + /// + public ChartLegend Legend + { + get; private set; + } + + /// + /// Represents the category axis + /// + public CategoryAxis CategoryAxis + { + get; private set; + } + + /// + /// Represents the values axis + /// + public ValueAxis ValueAxis + { + get; private set; + } + + /// + /// Represents existing the axis + /// + public virtual Boolean IsAxisExist + { + get + { + return true; + } + } + + /// + /// Get or set 3D view for this chart + /// + public Boolean View3D + { + get + { + return ChartXml.Name.LocalName.Contains( "3D" ); + } + set + { + if( value ) + { + if( !View3D ) + { + String currentName = ChartXml.Name.LocalName; + ChartXml.Name = XName.Get( currentName.Replace( "Chart", "3DChart" ), DocX.c.NamespaceName ); + } + } + else + { + if( View3D ) + { + String currentName = ChartXml.Name.LocalName; + ChartXml.Name = XName.Get( currentName.Replace( "3DChart", "Chart" ), DocX.c.NamespaceName ); + } + } + } + } + + /// + /// Specifies how blank cells shall be plotted on a chart + /// + public DisplayBlanksAs DisplayBlanksAs + { + get + { + return XElementHelpers.GetValueToEnum( + ChartRootXml.Element( XName.Get( "dispBlanksAs", DocX.c.NamespaceName ) ) ); + } + set + { + XElementHelpers.SetValueFromEnum( + ChartRootXml.Element( XName.Get( "dispBlanksAs", DocX.c.NamespaceName ) ), value ); + } + } + + #endregion + + #region Protected Properties + + protected XElement ChartXml + { + get; private set; + } + protected XElement ChartRootXml + { + get; private set; + } + + #endregion + + #region Constructors + + /// + /// Create an Chart for this document + /// + public Chart() + { + + // Create global xml + this.Xml = XDocument.Parse + ( @" + + + + + + + + + " ); + + // Create a real chart xml in an inheritor + this.ChartXml = this.CreateChartXml(); + + // Create result plotarea element + var plotAreaXml = new XElement( XName.Get( "plotArea", DocX.c.NamespaceName ), + new XElement( XName.Get( "layout", DocX.c.NamespaceName ) ), + this.ChartXml ); + + // Set labels + var dLblsXml = XElement.Parse( + @" + + + + + + + + " ); + this.ChartXml.Add( dLblsXml ); + + // if axes exists, create their + if( this.IsAxisExist ) + { + this.CategoryAxis = new CategoryAxis( "148921728" ); + this.ValueAxis = new ValueAxis( "154227840" ); + + var axIDcatXml = XElement.Parse( String.Format( @"", this.CategoryAxis.Id ) ); + var axIDvalXml = XElement.Parse( String.Format( @"", this.ValueAxis.Id ) ); + + var gapWidth = this.ChartXml.Element( XName.Get( "gapWidth", DocX.c.NamespaceName ) ); + if( gapWidth != null ) + { + gapWidth.AddAfterSelf( axIDvalXml ); + gapWidth.AddAfterSelf( axIDcatXml ); + } + else + { + this.ChartXml.Add( axIDcatXml ); + this.ChartXml.Add( axIDvalXml ); + } + + plotAreaXml.Add( this.CategoryAxis.Xml ); + plotAreaXml.Add( this.ValueAxis.Xml ); + } + + this.ChartRootXml = this.Xml.Root.Element( XName.Get( "chart", DocX.c.NamespaceName ) ); + this.ChartRootXml.Element( XName.Get( "autoTitleDeleted", DocX.c.NamespaceName ) ).AddAfterSelf( plotAreaXml ); + } + + #endregion + + #region Public Methods + + /// + /// Add a new series to this chart + /// + public void AddSeries( Series series ) + { + var seriesCount = ChartXml.Elements( XName.Get( "ser", DocX.c.NamespaceName ) ).Count(); + if( seriesCount >= MaxSeriesCount ) + throw new InvalidOperationException( "Maximum series for this chart is" + MaxSeriesCount.ToString() + "and have exceeded!" ); + + //To work in Words, all series need an Index and Order. + var value = seriesCount + 1; + var content = new XAttribute( XName.Get( "val" ), value.ToString() ); + series.Xml.AddFirst( new XElement( XName.Get( "order", DocX.c.NamespaceName ), content ) ); + series.Xml.AddFirst( new XElement( XName.Get( "idx", DocX.c.NamespaceName ), content ) ); + this.ChartXml.Add( series.Xml ); + } + + /// + /// Add standart legend to the chart. + /// + public void AddLegend() + { + AddLegend( ChartLegendPosition.Right, false ); + } + + /// + /// Add a legend with parameters to the chart. + /// + public void AddLegend( ChartLegendPosition position, Boolean overlay ) + { + if( Legend != null ) + { + this.RemoveLegend(); + } + this.Legend = new ChartLegend( position, overlay ); + this.ChartRootXml.Element( XName.Get( "plotArea", DocX.c.NamespaceName ) ).AddAfterSelf( Legend.Xml ); + } + + /// + /// Remove the legend from the chart. + /// + public void RemoveLegend() + { + Legend.Xml.Remove(); + Legend = null; + } + + #endregion + + #region Protected Methods + + /// + /// An abstract method which creates the current chart xml + /// + protected abstract XElement CreateChartXml(); + + #endregion + } + + /// + /// Represents a chart series + /// + public class Series + { + #region Private Members + + private XElement _strCache; + private XElement _numCache; + + #endregion + + #region Public Properties + + public Color Color + { + get + { + var colorElement = Xml.Element( XName.Get( "spPr", DocX.c.NamespaceName ) ); + if( colorElement == null ) + return Color.Transparent; + else + { + var val = colorElement.Element( XName.Get( "solidFill", DocX.a.NamespaceName ) ) + .Element( XName.Get( "srgbClr", DocX.a.NamespaceName ) ) + .Attribute( XName.Get( "val" ) ) + .Value; + return Color.FromArgb( Int32.Parse( val, NumberStyles.HexNumber ) ); + } + } + set + { + var colorElement = this.Xml.Element( XName.Get( "spPr", DocX.c.NamespaceName ) ); + if( colorElement != null ) + { + colorElement.Remove(); + } + colorElement = new XElement( XName.Get( "spPr", DocX.c.NamespaceName ), + new XElement( XName.Get( "solidFill", DocX.a.NamespaceName ), + new XElement( XName.Get( "srgbClr", DocX.a.NamespaceName ), new XAttribute( XName.Get( "val" ), value.ToHex() ) ) ) ); + this.Xml.Element( XName.Get( "tx", DocX.c.NamespaceName ) ).AddAfterSelf( colorElement ); + } + } + + #endregion + + #region Internal Properties + + /// + /// Series xml element + /// + internal XElement Xml + { + get; private set; + } + + #endregion + + #region Constructors + + internal Series( XElement xml ) + { + Xml = xml; + _strCache = xml.Element( XName.Get( "cat", DocX.c.NamespaceName ) ).Element( XName.Get( "strRef", DocX.c.NamespaceName ) ).Element( XName.Get( "strCache", DocX.c.NamespaceName ) ); + _numCache = xml.Element( XName.Get( "val", DocX.c.NamespaceName ) ).Element( XName.Get( "numRef", DocX.c.NamespaceName ) ).Element( XName.Get( "numCache", DocX.c.NamespaceName ) ); + } + + public Series( String name ) + { + _strCache = new XElement( XName.Get( "strCache", DocX.c.NamespaceName ) ); + _numCache = new XElement( XName.Get( "numCache", DocX.c.NamespaceName ) ); + + this.Xml = new XElement( XName.Get( "ser", DocX.c.NamespaceName ), + new XElement( XName.Get( "tx", DocX.c.NamespaceName ), + new XElement( XName.Get( "strRef", DocX.c.NamespaceName ), + new XElement( XName.Get( "f", DocX.c.NamespaceName ), "" ), + new XElement( XName.Get( "strCache", DocX.c.NamespaceName ), + new XElement( XName.Get( "pt", DocX.c.NamespaceName ), + new XAttribute( XName.Get( "idx" ), "0" ), + new XElement( XName.Get( "v", DocX.c.NamespaceName ), name ) ) ) ) ), + new XElement( XName.Get( "invertIfNegative", DocX.c.NamespaceName ), "0" ), + new XElement( XName.Get( "cat", DocX.c.NamespaceName ), + new XElement( XName.Get( "strRef", DocX.c.NamespaceName ), + new XElement( XName.Get( "f", DocX.c.NamespaceName ), "" ), + _strCache ) ), + new XElement( XName.Get( "val", DocX.c.NamespaceName ), + new XElement( XName.Get( "numRef", DocX.c.NamespaceName ), + new XElement( XName.Get( "f", DocX.c.NamespaceName ), "" ), + _numCache ) ) + ); + } + + #endregion + + #region Public Methods + + public void Bind( ICollection list, String categoryPropertyName, String valuePropertyName ) + { + var ptCount = new XElement( XName.Get( "ptCount", DocX.c.NamespaceName ), new XAttribute( XName.Get( "val" ), list.Count ) ); + var formatCode = new XElement( XName.Get( "formatCode", DocX.c.NamespaceName ), "General" ); + + _strCache.RemoveAll(); + _numCache.RemoveAll(); + + _strCache.Add( ptCount ); + _numCache.Add( formatCode ); + _numCache.Add( ptCount ); + + Int32 index = 0; + XElement pt; + foreach( var item in list ) + { + pt = new XElement( XName.Get( "pt", DocX.c.NamespaceName ), new XAttribute( XName.Get( "idx" ), index ), + new XElement( XName.Get( "v", DocX.c.NamespaceName ), item.GetType().GetProperty( categoryPropertyName ).GetValue( item, null ) ) ); + _strCache.Add( pt ); + pt = new XElement( XName.Get( "pt", DocX.c.NamespaceName ), new XAttribute( XName.Get( "idx" ), index ), + new XElement( XName.Get( "v", DocX.c.NamespaceName ), item.GetType().GetProperty( valuePropertyName ).GetValue( item, null ) ) ); + _numCache.Add( pt ); + index++; + } + } + + public void Bind( IList categories, IList values ) + { + if( categories.Count != values.Count ) + throw new ArgumentException( "Categories count must equal to Values count" ); + + var ptCount = new XElement( XName.Get( "ptCount", DocX.c.NamespaceName ), new XAttribute( XName.Get( "val" ), categories.Count ) ); + var formatCode = new XElement( XName.Get( "formatCode", DocX.c.NamespaceName ), "General" ); + + _strCache.RemoveAll(); + _numCache.RemoveAll(); + + _strCache.Add( ptCount ); + _numCache.Add( formatCode ); + _numCache.Add( ptCount ); + + XElement pt; + for( int index = 0; index < categories.Count; index++ ) + { + pt = new XElement( XName.Get( "pt", DocX.c.NamespaceName ), new XAttribute( XName.Get( "idx" ), index ), + new XElement( XName.Get( "v", DocX.c.NamespaceName ), categories[ index ].ToString() ) ); + _strCache.Add( pt ); + pt = new XElement( XName.Get( "pt", DocX.c.NamespaceName ), new XAttribute( XName.Get( "idx" ), index ), + new XElement( XName.Get( "v", DocX.c.NamespaceName ), values[ index ].ToString() ) ); + _numCache.Add( pt ); + } + } + + #endregion + } + + /// + /// Represents a chart legend + /// More: http://msdn.microsoft.com/ru-ru/library/cc845123.aspx + /// + public class ChartLegend + { + #region Public Properties + + /// + /// Specifies that other chart elements shall be allowed to overlap this chart element + /// + public Boolean Overlay + { + get + { + return Xml.Element( XName.Get( "overlay", DocX.c.NamespaceName ) ).Attribute( "val" ).Value == "1"; + } + set + { + Xml.Element( XName.Get( "overlay", DocX.c.NamespaceName ) ).Attribute( "val" ).Value = GetOverlayValue( value ); + } + } + + /// + /// Specifies the possible positions for a legend + /// + public ChartLegendPosition Position + { + get + { + return XElementHelpers.GetValueToEnum( + Xml.Element( XName.Get( "legendPos", DocX.c.NamespaceName ) ) ); + } + set + { + XElementHelpers.SetValueFromEnum( + Xml.Element( XName.Get( "legendPos", DocX.c.NamespaceName ) ), value ); + } + } + + #endregion + + #region Internal Properties + + /// + /// Legend xml element + /// + internal XElement Xml + { + get; private set; + } + + #endregion + + #region Constructors + + internal ChartLegend( ChartLegendPosition position, Boolean overlay ) + { + Xml = new XElement( + XName.Get( "legend", DocX.c.NamespaceName ), + new XElement( XName.Get( "legendPos", DocX.c.NamespaceName ), new XAttribute( "val", XElementHelpers.GetXmlNameFromEnum( position ) ) ), + new XElement( XName.Get( "overlay", DocX.c.NamespaceName ), new XAttribute( "val", GetOverlayValue( overlay ) ) ) + ); + } + + #endregion + + #region Private Methods + + /// + /// ECMA-376, page 3840 + /// 21.2.2.132 overlay (Overlay) + /// + private String GetOverlayValue( Boolean overlay ) + { + if( overlay ) + return "1"; + else + return "0"; + } + + #endregion + } + + /// + /// Specifies the possible positions for a legend. + /// 21.2.3.24 ST_LegendPos (Legend Position) + /// + public enum ChartLegendPosition + { + [XmlName( "t" )] + Top, + [XmlName( "b" )] + Bottom, + [XmlName( "l" )] + Left, + [XmlName( "r" )] + Right, + [XmlName( "tr" )] + TopRight + } + + /// + /// Specifies the possible ways to display blanks. + /// 21.2.3.10 ST_DispBlanksAs (Display Blanks As) + /// + public enum DisplayBlanksAs + { + [XmlName( "gap" )] + Gap, + [XmlName( "span" )] + Span, + [XmlName( "zero" )] + Zero + } +} diff --git a/Xceed.Words.NET/Src/Charts/LineChart.cs b/Xceed.Words.NET/Src/Charts/LineChart.cs new file mode 100644 index 00000000..8781cfa2 --- /dev/null +++ b/Xceed.Words.NET/Src/Charts/LineChart.cs @@ -0,0 +1,72 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + /// + /// This element contains the 2-D line chart series. + /// 21.2.2.97 lineChart (Line Charts) + /// + public class LineChart : Chart + { + #region Public Properties + + /// + /// Specifies the kind of grouping for a column, line, or area chart. + /// + public Grouping Grouping + { + get + { + return XElementHelpers.GetValueToEnum( + ChartXml.Element( XName.Get( "grouping", DocX.c.NamespaceName ) ) ); + } + set + { + XElementHelpers.SetValueFromEnum( + ChartXml.Element( XName.Get( "grouping", DocX.c.NamespaceName ) ), value ); + } + } + + #endregion + + #region Overrides + + protected override XElement CreateChartXml() + { + return XElement.Parse( + @" + + " ); + } + + #endregion + } + + /// + /// Specifies the kind of grouping for a column, line, or area chart. + /// 21.2.2.76 grouping (Grouping) + /// + public enum Grouping + { + [XmlName( "percentStacked" )] + PercentStacked, + [XmlName( "stacked" )] + Stacked, + [XmlName( "standard" )] + Standard + } +} diff --git a/Xceed.Words.NET/Src/Charts/PieChart.cs b/Xceed.Words.NET/Src/Charts/PieChart.cs new file mode 100644 index 00000000..3635c94f --- /dev/null +++ b/Xceed.Words.NET/Src/Charts/PieChart.cs @@ -0,0 +1,56 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + /// + /// This element contains the 2-D pie series for this chart. + /// 21.2.2.141 pieChart (Pie Charts) + /// + public class PieChart : Chart + { + #region Overrides Properties + + public override Boolean IsAxisExist + { + get + { + return false; + } + } + public override Int16 MaxSeriesCount + { + get + { + return 1; + } + } + + #endregion + + #region Overrides + + protected override XElement CreateChartXml() + { + return XElement.Parse( + @" + " ); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/Charts/XElementHelpers.cs b/Xceed.Words.NET/Src/Charts/XElementHelpers.cs new file mode 100644 index 00000000..1776c12e --- /dev/null +++ b/Xceed.Words.NET/Src/Charts/XElementHelpers.cs @@ -0,0 +1,102 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Linq; +using System.Reflection; +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + internal static class XElementHelpers + { + /// + /// Get value from XElement and convert it to enum + /// + /// Enum type + internal static T GetValueToEnum( XElement element ) + { + if( element == null ) + throw new ArgumentNullException( "element" ); + + var value = element.Attribute( XName.Get( "val" ) ).Value; + foreach( T e in Enum.GetValues( typeof( T ) ) ) + { + var fi = typeof( T ).GetField( e.ToString() ); + if( fi.GetCustomAttributes( typeof( XmlNameAttribute ), false ).Count() == 0 ) + throw new Exception( String.Format( "Attribute 'XmlNameAttribute' is not assigned to {0} fields!", typeof( T ).Name ) ); + var a = ( XmlNameAttribute )fi.GetCustomAttributes( typeof( XmlNameAttribute ), false ).First(); + if( a.XmlName == value ) + return e; + } + throw new ArgumentException( "Invalid element value!" ); + } + + /// + /// Convert value to xml string and set it into XElement + /// + /// Enum type + internal static void SetValueFromEnum( XElement element, T value ) + { + if( element == null ) + throw new ArgumentNullException( "element" ); + element.Attribute( XName.Get( "val" ) ).Value = GetXmlNameFromEnum( value ); + } + + /// + /// Return xml string for this value + /// + /// Enum type + internal static String GetXmlNameFromEnum( T value ) + { + if( value == null ) + throw new ArgumentNullException( "value" ); + + var fi = typeof( T ).GetField( value.ToString() ); + if( fi.GetCustomAttributes( typeof( XmlNameAttribute ), false ).Count() == 0 ) + throw new Exception( String.Format( "Attribute 'XmlNameAttribute' is not assigned to {0} fields!", typeof( T ).Name ) ); + var a = ( XmlNameAttribute )fi.GetCustomAttributes( typeof( XmlNameAttribute ), false ).First(); + return a.XmlName; + } + } + + /// + /// This attribute applied to enum's fields for definition their's real xml names in DocX file. + /// + /// + /// public enum MyEnum + /// { + /// [XmlName("one")] // This means, that xml element has 'val="one"' + /// ValueOne, + /// [XmlName("two")] // This means, that xml element has 'val="two"' + /// ValueTwo + /// } + /// + [AttributeUsage( AttributeTargets.Field, Inherited = false, AllowMultiple = false )] + internal sealed class XmlNameAttribute : Attribute + { + /// + /// Real xml name + /// + public String XmlName + { + get; private set; + } + + public XmlNameAttribute( String xmlName ) + { + XmlName = xmlName; + } + } +} diff --git a/Xceed.Words.NET/Src/Container.cs b/Xceed.Words.NET/Src/Container.cs new file mode 100644 index 00000000..e4499e05 --- /dev/null +++ b/Xceed.Words.NET/Src/Container.cs @@ -0,0 +1,1016 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using System.Text.RegularExpressions; +using System.IO.Packaging; +using System.IO; +using System.Drawing; +using System.Collections.ObjectModel; +using System.Diagnostics; + +namespace Xceed.Words.NET +{ + public abstract class Container : DocXElement + { + #region Public Properties + + /// + /// Returns a list of all Paragraphs inside this container. + /// + /// + /// + /// Load a document. + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // All Paragraphs in this document. + /// ]]> documentParagraphs = document.Paragraphs; + /// + /// // Make sure this document contains at least one Table. + /// if (document.Tables.Count() > 0) + /// { + /// // Get the first Table in this document. + /// Table t = document.Tables[0]; + /// + /// // All Paragraphs in this Table. + /// ]]> tableParagraphs = t.Paragraphs; + /// + /// // Make sure this Table contains at least one Row. + /// if (t.Rows.Count() > 0) + /// { + /// // Get the first Row in this document. + /// Row r = t.Rows[0]; + /// + /// // All Paragraphs in this Row. + /// ]]> rowParagraphs = r.Paragraphs; + /// + /// // Make sure this Row contains at least one Cell. + /// if (r.Cells.Count() > 0) + /// { + /// // Get the first Cell in this document. + /// Cell c = r.Cells[0]; + /// + /// // All Paragraphs in this Cell. + /// ]]> cellParagraphs = c.Paragraphs; + /// } + /// } + /// } + /// + /// // Save all changes to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public virtual ReadOnlyCollection Paragraphs + { + get + { + var paragraphs = this.GetParagraphs(); + this.InitParagraphs( paragraphs ); + + return paragraphs.AsReadOnly(); + } + } + + public virtual ReadOnlyCollection ParagraphsDeepSearch + { + get + { + return this.Paragraphs; + //var paragraphs = this.GetParagraphs( true ); + //this.InitParagraphs( paragraphs ); + + //return paragraphs.AsReadOnly(); + } + } + + public virtual List
Sections + { + get + { + var paragraphs = Paragraphs; + var sections = new List
(); + var sectionParagraphs = new List(); + + foreach( Paragraph paragraph in paragraphs ) + { + + var sectionInPara = paragraph.Xml.Descendants().FirstOrDefault( s => s.Name.LocalName == "sectPr" ); + + if( sectionInPara != null ) + { + sectionParagraphs.Add( paragraph ); + + var section = new Section( Document, sectionInPara ); + section.SectionParagraphs = sectionParagraphs; + + sections.Add( section ); + sectionParagraphs = new List(); + } + else + { + sectionParagraphs.Add( paragraph ); + } + } + + XElement body = Xml.Element( XName.Get( "body", DocX.w.NamespaceName ) ); + XElement baseSectionXml = body?.Element( XName.Get( "sectPr", DocX.w.NamespaceName ) ); + + if (baseSectionXml != null) + { + var baseSection = new Section( Document, baseSectionXml ); + baseSection.SectionParagraphs = sectionParagraphs; + sections.Add( baseSection ); + } + return sections; + } + } + + public virtual List
Tables + { + get + { + List
tables = + ( + from t in Xml.Descendants( DocX.w + "tbl" ) + select new Table( Document, t ) + ).ToList(); + + return tables; + } + } + + public virtual List Hyperlinks + { + get + { + List hyperlinks = new List(); + + foreach( Paragraph p in Paragraphs ) + hyperlinks.AddRange( p.Hyperlinks ); + + return hyperlinks; + } + } + + public virtual List Pictures + { + get + { + List pictures = new List(); + + foreach( Paragraph p in Paragraphs ) + pictures.AddRange( p.Pictures ); + + return pictures; + } + } + + public virtual List Lists + { + get + { + var lists = new List(); + var list = new List( Document, Xml ); + + foreach( var paragraph in Paragraphs ) + { + if( paragraph.IsListItem ) + { + if( list.CanAddListItem( paragraph ) ) + { + list.AddItem( paragraph ); + } + else + { + lists.Add( list ); + list = new List( Document, Xml ); + list.AddItem( paragraph ); + } + } + } + lists.Add( list ); + return lists; + } + } + + #endregion + + #region Public Methods + + /// + /// Sets the Direction of content. + /// + /// Direction either LeftToRight or RightToLeft + /// + /// Set the Direction of content in a Paragraph to RightToLeft. + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // Get the first Paragraph from this document. + /// Paragraph p = document.InsertParagraph(); + /// + /// // Set the Direction of this Paragraph. + /// p.Direction = Direction.RightToLeft; + /// + /// // Make sure the document contains at lest one Table. + /// if (document.Tables.Count() > 0) + /// { + /// // Get the first Table from this document. + /// Table t = document.Tables[0]; + /// + /// /* + /// * Set the direction of the entire Table. + /// * Note: The same function is available at the Row and Cell level. + /// */ + /// t.SetDirection(Direction.RightToLeft); + /// } + /// + /// // Save all changes to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public virtual void SetDirection( Direction direction ) + { + foreach( Paragraph p in Paragraphs ) + p.Direction = direction; + } + + public virtual List FindAll( string str ) + { + return FindAll( str, RegexOptions.None ); + } + + public virtual List FindAll( string str, RegexOptions options ) + { + List list = new List(); + + foreach( Paragraph p in Paragraphs ) + { + List indexes = p.FindAll( str, options ); + + for( int i = 0; i < indexes.Count(); i++ ) + indexes[ i ] += p._startIndex; + + list.AddRange( indexes ); + } + + return list; + } + + /// + /// Find all unique instances of the given Regex Pattern, + /// returning the list of the unique strings found + /// + /// + /// + /// + public virtual List FindUniqueByPattern( string pattern, RegexOptions options ) + { + var rawResults = new List(); + + foreach( Paragraph p in Paragraphs ) + { // accumulate the search results from all paragraphs + var partials = p.FindAllByPattern( pattern, options ); + rawResults.AddRange( partials ); + } + + // this dictionary is used to collect results and test for uniqueness + var uniqueResults = new Dictionary(); + + foreach( string currValue in rawResults ) + { + if( !uniqueResults.ContainsKey( currValue ) ) + { // if the dictionary doesn't have it, add it + uniqueResults.Add( currValue, 0 ); + } + } + + 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 fo = MatchFormattingOptions.SubsetMatch, + bool escapeRegEx = true, + bool useRegExSubstitutions = false ) + { + if( string.IsNullOrEmpty( searchValue ) ) + { + throw new ArgumentException( "searchValue cannot be null or empty.", "searchValue" ); + } + if( newValue == null ) + { + throw new ArgumentException( "newValue cannot be null.", "newValue" ); + } + + // ReplaceText in Headers of the document. + var headerList = new List
() { this.Document.Headers.First, this.Document.Headers.Even, this.Document.Headers.Odd }; + foreach( Header h in headerList ) + { + if( h != null ) + { + foreach( Paragraph p in h.Paragraphs ) + { + p.ReplaceText( searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, fo, escapeRegEx, useRegExSubstitutions ); + } + } + } + + // ReplaceText int main body of document. + foreach( Paragraph p in this.Paragraphs ) + { + p.ReplaceText( searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, fo, escapeRegEx, useRegExSubstitutions ); + } + + // ReplaceText in Footers of the document. + var footerList = new List
{ this.Document.Footers.First, this.Document.Footers.Even, this.Document.Footers.Odd }; + foreach( Footer f in footerList ) + { + if( f != null ) + { + foreach( Paragraph p in f.Paragraphs ) + { + p.ReplaceText( searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, fo, escapeRegEx, useRegExSubstitutions ); + } + } + } + } + + /// + /// + /// + /// The value to find. + /// A Func who accepts the matching regex search group value and passes it to this to return the replacement string. + /// Enable or disable the track changes. + /// The Regex options. + /// + /// + /// + public virtual void ReplaceText( string searchValue, + Func regexMatchHandler, + bool trackChanges = false, + RegexOptions options = RegexOptions.None, + Formatting newFormatting = null, + Formatting matchFormatting = null, + MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch ) + { + if( string.IsNullOrEmpty( searchValue ) ) + { + throw new ArgumentException( "searchValue cannot be null or empty.", "searchValue" ); + } + if( regexMatchHandler == null ) + { + throw new ArgumentException( "regexMatchHandler cannot be null", "regexMatchHandler" ); + } + + // Replace text in headers and footers of the Document. + var headersFootersList = new List() + { + this.Document.Headers.First, + this.Document.Headers.Even, + this.Document.Headers.Odd, + this.Document.Footers.First, + this.Document.Footers.Even, + this.Document.Footers.Odd, + }; + + foreach( var hf in headersFootersList ) + { + if( hf != null ) + { + foreach( var p in hf.Paragraphs ) + { + p.ReplaceText( searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, fo ); + } + } + } + + foreach( var p in this.Paragraphs ) + { + p.ReplaceText( searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, fo ); + } + } + + public virtual void InsertAtBookmark( string toInsert, string bookmarkName ) + { + if( string.IsNullOrWhiteSpace( bookmarkName ) ) + throw new ArgumentException( "bookmark cannot be null or empty", "bookmarkName" ); + + var headerCollection = Document.Headers; + var headers = new List
{ headerCollection.First, headerCollection.Even, headerCollection.Odd }; + foreach( var header in headers.Where( x => x != null ) ) + foreach( var paragraph in header.Paragraphs ) + paragraph.InsertAtBookmark( toInsert, bookmarkName ); + + foreach( var paragraph in Paragraphs ) + paragraph.InsertAtBookmark( toInsert, bookmarkName ); + + var footerCollection = Document.Footers; + var footers = new List
{ footerCollection.First, footerCollection.Even, footerCollection.Odd }; + foreach( var footer in footers.Where( x => x != null ) ) + foreach( var paragraph in footer.Paragraphs ) + paragraph.InsertAtBookmark( toInsert, bookmarkName ); + } + + public virtual Paragraph InsertParagraph( int index, string text, bool trackChanges ) + { + return InsertParagraph( index, text, trackChanges, null ); + } + + public virtual Paragraph InsertParagraph() + { + return InsertParagraph( string.Empty, false ); + } + + public virtual Paragraph InsertParagraph( int index, Paragraph p ) + { + var newXElement = new XElement( p.Xml ); + p.Xml = newXElement; + + var paragraph = HelperFunctions.GetFirstParagraphEffectedByInsert( Document, index ); + + if( paragraph == null ) + { + Xml.Add( p.Xml ); + } + else + { + var split = HelperFunctions.SplitParagraph( paragraph, index - paragraph._startIndex ); + + paragraph.Xml.ReplaceWith + ( + split[ 0 ], + newXElement, + split[ 1 ] + ); + } + this.SetParentContainer( p ); + return p; + } + + public virtual Paragraph InsertParagraph( Paragraph p ) + { + #region Styles + XDocument style_document; + + if( p._styles.Count() > 0 ) + { + var style_package_uri = new Uri( "/word/styles.xml", UriKind.Relative ); + if( !Document._package.PartExists( style_package_uri ) ) + { + var style_package = Document._package.CreatePart( style_package_uri, "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", CompressionOption.Maximum ); + using( TextWriter tw = new StreamWriter( new PackagePartStream( style_package.GetStream() ) ) ) + { + style_document = new XDocument + ( + new XDeclaration( "1.0", "UTF-8", "yes" ), + new XElement( XName.Get( "styles", DocX.w.NamespaceName ) ) + ); + + style_document.Save( tw ); + } + } + + var styles_document = Document._package.GetPart( style_package_uri ); + using( TextReader tr = new StreamReader( styles_document.GetStream() ) ) + { + style_document = XDocument.Load( tr ); + var styles_element = style_document.Element( XName.Get( "styles", DocX.w.NamespaceName ) ); + + var ids = from d in styles_element.Descendants( XName.Get( "style", DocX.w.NamespaceName ) ) + let a = d.Attribute( XName.Get( "styleId", DocX.w.NamespaceName ) ) + where a != null + select a.Value; + + foreach( XElement style in p._styles ) + { + // If styles_element does not contain this element, then add it. + + if( !ids.Contains( style.Attribute( XName.Get( "styleId", DocX.w.NamespaceName ) ).Value ) ) + { + styles_element.Add( style ); + } + } + } + + using( TextWriter tw = new StreamWriter( new PackagePartStream( styles_document.GetStream() ) ) ) + { + style_document.Save( tw ); + } + } + #endregion + + var newXElement = new XElement( p.Xml ); + + this.Xml.Add( newXElement ); + + int index = 0; + if( this.Document._paragraphLookup.Keys.Count() > 0 ) + { + index = this.Document._paragraphLookup.Last().Key; + + if( this.Document._paragraphLookup.Last().Value.Text.Length == 0 ) + { + index++; + } + else + { + index += this.Document._paragraphLookup.Last().Value.Text.Length; + } + } + + var newParagraph = new Paragraph( Document, newXElement, index ); + this.Document._paragraphLookup.Add( index, newParagraph ); + this.SetParentContainer( newParagraph ); + return newParagraph; + } + + public virtual Paragraph InsertParagraph( int index, string text, bool trackChanges, Formatting formatting ) + { + var newParagraph = new Paragraph( this.Document, new XElement( DocX.w + "p" ), index ); + newParagraph.InsertText( 0, text, trackChanges, formatting ); + + var firstPar = HelperFunctions.GetFirstParagraphEffectedByInsert( Document, index ); + if( firstPar != null ) + { + var splitIndex = index - firstPar._startIndex; + if( splitIndex > 0 ) + { + var splitParagraph = HelperFunctions.SplitParagraph( firstPar, splitIndex ); + firstPar.Xml.ReplaceWith( splitParagraph[ 0 ], newParagraph.Xml, splitParagraph[ 1 ] ); + } + else + { + firstPar.Xml.ReplaceWith( newParagraph.Xml, firstPar.Xml ); + } + } + else + { + this.Xml.Add( newParagraph ); + } + + this.SetParentContainer( newParagraph ); + return newParagraph; + } + + public virtual Paragraph InsertParagraph( string text ) + { + return InsertParagraph( text, false, new Formatting() ); + } + + public virtual Paragraph InsertParagraph( string text, bool trackChanges ) + { + return InsertParagraph( text, trackChanges, new Formatting() ); + } + + public virtual Paragraph InsertParagraph( string text, bool trackChanges, Formatting formatting ) + { + var newParagraph = new XElement + ( + XName.Get( "p", DocX.w.NamespaceName ), new XElement( XName.Get( "pPr", DocX.w.NamespaceName ) ), HelperFunctions.FormatInput( text, formatting.Xml ) + ); + + if( trackChanges ) + { + newParagraph = HelperFunctions.CreateEdit( EditType.ins, DateTime.Now, newParagraph ); + } + + this.Xml.Add( newParagraph ); + + var newParagraphAdded = new Paragraph( this.Document, newParagraph, 0 ); + var cell = this as Cell; + if( cell != null ) + { + newParagraphAdded.PackagePart = cell.PackagePart; + } + else + { + var docx = this as DocX; + if( docx != null ) + { + newParagraphAdded.PackagePart = this.Document.PackagePart; + } + else + { + var footer = this as Footer; + if( footer != null ) + { + newParagraphAdded.PackagePart = footer.PackagePart; + } + else + { + var header = this as Header; + if( header != null ) + { + newParagraphAdded.PackagePart = header.PackagePart; + } + else + { + newParagraphAdded.PackagePart = this.Document.PackagePart; + } + } + } + } + + this.SetParentContainer( newParagraphAdded ); + + return newParagraphAdded; + } + + /// + /// Removes paragraph at specified position + /// + /// Index of paragraph to remove + /// True if paragraph removed + public bool RemoveParagraphAt( int index ) + { + var paragraphs = Xml.Descendants( DocX.w + "p" ).ToList(); + if( index < paragraphs.Count ) + { + paragraphs[ index ].Remove(); + return true; + } + + return false; + } + + /// + /// Removes a paragraph + /// + /// The paragraph to remove + /// True if paragraph removed + public bool RemoveParagraph( Paragraph paragraph ) + { + var paragraphs = Xml.Descendants( DocX.w + "p" ); + var index = paragraphs.ToList().IndexOf( paragraph.Xml ); + + if( index == -1 ) + return false; + return this.RemoveParagraphAt( index ); + } + + public virtual Paragraph InsertEquation( string equation ) + { + Paragraph p = InsertParagraph(); + p.AppendEquation( equation ); + return p; + } + + public virtual Paragraph InsertBookmark( String bookmarkName ) + { + var p = InsertParagraph(); + p.AppendBookmark( bookmarkName ); + return p; + } + + public virtual Table InsertTable( int rowCount, int columnCount ) + { + var newTable = HelperFunctions.CreateTable( rowCount, columnCount ); + Xml.Add( newTable ); + + var table = new Table( this.Document, newTable ); + table.PackagePart = this.PackagePart; + return table; + } + + public virtual Table InsertTable( int index, int rowCount, int columnCount ) + { + var newTable = HelperFunctions.CreateTable( rowCount, columnCount ); + + var p = HelperFunctions.GetFirstParagraphEffectedByInsert( Document, index ); + if( p == null ) + { + Xml.Elements().First().AddFirst( newTable ); + } + else + { + var split = HelperFunctions.SplitParagraph( p, index - p._startIndex ); + p.Xml.ReplaceWith( split[ 0 ], newTable, split[ 1 ] ); + } + + var table = new Table( this.Document, newTable ); + table.PackagePart = this.PackagePart; + return table; + } + + public virtual Table InsertTable( Table t ) + { + var newXElement = new XElement( t.Xml ); + Xml.Add( newXElement ); + + var newTable = new Table( this.Document, newXElement ); + newTable.Design = t.Design; + newTable.PackagePart = this.PackagePart; + return newTable; + } + + public virtual Table InsertTable( int index, Table t ) + { + var p = HelperFunctions.GetFirstParagraphEffectedByInsert( this.Document, index ); + + var split = HelperFunctions.SplitParagraph( p, index - p._startIndex ); + var newXElement = new XElement( t.Xml ); + p.Xml.ReplaceWith( split[ 0 ], newXElement, split[ 1 ] ); + + var newTable = new Table( this.Document, newXElement ); + newTable.Design = t.Design; + newTable.PackagePart = this.PackagePart; + return newTable; + } + + public virtual void InsertSection() + { + this.InsertSection( false ); + } + + public virtual void InsertSection( bool trackChanges ) + { + var newSection = new XElement( XName.Get( "p", DocX.w.NamespaceName ), new XElement( XName.Get( "pPr", DocX.w.NamespaceName ), new XElement( XName.Get( "sectPr", DocX.w.NamespaceName ), new XElement( XName.Get( "type", DocX.w.NamespaceName ), new XAttribute( DocX.w + "val", "continuous" ) ) ) ) ); + + if( trackChanges ) + { + newSection = HelperFunctions.CreateEdit( EditType.ins, DateTime.Now, newSection ); + } + + this.Xml.Add( newSection ); + } + + public virtual void InsertSectionPageBreak( bool trackChanges = false ) + { + var newSection = new XElement( XName.Get( "p", DocX.w.NamespaceName ), new XElement( XName.Get( "pPr", DocX.w.NamespaceName ), new XElement( XName.Get( "sectPr", DocX.w.NamespaceName ) ) ) ); + + if( trackChanges ) + { + newSection = HelperFunctions.CreateEdit( EditType.ins, DateTime.Now, newSection ); + } + + this.Xml.Add( newSection ); + } + + public virtual List InsertList( List list ) + { + foreach( var item in list.Items ) + { + Xml.Add( item.Xml ); + } + return list; + } + + public virtual List InsertList( List list, double fontSize ) + { + foreach( var item in list.Items ) + { + item.FontSize( fontSize ); + Xml.Add( item.Xml ); + } + return list; + } + + public virtual List InsertList( List list, Font fontFamily, double fontSize ) + { + foreach( var item in list.Items ) + { + item.Font( fontFamily ); + item.FontSize( fontSize ); + Xml.Add( item.Xml ); + } + return list; + } + + public virtual List InsertList( int index, List list ) + { + var p = HelperFunctions.GetFirstParagraphEffectedByInsert( Document, index ); + + var split = HelperFunctions.SplitParagraph( p, index - p._startIndex ); + var elements = new List { split[ 0 ] }; + elements.AddRange( list.Items.Select( i => new XElement( i.Xml ) ) ); + elements.Add( split[ 1 ] ); + p.Xml.ReplaceWith( elements.ToArray() ); + + return list; + } + + public int RemoveTextInGivenFormat( Formatting formattingToMatch, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch ) + { + var count = 0; + foreach( var element in Xml.Elements() ) + count += RecursiveRemoveText( element, formattingToMatch, formattingOptions ); + + return count; + } + + public string[] ValidateBookmarks( params string[] bookmarkNames ) + { + var headers = new[] { Document.Headers.First, Document.Headers.Even, Document.Headers.Odd }.Where( h => h != null ).ToList(); + var footers = new[] { Document.Footers.First, Document.Footers.Even, Document.Footers.Odd }.Where( f => f != null ).ToList(); + + var result = new List(); + + foreach( var bookmarkName in bookmarkNames ) + { + if( headers.SelectMany( h => h.Paragraphs ).Any( p => p.ValidateBookmark( bookmarkName ) ) ) + return new string[ 0 ]; + if( footers.SelectMany( h => h.Paragraphs ).Any( p => p.ValidateBookmark( bookmarkName ) ) ) + return new string[ 0 ]; + if( Paragraphs.Any( p => p.ValidateBookmark( bookmarkName ) ) ) + return new string[ 0 ]; + result.Add( bookmarkName ); + } + return result.ToArray(); + } + + #endregion + + #region Internal Methods + + internal List GetParagraphs() + { + // Need some memory that can be updated by the recursive search. + int index = 0; + var paragraphs = new List(); + + var p = this.Xml.Descendants( XName.Get( "p", DocX.w.NamespaceName ) ); + if( p != null ) + { + foreach( XElement xElement in p ) + { + var paragraph = new Paragraph( this.Document, xElement, index ); + paragraphs.Add( paragraph ); + index += HelperFunctions.GetText( xElement ).Length; + } + } + + return paragraphs; + } + + internal void GetParagraphsRecursive( XElement xml, ref int index, ref List paragraphs, bool isDeepSearch = false ) + { + var keepSearching = true; + if( xml.Name.LocalName == "p" ) + { + paragraphs.Add( new Paragraph( Document, xml, index ) ); + + index += HelperFunctions.GetText( xml ).Length; + if( !isDeepSearch ) + { + keepSearching = false; + } + } + + if( keepSearching && xml.HasElements ) + { + foreach( XElement e in xml.Elements() ) + { + this.GetParagraphsRecursive( e, ref index, ref paragraphs, isDeepSearch ); + } + } + } + + internal int RecursiveRemoveText( XElement element, Formatting formattingToMatch, MatchFormattingOptions formattingOptions ) + { + var count = 0; + foreach( var subElement in element.Elements() ) + { + if( "rPr".Equals( subElement.Name.LocalName ) ) + { + if( HelperFunctions.ContainsEveryChildOf( formattingToMatch.Xml, subElement, formattingOptions ) ) + { + subElement.Parent.Remove(); + ++count; + } + } + + count += RecursiveRemoveText( subElement, formattingToMatch, formattingOptions ); + } + + return count; + } + + #endregion + + #region Private Methods + + private void GetListItemType( Paragraph p ) + { + var listItemType = HelperFunctions.GetListItemType( p, Document ); + if( listItemType != null ) + { + p.ListItemType = GetListItemType( HelperFunctions.GetListItemType( p, Document ) ); + } + } + + private ContainerType GetParentFromXmlName( string xmlName ) + { + switch( xmlName ) + { + case "body": + return ContainerType.Body; + case "p": + return ContainerType.Paragraph; + case "tbl": + return ContainerType.Table; + case "sectPr": + return ContainerType.Section; + case "tc": + return ContainerType.Cell; + default: + return ContainerType.None; + } + } + + private void SetParentContainer( Paragraph newParagraph ) + { + var containerType = GetType(); + + switch( containerType.Name ) + { + case "Body": + newParagraph.ParentContainer = ContainerType.Body; + break; + case "Table": + newParagraph.ParentContainer = ContainerType.Table; + break; + case "TOC": + newParagraph.ParentContainer = ContainerType.TOC; + break; + case "Section": + newParagraph.ParentContainer = ContainerType.Section; + break; + case "Cell": + newParagraph.ParentContainer = ContainerType.Cell; + break; + case "Header": + newParagraph.ParentContainer = ContainerType.Header; + break; + case "Footer": + newParagraph.ParentContainer = ContainerType.Footer; + break; + case "Paragraph": + newParagraph.ParentContainer = ContainerType.Paragraph; + break; + } + } + + private ListItemType GetListItemType( string styleName ) + { + switch( styleName ) + { + case "bullet": + return ListItemType.Bulleted; + default: + return ListItemType.Numbered; + } + } + + private void InitParagraphs( List paragraphs ) + { + 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 = this.GetParentFromXmlName( p.Xml.Ancestors().First().Name.LocalName ); + + if( p.IsListItem ) + { + this.GetListItemType( p ); + } + } + } + + #endregion + + #region Constructors + + internal Container( DocX document, XElement xml ) + : base( document, xml ) + { + + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/CustomProperty.cs b/Xceed.Words.NET/Src/CustomProperty.cs new file mode 100644 index 00000000..740145b5 --- /dev/null +++ b/Xceed.Words.NET/Src/CustomProperty.cs @@ -0,0 +1,159 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; + +namespace Xceed.Words.NET +{ + public class CustomProperty + { + #region Public Properties + + /// + /// The name of this CustomProperty. + /// + public string Name + { + get; + private set; + } + + /// + /// The value of this CustomProperty. + /// + public object Value + { + get; + private set; + } + + #endregion + + #region Internal Properties + + internal string Type + { + get; + private set; + } + + #endregion + + #region Constructors + + /// + /// Create a new CustomProperty to hold a string. + /// + /// The name of this CustomProperty. + /// The value of this CustomProperty. + public CustomProperty( string name, string value ) + : this( name, "lpwstr", value ) + { + } + + /// + /// Create a new CustomProperty to hold an int. + /// + /// The name of this CustomProperty. + /// The value of this CustomProperty. + public CustomProperty( string name, int value ) + : this( name, "i4", value ) + { + } + + /// + /// Create a new CustomProperty to hold a double. + /// + /// The name of this CustomProperty. + /// The value of this CustomProperty. + public CustomProperty( string name, double value ) + : this( name, "r8", value ) + { + } + + /// + /// Create a new CustomProperty to hold a DateTime. + /// + /// The name of this CustomProperty. + /// The value of this CustomProperty. + public CustomProperty( string name, DateTime value ) + : this( name, "filetime", value.ToUniversalTime() ) + { + } + + /// + /// Create a new CustomProperty to hold a bool. + /// + /// The name of this CustomProperty. + /// The value of this CustomProperty. + public CustomProperty( string name, bool value ) + : this( name, "bool", value ) + { + } + + internal CustomProperty( string name, string type, string value ) + { + object realValue; + switch( type ) + { + case "lpwstr": + { + realValue = value; + break; + } + + case "i4": + { + realValue = int.Parse( value, System.Globalization.CultureInfo.InvariantCulture ); + break; + } + + case "r8": + { + realValue = Double.Parse( value, System.Globalization.CultureInfo.InvariantCulture ); + break; + } + + case "filetime": + { + realValue = DateTime.Parse( value, System.Globalization.CultureInfo.InvariantCulture ); + break; + } + + case "bool": + { + realValue = bool.Parse( value ); + break; + } + + default: + throw new Exception(); + } + + this.Name = name; + this.Type = type; + this.Value = realValue; + } + + private CustomProperty( string name, string type, object value ) + { + + this.Name = name; + this.Type = type; + this.Value = value; + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/DocProperty.cs b/Xceed.Words.NET/Src/DocProperty.cs new file mode 100644 index 00000000..c81d1113 --- /dev/null +++ b/Xceed.Words.NET/Src/DocProperty.cs @@ -0,0 +1,55 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System.Xml.Linq; +using System.Text.RegularExpressions; + +namespace Xceed.Words.NET +{ + /// + /// Represents a field of type document property. This field displays the value stored in a custom property. + /// + public class DocProperty : DocXElement + { + + #region Internal Members + + internal Regex _extractName = new Regex( @"DOCPROPERTY (?.*) " ); + + #endregion + + #region Public Properties + + /// + /// The custom property to display. + /// + public string Name + { + get; + private set; + } + + #endregion + + #region Constructors + + internal DocProperty( DocX document, XElement xml ) : base( document, xml ) + { + var instr = Xml.Attribute( XName.Get( "instr", "http://schemas.openxmlformats.org/wordprocessingml/2006/main" ) ).Value; + this.Name = _extractName.Match( instr.Trim() ).Groups[ "name" ].Value; + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/DocX.cs b/Xceed.Words.NET/Src/DocX.cs new file mode 100644 index 00000000..c02f9a4a --- /dev/null +++ b/Xceed.Words.NET/Src/DocX.cs @@ -0,0 +1,4446 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using System.Xml; +using System.IO; +using System.Text.RegularExpressions; +using System.IO.Packaging; +using System.Security.Cryptography; +using System.Drawing; +using System.Collections.ObjectModel; + +namespace Xceed.Words.NET +{ + /// + /// Represents a document. + /// + public class DocX : Container, IDisposable + { + #region Namespaces + static internal XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; + static internal XNamespace rel = "http://schemas.openxmlformats.org/package/2006/relationships"; + + static internal XNamespace r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; + static internal XNamespace m = "http://schemas.openxmlformats.org/officeDocument/2006/math"; + static internal XNamespace customPropertiesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"; + static internal XNamespace customVTypesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"; + + static internal XNamespace wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"; + static internal XNamespace a = "http://schemas.openxmlformats.org/drawingml/2006/main"; + static internal XNamespace c = "http://schemas.openxmlformats.org/drawingml/2006/chart"; + internal static XNamespace n = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"; + static internal XNamespace v = "urn:schemas-microsoft-com:vml"; + #endregion + + #region Private Members + + private Headers _headers; + private Footers _footers; + + private float _pageSizeMultiplier = 20.0f; + + #endregion + + #region Internal Members + + // Get the word\settings.xml part + internal PackagePart _settingsPart; + internal PackagePart _endnotesPart; + internal PackagePart _footnotesPart; + internal PackagePart _stylesPart; + internal PackagePart _stylesWithEffectsPart; + internal PackagePart _numberingPart; + internal PackagePart _fontTablePart; + + #region Internal variables defined foreach DocX object + // Object representation of the .docx + internal Package _package; + + // The mainDocument is loaded into a XDocument object for easy querying and editing + internal XDocument _mainDoc; + internal XDocument _settings; + internal XDocument _endnotes; + internal XDocument _footnotes; + internal XDocument _styles; + internal XDocument _stylesWithEffects; + internal XDocument _numbering; + internal XDocument _fontTable; + + // A lookup for the Paragraphs in this document. + internal Dictionary _paragraphLookup = new Dictionary(); + // Every document is stored in a MemoryStream, all edits made to a document are done in memory. + internal MemoryStream _memoryStream; + // The filename that this document was loaded from + internal string _filename; + // The stream that this document was loaded from + internal Stream _stream; + #endregion + + #endregion + + #region Public Properties + + /// + /// Top margin in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. + /// + public float MarginTop + { + get + { + return getMarginAttribute( XName.Get( "top", w.NamespaceName ) ); + } + + set + { + setMarginAttribute( XName.Get( "top", w.NamespaceName ), value ); + } + } + + /// + /// Bottom margin in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. + /// + public float MarginBottom + { + get + { + return getMarginAttribute( XName.Get( "bottom", w.NamespaceName ) ); + } + + set + { + setMarginAttribute( XName.Get( "bottom", w.NamespaceName ), value ); + } + } + + /// + /// Left margin in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. + /// + public float MarginLeft + { + get + { + return getMarginAttribute( XName.Get( "left", w.NamespaceName ) ); + } + + set + { + setMarginAttribute( XName.Get( "left", w.NamespaceName ), value ); + } + } + + /// + /// Right margin in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. + /// + public float MarginRight + { + get + { + return getMarginAttribute( XName.Get( "right", w.NamespaceName ) ); + } + + set + { + setMarginAttribute( XName.Get( "right", w.NamespaceName ), value ); + } + } + + /// + /// Header margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. + /// + public float MarginHeader + { + get + { + return getMarginAttribute(XName.Get("header", w.NamespaceName)); + } + set + { + setMarginAttribute(XName.Get("header", w.NamespaceName), value); + } + } + + /// + /// Footer margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. + /// + public float MarginFooter + { + get + { + return getMarginAttribute(XName.Get("footer", w.NamespaceName)); + } + set + { + setMarginAttribute(XName.Get("footer", w.NamespaceName), value); + } + } + + public bool MirrorMargins + { + get + { + return getMirrorMargins(XName.Get("mirrorMargins", DocX.w.NamespaceName)); + } + set + { + setMirrorMargins(XName.Get("mirrorMargins", DocX.w.NamespaceName), value); + } + } + + /// + /// Page width in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. + /// + public float PageWidth + { + get + { + var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) ); + var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) ); + var pgSz = sectPr?.Element( XName.Get( "pgSz", w.NamespaceName ) ); + + if( pgSz != null ) + { + var w = pgSz.Attribute( XName.Get( "w", DocX.w.NamespaceName ) ); + if( w != null ) + { + float f; + if( float.TryParse( w.Value, out f ) ) + return ( int )( f / _pageSizeMultiplier ); + } + } + + return ( 12240.0f / _pageSizeMultiplier ); + } + + set + { + var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) ); + var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) ); + var pgSz = sectPr.Element( XName.Get( "pgSz", w.NamespaceName ) ); + pgSz?.SetAttributeValue( XName.Get( "w", w.NamespaceName ), value * Convert.ToInt32( _pageSizeMultiplier ) ); + } + } + + /// + /// Page height in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point. + /// + public float PageHeight + { + get + { + var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) ); + var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) ); + if( sectPr != null ) + { + var pgSz = sectPr.Element( XName.Get( "pgSz", w.NamespaceName ) ); + if( pgSz != null ) + { + var w = pgSz.Attribute( XName.Get( "h", DocX.w.NamespaceName ) ); + if( w != null ) + { + float f; + if( float.TryParse( w.Value, out f ) ) + return ( int )( f / _pageSizeMultiplier ); + } + } + } + + return ( 15840.0f / _pageSizeMultiplier ); + } + + set + { + var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) ); + if( body != null ) + { + var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) ); + if( sectPr != null ) + { + var pgSz = sectPr.Element( XName.Get( "pgSz", w.NamespaceName ) ); + if( pgSz != null ) + { + pgSz.SetAttributeValue( XName.Get( "h", w.NamespaceName ), value * Convert.ToInt32( _pageSizeMultiplier ) ); + } + } + } + } + } + /// + /// Returns true if any editing restrictions are imposed on this document. + /// + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// if(document.isProtected) + /// Console.WriteLine("Protected"); + /// else + /// Console.WriteLine("Not protected"); + /// + /// // Save the document. + /// document.Save(); + /// } + /// + /// + /// + /// + /// + public bool isProtected + { + get + { + return _settings.Descendants( XName.Get( "documentProtection", w.NamespaceName ) ).Count() > 0; + } + } + + public PageLayout PageLayout + { + get + { + XElement sectPr = Xml.Element( XName.Get( "sectPr", w.NamespaceName ) ); + if( sectPr == null ) + { + Xml.SetElementValue( XName.Get( "sectPr", w.NamespaceName ), string.Empty ); + sectPr = Xml.Element( XName.Get( "sectPr", w.NamespaceName ) ); + } + + return new PageLayout( this, sectPr ); + } + } + + /// + /// Returns a collection of Headers in this Document. + /// A document typically contains three Headers. + /// A default one (odd), one for the first page and one for even pages. + /// + /// + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add header support to this document. + /// document.AddHeaders(); + /// + /// // Get a collection of all headers in this document. + /// Headers headers = document.Headers; + /// + /// // The header used for the first page of this document. + /// Header first = headers.first; + /// + /// // The header used for odd pages of this document. + /// Header odd = headers.odd; + /// + /// // The header used for even pages of this document. + /// Header even = headers.even; + /// } + /// + /// + public Headers Headers + { + get + { + return _headers; + } + } + + /// + /// Returns a collection of Footers in this Document. + /// A document typically contains three Footers. + /// A default one (odd), one for the first page and one for even pages. + /// + /// + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add footer support to this document. + /// document.AddFooters(); + /// + /// // Get a collection of all footers in this document. + /// Footers footers = document.Footers; + /// + /// // The footer used for the first page of this document. + /// Footer first = footers.first; + /// + /// // The footer used for odd pages of this document. + /// Footer odd = footers.odd; + /// + /// // The footer used for even pages of this document. + /// Footer even = footers.even; + /// } + /// + /// + public Footers Footers + { + get + { + return _footers; + } + } + + /// + /// Should the Document use different Headers and Footers for odd and even pages? + /// + /// + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add header support to this document. + /// document.AddHeaders(); + /// + /// // Get a collection of all headers in this document. + /// Headers headers = document.Headers; + /// + /// // The header used for odd pages of this document. + /// Header odd = headers.odd; + /// + /// // The header used for even pages of this document. + /// Header even = headers.even; + /// + /// // Force the document to use a different header for odd and even pages. + /// document.DifferentOddAndEvenPages = true; + /// + /// // Content can be added to the Headers in the same manor that it would be added to the main document. + /// Paragraph p1 = odd.InsertParagraph(); + /// p1.Append("This is the odd pages header."); + /// + /// Paragraph p2 = even.InsertParagraph(); + /// p2.Append("This is the even pages header."); + /// + /// // Save all changes to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public bool DifferentOddAndEvenPages + { + get + { + XDocument settings; + using( TextReader tr = new StreamReader( _settingsPart.GetStream() ) ) + { + settings = XDocument.Load( tr ); + } + + var evenAndOddHeaders = settings.Root.Element( w + "evenAndOddHeaders" ); + + return ( evenAndOddHeaders != null ); + } + + set + { + XDocument settings; + using( TextReader tr = new StreamReader( _settingsPart.GetStream() ) ) + { + settings = XDocument.Load( tr ); + } + + var evenAndOddHeaders = settings.Root.Element( w + "evenAndOddHeaders" ); + if( evenAndOddHeaders == null ) + { + if( value ) + { + settings.Root.AddFirst( new XElement( w + "evenAndOddHeaders" ) ); + } + } + else + { + if( !value ) + { + evenAndOddHeaders.Remove(); + } + } + + using( TextWriter tw = new StreamWriter( new PackagePartStream( _settingsPart.GetStream() ) ) ) + { + settings.Save( tw ); + } + } + } + + /// + /// Should the Document use an independent Header and Footer for the first page? + /// + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add header support to this document. + /// document.AddHeaders(); + /// + /// // The header used for the first page of this document. + /// Header first = document.Headers.first; + /// + /// // Force the document to use a different header for first page. + /// document.DifferentFirstPage = true; + /// + /// // Content can be added to the Headers in the same manor that it would be added to the main document. + /// Paragraph p = first.InsertParagraph(); + /// p.Append("This is the first pages header."); + /// + /// // Save all changes to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + public bool DifferentFirstPage + { + get + { + var body = _mainDoc.Root.Element( w + "body" ); + var sectPr = body.Element( w + "sectPr" ); + var titlePg = sectPr?.Element( w + "titlePg" ); + return titlePg != null; + } + + set + { + var body = _mainDoc.Root.Element( w + "body" ); + body.Add( new XElement( w + "sectPr", string.Empty ) ); + var sectPr = body.Element( w + "sectPr" ); + var titlePg = sectPr.Element( w + "titlePg" ); + if( titlePg == null ) + { + if( value ) + { + sectPr.Add( new XElement( w + "titlePg", string.Empty ) ); + } + } + else + { + if( !value ) + { + titlePg.Remove(); + } + } + } + } + + /// + /// Returns a list of Images in this document. + /// + /// + /// Get the unique Id of every Image in this document. + /// + /// // Load a document. + /// DocX document = DocX.Load(@"C:\Example\Test.docx"); + /// + /// // Loop through each Image in this document. + /// foreach (Xceed.Words.NET.Image i in document.Images) + /// { + /// // Get the unique Id which identifies this Image. + /// string uniqueId = i.Id; + /// } + /// + /// + /// + /// + /// + /// + /// + public List Images + { + get + { + var imageRelationships = this.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ); + if( imageRelationships.Any() ) + { + return + ( + from i in imageRelationships + select new Image( this, i ) + ).ToList(); + } + + return new List(); + } + } + + /// + /// Returns a list of custom properties in this document. + /// + /// + /// Method 1: Get the name, type and value of each CustomProperty in this document. + /// + /// // Load Example.docx + /// DocX document = DocX.Load(@"C:\Example\Test.docx"); + /// + /// /* + /// * No two custom properties can have the same name, + /// * so a Dictionary is the perfect data structure to store them in. + /// * Each custom property can be accessed using its name. + /// */ + /// foreach (string name in document.CustomProperties.Keys) + /// { + /// // Grab a custom property using its name. + /// CustomProperty cp = document.CustomProperties[name]; + /// + /// // Write this custom properties details to Console. + /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value)); + /// } + /// + /// Console.WriteLine("Press any key..."); + /// + /// // Wait for the user to press a key before closing the Console. + /// Console.ReadKey(); + /// + /// + /// + /// Method 2: Get the name, type and value of each CustomProperty in this document. + /// + /// // Load Example.docx + /// DocX document = DocX.Load(@"C:\Example\Test.docx"); + /// + /// /* + /// * No two custom properties can have the same name, + /// * so a Dictionary is the perfect data structure to store them in. + /// * The values of this Dictionary are CustomProperties. + /// */ + /// foreach (CustomProperty cp in document.CustomProperties.Values) + /// { + /// // Write this custom properties details to Console. + /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value)); + /// } + /// + /// Console.WriteLine("Press any key..."); + /// + /// // Wait for the user to press a key before closing the Console. + /// Console.ReadKey(); + /// + /// + /// + public Dictionary CustomProperties + { + get + { + if( _package.PartExists( new Uri( "/docProps/custom.xml", UriKind.Relative ) ) ) + { + PackagePart docProps_custom = _package.GetPart( new Uri( "/docProps/custom.xml", UriKind.Relative ) ); + XDocument customPropDoc; + using( TextReader tr = new StreamReader( docProps_custom.GetStream( FileMode.Open, FileAccess.Read ) ) ) + customPropDoc = XDocument.Load( tr, LoadOptions.PreserveWhitespace ); + + // Get all of the custom properties in this document + return + ( + from p in customPropDoc.Descendants( XName.Get( "property", customPropertiesSchema.NamespaceName ) ) + let Name = p.Attribute( XName.Get( "name" ) ).Value + let Type = p.Descendants().Single().Name.LocalName + let Value = p.Descendants().Single().Value + select new CustomProperty( Name, Type, Value ) + ).ToDictionary( p => p.Name, StringComparer.CurrentCultureIgnoreCase ); + } + + return new Dictionary(); + } + } + + /// + /// Returns the list of document core properties with corresponding values. + /// + public Dictionary CoreProperties + { + get + { + if( _package.PartExists( new Uri( "/docProps/core.xml", UriKind.Relative ) ) ) + { + PackagePart docProps_Core = _package.GetPart( new Uri( "/docProps/core.xml", UriKind.Relative ) ); + XDocument corePropDoc; + using( TextReader tr = new StreamReader( docProps_Core.GetStream( FileMode.Open, FileAccess.Read ) ) ) + corePropDoc = XDocument.Load( tr, LoadOptions.PreserveWhitespace ); + + // Get all of the core properties in this document + return ( from docProperty in corePropDoc.Root.Elements() + select + new KeyValuePair( + string.Format( + "{0}:{1}", + corePropDoc.Root.GetPrefixOfNamespace( docProperty.Name.Namespace ), + docProperty.Name.LocalName ), + docProperty.Value ) ).ToDictionary( p => p.Key, v => v.Value ); + } + + return new Dictionary(); + } + } + + /// + /// Get the Text of this document. + /// + /// + /// Write to Console the Text from this document. + /// + /// // Load a document + /// DocX document = DocX.Load(@"C:\Example\Test.docx"); + /// + /// // Get the text of this document. + /// string text = document.Text; + /// + /// // Write the text of this document to Console. + /// Console.Write(text); + /// + /// // Wait for the user to press a key before closing the console window. + /// Console.ReadKey(); + /// + /// + public string Text + { + get + { + return HelperFunctions.GetText( Xml ); + } + } + + public override ReadOnlyCollection Paragraphs + { + get + { + var paragraphs = base.Paragraphs; + foreach( var paragraph in paragraphs ) + { + paragraph.PackagePart = this.PackagePart; + } + return paragraphs; + } + } + + public override List Lists + { + get + { + var l = base.Lists; + l.ForEach( x => x.Items.ForEach( i => i.PackagePart = this.PackagePart ) ); + return l; + } + } + + public override List
Tables + { + get + { + var l = base.Tables; + l.ForEach( x => x.PackagePart = this.PackagePart ); + return l; + } + } + + /// + /// Get the Footnotes of this document + /// + public IEnumerable FootnotesText + { + get + { + foreach( var note in _footnotes.Root.Elements( w + "footnote" ) ) + yield return HelperFunctions.GetText( note ); + } + } + + /// + /// Get the Endnotes of this document + /// + public IEnumerable EndnotesText + { + get + { + foreach( var note in _endnotes.Root.Elements( w + "endnote" ) ) + yield return HelperFunctions.GetText( note ); + } + } + + public BookmarkCollection Bookmarks + { + get + { + var bookmarks = new BookmarkCollection(); + for( int i = 0; i < this.Paragraphs.Count; ++i ) + { + bookmarks.AddRange( this.Paragraphs[ i ].GetBookmarks() ); + } + return bookmarks; + } + } + + #endregion + + #region Public Methods + + /// + /// Returns the type of editing protection imposed on this document. + /// + /// The type of editing protection imposed on this document. + /// + /// + /// Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Make sure the document is protected before checking the protection type. + /// if (document.isProtected) + /// { + /// EditRestrictions protection = document.GetProtectionType(); + /// Console.WriteLine("Document is protected using " + protection.ToString()); + /// } + /// + /// else + /// Console.WriteLine("Document is not protected."); + /// + /// // Save the document. + /// document.Save(); + /// } + /// + /// + /// + /// + /// + public EditRestrictions GetProtectionType() + { + if( isProtected ) + { + XElement documentProtection = _settings.Descendants( XName.Get( "documentProtection", w.NamespaceName ) ).FirstOrDefault(); + string edit_type = documentProtection.Attribute( XName.Get( "edit", w.NamespaceName ) ).Value; + return ( EditRestrictions )Enum.Parse( typeof( EditRestrictions ), edit_type ); + } + + return EditRestrictions.none; + } + + /// + /// Add editing protection to this document. + /// + /// The type of protection to add to this document. + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Allow no editing, only the adding of comment. + /// document.AddProtection(EditRestrictions.comments); + /// + /// // Save the document. + /// document.Save(); + /// } + /// + /// + /// + /// + /// + public void AddProtection( EditRestrictions er ) + { + // Call remove protection before adding a new protection element. + RemoveProtection(); + + if( er == EditRestrictions.none ) + return; + + var documentProtection = new XElement( XName.Get( "documentProtection", w.NamespaceName ) ); + documentProtection.Add( new XAttribute( XName.Get( "edit", w.NamespaceName ), er.ToString() ) ); + documentProtection.Add( new XAttribute( XName.Get( "enforcement", w.NamespaceName ), "1" ) ); + + _settings.Root.AddFirst( documentProtection ); + } + + /// + /// Remove editing protection from this document. + /// + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Remove any editing restrictions that are imposed on this document. + /// document.RemoveProtection(); + /// + /// // Save the document. + /// document.Save(); + /// } + /// + /// + /// + /// + /// + public void RemoveProtection() + { + // Remove every node of type documentProtection. + _settings.Descendants( XName.Get( "documentProtection", w.NamespaceName ) ).Remove(); + } + + /// + /// Insert the contents of another document at the end of this document. + /// + /// The document to insert at the end of this document. + /// When true, document is added at the end. If False, document is added at the beginning. + /// + /// Create a new document and insert an old document into it. + /// + /// // Create a new document. + /// using (DocX newDocument = DocX.Create(@"NewDocument.docx")) + /// { + /// // Load an old document. + /// using (DocX oldDocument = DocX.Load(@"OldDocument.docx")) + /// { + /// // Insert the old document into the new document. + /// newDocument.InsertDocument(oldDocument); + /// + /// // Save the new document. + /// newDocument.Save(); + /// }// Release the old document from memory. + /// }// Release the new document from memory. + /// + /// + /// If the document being inserted contains Images, CustomProperties and or custom styles, these will be correctly inserted into the new document. In the case of Images, new ID's are generated for the Images being inserted to avoid ID conflicts. CustomProperties with the same name will be ignored not replaced. + /// + /// + public void InsertDocument( DocX remote_document, bool append = true ) + { + // We don't want to effect the origional XDocument, so create a new one from the old one. + var remote_mainDoc = new XDocument( remote_document._mainDoc ); + + XDocument remote_footnotes = null; + if( remote_document._footnotes != null ) + { + remote_footnotes = new XDocument( remote_document._footnotes ); + } + + XDocument remote_endnotes = null; + if( remote_document._endnotes != null ) + { + remote_endnotes = new XDocument( remote_document._endnotes ); + } + + // Remove all header and footer references. + remote_mainDoc.Descendants( XName.Get( "headerReference", w.NamespaceName ) ).Remove(); + remote_mainDoc.Descendants( XName.Get( "footerReference", w.NamespaceName ) ).Remove(); + + // Get the body of the remote document. + var remote_body = remote_mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) ); + + // Every file that is missing from the local document will have to be copied, every file that already exists will have to be merged. + var ppc = remote_document._package.GetParts(); + + var ignoreContentTypes = new List + { + "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", + "application/vnd.openxmlformats-package.core-properties+xml", + "application/vnd.openxmlformats-officedocument.extended-properties+xml", + "application/vnd.openxmlformats-package.relationships+xml" + }; + + var imageContentTypes = new List + { + "image/jpeg", + "image/jpg", + "image/png", + "image/bmp", + "image/gif", + "image/tiff", + "image/icon", + "image/pcx", + "image/emf", + "image/wmf" + }; + // Check if each PackagePart pp exists in this document. + foreach( PackagePart remote_pp in ppc ) + { + if( ignoreContentTypes.Contains( remote_pp.ContentType ) || imageContentTypes.Contains( remote_pp.ContentType ) ) + continue; + + // If this external PackagePart already exits then we must merge them. + if( _package.PartExists( remote_pp.Uri ) ) + { + var local_pp = _package.GetPart( remote_pp.Uri ); + switch( remote_pp.ContentType ) + { + case "application/vnd.openxmlformats-officedocument.custom-properties+xml": + merge_customs( remote_pp, local_pp, remote_mainDoc ); + break; + + // Merge footnotes/endnotes before merging styles, then set the remote_footnotes to the just updated footnotes + case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": + remote_footnotes = _footnotes; + break; + + case "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": + remote_endnotes = _endnotes; + break; + + case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": + merge_styles( remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes ); + break; + + // Merges Styles after merging the footnotes, so the changes will be applied to the correct document/footnotes. + case "application/vnd.ms-word.stylesWithEffects+xml": + merge_styles( remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes ); + break; + + case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml": + merge_fonts( remote_pp, local_pp, remote_mainDoc, remote_document ); + break; + + case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": + merge_numbering( remote_pp, local_pp, remote_mainDoc, remote_document ); + break; + } + } + // If this external PackagePart does not exits in the internal document then we can simply copy it. + else + { + var packagePart = clonePackagePart( remote_pp ); + switch( remote_pp.ContentType ) + { + case "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": + _endnotesPart = packagePart; + _endnotes = remote_endnotes; + break; + + case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": + _footnotesPart = packagePart; + _footnotes = remote_footnotes; + break; + + case "application/vnd.openxmlformats-officedocument.custom-properties+xml": + break; + + case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": + _stylesPart = packagePart; + using( TextReader tr = new StreamReader( _stylesPart.GetStream() ) ) + _styles = XDocument.Load( tr ); + break; + + case "application/vnd.ms-word.stylesWithEffects+xml": + _stylesWithEffectsPart = packagePart; + using( TextReader tr = new StreamReader( _stylesWithEffectsPart.GetStream() ) ) + _stylesWithEffects = XDocument.Load( tr ); + break; + + case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml": + _fontTablePart = packagePart; + using( TextReader tr = new StreamReader( _fontTablePart.GetStream() ) ) + _fontTable = XDocument.Load( tr ); + break; + + case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": + _numberingPart = packagePart; + using( TextReader tr = new StreamReader( _numberingPart.GetStream() ) ) + _numbering = XDocument.Load( tr ); + break; + + } + + clonePackageRelationship( remote_document, remote_pp, remote_mainDoc ); + } + } + + foreach( var hyperlink_rel in remote_document.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ) ) + { + var old_rel_Id = hyperlink_rel.Id; + var new_rel_Id = this.PackagePart.CreateRelationship( hyperlink_rel.TargetUri, hyperlink_rel.TargetMode, hyperlink_rel.RelationshipType ).Id; + var hyperlink_refs = remote_mainDoc.Descendants( XName.Get( "hyperlink", w.NamespaceName ) ); + foreach( var hyperlink_ref in hyperlink_refs ) + { + var a0 = hyperlink_ref.Attribute( XName.Get( "id", r.NamespaceName ) ); + if( a0 != null && a0.Value == old_rel_Id ) + { + a0.SetValue( new_rel_Id ); + } + } + } + + foreach( var oleObject_rel in remote_document.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject" ) ) + { + var oldRelationshipID = oleObject_rel.Id; + var newRelationshipID = this.PackagePart.CreateRelationship( oleObject_rel.TargetUri, oleObject_rel.TargetMode, oleObject_rel.RelationshipType ).Id; + var references = remote_mainDoc.Descendants( XName.Get( "OLEObject", "urn:schemas-microsoft-com:office:office" ) ); + + foreach( var reference in references ) + { + var attribute = reference.Attribute( XName.Get( "id", r.NamespaceName ) ); + if( attribute != null && attribute.Value == oldRelationshipID ) + attribute.SetValue( newRelationshipID ); + } + } + + foreach( PackagePart remote_pp in ppc ) + { + if( imageContentTypes.Contains( remote_pp.ContentType ) ) + { + merge_images( remote_pp, remote_document, remote_mainDoc, remote_pp.ContentType ); + } + } + + int id = 0; + var local_docPrs = _mainDoc.Root.Descendants( XName.Get( "docPr", wp.NamespaceName ) ); + foreach( var local_docPr in local_docPrs ) + { + var a_id = local_docPr.Attribute( XName.Get( "id" ) ); + int a_id_value; + if( a_id != null && int.TryParse( a_id.Value, out a_id_value ) ) + { + if( a_id_value > id ) + { + id = a_id_value; + } + } + } + id++; + + // docPr must be sequential + var docPrs = remote_body.Descendants( XName.Get( "docPr", wp.NamespaceName ) ); + foreach( var docPr in docPrs ) + { + docPr.SetAttributeValue( XName.Get( "id" ), id ); + id++; + } + + // Add the remote documents contents to this document. + var local_body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) ); + if( append ) + { + local_body.Add( remote_body.Elements() ); + } + else + { + local_body.AddFirst( remote_body.Elements() ); + } + + // Copy any missing root attributes to the local document. + foreach( XAttribute a in remote_mainDoc.Root.Attributes() ) + { + if( _mainDoc.Root.Attribute( a.Name ) == null ) + { + _mainDoc.Root.SetAttributeValue( a.Name, a.Value ); + } + } + } + + /// + /// Insert a new Table at the end of this document. + /// + /// The number of columns to create. + /// The number of rows to create. + /// A new Table. + /// + /// Insert a new Table with 2 columns and 3 rows, at the end of a document. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"C:\Example\Test.docx")) + /// { + /// // Create a new Table with 2 columns and 3 rows. + /// Table newTable = document.InsertTable(2, 3); + /// + /// // Set the design of this Table. + /// newTable.Design = TableDesign.LightShadingAccent2; + /// + /// // Set the column names. + /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false); + /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false); + /// + /// // Fill row 1 + /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false); + /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false); + /// + /// // Fill row 2 + /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false); + /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false); + /// + /// // Save all changes made to document b. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public new Table InsertTable( int rowCount, int columnCount ) + { + if( rowCount < 1 || columnCount < 1 ) + throw new ArgumentOutOfRangeException( "Row and Column count must be greater than zero." ); + + var t = base.InsertTable( rowCount, columnCount ); + t.PackagePart = this.PackagePart; + return t; + } + + public Table AddTable( int rowCount, int columnCount ) + { + if( rowCount < 1 || columnCount < 1 ) + throw new ArgumentOutOfRangeException( "Row and Column count must be greater than zero." ); + + var t = new Table( this, HelperFunctions.CreateTable( rowCount, columnCount ) ); + t.PackagePart = this.PackagePart; + return t; + } + + /// + /// Insert a Table into this document. The Table's source can be a completely different document. + /// + /// The Table to insert. + /// The index to insert this Table at. + /// The Table now associated with this document. + /// + /// Extract a Table from document a and insert it into document b, at index 10. + /// + /// // Place holder for a Table. + /// Table t; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx")) + /// { + /// // Get the first Table from this document. + /// t = documentA.Tables[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx")) + /// { + /// /* + /// * Insert the Table that was extracted from document a, into document b. + /// * This creates a new Table that is now associated with document b. + /// */ + /// Table newTable = documentB.InsertTable(10, t); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public new Table InsertTable( int index, Table t ) + { + var t2 = base.InsertTable( index, t ); + t2.PackagePart = this.PackagePart; + return t2; + } + + /// + /// Insert a Table into this document. The Table's source can be a completely different document. + /// + /// The Table to insert. + /// The Table now associated with this document. + /// + /// Extract a Table from document a and insert it at the end of document b. + /// + /// // Place holder for a Table. + /// Table t; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx")) + /// { + /// // Get the first Table from this document. + /// t = documentA.Tables[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx")) + /// { + /// /* + /// * Insert the Table that was extracted from document a, into document b. + /// * This creates a new Table that is now associated with document b. + /// */ + /// Table newTable = documentB.InsertTable(t); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public new Table InsertTable( Table t ) + { + t = base.InsertTable( t ); + t.PackagePart = this.PackagePart; + return t; + } + + /// + /// Insert a new Table at the end of this document. + /// + /// The number of columns to create. + /// The number of rows to create. + /// The index to insert this Table at. + /// A new Table. + /// + /// Insert a new Table with 2 columns and 3 rows, at index 37 in this document. + /// + /// // Create a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Create a new Table with 3 rows and 2 columns. Insert this Table at index 37. + /// Table newTable = document.InsertTable(37, 3, 2); + /// + /// // Set the design of this Table. + /// newTable.Design = TableDesign.LightShadingAccent3; + /// + /// // Set the column names. + /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false); + /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false); + /// + /// // Fill row 1 + /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false); + /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false); + /// + /// // Fill row 2 + /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false); + /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false); + /// + /// // Save all changes made to document b. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public new Table InsertTable( int index, int rowCount, int columnCount ) + { + if( rowCount < 1 || columnCount < 1 ) + throw new ArgumentOutOfRangeException( "Row and Column count must be greater than zero." ); + + var t = base.InsertTable( index, rowCount, columnCount ); + t.PackagePart = this.PackagePart; + return t; + } + + /// + /// Creates a document using a Stream. + /// + /// The Stream to create the document from. + /// + /// Returns a DocX object which represents the document. + /// + /// Creating a document from a FileStream. + /// + /// // Use a FileStream fs to create a new document. + /// using(FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Create)) + /// { + /// // Load the document using fs + /// using (DocX document = DocX.Create(fs)) + /// { + /// // Do something with the document here. + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// } + /// + /// + /// + /// Creating a document in a SharePoint site. + /// + /// using(SPSite mySite = new SPSite("http://server/sites/site")) + /// { + /// // Open a connection to the SharePoint site + /// using(SPWeb myWeb = mySite.OpenWeb()) + /// { + /// // Create a MemoryStream ms. + /// using (MemoryStream ms = new MemoryStream()) + /// { + /// // Create a document using ms. + /// using (DocX document = DocX.Create(ms)) + /// { + /// // Do something with the document here. + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory + /// + /// // Add the document to the SharePoint site + /// web.Files.Add("filename", ms.ToArray(), true); + /// } + /// } + /// } + /// + /// + /// + /// + /// + public static DocX Create( Stream stream, DocumentTypes documentType = DocumentTypes.Document ) + { + var document = CreateDocument( documentType ); + document._stream = stream; + return document; + } + + /// + /// Creates a document using a fully qualified or relative filename. + /// + /// The fully qualified or relative filename. + /// + /// Returns a DocX object which represents the document. + /// + /// + /// // Create a document using a relative filename. + /// using (DocX document = DocX.Create(@"..\Test.docx")) + /// { + /// // Do something with the document here. + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory + /// + /// + /// // Create a document using a relative filename. + /// using (DocX document = DocX.Create(@"..\Test.docx")) + /// { + /// // Do something with the document here. + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory + /// + /// + /// + /// + /// + public static DocX Create( string filename, DocumentTypes documentType = DocumentTypes.Document ) + { + var document = CreateDocument( documentType ); + document._filename = filename; + return document; + } + + /// + /// Loads a document into a DocX object using a Stream. + /// + /// The Stream to load the document from. + /// + /// Returns a DocX object which represents the document. + /// + /// + /// Loading a document from a FileStream. + /// + /// // Open a FileStream fs to a document. + /// using (FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Open)) + /// { + /// // Load the document using fs. + /// using (DocX document = DocX.Load(fs)) + /// { + /// // Do something with the document here. + /// + /// // Save all changes made to the document. + /// document.Save(); + /// }// Release this document from memory. + /// } + /// + /// + /// + /// Loading a document from a SharePoint site. + /// + /// // Get the SharePoint site that you want to access. + /// using (SPSite mySite = new SPSite("http://server/sites/site")) + /// { + /// // Open a connection to the SharePoint site + /// using (SPWeb myWeb = mySite.OpenWeb()) + /// { + /// // Grab a document stored on this site. + /// SPFile file = web.GetFile("Source_Folder_Name/Source_File"); + /// + /// // DocX.Load requires a Stream, so open a Stream to this document. + /// Stream str = new MemoryStream(file.OpenBinary()); + /// + /// // Load the file using the Stream str. + /// using (DocX document = DocX.Load(str)) + /// { + /// // Do something with the document here. + /// + /// // Save all changes made to the document. + /// document.Save(); + /// }// Release this document from memory. + /// } + /// } + /// + /// + /// + /// + public static DocX Load( Stream stream ) + { + var ms = new MemoryStream(); + + stream.Position = 0; + var data = new byte[ stream.Length ]; + stream.Read( data, 0, ( int )stream.Length ); + ms.Write( data, 0, ( int )stream.Length ); + + // Open the docx package + var package = Package.Open( ms, FileMode.Open, FileAccess.ReadWrite ); + + var document = DocX.PostLoad( ref package ); + document._package = package; + document._memoryStream = ms; + document._stream = stream; + return document; + } + + /// + /// Loads a document into a DocX object using a fully qualified or relative filename. + /// + /// The fully qualified or relative filename. + /// + /// Returns a DocX object which represents the document. + /// + /// + /// + /// // Load a document using its fully qualified filename + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Do something with the document here + /// + /// // Save all changes made to document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// // Load a document using its relative filename. + /// using(DocX document = DocX.Load(@"..\..\Test.docx")) + /// { + /// // Do something with the document here. + /// + /// // Save all changes made to document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// + /// + public static DocX Load( string filename ) + { + if( !File.Exists( filename ) ) + throw new FileNotFoundException( string.Format( "File could not be found {0}", filename ) ); + + var ms = new MemoryStream(); + + using( FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + var data = new byte[ fs.Length ]; + fs.Read( data, 0, ( int )fs.Length ); + ms.Write( data, 0, ( int )fs.Length ); + } + + // Open the docx package + var package = Package.Open( ms, FileMode.Open, FileAccess.ReadWrite ); + + var document = PostLoad( ref package ); + document._package = package; + document._filename = filename; + document._memoryStream = ms; + + return document; + } + + /// + /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. + /// + ///The path to the document template file. + ///The document template file not found. + public void ApplyTemplate( string templateFilePath ) + { + ApplyTemplate( templateFilePath, true ); + } + + /// + /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. + /// + ///The path to the document template file. + ///Whether to copy the document template text content to document. + ///The document template file not found. + public void ApplyTemplate( string templateFilePath, bool includeContent ) + { + if( !File.Exists( templateFilePath ) ) + { + throw new FileNotFoundException( string.Format( "File could not be found {0}", templateFilePath ) ); + } + using( FileStream packageStream = new FileStream( templateFilePath, FileMode.Open, FileAccess.Read ) ) + { + ApplyTemplate( packageStream, includeContent ); + } + } + + /// + /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. + /// + ///The stream of the document template file. + public void ApplyTemplate( Stream templateStream ) + { + ApplyTemplate( templateStream, true ); + } + + /// + /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content. + /// + ///The stream of the document template file. + ///Whether to copy the document template text content to document. + public void ApplyTemplate( Stream templateStream, bool includeContent ) + { + var templatePackage = Package.Open( templateStream ); + try + { + PackagePart documentPart = null; + XDocument documentDoc = null; + foreach( PackagePart packagePart in templatePackage.GetParts() ) + { + switch( packagePart.Uri.ToString() ) + { + case "/word/document.xml": + documentPart = packagePart; + using( XmlReader xr = XmlReader.Create( packagePart.GetStream( FileMode.Open, FileAccess.Read ) ) ) + { + documentDoc = XDocument.Load( xr ); + } + break; + case "/_rels/.rels": + if( !_package.PartExists( packagePart.Uri ) ) + { + _package.CreatePart( packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption ); + } + var globalRelsPart = _package.GetPart( packagePart.Uri ); + using( + var tr = new StreamReader( + packagePart.GetStream( FileMode.Open, FileAccess.Read ), Encoding.UTF8 ) ) + { + using( + var tw = new StreamWriter( + new PackagePartStream( globalRelsPart.GetStream( FileMode.Create, FileAccess.Write ) ), Encoding.UTF8 ) ) + { + tw.Write( tr.ReadToEnd() ); + } + } + break; + case "/word/_rels/document.xml.rels": + break; + default: + if( !_package.PartExists( packagePart.Uri ) ) + { + _package.CreatePart( packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption ); + } + var packagePartEncoding = Encoding.Default; + if( packagePart.Uri.ToString().EndsWith( ".xml" ) || packagePart.Uri.ToString().EndsWith( ".rels" ) ) + { + packagePartEncoding = Encoding.UTF8; + } + var nativePart = _package.GetPart( packagePart.Uri ); + using( + var tr = new StreamReader( + packagePart.GetStream( FileMode.Open, FileAccess.Read ), packagePartEncoding ) ) + { + using( + var tw = new StreamWriter( + new PackagePartStream( nativePart.GetStream( FileMode.Create, FileAccess.Write ) ), tr.CurrentEncoding ) ) + { + tw.Write( tr.ReadToEnd() ); + } + } + break; + } + } + if( documentPart != null ) + { + string mainContentType = documentPart.ContentType.Replace( "template.main", "document.main" ); + if( _package.PartExists( documentPart.Uri ) ) + { + _package.DeletePart( documentPart.Uri ); + } + var documentNewPart = _package.CreatePart( + documentPart.Uri, mainContentType, documentPart.CompressionOption ); + using( XmlWriter xw = XmlWriter.Create( new PackagePartStream( documentNewPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + documentDoc.WriteTo( xw ); + } + foreach( PackageRelationship documentPartRel in documentPart.GetRelationships() ) + { + documentNewPart.CreateRelationship( + documentPartRel.TargetUri, + documentPartRel.TargetMode, + documentPartRel.RelationshipType, + documentPartRel.Id ); + } + this.PackagePart = documentNewPart; + _mainDoc = documentDoc; + PopulateDocument( this, templatePackage ); + + // DragonFire: I added next line and recovered ApplyTemplate method. + // I do it, becouse PopulateDocument(...) writes into field "settingsPart" the part of Template's package + // and after line "templatePackage.Close();" in finally, field "settingsPart" becomes not available and method "Save" throw an exception... + // That's why I recreated settingsParts and unlinked it from Template's package =) + _settingsPart = HelperFunctions.CreateOrGetSettingsPart( _package ); + } + if( !includeContent ) + { + foreach( Paragraph paragraph in this.Paragraphs ) + { + paragraph.Remove( false ); + } + } + } + finally + { + _package.Flush(); + var documentRelsPart = _package.GetPart( new Uri( "/word/_rels/document.xml.rels", UriKind.Relative ) ); + using( TextReader tr = new StreamReader( documentRelsPart.GetStream( FileMode.Open, FileAccess.Read ) ) ) + { + tr.Read(); + } + templatePackage.Close(); + PopulateDocument( Document, _package ); + } + } + + /// + /// Add an Image into this document from a fully qualified or relative filename. + /// + /// The fully qualified or relative filename. + /// An Image file. + /// + /// Add an Image into this document from a fully qualified filename. + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Add an Image from a file. + /// document.AddImage(@"C:\Example\Image.png"); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// + /// + public Image AddImage( string filename ) + { + string contentType = ""; + + // The extension this file has will be taken to be its format. + switch( Path.GetExtension( filename ) ) + { + case ".tiff": + contentType = "image/tif"; + break; + case ".tif": + contentType = "image/tif"; + break; + case ".png": + contentType = "image/png"; + break; + case ".bmp": + contentType = "image/png"; + break; + case ".gif": + contentType = "image/gif"; + break; + case ".jpg": + contentType = "image/jpg"; + break; + case ".jpeg": + contentType = "image/jpeg"; + break; + default: + contentType = "image/jpg"; + break; + } + + return AddImage( filename, contentType ); + } + + /// + /// Add an Image into this document from a Stream. + /// + /// A Stream stream. + /// An Image file. + /// + /// Add an Image into a document using a Stream. + /// + /// // Open a FileStream fs to an Image. + /// using (FileStream fs = new FileStream(@"C:\Example\Image.jpg", FileMode.Open)) + /// { + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Add an Image from a filestream fs. + /// document.AddImage(fs); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// } + /// + /// + /// + /// + public Image AddImage( Stream stream ) + { + return AddImage( stream as object ); + } + + /// + /// Adds a hyperlink to a document and creates a Paragraph which uses it. + /// + /// The text as displayed by the hyperlink. + /// The hyperlink itself. + /// Returns a hyperlink that can be inserted into a Paragraph. + /// + /// Adds a hyperlink to a document and creates a Paragraph which uses it. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add a hyperlink to this document. + /// Hyperlink h = document.AddHyperlink("Google", new Uri("http://www.google.com")); + /// + /// // Add a new Paragraph to this document. + /// Paragraph p = document.InsertParagraph(); + /// p.Append("My favourite search engine is "); + /// p.AppendHyperlink(h); + /// p.Append(", I think it's great."); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + public Hyperlink AddHyperlink( string text, Uri uri ) + { + var i = new XElement + ( + XName.Get( "hyperlink", w.NamespaceName ), + new XAttribute( r + "id", string.Empty ), + new XAttribute( w + "history", "1" ), + new XElement( XName.Get( "r", w.NamespaceName ), + new XElement( XName.Get( "rPr", w.NamespaceName ), + new XElement( XName.Get( "rStyle", w.NamespaceName ), + new XAttribute( w + "val", "Hyperlink" ) ) ), + new XElement( XName.Get( "t", w.NamespaceName ), text ) ) + ); + + var h = new Hyperlink( this, this.PackagePart, i ); + + h.text = text; + h.uri = uri; + + this.AddHyperlinkStyleIfNotPresent(); + + return h; + } + + /// + /// Adds three new Headers to this document. One for the first page, one for odd pages and one for even pages. + /// + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add header support to this document. + /// document.AddHeaders(); + /// + /// // Get a collection of all headers in this document. + /// Headers headers = document.Headers; + /// + /// // The header used for the first page of this document. + /// Header first = headers.first; + /// + /// // The header used for odd pages of this document. + /// Header odd = headers.odd; + /// + /// // The header used for even pages of this document. + /// Header even = headers.even; + /// + /// // Force the document to use a different header for first, odd and even pages. + /// document.DifferentFirstPage = true; + /// document.DifferentOddAndEvenPages = true; + /// + /// // Content can be added to the Headers in the same manor that it would be added to the main document. + /// Paragraph p = first.InsertParagraph(); + /// p.Append("This is the first pages header."); + /// + /// // Save all changes to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + public void AddHeaders() + { + this.AddHeadersOrFooters( true ); + + _headers.Odd = Document.GetHeaderByType( "default" ); + _headers.Even = Document.GetHeaderByType( "even" ); + _headers.First = Document.GetHeaderByType( "first" ); + } + + /// + /// Adds three new Footers to this document. One for the first page, one for odd pages and one for even pages. + /// + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add footer support to this document. + /// document.AddFooters(); + /// + /// // Get a collection of all footers in this document. + /// Footers footers = document.Footers; + /// + /// // The footer used for the first page of this document. + /// Footer first = footers.first; + /// + /// // The footer used for odd pages of this document. + /// Footer odd = footers.odd; + /// + /// // The footer used for even pages of this document. + /// Footer even = footers.even; + /// + /// // Force the document to use a different footer for first, odd and even pages. + /// document.DifferentFirstPage = true; + /// document.DifferentOddAndEvenPages = true; + /// + /// // Content can be added to the Footers in the same manor that it would be added to the main document. + /// Paragraph p = first.InsertParagraph(); + /// p.Append("This is the first pages footer."); + /// + /// // Save all changes to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + public void AddFooters() + { + AddHeadersOrFooters( false ); + + _footers.Odd = Document.GetFooterByType( "default" ); + _footers.Even = Document.GetFooterByType( "even" ); + _footers.First = Document.GetFooterByType( "first" ); + } + + /// + /// Save this document back to the location it was loaded from. + /// + /// + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Add an Image from a file. + /// document.AddImage(@"C:\Example\Image.jpg"); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// + /// + /// + /// + public void Save() + { + var headers = Headers; + + // Save the main document + using( TextWriter tw = new StreamWriter( new PackagePartStream( this.PackagePart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + _mainDoc.Save( tw, SaveOptions.None ); + } + + if( (_settings == null) || !this.isProtected ) + { + using( TextReader textReader = new StreamReader( _settingsPart.GetStream() ) ) + { + _settings = XDocument.Load( textReader ); + } + } + + var body = _mainDoc.Root.Element( w + "body" ); + var sectPr = body.Descendants( w + "sectPr" ).FirstOrDefault(); + + if( sectPr != null ) + { + var evenHeaderRef = + ( + from e in _mainDoc.Descendants( w + "headerReference" ) + let type = e.Attribute( w + "type" ) + where type != null && type.Value.Equals( "even", StringComparison.CurrentCultureIgnoreCase ) + select e.Attribute( r + "id" ).Value + ).LastOrDefault(); + + if( evenHeaderRef != null ) + { + var even = headers.Even.Xml; + + var target = PackUriHelper.ResolvePartUri + ( + this.PackagePart.Uri, + this.PackagePart.GetRelationship( evenHeaderRef ).TargetUri + ); + + using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + new XDocument + ( + new XDeclaration( "1.0", "UTF-8", "yes" ), + even + ).Save( tw, SaveOptions.None ); + } + } + + var oddHeaderRef = + ( + from e in _mainDoc.Descendants( w + "headerReference" ) + let type = e.Attribute( w + "type" ) + where type != null && type.Value.Equals( "default", StringComparison.CurrentCultureIgnoreCase ) + select e.Attribute( r + "id" ).Value + ).LastOrDefault(); + + if( oddHeaderRef != null ) + { + var odd = headers.Odd.Xml; + + var target = PackUriHelper.ResolvePartUri + ( + this.PackagePart.Uri, + this.PackagePart.GetRelationship( oddHeaderRef ).TargetUri + ); + + // Save header1 + using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + new XDocument + ( + new XDeclaration( "1.0", "UTF-8", "yes" ), + odd + ).Save( tw, SaveOptions.None ); + } + } + + var firstHeaderRef = + ( + from e in _mainDoc.Descendants( w + "headerReference" ) + let type = e.Attribute( w + "type" ) + where type != null && type.Value.Equals( "first", StringComparison.CurrentCultureIgnoreCase ) + select e.Attribute( r + "id" ).Value + ).LastOrDefault(); + + if( firstHeaderRef != null ) + { + var first = headers.First.Xml; + var target = PackUriHelper.ResolvePartUri + ( + this.PackagePart.Uri, + this.PackagePart.GetRelationship( firstHeaderRef ).TargetUri + ); + + // Save header3 + using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + new XDocument + ( + new XDeclaration( "1.0", "UTF-8", "yes" ), + first + ).Save( tw, SaveOptions.None ); + } + } + + var oddFooterRef = + ( + from e in _mainDoc.Descendants( w + "footerReference" ) + let type = e.Attribute( w + "type" ) + where type != null && type.Value.Equals( "default", StringComparison.CurrentCultureIgnoreCase ) + select e.Attribute( r + "id" ).Value + ).LastOrDefault(); + + if( oddFooterRef != null ) + { + var odd = _footers.Odd.Xml; + var target = PackUriHelper.ResolvePartUri + ( + this.PackagePart.Uri, + this.PackagePart.GetRelationship( oddFooterRef ).TargetUri + ); + + // Save header1 + using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + new XDocument + ( + new XDeclaration( "1.0", "UTF-8", "yes" ), + odd + ).Save( tw, SaveOptions.None ); + } + } + + var evenFooterRef = + ( + from e in _mainDoc.Descendants( w + "footerReference" ) + let type = e.Attribute( w + "type" ) + where type != null && type.Value.Equals( "even", StringComparison.CurrentCultureIgnoreCase ) + select e.Attribute( r + "id" ).Value + ).LastOrDefault(); + + if( evenFooterRef != null ) + { + var even = _footers.Even.Xml; + var target = PackUriHelper.ResolvePartUri + ( + this.PackagePart.Uri, + this.PackagePart.GetRelationship( evenFooterRef ).TargetUri + ); + + // Save header2 + using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + new XDocument + ( + new XDeclaration( "1.0", "UTF-8", "yes" ), + even + ).Save( tw, SaveOptions.None ); + } + } + + var firstFooterRef = + ( + from e in _mainDoc.Descendants( w + "footerReference" ) + let type = e.Attribute( w + "type" ) + where type != null && type.Value.Equals( "first", StringComparison.CurrentCultureIgnoreCase ) + select e.Attribute( r + "id" ).Value + ).LastOrDefault(); + + if( firstFooterRef != null ) + { + var first = _footers.First.Xml; + var target = PackUriHelper.ResolvePartUri + ( + this.PackagePart.Uri, + this.PackagePart.GetRelationship( firstFooterRef ).TargetUri + ); + + // Save header3 + using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + new XDocument + ( + new XDeclaration( "1.0", "UTF-8", "yes" ), + first + ).Save( tw, SaveOptions.None ); + } + } + + // Save the settings document. + using( TextWriter tw = new StreamWriter( new PackagePartStream( _settingsPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + _settings.Save( tw, SaveOptions.None ); + } + + if( _endnotesPart != null ) + { + using( TextWriter tw = new StreamWriter( new PackagePartStream( _endnotesPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + _endnotes.Save( tw, SaveOptions.None ); + } + } + + if( _footnotesPart != null ) + { + using( TextWriter tw = new StreamWriter( new PackagePartStream( _footnotesPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + _footnotes.Save( tw, SaveOptions.None ); + } + } + + if( _stylesPart != null ) + { + using( TextWriter tw = new StreamWriter( new PackagePartStream( _stylesPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + _styles.Save( tw, SaveOptions.None ); + } + } + + if( _stylesWithEffectsPart != null ) + { + using( TextWriter tw = new StreamWriter( new PackagePartStream( _stylesWithEffectsPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + _stylesWithEffects.Save( tw, SaveOptions.None ); + } + } + + if( _numberingPart != null ) + { + using( TextWriter tw = new StreamWriter( new PackagePartStream( _numberingPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + _numbering.Save( tw, SaveOptions.None ); + } + } + + if( _fontTablePart != null ) + { + using( TextWriter tw = new StreamWriter( new PackagePartStream( _fontTablePart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + _fontTable.Save( tw, SaveOptions.None ); + } + } + } + + // Close the document so that it can be saved. + _package.Flush(); + + #region Save this document back to a file or stream, that was specified by the user at save time. + if( _filename != null ) + { + using( FileStream fs = new FileStream( _filename, FileMode.Create ) ) + { + fs.Write( _memoryStream.ToArray(), 0, ( int )_memoryStream.Length ); + } + } + else if( _stream.CanSeek ) //Check if stream can be seeked to support System.Web.HttpResponseStream. + { + // Set the length of this stream to 0 + _stream.SetLength( 0 ); + + // Write to the beginning of the stream + _stream.Position = 0; + + _memoryStream.WriteTo( _stream ); + _memoryStream.Flush(); + } + #endregion + } + + /// + /// Save this document to a file. + /// + /// The filename to save this document as. + /// + /// Load a document from one file and save it to another. + /// + /// // Load a document using its fully qualified filename. + /// DocX document = DocX.Load(@"C:\Example\Test1.docx"); + /// + /// // Insert a new Paragraph + /// document.InsertParagraph("Hello world!", false); + /// + /// // Save the document to a new location. + /// document.SaveAs(@"C:\Example\Test2.docx"); + /// + /// + /// + /// Load a document from a Stream and save it to a file. + /// + /// DocX document; + /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open)) + /// { + /// // Load a document using a stream. + /// document = DocX.Load(fs1); + /// + /// // Insert a new Paragraph + /// document.InsertParagraph("Hello world again!", false); + /// } + /// + /// // Save the document to a new location. + /// document.SaveAs(@"C:\Example\Test2.docx"); + /// + /// + /// + /// + /// + public void SaveAs( string filename ) + { + _filename = filename; + _stream = null; + Save(); + } + + /// + /// Save this document to a Stream. + /// + /// The Stream to save this document to. + /// + /// Load a document from a file and save it to a Stream. + /// + /// // Place holder for a document. + /// DocX document; + /// + /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open)) + /// { + /// // Load a document using a stream. + /// document = DocX.Load(fs1); + /// + /// // Insert a new Paragraph + /// document.InsertParagraph("Hello world again!", false); + /// } + /// + /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create)) + /// { + /// // Save the document to a different stream. + /// document.SaveAs(fs2); + /// } + /// + /// // Release this document from memory. + /// document.Dispose(); + /// + /// + /// + /// Load a document from one Stream and save it to another. + /// + /// DocX document; + /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open)) + /// { + /// // Load a document using a stream. + /// document = DocX.Load(fs1); + /// + /// // Insert a new Paragraph + /// document.InsertParagraph("Hello world again!", false); + /// } + /// + /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create)) + /// { + /// // Save the document to a different stream. + /// document.SaveAs(fs2); + /// } + /// + /// + /// + /// + /// + public void SaveAs( Stream stream ) + { + _filename = null; + _stream = stream; + Save(); + } + + /// + /// Add a core property to this document. If a core property already exists with the same name it will be replaced. Core property names are case insensitive. + /// + ///The property name. + ///The property value. + /// + /// Add a core properties of each type to a document. + /// + /// // Load Example.docx + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // If this document does not contain a core property called 'forename', create one. + /// if (!document.CoreProperties.ContainsKey("forename")) + /// { + /// // Create a new core property called 'forename' and set its value. + /// document.AddCoreProperty("forename", "Cathal"); + /// } + /// + /// // Get this documents core property called 'forename'. + /// string forenameValue = document.CoreProperties["forename"]; + /// + /// // Print all of the information about this core property to Console. + /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", "forename", forenameValue)); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } // Release this document from memory. + /// + /// // Wait for the user to press a key before exiting. + /// Console.ReadKey(); + /// + /// + /// + /// + /// + public void AddCoreProperty( string propertyName, string propertyValue ) + { + var propertyNamespacePrefix = propertyName.Contains(":") ? propertyName.Split(':')[0] : "cp"; + var propertyLocalName = propertyName.Contains(":") ? propertyName.Split(':')[1] : propertyName; + + // If this document does not contain a coreFilePropertyPart create one.) + if( !_package.PartExists( new Uri( "/docProps/core.xml", UriKind.Relative ) ) ) + throw new Exception( "Core properties part doesn't exist." ); + + XDocument corePropDoc; + var corePropPart = _package.GetPart( new Uri( "/docProps/core.xml", UriKind.Relative ) ); + using( TextReader tr = new StreamReader( corePropPart.GetStream( FileMode.Open, FileAccess.Read ) ) ) + { + corePropDoc = XDocument.Load( tr ); + } + + var corePropElement = + ( from propElement in corePropDoc.Root.Elements() + where ( propElement.Name.LocalName.Equals( propertyLocalName ) ) + select propElement ).SingleOrDefault(); + if( corePropElement != null ) + { + corePropElement.SetValue( propertyValue ); + } + else + { + var propertyNamespace = corePropDoc.Root.GetNamespaceOfPrefix( propertyNamespacePrefix ); + corePropDoc.Root.Add( new XElement( XName.Get( propertyLocalName, propertyNamespace.NamespaceName ), propertyValue ) ); + } + + using( TextWriter tw = new StreamWriter( new PackagePartStream( corePropPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + corePropDoc.Save( tw ); + } + DocX.UpdateCorePropertyValue( this, propertyLocalName, propertyValue ); + } + + /// + /// Add a custom property to this document. If a custom property already exists with the same name it will be replace. CustomProperty names are case insensitive. + /// + /// The CustomProperty to add to this document. + /// + /// Add a custom properties of each type to a document. + /// + /// // Load Example.docx + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // A CustomProperty called forename which stores a string. + /// CustomProperty forename; + /// + /// // If this document does not contain a custom property called 'forename', create one. + /// if (!document.CustomProperties.ContainsKey("forename")) + /// { + /// // Create a new custom property called 'forename' and set its value. + /// document.AddCustomProperty(new CustomProperty("forename", "Cathal")); + /// } + /// + /// // Get this documents custom property called 'forename'. + /// forename = document.CustomProperties["forename"]; + /// + /// // Print all of the information about this CustomProperty to Console. + /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", forename.Name, forename.Value)); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } // Release this document from memory. + /// + /// // Wait for the user to press a key before exiting. + /// Console.ReadKey(); + /// + /// + /// + /// + public void AddCustomProperty( CustomProperty cp ) + { + // If this document does not contain a customFilePropertyPart create one. + if( !_package.PartExists( new Uri( "/docProps/custom.xml", UriKind.Relative ) ) ) + { + HelperFunctions.CreateCustomPropertiesPart( this ); + } + + XDocument customPropDoc; + var customPropPart = _package.GetPart( new Uri( "/docProps/custom.xml", UriKind.Relative ) ); + using( TextReader tr = new StreamReader( customPropPart.GetStream( FileMode.Open, FileAccess.Read ) ) ) + { + customPropDoc = XDocument.Load( tr, LoadOptions.PreserveWhitespace ); + } + + // Each custom property has a PID, get the highest PID in this document. + IEnumerable pids = + ( + from d in customPropDoc.Descendants() + where d.Name.LocalName == "property" + select int.Parse( d.Attribute( XName.Get( "pid" ) ).Value ) + ); + + int pid = 1; + if( pids.Count() > 0 ) + { + pid = pids.Max(); + } + + // Check if a custom property already exists with this name + var customProperty = + ( + from d in customPropDoc.Descendants() + where ( d.Name.LocalName == "property" ) && ( d.Attribute( XName.Get( "name" ) ).Value.Equals( cp.Name, StringComparison.InvariantCultureIgnoreCase ) ) + select d + ).SingleOrDefault(); + + // If a custom property with this name already exists remove it. + if( customProperty != null ) + { + customProperty.Remove(); + } + + var propertiesElement = customPropDoc.Element( XName.Get( "Properties", customPropertiesSchema.NamespaceName ) ); + propertiesElement.Add + ( + new XElement + ( + XName.Get( "property", customPropertiesSchema.NamespaceName ), + new XAttribute( "fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}" ), + new XAttribute( "pid", pid + 1 ), + new XAttribute( "name", cp.Name ), + new XElement( customVTypesSchema + cp.Type, cp.Value ?? "" ) + ) + ); + + // Save the custom properties + using( TextWriter tw = new StreamWriter( new PackagePartStream( customPropPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + customPropDoc.Save( tw, SaveOptions.None ); + } + + // Refresh all fields in this document which display this custom property. + DocX.UpdateCustomPropertyValue( this, cp.Name, ( cp.Value ?? "" ).ToString() ); + } + + public override Paragraph InsertParagraph() + { + var p = base.InsertParagraph(); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( int index, string text, bool trackChanges ) + { + var p = base.InsertParagraph( index, text, trackChanges ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( Paragraph p ) + { + p.PackagePart = this.PackagePart; + return base.InsertParagraph( p ); + } + + public override Paragraph InsertParagraph( int index, Paragraph p ) + { + p.PackagePart = this.PackagePart; + return base.InsertParagraph( index, p ); + } + + public override Paragraph InsertParagraph( int index, string text, bool trackChanges, Formatting formatting ) + { + var p = base.InsertParagraph( index, text, trackChanges, formatting ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( string text ) + { + var p = base.InsertParagraph( text ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( string text, bool trackChanges ) + { + var p = base.InsertParagraph( text, trackChanges ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( string text, bool trackChanges, Formatting formatting ) + { + var p = base.InsertParagraph( text, trackChanges, formatting ); + p.PackagePart = this.PackagePart; + + return p; + } + + public Paragraph[] InsertParagraphs( string text ) + { + var textArray = text.Split( '\n' ); + var paragraphs = new List(); + foreach( var textForParagraph in textArray ) + { + var p = base.InsertParagraph( text ); + p.PackagePart = this.PackagePart; + paragraphs.Add( p ); + } + return paragraphs.ToArray(); + } + + /// + /// Create an equation and insert it in the new paragraph + /// + public override Paragraph InsertEquation( String equation ) + { + var p = base.InsertEquation( equation ); + p.PackagePart = this.PackagePart; + return p; + } + + /// + /// Insert a chart in document + /// + public void InsertChart( Chart chart ) + { + this.InsertChart( chart, null ); + } + + /// + /// Insert a chart in document after the specified paragraph + /// + public void InsertChartAfterParagraph( Chart chart, Paragraph paragraph ) + { + this.InsertChart( chart, paragraph ); + } + + private void InsertChart( Chart chart, Paragraph paragraph ) + { + Paragraph p; + + // Create a new chart part uri. + var chartPartUriPath = String.Empty; + var chartIndex = 1; + do + { + chartPartUriPath = String.Format( "/word/charts/chart{0}.xml", chartIndex ); + chartIndex++; + } while( _package.PartExists( new Uri( chartPartUriPath, UriKind.Relative ) ) ); + + // Create chart part. + var chartPackagePart = _package.CreatePart( new Uri( chartPartUriPath, UriKind.Relative ), "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", CompressionOption.Normal ); + + // Create a new chart relationship + var relID = this.GetNextFreeRelationshipID(); + var rel = this.PackagePart.CreateRelationship( chartPackagePart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", relID ); + + // Save a chart info the chartPackagePart + if( paragraph == null ) + { + using( TextWriter tw = new StreamWriter( new PackagePartStream( chartPackagePart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + chart.Xml.Save( tw ); + } + p = InsertParagraph(); + } + else + { + using( TextWriter tw = new StreamWriter( chartPackagePart.GetStream( FileMode.Create, FileAccess.Write ) ) ) + { + chart.Xml.Save( tw ); + } + p = paragraph; + } + + // Insert a new chart into a paragraph. + var chartElement = new XElement( XName.Get( "r", w.NamespaceName ), + new XElement( XName.Get( "drawing", w.NamespaceName ), + new XElement( XName.Get( "inline", wp.NamespaceName ), + new XElement( XName.Get( "extent", wp.NamespaceName ), new XAttribute( "cx", "5486400" ), new XAttribute( "cy", "3200400" ) ), + new XElement( XName.Get( "effectExtent", wp.NamespaceName ), new XAttribute( "l", "0" ), new XAttribute( "t", "0" ), new XAttribute( "r", "19050" ), new XAttribute( "b", "19050" ) ), + new XElement( XName.Get( "docPr", wp.NamespaceName ), new XAttribute( "id", "1" ), new XAttribute( "name", "chart" ) ), + new XElement( XName.Get( "graphic", a.NamespaceName ), + new XElement( XName.Get( "graphicData", a.NamespaceName ), + new XAttribute( "uri", c.NamespaceName ), + new XElement( XName.Get( "chart", c.NamespaceName ), + new XAttribute( XName.Get( "id", r.NamespaceName ), relID ) ) ) ) ) ) ); + p.Xml.Add( chartElement ); + } + + public List
GetSections() + { + var paragraphs = Paragraphs; + var sections = new List
(); + var sectionParagraphs = new List(); + + foreach( Paragraph paragraph in paragraphs ) + { + + var sectionInPara = paragraph.Xml.Descendants().FirstOrDefault( s => s.Name.LocalName == "sectPr" ); + + if( sectionInPara != null ) + { + sectionParagraphs.Add( paragraph ); + + var section = new Section( Document, sectionInPara ); + section.SectionParagraphs = sectionParagraphs; + + sections.Add( section ); + sectionParagraphs = new List(); + } + else + { + sectionParagraphs.Add( paragraph ); + } + } + + XElement body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) ); + XElement baseSectionXml = body.Element( XName.Get( "sectPr", w.NamespaceName ) ); + + var baseSection = new Section( Document, baseSectionXml ); + baseSection.SectionParagraphs = sectionParagraphs; + sections.Add( baseSection ); + + return sections; + } + + /// + /// Create a new List + /// + public List AddList( string listText = null, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false ) + { + return AddListItem( new List( this, null ), listText, level, listType, startNumber, trackChanges, continueNumbering ); + } + + /// + /// Add a list item to an existing list + /// + public List AddListItem( List list, string listText, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false ) + { + if( startNumber.HasValue && continueNumbering ) + throw new InvalidOperationException( "Cannot specify a start number and at the same time continue numbering from another list" ); + + var result = HelperFunctions.CreateItemInList( list, listText, level, listType, startNumber, trackChanges, continueNumbering ); + var lastItem = result.Items.LastOrDefault(); + + if( lastItem != null ) + { + lastItem.PackagePart = this.PackagePart; + } + + return result; + } + + /// + /// Insert a list in the document + /// + /// The list to insert into the document. + /// The list that was inserted into the document. + public override List InsertList( List list ) + { + base.InsertList( list ); + return list; + } + + public override List InsertList( List list, Font fontFamily, double fontSize ) + { + base.InsertList( list, fontFamily, fontSize ); + return list; + } + + public override List InsertList( List list, double fontSize ) + { + base.InsertList( list, fontSize ); + return list; + } + + /// + /// Insert a list at an index location in the document + /// + /// Index in document to insert the list. + /// The list that was inserted into the document. + /// + public new List InsertList( int index, List list ) + { + base.InsertList( index, list ); + return list; + } + + /// + /// Insert a default Table of Contents in the current document + /// + public TableOfContents InsertDefaultTableOfContents() + { + return InsertTableOfContents( "Table of contents", TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | TableOfContentsSwitches.U ); + } + + /// + /// Insert a Table of Contents in the current document + /// + public TableOfContents InsertTableOfContents( string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null ) + { + var toc = TableOfContents.CreateTableOfContents( this, title, switches, headerStyle, maxIncludeLevel, rightTabPos ); + Xml.Add( toc.Xml ); + return toc; + } + + /// + /// Insert a Table of Contents in the current document at a specific location (prior to the referenced paragraph) + /// + public TableOfContents InsertTableOfContents( Paragraph reference, string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null ) + { + var toc = TableOfContents.CreateTableOfContents( this, title, switches, headerStyle, maxIncludeLevel, rightTabPos ); + reference.Xml.AddBeforeSelf( toc.Xml ); + return toc; + } + + /// + /// Copy the Document into a new Document + /// + /// Returns a copy of a the Document + public DocX Copy() + { + var memorystream = new MemoryStream(); + this.SaveAs( memorystream ); + memorystream.Seek( 0, SeekOrigin.Begin ); + return Load( memorystream ); + } + + public void AddPasswordProtection( EditRestrictions editRestrictions, string password ) + { + // Intellectual Property information : + // + // The following code handles password protection of Word documents (Open Specifications) + // and is an implementation of algorithm(s) described in Office Document Cryptography Structure + // here: https://msdn.microsoft.com/en-us/library/cc313071.aspx. + // + // The code’s use is covered under Microsoft’s Open Specification Promise + // described here: https://msdn.microsoft.com/en-US/openspecifications/dn646765 + + + // Remove existing password protection + this.RemoveProtection(); + + // If no EditRestrictions, nothing to do + if( editRestrictions == EditRestrictions.none ) + return; + + // Variables + int maxPasswordLength = 15; + var saltArray = new byte[ 16 ]; + var keyValues = new byte[ 14 ]; + + // Init DocumentProtection element + var documentProtection = new XElement( XName.Get( "documentProtection", w.NamespaceName ) ); + documentProtection.Add( new XAttribute( XName.Get( "edit", w.NamespaceName ), editRestrictions.ToString() ) ); + documentProtection.Add( new XAttribute( XName.Get( "enforcement", w.NamespaceName ), "1" ) ); + + int[] InitialCodeArray = { 0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3 }; + int[,] EncryptionMatrix = new int[ 15, 7 ] + { + /* char 1 */ { 0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09}, + /* char 2 */ { 0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF}, + /* char 3 */ { 0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0}, + /* char 4 */ { 0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40}, + /* char 5 */ { 0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5}, + /* char 6 */ { 0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A}, + /* char 7 */ { 0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9}, + /* char 8 */ { 0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0}, + /* char 9 */ { 0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC}, + /* char 10 */ { 0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10}, + /* char 11 */ { 0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168}, + /* char 12 */ { 0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C}, + /* char 13 */ { 0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD}, + /* char 14 */ { 0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC}, + /* char 15 */ { 0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4} + }; + + // Generate the salt + var random = new RNGCryptoServiceProvider(); + random.GetNonZeroBytes( saltArray ); + + // Validate the provided password + if( !String.IsNullOrEmpty( password ) ) + { + password = password.Substring( 0, Math.Min( password.Length, maxPasswordLength ) ); + var byteChars = new byte[ password.Length ]; + + for( int i = 0; i < password.Length; i++ ) + { + var temp = Convert.ToInt32( password[ i ] ); + byteChars[ i ] = Convert.ToByte( temp & 0x00FF ); + + if( byteChars[ i ] == 0 ) + { + byteChars[ i ] = Convert.ToByte( ( temp & 0x00FF ) >> 8 ); + } + } + + var intHighOrderWord = InitialCodeArray[ byteChars.Length - 1 ]; + + for( int i = 0; i < byteChars.Length; i++ ) + { + int tmp = maxPasswordLength - byteChars.Length + i; + for( int intBit = 0; intBit < 7; intBit++ ) + { + if( ( byteChars[ i ] & ( 0x0001 << intBit ) ) != 0 ) + { + intHighOrderWord ^= EncryptionMatrix[ tmp, intBit ]; + } + } + } + + int intLowOrderWord = 0; + + // For each character in the strPassword, going backwards + for( int i = byteChars.Length - 1; i >= 0; i-- ) + { + intLowOrderWord = ( ( ( intLowOrderWord >> 14 ) & 0x0001 ) | ( ( intLowOrderWord << 1 ) & 0x7FFF ) ) ^ byteChars[ i ]; + } + + intLowOrderWord = ( ( ( intLowOrderWord >> 14 ) & 0x0001 ) | ( ( intLowOrderWord << 1 ) & 0x7FFF ) ) ^ byteChars.Length ^ 0xCE4B; + + // Combine the Low and High Order Word + var intCombinedkey = ( intHighOrderWord << 16 ) + intLowOrderWord; + + // The byte order of the result shall be reversed [Example: 0x64CEED7E becomes 7EEDCE64. end example], + // and that value shall be hashed as defined by the attribute values. + + for( int i = 0; i < 4; i++ ) + { + keyValues[ i ] = Convert.ToByte( ( ( uint )( intCombinedkey & ( 0x000000FF << ( i * 8 ) ) ) ) >> ( i * 8 ) ); + } + } + + var sb = new StringBuilder(); + for( int intTemp = 0; intTemp < 4; intTemp++ ) + { + sb.Append( Convert.ToString( keyValues[ intTemp ], 16 ) ); + } + + keyValues = Encoding.Unicode.GetBytes( sb.ToString().ToUpper() ); + keyValues = MergeArrays( keyValues, saltArray ); + + int iterations = 100000; + + var sha1 = new SHA1Managed(); + keyValues = sha1.ComputeHash( keyValues ); + var iterator = new byte[ 4 ]; + for( int i = 0; i < iterations; i++ ) + { + iterator[ 0 ] = Convert.ToByte( ( i & 0x000000FF ) >> 0 ); + iterator[ 1 ] = Convert.ToByte( ( i & 0x0000FF00 ) >> 8 ); + iterator[ 2 ] = Convert.ToByte( ( i & 0x00FF0000 ) >> 16 ); + iterator[ 3 ] = Convert.ToByte( ( i & 0xFF000000 ) >> 24 ); + + keyValues = MergeArrays( iterator, keyValues ); + keyValues = sha1.ComputeHash( keyValues ); + } + + documentProtection.Add( new XAttribute( XName.Get( "cryptProviderType", w.NamespaceName ), "rsaFull" ) ); + documentProtection.Add( new XAttribute( XName.Get( "cryptAlgorithmClass", w.NamespaceName ), "hash" ) ); + documentProtection.Add( new XAttribute( XName.Get( "cryptAlgorithmType", w.NamespaceName ), "typeAny" ) ); + documentProtection.Add( new XAttribute( XName.Get( "cryptAlgorithmSid", w.NamespaceName ), "4" ) ); + documentProtection.Add( new XAttribute( XName.Get( "cryptSpinCount", w.NamespaceName ), iterations.ToString() ) ); + documentProtection.Add( new XAttribute( XName.Get( "hash", w.NamespaceName ), Convert.ToBase64String( keyValues ) ) ); + documentProtection.Add( new XAttribute( XName.Get( "salt", w.NamespaceName ), Convert.ToBase64String( saltArray ) ) ); + + _settings.Root.AddFirst( documentProtection ); + } + + #endregion + + #region Internal Methods + + internal float getMarginAttribute( XName name ) + { + var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) ); + var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) ); + var pgMar = sectPr?.Element( XName.Get( "pgMar", w.NamespaceName ) ); + var top = pgMar?.Attribute( name ); + if( top != null ) + { + float f; + if( float.TryParse( top.Value, out f ) ) + return ( int )( f / _pageSizeMultiplier ); + } + + return 0; + } + + internal void setMarginAttribute( XName xName, float value ) + { + var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) ); + var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) ); + var pgMar = sectPr?.Element( XName.Get( "pgMar", w.NamespaceName ) ); + var top = pgMar?.Attribute( xName ); + top?.SetValue( value * Convert.ToInt32( _pageSizeMultiplier ) ); + } + + internal string GetCollectiveText( List list ) + { + var text = string.Empty; + + foreach( var hp in list ) + { + using( TextReader tr = new StreamReader( hp.GetStream() ) ) + { + var d = XDocument.Load( tr ); + + var sb = new StringBuilder(); + + // Loop through each text item in this run + foreach( XElement descendant in d.Descendants() ) + { + switch( descendant.Name.LocalName ) + { + case "tab": + sb.Append( "\t" ); + break; + case "br": + sb.Append( "\n" ); + break; + case "t": + goto case "delText"; + case "delText": + sb.Append( descendant.Value ); + break; + default: + break; + } + } + + text += "\n" + sb; + } + } + + return text; + } + + internal static void PostCreation( Package package, DocumentTypes documentType = DocumentTypes.Document ) + { + XDocument mainDoc, stylesDoc, numberingDoc; + + #region MainDocumentPart + // Create the main document part for this package + var mainDocPart = ( documentType == DocumentTypes.Document ) + ? package.CreatePart( new Uri( "/word/document.xml", UriKind.Relative ), HelperFunctions.DOCUMENT_DOCUMENTTYPE, CompressionOption.Normal ) + : package.CreatePart( new Uri( "/word/document.xml", UriKind.Relative ), HelperFunctions.TEMPLATE_DOCUMENTTYPE, CompressionOption.Normal ); + + package.CreateRelationship( mainDocPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" ); + + // Load the document part into a XDocument object + using( TextReader tr = new StreamReader( mainDocPart.GetStream( FileMode.Create, FileAccess.ReadWrite ) ) ) + { + mainDoc = XDocument.Parse + ( @" + + + + + + + + + + " + ); + } + + // Save the main document + using( TextWriter tw = new StreamWriter( new PackagePartStream( mainDocPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + mainDoc.Save( tw, SaveOptions.None ); + } + #endregion + + #region StylePart + stylesDoc = HelperFunctions.AddDefaultStylesXml( package ); + #endregion + + #region NumberingPart + numberingDoc = HelperFunctions.AddDefaultNumberingXml( package ); + #endregion + + package.Close(); + } + + internal static DocX PostLoad( ref Package package ) + { + var document = new DocX( null, null ); + document._package = package; + document.Document = document; + + #region MainDocumentPart + document.PackagePart = package.GetParts().Where + ( + p => p.ContentType.Equals( HelperFunctions.DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) || + p.ContentType.Equals( HelperFunctions.TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) + ).Single(); + + using( TextReader tr = new StreamReader( document.PackagePart.GetStream( FileMode.Open, FileAccess.Read ) ) ) + { + document._mainDoc = XDocument.Load( tr, LoadOptions.PreserveWhitespace ); + } + #endregion + + DocX.PopulateDocument( document, package ); + + using( TextReader tr = new StreamReader( document._settingsPart.GetStream() ) ) + { + document._settings = XDocument.Load( tr ); + } + + document._paragraphLookup.Clear(); + var paragraphs = document.Paragraphs; + foreach( var p in paragraphs ) + { + if( !document._paragraphLookup.ContainsKey( p._endIndex ) ) + { + document._paragraphLookup.Add( p._endIndex, p ); + } + } + + return document; + } + + internal void AddHyperlinkStyleIfNotPresent() + { + var word_styles_Uri = new Uri( "/word/styles.xml", UriKind.Relative ); + + // If the internal document contains no /word/styles.xml create one. + if( !_package.PartExists( word_styles_Uri ) ) + { + HelperFunctions.AddDefaultStylesXml( _package ); + } + + // Load the styles.xml into memory. + XDocument word_styles; + using( TextReader tr = new StreamReader( _package.GetPart( word_styles_Uri ).GetStream() ) ) + { + word_styles = XDocument.Load( tr ); + } + + bool hyperlinkStyleExists = + ( + from s in word_styles.Element( w + "styles" ).Elements() + let styleId = s.Attribute( XName.Get( "styleId", w.NamespaceName ) ) + where ( styleId != null && styleId.Value == "Hyperlink" ) + select s + ).Count() > 0; + + if( !hyperlinkStyleExists ) + { + var style = new XElement + ( + w + "style", + new XAttribute( w + "type", "character" ), + new XAttribute( w + "styleId", "Hyperlink" ), + new XElement( w + "name", new XAttribute( w + "val", "Hyperlink" ) ), + new XElement( w + "basedOn", new XAttribute( w + "val", "DefaultParagraphFont" ) ), + new XElement( w + "uiPriority", new XAttribute( w + "val", "99" ) ), + new XElement( w + "unhideWhenUsed" ), + new XElement( w + "rsid", new XAttribute( w + "val", "0005416C" ) ), + new XElement + ( + w + "rPr", + new XElement( w + "color", new XAttribute( w + "val", "0000FF" ), new XAttribute( w + "themeColor", "hyperlink" ) ), + new XElement + ( + w + "u", + new XAttribute( w + "val", "single" ) + ) + ) + ); + word_styles.Element( w + "styles" ).Add( style ); + + // Save the styles document. + using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( word_styles_Uri ).GetStream() ) ) ) + { + word_styles.Save( tw ); + } + } + } + + /// + /// Adds a Header to a document. + /// If the document already contains a Header it will be replaced. + /// + /// The Header that was added to the document. + internal void AddHeadersOrFooters( bool b ) + { + var element = b ? "hdr" : "ftr"; + var reference = b ? "header" : "footer"; + + this.DeleteHeadersOrFooters( b ); + + var sectPr = _mainDoc.Root.Element( w + "body" ).Element( w + "sectPr" ); + + for( int i = 1; i < 4; i++ ) + { + var header_uri = string.Format( "/word/{0}{1}.xml", reference, i ); + + var headerPart = _package.CreatePart( new Uri( header_uri, UriKind.Relative ), string.Format( "application/vnd.openxmlformats-officedocument.wordprocessingml.{0}+xml", reference ), CompressionOption.Normal ); + var headerRelationship = this.PackagePart.CreateRelationship( headerPart.Uri, TargetMode.Internal, string.Format( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference ) ); + + XDocument header; + + // Load the document part into a XDocument object + using( TextReader tr = new StreamReader( headerPart.GetStream( FileMode.Create, FileAccess.ReadWrite ) ) ) + { + header = XDocument.Parse + ( string.Format( @" + + + + + + + ", element, reference ) + ); + } + + // Save the main document + using( TextWriter tw = new StreamWriter( new PackagePartStream( headerPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + header.Save( tw, SaveOptions.None ); + } + + string type; + switch( i ) + { + case 1: + type = "default"; + break; + case 2: + type = "even"; + break; + case 3: + type = "first"; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + sectPr.Add + ( + new XElement + ( + w + string.Format( "{0}Reference", reference ), + new XAttribute( w + "type", type ), + new XAttribute( r + "id", headerRelationship.Id ) + ) + ); + } + } + + internal void DeleteHeadersOrFooters( bool b ) + { + string reference = "footer"; + if( b ) + reference = "header"; + + // Get all header Relationships in this document. + var header_relationships = this.PackagePart.GetRelationshipsByType( string.Format( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference ) ); + + foreach( PackageRelationship header_relationship in header_relationships ) + { + // Get the TargetUri for this Part. + Uri header_uri = header_relationship.TargetUri; + + // Check to see if the document actually contains the Part. + if( !header_uri.OriginalString.StartsWith( "/word/" ) ) + header_uri = new Uri( "/word/" + header_uri.OriginalString, UriKind.Relative ); + + if( _package.PartExists( header_uri ) ) + { + // Delete the Part + _package.DeletePart( header_uri ); + + // Get all references to this Relationship in the document. + var query = + ( + from e in _mainDoc.Descendants( XName.Get( "body", w.NamespaceName ) ).Descendants() + where ( e.Name.LocalName == string.Format( "{0}Reference", reference ) ) && ( e.Attribute( r + "id" ).Value == header_relationship.Id ) + select e + ); + + // Remove all references to this Relationship in the document. + for( int i = 0; i < query.Count(); i++ ) + query.ElementAt( i ).Remove(); + + // Delete the Relationship. + _package.DeleteRelationship( header_relationship.Id ); + } + } + } + + internal Image AddImage( object o, string contentType = "image/jpeg" ) + { + // Open a Stream to the new image being added. + var newImageStream = ( o is string ) ? new FileStream( o as string, FileMode.Open, FileAccess.Read ) : o as Stream; + + // Get all image parts in word\document.xml + var ImageRelationships = this.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ); + var imageParts = ImageRelationships.Select( ir => _package.GetParts().FirstOrDefault( p => p.Uri.ToString().EndsWith( ir.TargetUri.ToString() ) ) ) + .Where( x => ( x != null ) ) + .ToList(); + + foreach( PackagePart relsPart in _package.GetParts().Where( part => part.Uri.ToString().Contains( "/word/" ) ).Where( part => part.ContentType.Equals( "application/vnd.openxmlformats-package.relationships+xml" ) ) ) + { + XDocument relsPartContent; + using( TextReader tr = new StreamReader( relsPart.GetStream( FileMode.Open, FileAccess.Read ) ) ) + { + relsPartContent = XDocument.Load( tr ); + } + + var imageRelationships = + relsPartContent.Root.Elements().Where + ( + imageRel => + imageRel.Attribute( XName.Get( "Type" ) ).Value.Equals( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ) + ); + + foreach( XElement imageRelationship in imageRelationships ) + { + if( imageRelationship.Attribute( XName.Get( "Target" ) ) != null ) + { + var targetModeAttr = imageRelationship.Attribute( XName.Get( "TargetMode" ) ); + var targetMode = ( targetModeAttr != null ) ? targetModeAttr.Value : string.Empty; + + if( !targetMode.Equals( "External" ) ) + { + var imagePartUri = Path.Combine( Path.GetDirectoryName( relsPart.Uri.ToString() ), imageRelationship.Attribute( XName.Get( "Target" ) ).Value ); + imagePartUri = Path.GetFullPath( imagePartUri.Replace( "\\_rels", string.Empty ) ); + imagePartUri = imagePartUri.Replace( Path.GetFullPath( "\\" ), string.Empty ).Replace( "\\", "/" ); + + if( !imagePartUri.StartsWith( "/" ) ) + { + imagePartUri = "/" + imagePartUri; + } + + var imagePart = _package.GetPart( new Uri( imagePartUri, UriKind.Relative ) ); + imageParts.Add( imagePart ); + } + } + } + } + + // Loop through each image part in this document. + foreach( PackagePart pp in imageParts ) + { + // Open a tempory Stream to this image part. + using( Stream tempStream = pp.GetStream( FileMode.Open, FileAccess.Read ) ) + { + // Compare this image to the new image being added. + if( HelperFunctions.IsSameFile( tempStream, newImageStream ) ) + { + // Get the image object for this image part + var id = this.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ) + .Where( r => r.TargetUri == pp.Uri ) + .Select( r => r.Id ).First(); + + // Return the Image object + return Images.Where( i => i.Id == id ).First(); + } + } + } + + var imgPartUriPath = string.Empty; + var extension = contentType.Substring( contentType.LastIndexOf( "/" ) + 1 ); + do + { + // Create a new image part. + imgPartUriPath = string.Format + ( + "/word/media/{0}.{1}", + Guid.NewGuid(), // The unique part. + extension + ); + + } while( _package.PartExists( new Uri( imgPartUriPath, UriKind.Relative ) ) ); + + // We are now guareenteed that imgPartUriPath is unique. + var img = _package.CreatePart( new Uri( imgPartUriPath, UriKind.Relative ), contentType, CompressionOption.Normal ); + + // Create a new image relationship + var rel = this.PackagePart.CreateRelationship( img.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ); + + // Open a Stream to the newly created Image part. + using( Stream stream = new PackagePartStream( img.GetStream( FileMode.Create, FileAccess.Write ) ) ) + { + // Using the Stream to the real image, copy this streams data into the newly create Image part. + using( newImageStream ) + { + byte[] bytes = new byte[ newImageStream.Length ]; + newImageStream.Read( bytes, 0, ( int )newImageStream.Length ); + stream.Write( bytes, 0, ( int )newImageStream.Length ); + }// Close the Stream to the new image. + }// Close the Stream to the new image part. + + return new Image( this, rel ); + } + + internal static void UpdateCorePropertyValue( DocX document, string corePropertyName, string corePropertyValue ) + { + var matchPattern = string.Format( @"(DOCPROPERTY)?{0}\\\*MERGEFORMAT", corePropertyName ).ToLower(); + foreach( XElement e in document._mainDoc.Descendants( XName.Get( "fldSimple", w.NamespaceName ) ) ) + { + var attr_value = e.Attribute( XName.Get( "instr", w.NamespaceName ) ).Value.Replace( " ", string.Empty ).Trim().ToLower(); + + if( Regex.IsMatch( attr_value, matchPattern ) ) + { + var firstRun = e.Element( w + "r" ); + var firstText = firstRun.Element( w + "t" ); + var rPr = firstText.Element( w + "rPr" ); + + // Delete everything and insert updated text value + e.RemoveNodes(); + + var t = new XElement( w + "t", rPr, corePropertyValue ); + Xceed.Words.NET.Text.PreserveSpace( t ); + e.Add( new XElement( firstRun.Name, firstRun.Attributes(), firstRun.Element( XName.Get( "rPr", w.NamespaceName ) ), t ) ); + } + } + + #region Headers + + var headerParts = from headerPart in document._package.GetParts() + where ( Regex.IsMatch( headerPart.Uri.ToString(), @"/word/header\d?.xml" ) ) + select headerPart; + foreach( PackagePart pp in headerParts ) + { + var header = XDocument.Load( new StreamReader( pp.GetStream() ) ); + + foreach( XElement e in header.Descendants( XName.Get( "fldSimple", w.NamespaceName ) ) ) + { + string attr_value = e.Attribute( XName.Get( "instr", w.NamespaceName ) ).Value.Replace( " ", string.Empty ).Trim().ToLower(); + if( Regex.IsMatch( attr_value, matchPattern ) ) + { + var firstRun = e.Element( w + "r" ); + + // Delete everything and insert updated text value + e.RemoveNodes(); + + var t = new XElement( w + "t", corePropertyValue ); + Xceed.Words.NET.Text.PreserveSpace( t ); + e.Add( new XElement( firstRun.Name, firstRun.Attributes(), firstRun.Element( XName.Get( "rPr", w.NamespaceName ) ), t ) ); + } + } + + using( TextWriter tw = new StreamWriter( new PackagePartStream( pp.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + header.Save( tw ); + } + } + #endregion + + #region Footers + var footerParts = from footerPart in document._package.GetParts() + where ( Regex.IsMatch( footerPart.Uri.ToString(), @"/word/footer\d?.xml" ) ) + select footerPart; + foreach( PackagePart pp in footerParts ) + { + var footer = XDocument.Load( new StreamReader( pp.GetStream() ) ); + + foreach( XElement e in footer.Descendants( XName.Get( "fldSimple", w.NamespaceName ) ) ) + { + string attr_value = e.Attribute( XName.Get( "instr", w.NamespaceName ) ).Value.Replace( " ", string.Empty ).Trim().ToLower(); + if( Regex.IsMatch( attr_value, matchPattern ) ) + { + var firstRun = e.Element( w + "r" ); + + // Delete everything and insert updated text value + e.RemoveNodes(); + + var t = new XElement( w + "t", corePropertyValue ); + Xceed.Words.NET.Text.PreserveSpace( t ); + e.Add( new XElement( firstRun.Name, firstRun.Attributes(), firstRun.Element( XName.Get( "rPr", w.NamespaceName ) ), t ) ); + } + } + + using( TextWriter tw = new StreamWriter( new PackagePartStream( pp.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + footer.Save( tw ); + } + } + #endregion + DocX.PopulateDocument( document, document._package ); + } + + /// + /// Update the custom properties inside the document + /// + /// The DocX document + /// The property used inside the document + /// The new value for the property + /// Different version of Word create different Document XML. + internal static void UpdateCustomPropertyValue( DocX document, string customPropertyName, string customPropertyValue ) + { + // A list of documents, which will contain, The Main Document and if they exist: header1, header2, header3, footer1, footer2, footer3. + var documents = new List { document._mainDoc.Root }; + + // Check if each header exists and add if if so. + #region Headers + var headers = document.Headers; + if( headers.First != null ) + { + documents.Add( headers.First.Xml ); + } + if( headers.Odd != null ) + { + documents.Add( headers.Odd.Xml ); + } + if( headers.Even != null ) + { + documents.Add( headers.Even.Xml ); + } + #endregion + + // Check if each footer exists and add if if so. + #region Footers + var footers = document.Footers; + if( footers.First != null ) + { + documents.Add( footers.First.Xml ); + } + if( footers.Odd != null ) + { + documents.Add( footers.Odd.Xml ); + } + if( footers.Even != null ) + { + documents.Add( footers.Even.Xml ); + } + #endregion + + var match_value = string.Format( @"DOCPROPERTY {0} \* MERGEFORMAT", customPropertyName.Contains( " " ) ? "\"" + customPropertyName + "\"" : customPropertyName ) + .Replace( " ", string.Empty ); + + // Process each document in the list. + foreach( XElement doc in documents ) + { + #region Word 2010+ + foreach( XElement e in doc.Descendants( XName.Get( "instrText", w.NamespaceName ) ) ) + { + var attr_value = e.Value.Replace( " ", string.Empty ).Trim(); + + if( attr_value.Equals( match_value, StringComparison.CurrentCultureIgnoreCase ) ) + { + var node = e.Parent.NextNode; + bool found = false; + while( true ) + { + if( node.NodeType == XmlNodeType.Element ) + { + var ele = node as XElement; + var match = ele.Descendants( XName.Get( "t", w.NamespaceName ) ); + if( match.Any() ) + { + if( !found ) + { + match.First().Value = customPropertyValue; + found = true; + } + else + { + ele.RemoveNodes(); + } + } + else + { + match = ele.Descendants( XName.Get( "fldChar", w.NamespaceName ) ); + if( match.Any() ) + { + var endMatch = match.First().Attribute( XName.Get( "fldCharType", w.NamespaceName ) ); + if( endMatch != null && endMatch.Value == "end" ) + { + break; + } + } + } + } + node = node.NextNode; + } + } + } + #endregion + + #region < Word 2010 + foreach( XElement e in doc.Descendants( XName.Get( "fldSimple", w.NamespaceName ) ) ) + { + var attr_value = e.Attribute( XName.Get( "instr", w.NamespaceName ) ).Value.Replace( " ", string.Empty ).Trim(); + + if( attr_value.Equals( match_value, StringComparison.CurrentCultureIgnoreCase ) ) + { + var firstRun = e.Element( w + "r" ); + var firstText = firstRun.Element( w + "t" ); + var rPr = firstText.Element( w + "rPr" ); + + // Delete everything and insert updated text value + e.RemoveNodes(); + + var t = new XElement( w + "t", rPr, customPropertyValue ); + Xceed.Words.NET.Text.PreserveSpace( t ); + e.Add( new XElement( firstRun.Name, firstRun.Attributes(), firstRun.Element( XName.Get( "rPr", w.NamespaceName ) ), t ) ); + } + } + #endregion + } + } + + internal XDocument AddStylesForList() + { + var fileUri = new Uri( "/word/styles.xml", UriKind.Relative ); + + // Create the /word/styles.xml if it doesn't already exist + if( !_package.PartExists( fileUri ) ) + HelperFunctions.AddDefaultStylesXml( _package ); + + // Load the xml into memory. + XDocument stylesDoc; + using( TextReader tr = new StreamReader( _package.GetPart( fileUri ).GetStream() ) ) + stylesDoc = XDocument.Load( tr ); + + bool listStyleExists = + ( + from s in stylesDoc.Element( w + "styles" ).Elements() + let styleId = s.Attribute( XName.Get( "styleId", w.NamespaceName ) ) + where ( styleId != null && styleId.Value == "ListParagraph" ) + select s + ).Any(); + + if( !listStyleExists ) + { + var style = new XElement + ( + w + "style", + new XAttribute( w + "type", "paragraph" ), + new XAttribute( w + "styleId", "ListParagraph" ), + new XElement( w + "name", new XAttribute( w + "val", "List Paragraph" ) ), + new XElement( w + "basedOn", new XAttribute( w + "val", "Normal" ) ), + new XElement( w + "uiPriority", new XAttribute( w + "val", "34" ) ), + new XElement( w + "qformat" ), + new XElement( w + "rsid", new XAttribute( w + "val", "00832EE1" ) ), + new XElement + ( + w + "rPr", + new XElement( w + "ind", new XAttribute( w + "left", "720" ) ), + new XElement + ( + w + "contextualSpacing" + ) + ) + ); + stylesDoc.Element( w + "styles" ).Add( style ); + + // Save the document + using( TextWriter tw = new StreamWriter( _package.GetPart( fileUri ).GetStream() ) ) + stylesDoc.Save( tw ); + } + + return stylesDoc; + } + + internal bool getMirrorMargins(XName name) + { + var body = _mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); + var sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); + var mirrorMargins = sectPr?.Element(XName.Get("mirrorMargins", DocX.w.NamespaceName)); + return (mirrorMargins != null); + } + + internal void setMirrorMargins(XName name, bool value) + { + var body = _mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); + var sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); + var mirrorMargins = sectPr?.Element(XName.Get("mirrorMargins", DocX.w.NamespaceName)); + + if (mirrorMargins == null) + sectPr.Add(new XElement(w + "mirrorMargins", string.Empty)); + + else + { + if (!value) + mirrorMargins.Remove(); + } + } + + #endregion + + #region Private Methods + + private static DocX CreateDocument( DocumentTypes documentType ) + { + // Store this document in memory + var ms = new MemoryStream(); + + // Create the docx package + var package = Package.Open( ms, FileMode.Create, FileAccess.ReadWrite ); + + DocX.PostCreation( package, documentType ); + return DocX.Load( ms ); + } + + private Header GetHeaderByType( string type ) + { + return ( Header )GetHeaderOrFooterByType( type, true ); + } + + private Footer GetFooterByType( string type ) + { + return ( Footer )GetHeaderOrFooterByType( type, false ); + } + + private object GetHeaderOrFooterByType( string type, bool isHeader ) + { + // Switch which handles either case Header\Footer, this just cuts down on code duplication. + string reference = "footerReference"; + if( isHeader ) + reference = "headerReference"; + + // Get the Id of the [default, even or first] [Header or Footer] + string Id = + ( + from e in _mainDoc.Descendants( XName.Get( "body", w.NamespaceName ) ).Descendants() + where ( e.Name.LocalName == reference ) && ( e.Attribute( w + "type" ).Value == type ) + select e.Attribute( r + "id" ).Value + ).LastOrDefault(); + + if( Id != null ) + { + // Get the Xml file for this Header or Footer. + var partUri = this.PackagePart.GetRelationship( Id ).TargetUri; + + // Weird problem with PackaePart API. + if( !partUri.OriginalString.StartsWith( "/word/" ) ) + partUri = new Uri( "/word/" + partUri.OriginalString, UriKind.Relative ); + + // Get the Part and open a stream to get the Xml file. + var part = _package.GetPart( partUri ); + + using( TextReader tr = new StreamReader( part.GetStream() ) ) + { + var doc = XDocument.Load( tr ); + + // Header and Footer extend Container. + Container c; + if( isHeader ) + { + c = new Header( this, doc.Element( w + "hdr" ), part ); + } + else + { + c = new Footer( this, doc.Element( w + "ftr" ), part ); + } + + return c; + } + } + + // If we got this far something went wrong. + return null; + } + + private void merge_images( PackagePart remote_pp, DocX remote_document, XDocument remote_mainDoc, String contentType ) + { + // Before doing any other work, check to see if this image is actually referenced in the document. + // In my testing I have found cases of Images inside documents that are not referenced + var remote_rel = remote_document.PackagePart.GetRelationships().Where( r => r.TargetUri.OriginalString.Equals( remote_pp.Uri.OriginalString.Replace( "/word/", "" ) ) ).FirstOrDefault(); + if( remote_rel == null ) + { + remote_rel = remote_document.PackagePart.GetRelationships().Where( r => r.TargetUri.OriginalString.Equals( remote_pp.Uri.OriginalString ) ).FirstOrDefault(); + if( remote_rel == null ) + return; + } + + var remote_Id = remote_rel.Id; + + var remote_hash = this.ComputeMD5HashString( remote_pp.GetStream() ); + var image_parts = _package.GetParts().Where( pp => pp.ContentType.Equals( contentType ) ); + + bool found = false; + foreach( var part in image_parts ) + { + var local_hash = ComputeMD5HashString( part.GetStream() ); + if( local_hash.Equals( remote_hash ) ) + { + // This image already exists in this document. + found = true; + + var local_rel = this.PackagePart.GetRelationships().Where( r => r.TargetUri.OriginalString.Equals( part.Uri.OriginalString.Replace( "/word/", "" ) ) ).FirstOrDefault(); + + if( local_rel == null ) + { + local_rel = this.PackagePart.GetRelationships().Where( r => r.TargetUri.OriginalString.Equals( part.Uri.OriginalString ) ).FirstOrDefault(); + } + + if( local_rel != null ) + { + var new_Id = local_rel.Id; + + // Replace all instances of remote_Id in the local document with local_Id + this.ReplaceAllRemoteID( remote_mainDoc, "blip", "embed", a.NamespaceName, remote_Id, new_Id ); + // Replace all instances of remote_Id in the local document with local_Id (for shapes) + this.ReplaceAllRemoteID( remote_mainDoc, "imagedata", "id", v.NamespaceName, remote_Id, new_Id ); + } + + break; + } + } + + // This image does not exist in this document. + if( !found ) + { + var new_uri = remote_pp.Uri.OriginalString; + new_uri = new_uri.Remove( new_uri.LastIndexOf( "/" ) ); + new_uri += "/" + Guid.NewGuid() + contentType.Replace( "image/", "." ); + if( !new_uri.StartsWith( "/" ) ) + { + new_uri = "/" + new_uri; + } + + var new_pp = _package.CreatePart( new Uri( new_uri, UriKind.Relative ), remote_pp.ContentType, CompressionOption.Normal ); + + using( Stream s_read = remote_pp.GetStream() ) + { + using( Stream s_write = new PackagePartStream( new_pp.GetStream( FileMode.Create ) ) ) + { + var buffer = new byte[ 32768 ]; + int read; + while( ( read = s_read.Read( buffer, 0, buffer.Length ) ) > 0 ) + { + s_write.Write( buffer, 0, read ); + } + } + } + + var pr = this.PackagePart.CreateRelationship( new Uri( new_uri, UriKind.Relative ), TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ); + + var new_Id = pr.Id; + + //Check if the remote relationship id is a default rId from Word + Match relationshipID = Regex.Match( remote_Id, @"rId\d+", RegexOptions.IgnoreCase ); + + // Replace all instances of remote_Id in the local document with local_Id + this.ReplaceAllRemoteID( remote_mainDoc, "blip", "embed", a.NamespaceName, remote_Id, new_Id ); + + if( !relationshipID.Success ) + { + // Replace all instances of remote_Id in the local document with local_Id + this.ReplaceAllRemoteID( _mainDoc, "blip", "embed", a.NamespaceName, remote_Id, new_Id ); + + // Replace all instances of remote_Id in the local document with local_Id (for shapes) + this.ReplaceAllRemoteID( _mainDoc, "imagedata", "id", v.NamespaceName, remote_Id, new_Id ); + } + + // Replace all instances of remote_Id in the local document with local_Id (for shapes) + this.ReplaceAllRemoteID( remote_mainDoc, "imagedata", "id", v.NamespaceName, remote_Id, new_Id ); + } + } + + private void ReplaceAllRemoteID( XDocument remote_mainDoc, string localName, string localNameAttribute, string namespaceName, string remote_Id, string new_Id ) + { + // Replace all instances of remote_Id in the local document with local_Id + var elems = remote_mainDoc.Descendants( XName.Get( localName, namespaceName ) ); + foreach( var elem in elems ) + { + var attribute = elem.Attribute( XName.Get( localNameAttribute, DocX.r.NamespaceName ) ); + if( attribute != null && attribute.Value == remote_Id ) + { + attribute.SetValue( new_Id ); + } + } + } + + private string ComputeMD5HashString( Stream stream ) + { + MD5 md5 = MD5.Create(); + byte[] hash = md5.ComputeHash( stream ); + StringBuilder sb = new StringBuilder(); + foreach( byte b in hash ) + sb.Append( b.ToString( "X2" ) ); + return sb.ToString(); + } + + private void merge_endnotes( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_endnotes ) + { + IEnumerable ids = + ( + from d in _endnotes.Root.Descendants() + where d.Name.LocalName == "endnote" + select int.Parse( d.Attribute( XName.Get( "id", w.NamespaceName ) ).Value ) + ); + + int max_id = ids.Max() + 1; + var endnoteReferences = remote_mainDoc.Descendants( XName.Get( "endnoteReference", w.NamespaceName ) ); + + foreach( var endnote in remote_endnotes.Root.Elements().OrderBy( fr => fr.Attribute( XName.Get( "id", r.NamespaceName ) ) ).Reverse() ) + { + XAttribute id = endnote.Attribute( XName.Get( "id", w.NamespaceName ) ); + int i; + if( id != null && int.TryParse( id.Value, out i ) ) + { + if( i > 0 ) + { + foreach( var endnoteRef in endnoteReferences ) + { + XAttribute a = endnoteRef.Attribute( XName.Get( "id", w.NamespaceName ) ); + if( a != null && int.Parse( a.Value ).Equals( i ) ) + { + a.SetValue( max_id ); + } + } + + // We care about copying this footnote. + endnote.SetAttributeValue( XName.Get( "id", w.NamespaceName ), max_id ); + _endnotes.Root.Add( endnote ); + max_id++; + } + } + } + } + + private void merge_footnotes( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes ) + { + IEnumerable ids = + ( + from d in _footnotes.Root.Descendants() + where d.Name.LocalName == "footnote" + select int.Parse( d.Attribute( XName.Get( "id", DocX.w.NamespaceName ) ).Value ) + ); + + int max_id = ids.Max() + 1; + var footnoteReferences = remote_mainDoc.Descendants( XName.Get( "footnoteReference", DocX.w.NamespaceName ) ); + + foreach( var footnote in remote_footnotes.Root.Elements().OrderBy( fr => fr.Attribute( XName.Get( "id", DocX.r.NamespaceName ) ) ).Reverse() ) + { + XAttribute id = footnote.Attribute( XName.Get( "id", DocX.w.NamespaceName ) ); + int i; + if( id != null && int.TryParse( id.Value, out i ) ) + { + if( i > 0 ) + { + foreach( var footnoteRef in footnoteReferences ) + { + XAttribute a = footnoteRef.Attribute( XName.Get( "id", DocX.w.NamespaceName ) ); + if( a != null && int.Parse( a.Value ).Equals( i ) ) + { + a.SetValue( max_id ); + } + } + + // We care about copying this footnote. + footnote.SetAttributeValue( XName.Get( "id", DocX.w.NamespaceName ), max_id ); + _footnotes.Root.Add( footnote ); + max_id++; + } + } + } + } + + private void merge_customs( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc ) + { + // Get the remote documents custom.xml file. + XDocument remote_custom_document; + using( TextReader tr = new StreamReader( remote_pp.GetStream() ) ) + { + remote_custom_document = XDocument.Load( tr ); + } + + // Get the local documents custom.xml file. + XDocument local_custom_document; + using( TextReader tr = new StreamReader( local_pp.GetStream() ) ) + { + local_custom_document = XDocument.Load( tr ); + } + + IEnumerable pids = + ( + from d in remote_custom_document.Root.Descendants() + where d.Name.LocalName == "property" + select int.Parse( d.Attribute( XName.Get( "pid" ) ).Value ) + ); + + int pid = pids.Max() + 1; + + foreach( XElement remote_property in remote_custom_document.Root.Elements() ) + { + bool found = false; + foreach( XElement local_property in local_custom_document.Root.Elements() ) + { + var remote_property_name = remote_property.Attribute( XName.Get( "name" ) ); + var local_property_name = local_property.Attribute( XName.Get( "name" ) ); + + if( remote_property != null && local_property_name != null && remote_property_name.Value.Equals( local_property_name.Value ) ) + { + found = true; + } + } + + if( !found ) + { + remote_property.SetAttributeValue( XName.Get( "pid" ), pid ); + local_custom_document.Root.Add( remote_property ); + + pid++; + } + } + + // Save the modified local custom styles.xml file. + using( TextWriter tw = new StreamWriter( new PackagePartStream( local_pp.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + local_custom_document.Save( tw, SaveOptions.None ); + } + } + + private void merge_numbering( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote ) + { + // Add each remote numbering to this document. + var remote_abstractNums = remote._numbering.Root.Elements( XName.Get( "abstractNum", w.NamespaceName ) ); + int guidd = 0; + foreach( var an in remote_abstractNums ) + { + var a = an.Attribute( XName.Get( "abstractNumId", w.NamespaceName ) ); + if( a != null ) + { + int i; + if( int.TryParse( a.Value, out i ) ) + { + if( i > guidd ) + { + guidd = i; + } + } + } + } + guidd++; + + var remote_nums = remote._numbering.Root.Elements( XName.Get( "num", w.NamespaceName ) ); + int guidd2 = 0; + foreach( var an in remote_nums ) + { + var a = an.Attribute( XName.Get( "numId", w.NamespaceName ) ); + if( a != null ) + { + int i; + if( int.TryParse( a.Value, out i ) ) + { + if( i > guidd2 ) + { + guidd2 = i; + } + } + } + } + guidd2++; + + foreach( XElement remote_abstractNum in remote_abstractNums ) + { + var abstractNumId = remote_abstractNum.Attribute( XName.Get( "abstractNumId", w.NamespaceName ) ); + if( abstractNumId != null ) + { + var abstractNumIdValue = abstractNumId.Value; + abstractNumId.SetValue( guidd ); + + foreach( XElement remote_num in remote_nums ) + { + var numIds = remote_mainDoc.Descendants( XName.Get( "numId", w.NamespaceName ) ); + foreach( var numId in numIds ) + { + var attr = numId.Attribute( XName.Get( "val", w.NamespaceName ) ); + if( attr != null && attr.Value.Equals( remote_num.Attribute( XName.Get( "numId", w.NamespaceName ) ).Value ) ) + { + attr.SetValue( guidd2 ); + } + + } + remote_num.SetAttributeValue( XName.Get( "numId", w.NamespaceName ), guidd2 ); + + var e = remote_num.Element( XName.Get( "abstractNumId", w.NamespaceName ) ); + var a2 = e.Attribute( XName.Get( "val", w.NamespaceName ) ); + if ( a2 != null && a2.Value.Equals( abstractNumIdValue ) ) + a2.SetValue( guidd ); + guidd2++; + } + } + + guidd++; + } + + var abstractNumElement = _numbering.Root.Elements( XName.Get( "abstractNum", w.NamespaceName ) ); + if( ( abstractNumElement != null ) && ( abstractNumElement.Count() > 0 ) ) + { + abstractNumElement.Last().AddAfterSelf( remote_abstractNums ); + } + var numElement = _numbering.Root.Elements( XName.Get( "num", w.NamespaceName ) ); + if( ( numElement != null ) && ( numElement.Count() > 0 ) ) + { + numElement.Last().AddAfterSelf( remote_nums ); + } + } + + private void merge_fonts( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote ) + { + // Add each remote font to this document. + IEnumerable remote_fonts = remote._fontTable.Root.Elements( XName.Get( "font", DocX.w.NamespaceName ) ); + IEnumerable local_fonts = _fontTable.Root.Elements( XName.Get( "font", DocX.w.NamespaceName ) ); + + foreach( XElement remote_font in remote_fonts ) + { + bool flag_addFont = true; + foreach( XElement local_font in local_fonts ) + { + if( local_font.Attribute( XName.Get( "name", DocX.w.NamespaceName ) ).Value == remote_font.Attribute( XName.Get( "name", DocX.w.NamespaceName ) ).Value ) + { + flag_addFont = false; + break; + } + } + + if( flag_addFont ) + { + _fontTable.Root.Add( remote_font ); + } + } + } + + private void merge_styles( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes, XDocument remote_endnotes ) + { + var local_styles = new Dictionary(); + foreach( XElement local_style in _styles.Root.Elements( XName.Get( "style", w.NamespaceName ) ) ) + { + var temp = new XElement( local_style ); + var styleId = temp.Attribute( XName.Get( "styleId", w.NamespaceName ) ); + var value = styleId.Value; + styleId.Remove(); + var key = Regex.Replace( temp.ToString(), @"\s+", "" ); + if( !local_styles.ContainsKey( key ) ) + { + local_styles.Add( key, value ); + } + } + + // Add each remote style to this document. + var remote_styles = remote._styles.Root.Elements( XName.Get( "style", w.NamespaceName ) ); + foreach( XElement remote_style in remote_styles ) + { + var temp = new XElement( remote_style ); + var styleId = temp.Attribute( XName.Get( "styleId", w.NamespaceName ) ); + var value = styleId.Value; + styleId.Remove(); + var key = Regex.Replace( temp.ToString(), @"\s+", "" ); + String guuid; + + // Check to see if the local document already contains the remote style. + if( local_styles.ContainsKey( key ) ) + { + String local_value; + local_styles.TryGetValue( key, out local_value ); + + // If the styleIds are the same then nothing needs to be done. + if( local_value == value ) + continue; + // All we need to do is update the styleId. + guuid = local_value; + } + else + { + guuid = Guid.NewGuid().ToString(); + // Set the styleId in the remote_style to this new Guid + remote_style.SetAttributeValue( XName.Get( "styleId", w.NamespaceName ), guuid ); + } + + foreach( XElement e in remote_mainDoc.Root.Descendants( XName.Get( "pStyle", w.NamespaceName ) ) ) + { + var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) ); + if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) ) + { + e_styleId.SetValue( guuid ); + } + } + + foreach( XElement e in remote_mainDoc.Root.Descendants( XName.Get( "rStyle", w.NamespaceName ) ) ) + { + var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) ); + if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) ) + { + e_styleId.SetValue( guuid ); + } + } + + foreach( XElement e in remote_mainDoc.Root.Descendants( XName.Get( "tblStyle", w.NamespaceName ) ) ) + { + var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) ); + if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) ) + { + e_styleId.SetValue( guuid ); + } + } + + if( remote_endnotes != null ) + { + foreach( XElement e in remote_endnotes.Root.Descendants( XName.Get( "rStyle", w.NamespaceName ) ) ) + { + var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) ); + if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) ) + { + e_styleId.SetValue( guuid ); + } + } + + foreach( XElement e in remote_endnotes.Root.Descendants( XName.Get( "pStyle", w.NamespaceName ) ) ) + { + var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) ); + if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) ) + { + e_styleId.SetValue( guuid ); + } + } + } + + if( remote_footnotes != null ) + { + foreach( XElement e in remote_footnotes.Root.Descendants( XName.Get( "rStyle", w.NamespaceName ) ) ) + { + var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) ); + if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) ) + { + e_styleId.SetValue( guuid ); + } + } + + foreach( XElement e in remote_footnotes.Root.Descendants( XName.Get( "pStyle", w.NamespaceName ) ) ) + { + var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) ); + if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) ) + { + e_styleId.SetValue( guuid ); + } + } + } + + // Make sure they don't clash by using a uuid. + styleId.SetValue( guuid ); + _styles.Root.Add( remote_style ); + } + } + + protected void clonePackageRelationship( DocX remote_document, PackagePart pp, XDocument remote_mainDoc ) + { + var url = pp.Uri.OriginalString.Replace( "/", "" ); + var remote_rels = remote_document.PackagePart.GetRelationships(); + foreach( var remote_rel in remote_rels ) + { + if( url.Equals( "word" + remote_rel.TargetUri.OriginalString.Replace( "/", "" ) ) ) + { + var remote_Id = remote_rel.Id; + var local_Id = this.PackagePart.CreateRelationship( remote_rel.TargetUri, remote_rel.TargetMode, remote_rel.RelationshipType ).Id; + + // Replace all instances of remote_Id in the local document with local_Id + this.ReplaceAllRemoteID( remote_mainDoc, "blip", "embed", a.NamespaceName, remote_Id, local_Id ); + // Replace all instances of remote_Id in the local document with local_Id (for shapes) + this.ReplaceAllRemoteID( remote_mainDoc, "imagedata", "id", v.NamespaceName, remote_Id, local_Id ); + break; + } + } + } + + protected PackagePart clonePackagePart( PackagePart pp ) + { + var new_pp = _package.CreatePart( pp.Uri, pp.ContentType, CompressionOption.Normal ); + + using( Stream s_read = pp.GetStream() ) + { + using( Stream s_write = new PackagePartStream( new_pp.GetStream( FileMode.Create ) ) ) + { + var buffer = new byte[ 32768 ]; + int read; + while( ( read = s_read.Read( buffer, 0, buffer.Length ) ) > 0 ) + { + s_write.Write( buffer, 0, read ); + } + } + } + + return new_pp; + } + + protected string GetMD5HashFromStream( Stream stream ) + { + MD5 md5 = new MD5CryptoServiceProvider(); + byte[] retVal = md5.ComputeHash( stream ); + + StringBuilder sb = new StringBuilder(); + for( int i = 0; i < retVal.Length; i++ ) + { + sb.Append( retVal[ i ].ToString( "x2" ) ); + } + return sb.ToString(); + } + + private static void PopulateDocument( DocX document, Package package ) + { + var headers = new Headers(); + headers.Odd = document.GetHeaderByType( "default" ); + headers.Even = document.GetHeaderByType( "even" ); + headers.First = document.GetHeaderByType( "first" ); + + var footers = new Footers(); + footers.Odd = document.GetFooterByType( "default" ); + footers.Even = document.GetFooterByType( "even" ); + footers.First = document.GetFooterByType( "first" ); + + //// Get the sectPr for this document. + //XElement sectPr = document.mainDoc.Descendants(XName.Get("sectPr", DocX.w.NamespaceName)).Single(); + + //if (sectPr != null) + //{ + // // Extract the even header reference + // var header_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even"); + // string id = header_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; + // var res = document.mainPart.GetRelationship(id); + // string ans = res.SourceUri.OriginalString; + // headers.even.xml_filename = ans; + + // // Extract the odd header reference + // var header_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default"); + // string id2 = header_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; + // var res2 = document.mainPart.GetRelationship(id2); + // string ans2 = res2.SourceUri.OriginalString; + // headers.odd.xml_filename = ans2; + + // // Extract the first header reference + // var header_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "h + //eaderReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first"); + // string id3 = header_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; + // var res3 = document.mainPart.GetRelationship(id3); + // string ans3 = res3.SourceUri.OriginalString; + // headers.first.xml_filename = ans3; + + // // Extract the even footer reference + // var footer_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even"); + // string id4 = footer_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; + // var res4 = document.mainPart.GetRelationship(id4); + // string ans4 = res4.SourceUri.OriginalString; + // footers.even.xml_filename = ans4; + + // // Extract the odd footer reference + // var footer_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default"); + // string id5 = footer_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; + // var res5 = document.mainPart.GetRelationship(id5); + // string ans5 = res5.SourceUri.OriginalString; + // footers.odd.xml_filename = ans5; + + // // Extract the first footer reference + // var footer_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first"); + // string id6 = footer_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value; + // var res6 = document.mainPart.GetRelationship(id6); + // string ans6 = res6.SourceUri.OriginalString; + // footers.first.xml_filename = ans6; + + //} + + document.Xml = document._mainDoc.Root.Element( w + "body" ); + document._headers = headers; + document._footers = footers; + document._settingsPart = HelperFunctions.CreateOrGetSettingsPart( package ); + + var ps = package.GetParts(); + + //document.endnotesPart = HelperFunctions.GetPart(); + foreach( var rel in document.PackagePart.GetRelationships() ) + { + var uriString = "/word/" + rel.TargetUri.OriginalString.Replace( "/word/", "" ).Replace( "file://", "" ); + + switch( rel.RelationshipType ) + { + case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes": + document._endnotesPart = package.GetPart( new Uri( uriString, UriKind.Relative ) ); + using( TextReader tr = new StreamReader( document._endnotesPart.GetStream() ) ) + document._endnotes = XDocument.Load( tr ); + break; + + case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes": + document._footnotesPart = package.GetPart( new Uri( uriString, UriKind.Relative ) ); + using( TextReader tr = new StreamReader( document._footnotesPart.GetStream() ) ) + document._footnotes = XDocument.Load( tr ); + break; + + case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles": + document._stylesPart = package.GetPart( new Uri( uriString, UriKind.Relative ) ); + using( TextReader tr = new StreamReader( document._stylesPart.GetStream() ) ) + document._styles = XDocument.Load( tr ); + break; + + case "http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects": + document._stylesWithEffectsPart = package.GetPart( new Uri( uriString, UriKind.Relative ) ); + using( TextReader tr = new StreamReader( document._stylesWithEffectsPart.GetStream() ) ) + document._stylesWithEffects = XDocument.Load( tr ); + break; + + case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable": + document._fontTablePart = package.GetPart( new Uri( uriString, UriKind.Relative ) ); + using( TextReader tr = new StreamReader( document._fontTablePart.GetStream() ) ) + document._fontTable = XDocument.Load( tr ); + break; + + case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering": + document._numberingPart = package.GetPart( new Uri( uriString, UriKind.Relative ) ); + using( TextReader tr = new StreamReader( document._numberingPart.GetStream() ) ) + document._numbering = XDocument.Load( tr ); + break; + + default: + break; + } + } + } + + private string GetNextFreeRelationshipID() + { + int id = + ( + from r in this.PackagePart.GetRelationships() + where r.Id.Substring( 0, 3 ).Equals( "rId" ) + select int.Parse( r.Id.Substring( 3 ) ) + ).DefaultIfEmpty().Max(); + + // The convension for ids is rid01, rid02, etc + var newId = id.ToString(); + int result; + if( int.TryParse( newId, out result ) ) + return ( "rId" + ( result + 1 ) ); + + var guid = String.Empty; + do + { + guid = Guid.NewGuid().ToString(); + } while( Char.IsDigit( guid[ 0 ] ) ); + return guid; + } + + private byte[] MergeArrays( byte[] array1, byte[] array2 ) + { + byte[] result = new byte[ array1.Length + array2.Length ]; + Buffer.BlockCopy( array2, 0, result, 0, array2.Length ); + Buffer.BlockCopy( array1, 0, result, array2.Length, array1.Length ); + return result; + } + + #endregion + + #region Constructors + + internal DocX( DocX document, XElement xml ) + : base( document, xml ) + { + + } + + #endregion + + #region IDisposable Members + + /// + /// Releases all resources used by this document. + /// + /// + /// If you take advantage of the using keyword, Dispose() is automatically called for you. + /// + /// // Load document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // The document is only in memory while in this scope. + /// + /// }// Dispose() is automatically called at this point. + /// + /// + /// + /// This example is equilivant to the one above example. + /// + /// // Load document. + /// DocX document = DocX.Load(@"C:\Example\Test.docx"); + /// + /// // Do something with the document here. + /// + /// // Dispose of the document. + /// document.Dispose(); + /// + /// + public void Dispose() + { + _package.Close(); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/ExtensionsHeadings.cs b/Xceed.Words.NET/Src/ExtensionsHeadings.cs new file mode 100644 index 00000000..cfe991a6 --- /dev/null +++ b/Xceed.Words.NET/Src/ExtensionsHeadings.cs @@ -0,0 +1,60 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Reflection; +using System.ComponentModel; + +namespace Xceed.Words.NET +{ + public static class ExtensionsHeadings + { + + public static Paragraph Heading( this Paragraph paragraph, HeadingType headingType ) + { + var description = headingType.EnumDescription(); + paragraph.StyleName = description; + return paragraph; + } + + public static string EnumDescription( this Enum enumValue ) + { + if( (enumValue == null) || (enumValue.ToString() == "0") ) + return string.Empty; + + var enumInfo = enumValue.GetType().GetField( enumValue.ToString() ); + var enumAttributes = ( DescriptionAttribute[] )enumInfo.GetCustomAttributes( typeof( DescriptionAttribute ), false ); + + if( enumAttributes.Length > 0 ) + return enumAttributes[ 0 ].Description; + else + return enumValue.ToString(); + } + + public static bool HasFlag( this Enum variable, Enum value ) + { + if( variable == null ) + return false; + + if( value == null ) + throw new ArgumentNullException( "value" ); + + if( !Enum.IsDefined( variable.GetType(), value ) ) + throw new ArgumentException( string.Format( "Enumeration type mismatch. The flag is of type '{0}', was expecting '{1}'.", value.GetType(), variable.GetType() ) ); + + var num = Convert.ToUInt64( value ); + return ( ( Convert.ToUInt64( variable ) & num ) == num ); + } + } +} diff --git a/Xceed.Words.NET/Src/Font.cs b/Xceed.Words.NET/Src/Font.cs new file mode 100644 index 00000000..d25afb68 --- /dev/null +++ b/Xceed.Words.NET/Src/Font.cs @@ -0,0 +1,40 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; + +namespace Xceed.Words.NET +{ + public sealed class Font + { + public Font(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException(nameof(name)); + + Name = name; + } + + public string Name + { + get; + private set; + } + + public override string ToString() + { + return Name; + } + } +} diff --git a/Xceed.Words.NET/Src/Footer.cs b/Xceed.Words.NET/Src/Footer.cs new file mode 100644 index 00000000..74627962 --- /dev/null +++ b/Xceed.Words.NET/Src/Footer.cs @@ -0,0 +1,205 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Xml.Linq; +using System.IO.Packaging; +using System.Collections.ObjectModel; + +namespace Xceed.Words.NET +{ + public class Footer : Container, IParagraphContainer + { + #region Public Properties + + public bool PageNumbers + { + get + { + return false; + } + + set + { + XElement e = XElement.Parse + ( @" + + + + + + + + + + + + + + + + + + + 1 + + + + + " + ); + + Xml.AddFirst( e ); + } + } + + public override ReadOnlyCollection Paragraphs + { + get + { + var paragraphs = base.Paragraphs; + foreach( var paragraph in paragraphs ) + { + paragraph.PackagePart = this.PackagePart; + } + return paragraphs; + } + } + + public override List
Tables + { + get + { + var l = base.Tables; + l.ForEach( x => x.PackagePart = this.PackagePart ); + return l; + } + } + + #endregion + + #region Constructors + + internal Footer( DocX document, XElement xml, PackagePart mainPart ) : base( document, xml ) + { + this.PackagePart = mainPart; + } + + #endregion + + #region Public Methods + + public override Paragraph InsertParagraph() + { + var p = base.InsertParagraph(); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( int index, string text, bool trackChanges ) + { + var p = base.InsertParagraph( index, text, trackChanges ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( Paragraph p ) + { + p.PackagePart = this.PackagePart; + return base.InsertParagraph( p ); + } + + public override Paragraph InsertParagraph( int index, Paragraph p ) + { + p.PackagePart = this.PackagePart; + return base.InsertParagraph( index, p ); + } + + public override Paragraph InsertParagraph( int index, string text, bool trackChanges, Formatting formatting ) + { + var p = base.InsertParagraph( index, text, trackChanges, formatting ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( string text ) + { + var p = base.InsertParagraph( text ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( string text, bool trackChanges ) + { + var p = base.InsertParagraph( text, trackChanges ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( string text, bool trackChanges, Formatting formatting ) + { + var p = base.InsertParagraph( text, trackChanges, formatting ); + p.PackagePart = this.PackagePart; + + return p; + } + + public override Paragraph InsertEquation( String equation ) + { + var p = base.InsertEquation( equation ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Table InsertTable( int rowCount, int columnCount ) + { + var table = base.InsertTable( rowCount, columnCount ); + return this.SetMainPart( table ); + } + + public override Table InsertTable( int index, Table t ) + { + var table = base.InsertTable( index, t ); + return this.SetMainPart( table ); + } + + public override Table InsertTable( Table t ) + { + var table = base.InsertTable( t ); + return this.SetMainPart( table ); + } + + public override Table InsertTable( int index, int rowCount, int columnCount ) + { + var table = base.InsertTable( index, rowCount, columnCount ); + return this.SetMainPart( table ); + } + + #endregion + + #region Private Methods + + private Table SetMainPart( Table table ) + { + if( table != null ) + { + table.PackagePart = this.PackagePart; + } + return table; + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/Footers.cs b/Xceed.Words.NET/Src/Footers.cs new file mode 100644 index 00000000..57e20397 --- /dev/null +++ b/Xceed.Words.NET/Src/Footers.cs @@ -0,0 +1,49 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +namespace Xceed.Words.NET +{ + public class Footers + { + #region Public Properties + + public Footer Odd + { + get; + set; + } + + public Footer Even + { + get; + set; + } + + public Footer First + { + get; + set; + } + + #endregion + + #region Constructors + + internal Footers() + { + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/FormattedText.cs b/Xceed.Words.NET/Src/FormattedText.cs new file mode 100644 index 00000000..acd8c8ee --- /dev/null +++ b/Xceed.Words.NET/Src/FormattedText.cs @@ -0,0 +1,52 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; + +namespace Xceed.Words.NET +{ + public class FormattedText : IComparable + { + #region Public Members + + public int index; + public string text; + public Formatting formatting; + + #endregion + + #region Constructors + + public FormattedText() + { + } + + #endregion + + #region Public Methods + + public int CompareTo( object obj ) + { + FormattedText other = ( FormattedText )obj; + FormattedText tf = this; + + if( other.formatting == null || tf.formatting == null ) + return -1; + + return tf.formatting.CompareTo( other.formatting ); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/Formatting.cs b/Xceed.Words.NET/Src/Formatting.cs new file mode 100644 index 00000000..c0a00672 --- /dev/null +++ b/Xceed.Words.NET/Src/Formatting.cs @@ -0,0 +1,799 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Linq; +using System.Xml.Linq; +using System.Drawing; +using System.Globalization; + +namespace Xceed.Words.NET +{ + /// + /// A text formatting. + /// + public class Formatting : IComparable + { + #region Private Members + + private XElement _rPr; + private bool? _hidden; + private bool? _bold; + private bool? _italic; + private StrikeThrough? _strikethrough; + private Script? _script; + private Highlight? _highlight; + private double? _size; + private Color? _fontColor; + private Color? _underlineColor; + private UnderlineStyle? _underlineStyle; + private Misc? _misc; + private CapsStyle? _capsStyle; + private Font _fontFamily; + private int? _percentageScale; + private int? _kerning; + private int? _position; + private double? _spacing; + + private CultureInfo _language; + + #endregion + + #region Constructors + + /// + /// A text formatting. + /// + public Formatting() + { + _capsStyle = Xceed.Words.NET.CapsStyle.none; + _strikethrough = Xceed.Words.NET.StrikeThrough.none; + _script = Xceed.Words.NET.Script.none; + _highlight = Xceed.Words.NET.Highlight.none; + _underlineStyle = Xceed.Words.NET.UnderlineStyle.none; + _misc = Xceed.Words.NET.Misc.none; + + // Use current culture by default + _language = CultureInfo.CurrentCulture; + + _rPr = new XElement( XName.Get( "rPr", DocX.w.NamespaceName ) ); + } + + #endregion + + #region Public Properties + + /// + /// Text language + /// + public CultureInfo Language + { + get + { + return _language; + } + + set + { + _language = value; + } + } + + /// + /// This formatting will apply Bold. + /// + public bool? Bold + { + get + { + return _bold; + } + set + { + _bold = value; + } + } + + /// + /// This formatting will apply Italic. + /// + public bool? Italic + { + get + { + return _italic; + } + set + { + _italic = value; + } + } + + /// + /// This formatting will apply StrickThrough. + /// + public StrikeThrough? StrikeThrough + { + get + { + return _strikethrough; + } + set + { + _strikethrough = value; + } + } + + /// + /// The script that this formatting should be, normal, superscript or subscript. + /// + public Script? Script + { + get + { + return _script; + } + set + { + _script = value; + } + } + + /// + /// The Size of this text, must be between 0 and 1638. + /// + public double? Size + { + get + { + return _size; + } + + set + { + double? temp = value * 2; + + if( temp - ( int )temp == 0 ) + { + if( value > 0 && value < 1639 ) + { + _size = value; + } + else + throw new ArgumentException( "Size", "Value must be in the range 0 - 1638" ); + } + else + throw new ArgumentException( "Size", "Value must be either a whole or half number, examples: 32, 32.5" ); + } + } + + /// + /// Percentage scale must be one of the following values 200, 150, 100, 90, 80, 66, 50 or 33. + /// + public int? PercentageScale + { + get + { + return _percentageScale; + } + + set + { + if( ( new int?[] { 200, 150, 100, 90, 80, 66, 50, 33 } ).Contains( value ) ) + { + _percentageScale = value; + } + else + throw new ArgumentOutOfRangeException( "PercentageScale", "Value must be one of the following: 200, 150, 100, 90, 80, 66, 50 or 33" ); + } + } + + /// + /// The Kerning to apply to this text must be one of the following values 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72. + /// + public int? Kerning + { + get + { + return _kerning; + } + + set + { + if( new int?[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72 }.Contains( value ) ) + _kerning = value; + else + throw new ArgumentOutOfRangeException( "Kerning", "Value must be one of the following: 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48 or 72" ); + } + } + + /// + /// Text position must be in the range (-1585 - 1585). + /// + public int? Position + { + get + { + return _position; + } + + set + { + if( value > -1585 && value < 1585 ) + _position = value; + else + throw new ArgumentOutOfRangeException( "Position", "Value must be in the range -1585 - 1585" ); + } + } + + /// + /// Text spacing must be in the range (-1585 - 1585). + /// + public double? Spacing + { + get + { + return _spacing; + } + + set + { + double? temp = value * 20; + + if( temp - ( int )temp == 0 ) + { + if( value > -1585 && value < 1585 ) + _spacing = value; + else + throw new ArgumentException( "Spacing", "Value must be in the range: -1584 - 1584" ); + } + + else + throw new ArgumentException( "Spacing", "Value must be either a whole or acurate to one decimal, examples: 32, 32.1, 32.2, 32.9" ); + } + } + + /// + /// The colour of the text. + /// + public Color? FontColor + { + get + { + return _fontColor; + } + set + { + _fontColor = value; + } + } + + /// + /// Highlight colour. + /// + public Highlight? Highlight + { + get + { + return _highlight; + } + set + { + _highlight = value; + } + } + + /// + /// The Underline style that this formatting applies. + /// + public UnderlineStyle? UnderlineStyle + { + get + { + return _underlineStyle; + } + set + { + _underlineStyle = value; + } + } + + /// + /// The underline colour. + /// + public Color? UnderlineColor + { + get + { + return _underlineColor; + } + set + { + _underlineColor = value; + } + } + + /// + /// Misc settings. + /// + public Misc? Misc + { + get + { + return _misc; + } + set + { + _misc = value; + } + } + + /// + /// Is this text hidden or visible. + /// + public bool? Hidden + { + get + { + return _hidden; + } + set + { + _hidden = value; + } + } + + /// + /// Capitalization style. + /// + public CapsStyle? CapsStyle + { + get + { + return _capsStyle; + } + set + { + _capsStyle = value; + } + } + + /// + /// The font Family of this formatting. + /// + /// + public Font FontFamily + { + get + { + return _fontFamily; + } + set + { + _fontFamily = value; + } + } + + #endregion + + #region Internal Properties + + internal XElement Xml + { + get + { + _rPr = new XElement( XName.Get( "rPr", DocX.w.NamespaceName ) ); + + if( _language != null ) + { + _rPr.Add( new XElement( XName.Get( "lang", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), _language.Name ) ) ); + } + + if( _spacing.HasValue ) + { + _rPr.Add( new XElement( XName.Get( "spacing", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), _spacing.Value * 20 ) ) ); + } + + if( _position.HasValue ) + { + _rPr.Add( new XElement( XName.Get( "position", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), _position.Value * 2 ) ) ); + } + + if( _kerning.HasValue ) + { + _rPr.Add( new XElement( XName.Get( "kern", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), _kerning.Value * 2 ) ) ); + } + + if( _percentageScale.HasValue ) + { + _rPr.Add( new XElement( XName.Get( "w", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), _percentageScale ) ) ); + } + + if( _fontFamily != null ) + { + _rPr.Add + ( + new XElement( XName.Get( "rFonts", DocX.w.NamespaceName ), new XAttribute( XName.Get( "ascii", DocX.w.NamespaceName ), _fontFamily.Name ), + new XAttribute( XName.Get( "hAnsi", DocX.w.NamespaceName ), _fontFamily.Name ), + new XAttribute( XName.Get( "cs", DocX.w.NamespaceName ), _fontFamily.Name ) ) + ); + } + + if( _hidden.HasValue && _hidden.Value ) + { + _rPr.Add( new XElement( XName.Get( "vanish", DocX.w.NamespaceName ) ) ); + } + + if( _bold.HasValue && _bold.Value ) + { + _rPr.Add( new XElement( XName.Get( "b", DocX.w.NamespaceName ) ) ); + } + + if( _italic.HasValue && _italic.Value ) + { + _rPr.Add( new XElement( XName.Get( "i", DocX.w.NamespaceName ) ) ); + } + + if( _underlineStyle.HasValue ) + { + switch( _underlineStyle ) + { + case Xceed.Words.NET.UnderlineStyle.none: + break; + case Xceed.Words.NET.UnderlineStyle.singleLine: + _rPr.Add( new XElement( XName.Get( "u", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), "single" ) ) ); + break; + case Xceed.Words.NET.UnderlineStyle.doubleLine: + _rPr.Add( new XElement( XName.Get( "u", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), "double" ) ) ); + break; + default: + _rPr.Add( new XElement( XName.Get( "u", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), _underlineStyle.ToString() ) ) ); + break; + } + } + + if( _underlineColor.HasValue ) + { + // If an underlineColor has been set but no underlineStyle has been set + if( _underlineStyle == Xceed.Words.NET.UnderlineStyle.none ) + { + // Set the underlineStyle to the default + _underlineStyle = Xceed.Words.NET.UnderlineStyle.singleLine; + _rPr.Add( new XElement( XName.Get( "u", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), "single" ) ) ); + } + + _rPr.Element( XName.Get( "u", DocX.w.NamespaceName ) ).Add( new XAttribute( XName.Get( "color", DocX.w.NamespaceName ), _underlineColor.Value.ToHex() ) ); + } + + if( _strikethrough.HasValue ) + { + switch( _strikethrough ) + { + case Xceed.Words.NET.StrikeThrough.none: + break; + case Xceed.Words.NET.StrikeThrough.strike: + _rPr.Add( new XElement( XName.Get( "strike", DocX.w.NamespaceName ) ) ); + break; + case Xceed.Words.NET.StrikeThrough.doubleStrike: + _rPr.Add( new XElement( XName.Get( "dstrike", DocX.w.NamespaceName ) ) ); + break; + default: + break; + } + } + + if( _script.HasValue ) + { + switch( _script ) + { + case Xceed.Words.NET.Script.none: + break; + default: + _rPr.Add( new XElement( XName.Get( "vertAlign", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), _script.ToString() ) ) ); + break; + } + } + + if( _size.HasValue ) + { + _rPr.Add( new XElement( XName.Get( "sz", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), ( _size * 2 ).ToString() ) ) ); + _rPr.Add( new XElement( XName.Get( "szCs", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), ( _size * 2 ).ToString() ) ) ); + } + + if( _fontColor.HasValue ) + { + _rPr.Add( new XElement( XName.Get( "color", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), _fontColor.Value.ToHex() ) ) ); + } + + if( _highlight.HasValue ) + { + switch( _highlight ) + { + case Xceed.Words.NET.Highlight.none: + break; + default: + _rPr.Add( new XElement( XName.Get( "highlight", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), _highlight.ToString() ) ) ); + break; + } + } + + if( _capsStyle.HasValue ) + { + switch( _capsStyle ) + { + case Xceed.Words.NET.CapsStyle.none: + break; + default: + _rPr.Add( new XElement( XName.Get( _capsStyle.ToString(), DocX.w.NamespaceName ) ) ); + break; + } + } + + if( _misc.HasValue ) + { + switch( _misc ) + { + case Xceed.Words.NET.Misc.none: + break; + case Xceed.Words.NET.Misc.outlineShadow: + _rPr.Add( new XElement( XName.Get( "outline", DocX.w.NamespaceName ) ) ); + _rPr.Add( new XElement( XName.Get( "shadow", DocX.w.NamespaceName ) ) ); + break; + case Xceed.Words.NET.Misc.engrave: + _rPr.Add( new XElement( XName.Get( "imprint", DocX.w.NamespaceName ) ) ); + break; + default: + _rPr.Add( new XElement( XName.Get( _misc.ToString(), DocX.w.NamespaceName ) ) ); + break; + } + } + + return _rPr; + } + } + + #endregion + + #region Public Methods + + /// + /// Returns a cloned instance of Formatting. + /// + /// + public Formatting Clone() + { + var clone = new Formatting(); + clone.Bold = _bold; + clone.CapsStyle = _capsStyle; + clone.FontColor = _fontColor; + clone.FontFamily = _fontFamily; + clone.Hidden = _hidden; + clone.Highlight = _highlight; + clone.Italic = _italic; + if( _kerning.HasValue ) + { + clone.Kerning = _kerning; + } + clone.Language = _language; + clone.Misc = _misc; + if( _percentageScale.HasValue ) + { + clone.PercentageScale = _percentageScale; + } + if( _position.HasValue ) + { + clone.Position = _position; + } + clone.Script = _script; + if( _size.HasValue ) + { + clone.Size = _size; + } + if( _spacing.HasValue ) + { + clone.Spacing = _spacing; + } + clone.StrikeThrough = _strikethrough; + clone.UnderlineColor = _underlineColor; + clone.UnderlineStyle = _underlineStyle; + + return clone; + } + + + public static Formatting Parse( XElement rPr ) + { + var formatting = new Formatting(); + + // Build up the Formatting object. + foreach( XElement option in rPr.Elements() ) + { + switch( option.Name.LocalName ) + { + case "lang": + formatting.Language = new CultureInfo(option.GetAttribute(XName.Get("val", DocX.w.NamespaceName), null) ?? option.GetAttribute(XName.Get("eastAsia", DocX.w.NamespaceName), null) ?? option.GetAttribute(XName.Get("bidi", DocX.w.NamespaceName))); + break; + case "spacing": + formatting.Spacing = Double.Parse(option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 20.0; + break; + case "position": + formatting.Position = Int32.Parse(option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 2; + break; + case "kern": + formatting.Position = Int32.Parse(option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 2; + break; + case "w": + formatting.PercentageScale = Int32.Parse(option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))); + break; + case "sz": + formatting.Size = Int32.Parse(option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 2; + break; + case "rFonts": + formatting.FontFamily = new Font(option.GetAttribute(XName.Get("cs", DocX.w.NamespaceName), null) ?? option.GetAttribute(XName.Get("ascii", DocX.w.NamespaceName), null) ?? option.GetAttribute(XName.Get("hAnsi", DocX.w.NamespaceName), null) ?? option.GetAttribute(XName.Get("eastAsia", DocX.w.NamespaceName))); + break; + case "color": + try + { + var color = option.GetAttribute(XName.Get("val", DocX.w.NamespaceName)); + formatting.FontColor = System.Drawing.ColorTranslator.FromHtml(string.Format("#{0}", color)); + } + catch (Exception) + { + // ignore + } + break; + case "vanish": + formatting._hidden = true; + break; + case "b": + formatting.Bold = true; + break; + case "i": + formatting.Italic = true; + break; + case "highlight": + switch( option.GetAttribute( XName.Get( "val", DocX.w.NamespaceName ) ) ) + { + case "yellow": + formatting.Highlight = NET.Highlight.yellow; + break; + case "green": + formatting.Highlight = NET.Highlight.green; + break; + case "cyan": + formatting.Highlight = NET.Highlight.cyan; + break; + case "magenta": + formatting.Highlight = NET.Highlight.magenta; + break; + case "blue": + formatting.Highlight = NET.Highlight.blue; + break; + case "red": + formatting.Highlight = NET.Highlight.red; + break; + case "darkBlue": + formatting.Highlight = NET.Highlight.darkBlue; + break; + case "darkCyan": + formatting.Highlight = NET.Highlight.darkCyan; + break; + case "darkGreen": + formatting.Highlight = NET.Highlight.darkGreen; + break; + case "darkMagenta": + formatting.Highlight = NET.Highlight.darkMagenta; + break; + case "darkRed": + formatting.Highlight = NET.Highlight.darkRed; + break; + case "darkYellow": + formatting.Highlight = NET.Highlight.darkYellow; + break; + case "darkGray": + formatting.Highlight = NET.Highlight.darkGray; + break; + case "lightGray": + formatting.Highlight = NET.Highlight.lightGray; + break; + case "black": + formatting.Highlight = NET.Highlight.black; + break; + } + break; + case "strike": + formatting.StrikeThrough = NET.StrikeThrough.strike; + break; + case "u": + formatting.UnderlineStyle = HelperFunctions.GetUnderlineStyle(option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))); + break; + case "vertAlign": + var script = option.GetAttribute(XName.Get("val", DocX.w.NamespaceName), null); + formatting.Script = (Script)Enum.Parse(typeof(Script), script); + break; + default: + break; + } + } + + return formatting; + } + + public int CompareTo( object obj ) + { + Formatting other = ( Formatting )obj; + + if( other._hidden != _hidden ) + return -1; + + if( other._bold != _bold ) + return -1; + + if( other._italic != _italic ) + return -1; + + if( other._strikethrough != _strikethrough ) + return -1; + + if( other._script != _script ) + return -1; + + if( other._highlight != _highlight ) + return -1; + + if( other._size != _size ) + return -1; + + if( other._fontColor != _fontColor ) + return -1; + + if( other._underlineColor != _underlineColor ) + return -1; + + if( other._underlineStyle != _underlineStyle ) + return -1; + + if( other._misc != _misc ) + return -1; + + if( other._capsStyle != _capsStyle ) + return -1; + + if( other._fontFamily != _fontFamily ) + return -1; + + if( other._percentageScale != _percentageScale ) + return -1; + + if( other._kerning != _kerning ) + return -1; + + if( other._position != _position ) + return -1; + + if( other._spacing != _spacing ) + return -1; + + if( !other._language.Equals(_language) ) + return -1; + + return 0; + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/Header.cs b/Xceed.Words.NET/Src/Header.cs new file mode 100644 index 00000000..bdb53953 --- /dev/null +++ b/Xceed.Words.NET/Src/Header.cs @@ -0,0 +1,233 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using System.IO.Packaging; +using System.Collections.ObjectModel; + +namespace Xceed.Words.NET +{ + public class Header : Container, IParagraphContainer + { + + #region Public Properties + + public Paragraph PageNumberParagraph + { + get; + set; + } + + public bool PageNumbers + { + get + { + return false; + } + + set + { + XElement e = XElement.Parse + ( @" + + + + + + + + + + + + + + + + + + + 1 + + + + + " + ); + + Xml.AddFirst( e ); + + this.PageNumberParagraph = new Paragraph( this.Document, e.Descendants( XName.Get( "p", DocX.w.NamespaceName ) ).SingleOrDefault(), 0 ); + } + } + + public override ReadOnlyCollection Paragraphs + { + get + { + var paragraphs = base.Paragraphs; + foreach( var paragraph in paragraphs ) + { + paragraph.PackagePart = this.PackagePart; + } + return paragraphs; + } + } + + public override List
Tables + { + get + { + var l = base.Tables; + l.ForEach( x => x.PackagePart = this.PackagePart ); + return l; + } + } + + public List Images + { + get + { + var imageRelationships = this.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ); + if( imageRelationships.Count() > 0 ) + { + return + ( + from i in imageRelationships + select new Image( Document, i ) + ).ToList(); + } + + return new List(); + } + } + + #endregion + + #region Constructors + + internal Header( DocX document, XElement xml, PackagePart mainPart ) : base( document, xml ) + { + this.PackagePart = mainPart; + } + + #endregion + + #region Public Methods + + public override Paragraph InsertParagraph() + { + var p = base.InsertParagraph(); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( int index, string text, bool trackChanges ) + { + var p = base.InsertParagraph( index, text, trackChanges ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( Paragraph p ) + { + p.PackagePart = this.PackagePart; + return base.InsertParagraph( p ); + } + + public override Paragraph InsertParagraph( int index, Paragraph p ) + { + p.PackagePart = this.PackagePart; + return base.InsertParagraph( index, p ); + } + + public override Paragraph InsertParagraph( int index, string text, bool trackChanges, Formatting formatting ) + { + var p = base.InsertParagraph( index, text, trackChanges, formatting ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( string text ) + { + var p = base.InsertParagraph( text ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( string text, bool trackChanges ) + { + var p = base.InsertParagraph( text, trackChanges ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Paragraph InsertParagraph( string text, bool trackChanges, Formatting formatting ) + { + var p = base.InsertParagraph( text, trackChanges, formatting ); + p.PackagePart = this.PackagePart; + + return p; + } + + public override Paragraph InsertEquation( String equation ) + { + var p = base.InsertEquation( equation ); + p.PackagePart = this.PackagePart; + return p; + } + + public override Table InsertTable( int rowCount, int columnCount ) + { + var table = base.InsertTable( rowCount, columnCount ); + return this.SetMainPart( table ); + } + + public override Table InsertTable( int index, Table t ) + { + var table = base.InsertTable( index, t ); + return this.SetMainPart( table ); + } + + public override Table InsertTable( Table t ) + { + var table = base.InsertTable( t ); + return this.SetMainPart( table ); + } + + public override Table InsertTable( int index, int rowCount, int columnCount ) + { + var table = base.InsertTable( index, rowCount, columnCount ); + return this.SetMainPart( table ); + } + + #endregion + + #region Private Methods + + private Table SetMainPart( Table table ) + { + if( table != null ) + { + table.PackagePart = this.PackagePart; + } + return table; + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/Headers.cs b/Xceed.Words.NET/Src/Headers.cs new file mode 100644 index 00000000..9536d2be --- /dev/null +++ b/Xceed.Words.NET/Src/Headers.cs @@ -0,0 +1,49 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +namespace Xceed.Words.NET +{ + public class Headers + { + #region Public Properties + + public Header Odd + { + get; + set; + } + + public Header Even + { + get; + set; + } + + public Header First + { + get; + set; + } + + #endregion + + #region Constructors + + internal Headers() + { + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/HelperFunctions.cs b/Xceed.Words.NET/Src/HelperFunctions.cs new file mode 100644 index 00000000..f71b59db --- /dev/null +++ b/Xceed.Words.NET/Src/HelperFunctions.cs @@ -0,0 +1,755 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO.Packaging; +using System.Xml.Linq; +using System.IO; +using System.Reflection; +using System.IO.Compression; +using System.Security.Principal; +using System.Globalization; +using System.Xml; + +namespace Xceed.Words.NET +{ + internal static class HelperFunctions + { + public const string DOCUMENT_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"; + public const string TEMPLATE_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml"; + public const string SETTING_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"; + + internal static void CreateRelsPackagePart( DocX Document, Uri uri ) + { + PackagePart pp = Document._package.CreatePart( uri, "application/vnd.openxmlformats-package.relationships+xml", CompressionOption.Maximum ); + using( TextWriter tw = new StreamWriter( new PackagePartStream( pp.GetStream() ) ) ) + { + XDocument d = new XDocument + ( + new XDeclaration( "1.0", "UTF-8", "yes" ), + new XElement( XName.Get( "Relationships", DocX.rel.NamespaceName ) ) + ); + var root = d.Root; + d.Save( tw ); + } + } + + internal static int GetSize( XElement Xml ) + { + switch( Xml.Name.LocalName ) + { + case "tab": + return 1; + case "br": + return 1; + case "t": + goto case "delText"; + case "delText": + return Xml.Value.Length; + case "tr": + goto case "br"; + case "tc": + goto case "br"; + default: + return 0; + } + } + + internal static string GetText( XElement e ) + { + StringBuilder sb = new StringBuilder(); + GetTextRecursive( e, ref sb ); + return sb.ToString(); + } + + internal static void GetTextRecursive( XElement Xml, ref StringBuilder sb ) + { + sb.Append( ToText( Xml ) ); + + if( Xml.HasElements ) + foreach( XElement e in Xml.Elements() ) + GetTextRecursive( e, ref sb ); + } + + internal static List GetFormattedText( XElement e ) + { + List alist = new List(); + GetFormattedTextRecursive( e, ref alist ); + return alist; + } + + internal static void GetFormattedTextRecursive( XElement Xml, ref List alist ) + { + FormattedText ft = ToFormattedText( Xml ); + FormattedText last = null; + + if( ft != null ) + { + if( alist.Count() > 0 ) + last = alist.Last(); + + if( last != null && last.CompareTo( ft ) == 0 ) + { + // Update text of last entry. + last.text += ft.text; + } + + else + { + if( last != null ) + ft.index = last.index + last.text.Length; + + alist.Add( ft ); + } + } + + if( Xml.HasElements ) + foreach( XElement e in Xml.Elements() ) + GetFormattedTextRecursive( e, ref alist ); + } + + internal static FormattedText ToFormattedText( XElement e ) + { + // The text representation of e. + String text = ToText( e ); + if( text == String.Empty ) + return null; + + // e is a w:t element, it must exist inside a w:r element or a w:tabs, lets climb until we find it. + while( !e.Name.Equals( XName.Get( "r", DocX.w.NamespaceName ) ) && !e.Name.Equals( XName.Get( "tabs", DocX.w.NamespaceName ) ) ) + e = e.Parent; + + // e is a w:r element, lets find the rPr element. + XElement rPr = e.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + + FormattedText ft = new FormattedText(); + ft.text = text; + ft.index = 0; + ft.formatting = null; + + // Return text with formatting. + if( rPr != null ) + ft.formatting = Formatting.Parse( rPr ); + + return ft; + } + + internal static string ToText( XElement e ) + { + switch( e.Name.LocalName ) + { + case "tab": + return "\t"; + case "br": + return "\n"; + case "t": + goto case "delText"; + case "delText": + { + if( e.Parent != null && e.Parent.Name.LocalName == "r" ) + { + XElement run = e.Parent; + var rPr = run.Elements().FirstOrDefault( a => a.Name.LocalName == "rPr" ); + if( rPr != null ) + { + var caps = rPr.Elements().FirstOrDefault( a => a.Name.LocalName == "caps" ); + + if( caps != null ) + return e.Value.ToUpper(); + } + } + + return e.Value; + } + case "tr": + goto case "br"; + case "tc": + goto case "tab"; + default: + return ""; + } + } + + internal static XElement CloneElement( XElement element ) + { + return new XElement + ( + element.Name, + element.Attributes(), + element.Nodes().Select + ( + n => + { + XElement e = n as XElement; + if( e != null ) + return CloneElement( e ); + return n; + } + ) + ); + } + + internal static PackagePart CreateOrGetSettingsPart( Package package ) + { + PackagePart settingsPart; + + var settingsUri = new Uri( "/word/settings.xml", UriKind.Relative ); + if( !package.PartExists( settingsUri ) ) + { + settingsPart = package.CreatePart( settingsUri, HelperFunctions.SETTING_DOCUMENTTYPE, CompressionOption.Maximum ); + + var mainDocPart = package.GetParts().Single( p => p.ContentType.Equals( DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) || + p.ContentType.Equals( TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) ); + + mainDocPart.CreateRelationship( settingsUri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" ); + + var settings = XDocument.Parse + ( @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " + ); + + var themeFontLang = settings.Root.Element( XName.Get( "themeFontLang", DocX.w.NamespaceName ) ); + themeFontLang.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), CultureInfo.CurrentCulture ); + + // Save the settings document. + using( TextWriter tw = new StreamWriter( new PackagePartStream( settingsPart.GetStream() ) ) ) + { + settings.Save( tw ); + } + } + else + { + settingsPart = package.GetPart( settingsUri ); + } + return settingsPart; + } + + internal static void CreateCustomPropertiesPart( DocX document ) + { + var customPropertiesPart = document._package.CreatePart( new Uri( "/docProps/custom.xml", UriKind.Relative ), "application/vnd.openxmlformats-officedocument.custom-properties+xml", CompressionOption.Maximum ); + + var customPropDoc = new XDocument + ( + new XDeclaration( "1.0", "UTF-8", "yes" ), + new XElement + ( + XName.Get( "Properties", DocX.customPropertiesSchema.NamespaceName ), + new XAttribute( XNamespace.Xmlns + "vt", DocX.customVTypesSchema ) + ) + ); + + using( TextWriter tw = new StreamWriter( new PackagePartStream( customPropertiesPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + customPropDoc.Save( tw, SaveOptions.None ); + } + + document._package.CreateRelationship( customPropertiesPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties" ); + } + + internal static XDocument DecompressXMLResource( string manifest_resource_name ) + { + // XDocument to load the compressed Xml resource into. + XDocument document; + + // Get a reference to the executing assembly. + Assembly assembly = Assembly.GetExecutingAssembly(); + + // Open a Stream to the embedded resource. + Stream stream = assembly.GetManifestResourceStream( manifest_resource_name ); + + // Decompress the embedded resource. + using( GZipStream zip = new GZipStream( stream, CompressionMode.Decompress ) ) + { + // Load this decompressed embedded resource into an XDocument using a TextReader. + using( TextReader sr = new StreamReader( zip ) ) + { + document = XDocument.Load( sr ); + } + } + + // Return the decompressed Xml as an XDocument. + return document; + } + + /// + /// If this document does not contain a /word/styles.xml add the default one generated by Microsoft Word. + /// + /// + /// + internal static XDocument AddDefaultStylesXml( Package package ) + { + XDocument stylesDoc; + // Create the main document part for this package + var word_styles = package.CreatePart( new Uri( "/word/styles.xml", UriKind.Relative ), "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", CompressionOption.Maximum ); + + stylesDoc = HelperFunctions.DecompressXMLResource( "Xceed.Words.NET.Resources.default_styles.xml.gz" ); + var lang = stylesDoc.Root.Element( XName.Get( "docDefaults", DocX.w.NamespaceName ) ).Element( XName.Get( "rPrDefault", DocX.w.NamespaceName ) ).Element( XName.Get( "rPr", DocX.w.NamespaceName ) ).Element( XName.Get( "lang", DocX.w.NamespaceName ) ); + lang.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), CultureInfo.CurrentCulture ); + + // Save /word/styles.xml + using( TextWriter tw = new StreamWriter( new PackagePartStream( word_styles.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + stylesDoc.Save( tw, SaveOptions.None ); + } + + var mainDocumentPart = package.GetParts().Where + ( + p => p.ContentType.Equals( DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) || + p.ContentType.Equals( TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) + ).Single(); + + mainDocumentPart.CreateRelationship( word_styles.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" ); + return stylesDoc; + } + + internal static XElement CreateEdit( EditType t, DateTime edit_time, object content ) + { + if( t == EditType.del ) + { + foreach( object o in ( IEnumerable )content ) + { + if( o is XElement ) + { + XElement e = ( o as XElement ); + IEnumerable ts = e.DescendantsAndSelf( XName.Get( "t", DocX.w.NamespaceName ) ); + + for( int i = 0; i < ts.Count(); i++ ) + { + XElement text = ts.ElementAt( i ); + text.ReplaceWith( new XElement( DocX.w + "delText", text.Attributes(), text.Value ) ); + } + } + } + } + + return + ( + new XElement( DocX.w + t.ToString(), + new XAttribute( DocX.w + "id", 0 ), + new XAttribute( DocX.w + "author", WindowsIdentity.GetCurrent().Name ), + new XAttribute( DocX.w + "date", edit_time ), + content ) + ); + } + + internal static XElement CreateTable( int rowCount, int columnCount ) + { + if( ( rowCount <= 0 ) || ( columnCount <= 0 ) ) + { + throw new ArgumentOutOfRangeException( "Row and Column count must be greater than 0." ); + } + + int[] columnWidths = new int[columnCount]; + for (int i = 0; i < columnCount; i++) + { + columnWidths[i] = 2310; + } + return CreateTable(rowCount, columnWidths); + } + + internal static XElement CreateTable( int rowCount, int[] columnWidths ) + { + var newTable = new XElement( XName.Get( "tbl", DocX.w.NamespaceName ), + new XElement( XName.Get( "tblPr", DocX.w.NamespaceName ), + new XElement( XName.Get( "tblStyle", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), "TableGrid" ) ), + new XElement( XName.Get( "tblW", DocX.w.NamespaceName ), new XAttribute( XName.Get( "w", DocX.w.NamespaceName ), "5000" ), new XAttribute( XName.Get( "type", DocX.w.NamespaceName ), "auto" ) ), + new XElement( XName.Get( "tblLook", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), "04A0" ) ) ) ); + + for( int i = 0; i < rowCount; i++ ) + { + var row = new XElement( XName.Get( "tr", DocX.w.NamespaceName ) ); + + for( int j = 0; j < columnWidths.Length; j++ ) + { + var cell = HelperFunctions.CreateTableCell(); + row.Add( cell ); + } + + newTable.Add( row ); + } + return newTable; + } + + /// + /// Create and return a cell of a table + /// + internal static XElement CreateTableCell( double w = 2310 ) + { + return new XElement( XName.Get( "tc", DocX.w.NamespaceName ), + new XElement( XName.Get( "tcPr", DocX.w.NamespaceName ), + new XElement( XName.Get( "tcW", DocX.w.NamespaceName ), + new XAttribute( XName.Get( "w", DocX.w.NamespaceName ), w ), + new XAttribute( XName.Get( "type", DocX.w.NamespaceName ), "dxa" ) ) ), + new XElement( XName.Get( "p", DocX.w.NamespaceName ), new XElement( XName.Get( "pPr", DocX.w.NamespaceName ) ) ) ); + } + + internal static void RenumberIDs( DocX document ) + { + IEnumerable trackerIDs = + ( from d in document._mainDoc.Descendants() + where d.Name.LocalName == "ins" || d.Name.LocalName == "del" + select d.Attribute( XName.Get( "id", "http://schemas.openxmlformats.org/wordprocessingml/2006/main" ) ) ); + + for( int i = 0; i < trackerIDs.Count(); i++ ) + trackerIDs.ElementAt( i ).Value = i.ToString(); + } + + internal static Paragraph GetFirstParagraphEffectedByInsert( DocX document, int index ) + { + // This document contains no Paragraphs and insertion is at index 0 + if( document._paragraphLookup.Keys.Count() == 0 && index == 0 ) + return null; + + foreach( int paragraphEndIndex in document._paragraphLookup.Keys ) + { + if( paragraphEndIndex >= index ) + return document._paragraphLookup[ paragraphEndIndex ]; + } + + throw new ArgumentOutOfRangeException(); + } + + internal static List FormatInput( string text, XElement rPr ) + { + var newRuns = new List(); + var tabRun = new XElement( DocX.w + "tab" ); + var breakRun = new XElement( DocX.w + "br" ); + + var sb = new StringBuilder(); + + if( string.IsNullOrEmpty( text ) ) + { + return newRuns; //I dont wanna get an exception if text == null, so just return empy list + } + + char lastCharacter = '\0'; + foreach( char c in text ) + { + switch( c ) + { + case '\t': + if( sb.Length > 0 ) + { + var t = new XElement( DocX.w + "t", sb.ToString() ); + Xceed.Words.NET.Text.PreserveSpace( t ); + newRuns.Add( new XElement( DocX.w + "r", rPr, t ) ); + sb = new StringBuilder(); + } + newRuns.Add( new XElement( DocX.w + "r", rPr, tabRun ) ); + break; + case '\n': + if( lastCharacter == '\r' ) + break; + if( sb.Length > 0 ) + { + var t = new XElement( DocX.w + "t", sb.ToString() ); + Xceed.Words.NET.Text.PreserveSpace( t ); + newRuns.Add( new XElement( DocX.w + "r", rPr, t ) ); + sb = new StringBuilder(); + } + newRuns.Add( new XElement( DocX.w + "r", rPr, breakRun ) ); + break; + case '\r': + if( sb.Length > 0 ) + { + var t = new XElement( DocX.w + "t", sb.ToString() ); + Xceed.Words.NET.Text.PreserveSpace( t ); + newRuns.Add( new XElement( DocX.w + "r", rPr, t ) ); + sb = new StringBuilder(); + } + newRuns.Add( new XElement( DocX.w + "r", rPr, breakRun ) ); + break; + + default: + sb.Append( c ); + break; + } + + lastCharacter = c; + } + + if( sb.Length > 0 ) + { + var t = new XElement( DocX.w + "t", sb.ToString() ); + Xceed.Words.NET.Text.PreserveSpace( t ); + newRuns.Add( new XElement( DocX.w + "r", rPr, t ) ); + } + + return newRuns; + } + + internal static XElement[] SplitParagraph( Paragraph p, int index ) + { + // In this case edit dosent really matter, you have a choice. + Run r = p.GetFirstRunEffectedByEdit( index, EditType.ins ); + + XElement[] split; + XElement before, after; + + if( r.Xml.Parent.Name.LocalName == "ins" ) + { + split = p.SplitEdit( r.Xml.Parent, index, EditType.ins ); + before = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsBeforeSelf(), split[ 0 ] ); + after = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsAfterSelf(), split[ 1 ] ); + } + + else if( r.Xml.Parent.Name.LocalName == "del" ) + { + split = p.SplitEdit( r.Xml.Parent, index, EditType.del ); + + before = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsBeforeSelf(), split[ 0 ] ); + after = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsAfterSelf(), split[ 1 ] ); + } + + else + { + split = Run.SplitRun( r, index ); + + before = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.ElementsBeforeSelf(), split[ 0 ] ); + after = new XElement( p.Xml.Name, p.Xml.Attributes(), split[ 1 ], r.Xml.ElementsAfterSelf() ); + } + + if( before.Elements().Count() == 0 ) + before = null; + + if( after.Elements().Count() == 0 ) + after = null; + + return new XElement[] { before, after }; + } + + /// + internal static bool IsSameFile( Stream streamOne, Stream streamTwo ) + { + int file1byte, file2byte; + + if( streamOne.Length != streamTwo.Length ) + { + // Return false to indicate files are different + return false; + } + + // Read and compare a byte from each file until either a + // non-matching set of bytes is found or until the end of + // file1 is reached. + do + { + // Read one byte from each file. + file1byte = streamOne.ReadByte(); + file2byte = streamTwo.ReadByte(); + } + while( ( file1byte == file2byte ) && ( file1byte != -1 ) ); + + // Return the success of the comparison. "file1byte" is + // equal to "file2byte" at this point only if the files are + // the same. + + streamOne.Position = 0; + streamTwo.Position = 0; + + return ( ( file1byte - file2byte ) == 0 ); + } + + /// + /// Add the default numbering.xml if it is missing from this document + /// + internal static XDocument AddDefaultNumberingXml(Package package) + { + XDocument numberingDoc; + + var numberingPart = package.CreatePart(new Uri("/word/numbering.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", CompressionOption.Maximum); + numberingDoc = DecompressXMLResource("Xceed.Words.NET.Resources.numbering.xml.gz"); + + using( TextWriter tw = new StreamWriter( new PackagePartStream( numberingPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) ) + { + numberingDoc.Save( tw, SaveOptions.None ); + } + + var mainDocPart = package.GetParts().Single( p => p.ContentType.Equals( DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) || + p.ContentType.Equals( TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) ); + + mainDocPart.CreateRelationship(numberingPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"); + return numberingDoc; + } + + internal static List CreateItemInList(List list, string listText, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false) + { + if (list.NumId == 0) + { + list.CreateNewNumberingNumId(level, listType, startNumber, continueNumbering); + } + + if (listText != null) + { + var newSection = new XElement + ( + XName.Get("p", DocX.w.NamespaceName), + new XElement(XName.Get("pPr", DocX.w.NamespaceName), + new XElement(XName.Get("numPr", DocX.w.NamespaceName), + new XElement(XName.Get("ilvl", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", level)), + new XElement(XName.Get("numId", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", list.NumId)))), + new XElement(XName.Get("r", DocX.w.NamespaceName), new XElement(XName.Get("t", DocX.w.NamespaceName), listText)) + ); + + if (trackChanges) + newSection = CreateEdit(EditType.ins, DateTime.Now, newSection); + + if (startNumber == null) + list.AddItem(new Paragraph(list.Document, newSection, 0, ContainerType.Paragraph)); + else + list.AddItemWithStartValue(new Paragraph(list.Document, newSection, 0, ContainerType.Paragraph), (int)startNumber); + } + return list; + } + + internal static UnderlineStyle GetUnderlineStyle(string styleName) + { + switch (styleName) + { + case "single": + return UnderlineStyle.singleLine; + case "double": + return UnderlineStyle.doubleLine; + case "thick": + return UnderlineStyle.thick; + case "dotted": + return UnderlineStyle.dotted; + case "dottedHeavy": + return UnderlineStyle.dottedHeavy; + case "dash": + return UnderlineStyle.dash; + case "dashedHeavy": + return UnderlineStyle.dashedHeavy; + case "dashLong": + return UnderlineStyle.dashLong; + case "dashLongHeavy": + return UnderlineStyle.dashLongHeavy; + case "dotDash": + return UnderlineStyle.dotDash; + case "dashDotHeavy": + return UnderlineStyle.dashDotHeavy; + case "dotDotDash": + return UnderlineStyle.dotDotDash; + case "dashDotDotHeavy": + return UnderlineStyle.dashDotDotHeavy; + case "wave": + return UnderlineStyle.wave; + case "wavyHeavy": + return UnderlineStyle.wavyHeavy; + case "wavyDouble": + return UnderlineStyle.wavyDouble; + case "words": + return UnderlineStyle.words; + default: + return UnderlineStyle.none; + } + } + + internal static bool ContainsEveryChildOf(XElement elementWanted, XElement elementToValidate, MatchFormattingOptions formattingOptions) + { + foreach (XElement subElement in elementWanted.Elements()) + { + if (!elementToValidate.Elements(subElement.Name).Where(bElement => bElement.GetAttribute(XName.Get("val", DocX.w.NamespaceName)) == subElement.GetAttribute(XName.Get("val", DocX.w.NamespaceName))).Any()) + return false; + } + + if (formattingOptions == MatchFormattingOptions.ExactMatch) + return elementWanted.Elements().Count() == elementToValidate.Elements().Count(); + + return true; + } + + internal static string GetListItemType( Paragraph p, DocX document ) + { + var ilvlNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault( el => el.Name.LocalName == "ilvl" ); + var ilvlValue = ilvlNode.Attribute( DocX.w + "val" ).Value; + + var numIdNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault( el => el.Name.LocalName == "numId" ); + var numIdValue = numIdNode.Attribute( DocX.w + "val" ).Value; + + //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" ); + return numFmtNode.Attribute( DocX.w + "val" ).Value; + } + + return null; + } + } +} diff --git a/Xceed.Words.NET/Src/Hyperlink.cs b/Xceed.Words.NET/Src/Hyperlink.cs new file mode 100644 index 00000000..7978e78b --- /dev/null +++ b/Xceed.Words.NET/Src/Hyperlink.cs @@ -0,0 +1,262 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using System.IO.Packaging; + +namespace Xceed.Words.NET +{ + /// + /// Represents a Hyperlink in a document. + /// + public class Hyperlink : DocXElement + { + #region Internal Members + + internal Uri uri; + internal String text; + + internal Dictionary hyperlink_rels; + internal int type; + internal String id; + internal XElement instrText; + internal List runs; + + #endregion + + #region Public Properties + + /// + /// Change the Text of a Hyperlink. + /// + /// + /// Change the Text of a Hyperlink. + /// + /// // Create a document. + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // Get all of the hyperlinks in this document + /// List<Hyperlink> hyperlinks = document.Hyperlinks; + /// + /// // Change the first hyperlinks text and Uri + /// Hyperlink h0 = hyperlinks[0]; + /// h0.Text = "DocX"; + /// h0.Uri = new Uri("http://docx.codeplex.com"); + /// + /// // Save this document. + /// document.Save(); + /// } + /// + /// + public string Text + { + get + { + return this.text; + } + + set + { + XElement rPr = + new XElement + ( + DocX.w + "rPr", + new XElement + ( + DocX.w + "rStyle", + new XAttribute( DocX.w + "val", "Hyperlink" ) + ) + ); + + // Format and add the new text. + List newRuns = HelperFunctions.FormatInput( value, rPr ); + + if( type == 0 ) + { + // Get all the runs in this Text. + var runs = from r in Xml.Elements() + where r.Name.LocalName == "r" + select r; + + // Remove each run. + for( int i = 0; i < runs.Count(); i++ ) + runs.Remove(); + + Xml.Add( newRuns ); + } + + else + { + XElement separate = XElement.Parse( @" + + + " ); + + XElement end = XElement.Parse( @" + + + " ); + + runs.Last().AddAfterSelf( separate, newRuns, end ); + runs.ForEach( r => r.Remove() ); + } + + this.text = value; + } + } + + /// + /// Change the Uri of a Hyperlink. + /// + /// + /// Change the Uri of a Hyperlink. + /// + /// hyperlinks = document.Hyperlinks; + /// + /// // Change the first hyperlinks text and Uri + /// Hyperlink h0 = hyperlinks[0]; + /// h0.Text = "DocX"; + /// h0.Uri = new Uri("http://docx.codeplex.com"); + /// + /// // Save this document. + /// document.Save(); + /// } + /// ]]> + /// + /// + public Uri Uri + { + get + { + if( type == 0 && id != String.Empty ) + { + var r = this.PackagePart.GetRelationship( id ); + return r.TargetUri; + } + + return this.uri; + } + + set + { + if( type == 0 ) + { + var r = this.PackagePart.GetRelationship( id ); + + // Get all of the information about this relationship. + var r_tm = r.TargetMode; + var r_rt = r.RelationshipType; + var r_id = r.Id; + + // Delete the relationship + this.PackagePart.DeleteRelationship( r_id ); + this.PackagePart.CreateRelationship( value, r_tm, r_rt, r_id ); + } + + else + { + instrText.Value = "HYPERLINK " + "\"" + value + "\""; + } + + this.uri = value; + } + } + + #endregion + + #region Constructors + + internal Hyperlink( DocX document, PackagePart mainPart, XElement i ) : base( document, i ) + { + this.type = 0; + this.id = i.Attribute( XName.Get( "id", DocX.r.NamespaceName ) ).Value; + + StringBuilder sb = new StringBuilder(); + HelperFunctions.GetTextRecursive( i, ref sb ); + this.text = sb.ToString(); + } + + internal Hyperlink( DocX document, XElement instrText, List runs ) : base( document, null ) + { + this.type = 1; + this.instrText = instrText; + this.runs = runs; + + try + { + int start = instrText.Value.IndexOf( "HYPERLINK \"" ) + "HYPERLINK \"".Length; + int end = instrText.Value.IndexOf( "\"", start ); + if( start != -1 && end != -1 ) + { + this.uri = new Uri( instrText.Value.Substring( start, end - start ), UriKind.Absolute ); + + StringBuilder sb = new StringBuilder(); + HelperFunctions.GetTextRecursive( new XElement( XName.Get( "temp", DocX.w.NamespaceName ), runs ), ref sb ); + this.text = sb.ToString(); + } + } + + catch( Exception e ) { throw e; } + } + + #endregion + + #region Public Methods + + /// + /// Remove a Hyperlink from this Paragraph only. + /// + /// + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add a hyperlink to this document. + /// Hyperlink h = document.AddHyperlink("link", new Uri("http://www.google.com")); + /// + /// // Add a Paragraph to this document and insert the hyperlink + /// Paragraph p1 = document.InsertParagraph(); + /// p1.Append("This is a cool ").AppendHyperlink(h).Append(" ."); + /// + /// /* + /// * Remove the hyperlink from this Paragraph only. + /// * Note a reference to the hyperlink will still exist in the document and it can thus be reused. + /// */ + /// p1.Hyperlinks[0].Remove(); + /// + /// // Add a new Paragraph to this document and reuse the hyperlink h. + /// Paragraph p2 = document.InsertParagraph(); + /// p2.Append("This is the same cool ").AppendHyperlink(h).Append(" ."); + /// + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public void Remove() + { + Xml.Remove(); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/IParagraphContainer.cs b/Xceed.Words.NET/Src/IParagraphContainer.cs new file mode 100644 index 00000000..aa1bf5ee --- /dev/null +++ b/Xceed.Words.NET/Src/IParagraphContainer.cs @@ -0,0 +1,26 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System.Collections.ObjectModel; + +namespace Xceed.Words.NET +{ + public interface IParagraphContainer + { + ReadOnlyCollection Paragraphs + { + get; + } + } +} diff --git a/Xceed.Words.NET/Src/Image.cs b/Xceed.Words.NET/Src/Image.cs new file mode 100644 index 00000000..9f1800c4 --- /dev/null +++ b/Xceed.Words.NET/Src/Image.cs @@ -0,0 +1,137 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.IO.Packaging; +using System.IO; + +namespace Xceed.Words.NET +{ + /// + /// Represents an Image embedded in a document. + /// + public class Image + { + #region Private Members + + /// + /// A unique id which identifies this Image. + /// + private string _id; + private DocX _document; + + #endregion + + #region Internal Members + + internal PackageRelationship _pr; + + #endregion + + #region Public Properties + + /// + /// Returns the id of this Image. + /// + public string Id + { + get + { + return _id; + } + } + + /// + /// Returns the name of the image file. + /// + public string FileName + { + get + { + return Path.GetFileName( _pr.TargetUri.ToString() ); + } + } + + #endregion + + #region Constructors + + internal Image( DocX document, PackageRelationship pr ) + { + _document = document; + _pr = pr; + _id = pr.Id; + } + + #endregion + + #region Public Methods + + public Stream GetStream( FileMode mode, FileAccess access ) + { + string temp = _pr.SourceUri.OriginalString; + string start = temp.Remove( temp.LastIndexOf( '/' ) ); + string end = _pr.TargetUri.OriginalString; + string full = end.Contains( start ) ? end : start + "/" + end; + + return ( new PackagePartStream( _document._package.GetPart( new Uri( full, UriKind.Relative ) ).GetStream( mode, access ) ) ); + } + + /// + /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append. + /// + /// + /// + /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append. + /// + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Add an image to the document. + /// Image i = document.AddImage(@"Image.jpg"); + /// + /// // Create a picture i.e. (A custom view of an image) + /// Picture p = i.CreatePicture(); + /// p.FlipHorizontal = true; + /// p.Rotation = 10; + /// + /// // Create a new Paragraph. + /// Paragraph par = document.InsertParagraph(); + /// + /// // Append content to the Paragraph. + /// par.Append("Here is a cool picture") + /// .AppendPicture(p) + /// .Append(" don't you think so?"); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + /// + public Picture CreatePicture() + { + return this.CreatePicture( -1, -1 ); + } + + /// + /// Add an image to a document with specific height and width, create a custom view of that image (picture) and then insert it into a Paragraph using append. + /// + public Picture CreatePicture( int height, int width ) + { + return Paragraph.CreatePicture( _document, _id, string.Empty, string.Empty, width, height ); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/List.cs b/Xceed.Words.NET/Src/List.cs new file mode 100644 index 00000000..71031cbe --- /dev/null +++ b/Xceed.Words.NET/Src/List.cs @@ -0,0 +1,273 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Linq; +using System.Xml.Linq; +using System.Collections.Generic; + +namespace Xceed.Words.NET +{ + /// + /// Represents a List in a document. + /// + public class List : InsertBeforeOrAfter + { + #region Public Members + + /// + /// This is a list of paragraphs that will be added to the document + /// when the list is inserted into the document. + /// The paragraph needs a numPr defined to be in this items collection. + /// + public List Items + { + get; private set; + } + + /// + /// The numId used to reference the list settings in the numbering.xml + /// + public int NumId + { + get; private set; + } + + /// + /// The ListItemType (bullet or numbered) of the list. + /// + public ListItemType? ListType + { + get; private set; + } + + #endregion + + #region Constructors + + internal List( DocX document, XElement xml ) + : base( document, xml ) + { + Items = new List(); + ListType = null; + } + + #endregion + + #region Public Methods + + /// + /// Adds an item to the list. + /// + /// + /// + /// Throws an InvalidOperationException if the item cannot be added to the list. + /// + public void AddItem( Paragraph paragraph ) + { + if( paragraph.IsListItem ) + { + var numIdNode = paragraph.Xml.Descendants().First( s => s.Name.LocalName == "numId" ); + var numId = Int32.Parse( numIdNode.Attribute( DocX.w + "val" ).Value ); + + if( CanAddListItem( paragraph ) ) + { + NumId = numId; + Items.Add( paragraph ); + } + else + throw new InvalidOperationException( "New list items can only be added to this list if they are have the same numId." ); + } + } + + public void AddItemWithStartValue( Paragraph paragraph, int start ) + { + //TODO: Update the numbering + UpdateNumberingForLevelStartNumber( int.Parse( paragraph.IndentLevel.ToString() ), start ); + if( ContainsLevel( start ) ) + throw new InvalidOperationException( "Cannot add a paragraph with a start value if another element already exists in this list with that level." ); + AddItem( paragraph ); + } + + /// + /// Determine if it is able to add the item to the list + /// + /// + /// + /// Return true if AddItem(...) will succeed with the given paragraph. + /// + public bool CanAddListItem( Paragraph paragraph ) + { + if( paragraph.IsListItem ) + { + //var lvlNode = paragraph.Xml.Descendants().First(s => s.Name.LocalName == "ilvl"); + var numIdNode = paragraph.Xml.Descendants().First( s => s.Name.LocalName == "numId" ); + var numId = Int32.Parse( numIdNode.Attribute( DocX.w + "val" ).Value ); + + //Level = Int32.Parse(lvlNode.Attribute(DocX.w + "val").Value); + if( NumId == 0 || ( numId == NumId && numId > 0 ) ) + { + return true; + } + } + return false; + } + + public bool ContainsLevel( int ilvl ) + { + return Items.Any( i => i.ParagraphNumberProperties.Descendants().First( el => el.Name.LocalName == "ilvl" ).Value == ilvl.ToString() ); + } + + #endregion + + #region Internal Methods + + internal void CreateNewNumberingNumId( int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool continueNumbering = false ) + { + ValidateDocXNumberingPartExists(); + if( Document._numbering.Root == null ) + { + throw new InvalidOperationException( "Numbering section did not instantiate properly." ); + } + + ListType = listType; + + var numId = GetMaxNumId() + 1; + var abstractNumId = GetMaxAbstractNumId() + 1; + + XDocument listTemplate; + switch( listType ) + { + case ListItemType.Bulleted: + listTemplate = HelperFunctions.DecompressXMLResource( "Xceed.Words.NET.Resources.numbering.default_bullet_abstract.xml.gz" ); + break; + case ListItemType.Numbered: + listTemplate = HelperFunctions.DecompressXMLResource( "Xceed.Words.NET.Resources.numbering.default_decimal_abstract.xml.gz" ); + break; + default: + throw new InvalidOperationException( string.Format( "Unable to deal with ListItemType: {0}.", listType.ToString() ) ); + } + var abstractNumTemplate = listTemplate.Descendants().Single( d => d.Name.LocalName == "abstractNum" ); + abstractNumTemplate.SetAttributeValue( DocX.w + "abstractNumId", abstractNumId ); + var abstractNumXml = GetAbstractNumXml( abstractNumId, numId, startNumber, continueNumbering ); + + var abstractNumNode = Document._numbering.Root.Descendants().LastOrDefault( xElement => xElement.Name.LocalName == "abstractNum" ); + var numXml = Document._numbering.Root.Descendants().LastOrDefault( xElement => xElement.Name.LocalName == "num" ); + + if( abstractNumNode == null || numXml == null ) + { + Document._numbering.Root.Add( abstractNumTemplate ); + Document._numbering.Root.Add( abstractNumXml ); + } + else + { + abstractNumNode.AddAfterSelf( abstractNumTemplate ); + numXml.AddAfterSelf( + abstractNumXml + ); + } + + NumId = numId; + } + + /// + /// Get the abstractNum definition for the given numId + /// + /// The numId on the pPr element + /// XElement representing the requested abstractNum + internal XElement GetAbstractNum( int numId ) + { + var num = Document._numbering.Descendants().First( d => d.Name.LocalName == "num" && d.GetAttribute( DocX.w + "numId" ).Equals( numId.ToString() ) ); + var abstractNumId = num.Descendants().First( d => d.Name.LocalName == "abstractNumId" ); + return Document._numbering.Descendants().First( d => d.Name.LocalName == "abstractNum" && d.GetAttribute( "abstractNumId" ).Equals( abstractNumId.Value ) ); + } + + #endregion + + #region Private Methods + + private void UpdateNumberingForLevelStartNumber( int iLevel, int start ) + { + var abstractNum = GetAbstractNum( NumId ); + var level = abstractNum.Descendants().First( el => el.Name.LocalName == "lvl" && el.GetAttribute( DocX.w + "ilvl" ) == iLevel.ToString() ); + level.Descendants().First( el => el.Name.LocalName == "start" ).SetAttributeValue( DocX.w + "val", start ); + } + + private XElement GetAbstractNumXml( int abstractNumId, int numId, int? startNumber, bool continueNumbering ) + { + var start = new XElement( XName.Get( "startOverride", DocX.w.NamespaceName ), new XAttribute( DocX.w + "val", startNumber ?? 1 ) ); + var level = new XElement( XName.Get( "lvlOverride", DocX.w.NamespaceName ), new XAttribute( DocX.w + "ilvl", 0 ), start ); + var element = new XElement( XName.Get( "abstractNumId", DocX.w.NamespaceName ), new XAttribute( DocX.w + "val", abstractNumId ) ); + + return continueNumbering + ? new XElement( XName.Get( "num", DocX.w.NamespaceName ), new XAttribute( DocX.w + "numId", numId ), element ) + : new XElement( XName.Get( "num", DocX.w.NamespaceName ), new XAttribute( DocX.w + "numId", numId ), element, level ); + } + + /// + /// Method to determine the last numId for a list element. + /// Also useful for determining the next numId to use for inserting a new list element into the document. + /// + /// + /// 0 if there are no elements in the list already. + /// Increment the return for the next valid value of a new list element. + /// + private int GetMaxNumId() + { + const int defaultValue = 0; + if( Document._numbering == null ) + return defaultValue; + + var numlist = Document._numbering.Descendants().Where( d => d.Name.LocalName == "num" ).ToList(); + if( numlist.Any() ) + return numlist.Attributes( DocX.w + "numId" ).Max( e => int.Parse( e.Value ) ); + return defaultValue; + } + + /// + /// Method to determine the last abstractNumId for a list element. + /// Also useful for determining the next abstractNumId to use for inserting a new list element into the document. + /// + /// + /// -1 if there are no elements in the list already. + /// Increment the return for the next valid value of a new list element. + /// + private int GetMaxAbstractNumId() + { + const int defaultValue = -1; + + if( Document._numbering == null ) + return defaultValue; + + var numlist = Document._numbering.Descendants().Where( d => d.Name.LocalName == "abstractNum" ).ToList(); + if( numlist.Any() ) + { + var maxAbstractNumId = numlist.Attributes( DocX.w + "abstractNumId" ).Max( e => int.Parse( e.Value ) ); + return maxAbstractNumId; + } + return defaultValue; + } + + private void ValidateDocXNumberingPartExists() + { + var numberingUri = new Uri( "/word/numbering.xml", UriKind.Relative ); + + // If the internal document contains no /word/numbering.xml create one. + if( !Document._package.PartExists( numberingUri ) ) + Document._numbering = HelperFunctions.AddDefaultNumberingXml( Document._package ); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/PackagePartStream.cs b/Xceed.Words.NET/Src/PackagePartStream.cs new file mode 100644 index 00000000..5360934e --- /dev/null +++ b/Xceed.Words.NET/Src/PackagePartStream.cs @@ -0,0 +1,133 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System.IO; +using System.Threading; + +// This classe is used to prevent deadlocks. +// It is based on https://stackoverflow.com/questions/21482820/openxml-hanging-while-writing-elements + +namespace Xceed.Words.NET +{ + public class PackagePartStream : Stream + { + #region Private Members + + private static readonly Mutex _mutex = new Mutex( false ); + private readonly Stream _stream; + + #endregion + + #region constructors + + public PackagePartStream( Stream stream ) + { + _stream = stream; + } + + #endregion + + #region Overrides Properties + + public override bool CanRead + { + get + { + return _stream.CanRead; + } + } + + public override bool CanSeek + { + get + { + return _stream.CanSeek; + } + } + + public override bool CanWrite + { + get + { + return _stream.CanWrite; + } + } + + public override long Length + { + get + { + return _stream.Length; + } + } + + public override long Position + { + get + { + return _stream.Position; + } + + set + { + _stream.Position = value; + } + } + + #endregion + + #region Overrides Methods + + public override long Seek( long offset, SeekOrigin origin ) + { + return _stream.Seek( offset, origin ); + } + + public override void SetLength( long value ) + { + _stream.SetLength( value ); + } + + public override int Read( byte[] buffer, int offset, int count ) + { + return _stream.Read( buffer, offset, count ); + } + + public override void Write( byte[] buffer, int offset, int count ) + { + _mutex.WaitOne( Timeout.Infinite, false ); + _stream.Write( buffer, offset, count ); + _mutex.ReleaseMutex(); + } + + public override void Flush() + { + _mutex.WaitOne( Timeout.Infinite, false ); + _stream.Flush(); + _mutex.ReleaseMutex(); + } + + public override void Close() + { + _stream.Close(); + } + + protected override void Dispose( bool disposing ) + { + _stream.Dispose(); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/PageLayout.cs b/Xceed.Words.NET/Src/PageLayout.cs new file mode 100644 index 00000000..18286f4e --- /dev/null +++ b/Xceed.Words.NET/Src/PageLayout.cs @@ -0,0 +1,95 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + public class PageLayout : DocXElement + { + #region Constructors + + internal PageLayout( DocX document, XElement xml ) : base( document, xml ) + { + + } + + #endregion + + #region Public Properties + + public Orientation Orientation + { + get + { + /* + * Get the pgSz (page size) element for this Section, + * null will be return if no such element exists. + */ + XElement pgSz = Xml.Element( XName.Get( "pgSz", DocX.w.NamespaceName ) ); + + if( pgSz == null ) + return Orientation.Portrait; + + // Get the attribute of the pgSz element. + XAttribute val = pgSz.Attribute( XName.Get( "orient", DocX.w.NamespaceName ) ); + + // If val is null, this cell contains no information. + if( val == null ) + return Orientation.Portrait; + + if( val.Value.Equals( "Landscape", StringComparison.CurrentCultureIgnoreCase ) ) + return Orientation.Landscape; + else + return Orientation.Portrait; + } + + set + { + // Check if already correct value. + if( Orientation == value ) + return; + + /* + * Get the pgSz (page size) element for this Section, + * null will be return if no such element exists. + */ + XElement pgSz = Xml.Element( XName.Get( "pgSz", DocX.w.NamespaceName ) ); + + if( pgSz == null ) + { + Xml.SetElementValue( XName.Get( "pgSz", DocX.w.NamespaceName ), string.Empty ); + pgSz = Xml.Element( XName.Get( "pgSz", DocX.w.NamespaceName ) ); + } + + pgSz.SetAttributeValue( XName.Get( "orient", DocX.w.NamespaceName ), value.ToString().ToLower() ); + + if( value == Xceed.Words.NET.Orientation.Landscape ) + { + pgSz.SetAttributeValue( XName.Get( "w", DocX.w.NamespaceName ), "16838" ); + pgSz.SetAttributeValue( XName.Get( "h", DocX.w.NamespaceName ), "11906" ); + } + + else if( value == Xceed.Words.NET.Orientation.Portrait ) + { + pgSz.SetAttributeValue( XName.Get( "w", DocX.w.NamespaceName ), "11906" ); + pgSz.SetAttributeValue( XName.Get( "h", DocX.w.NamespaceName ), "16838" ); + } + } + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/Paragraph.cs b/Xceed.Words.NET/Src/Paragraph.cs new file mode 100644 index 00000000..b2db027b --- /dev/null +++ b/Xceed.Words.NET/Src/Paragraph.cs @@ -0,0 +1,5039 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using System.Text.RegularExpressions; +using System.Security.Principal; +using System.IO.Packaging; +using System.Drawing; +using System.Globalization; + +namespace Xceed.Words.NET +{ + /// + /// Represents a document paragraph. + /// + public class Paragraph : InsertBeforeOrAfter + { + + #region Internal Members + + // The Append family of functions use this List to apply style. + internal List _runs; + internal int _startIndex, _endIndex; + internal List _styles = new List(); + + #endregion + + #region Private Members + + // This paragraphs text alignment + private Alignment alignment; + // A collection of field type DocProperty. + private List docProperties; + private Direction direction; + private float indentationFirstLine; + private float indentationHanging; + private float indentationBefore; + private float indentationAfter = 0.0f; + private Table followingTable; + + #endregion + + #region Private Properties + private XElement ParagraphNumberPropertiesBacker + { + get; set; + } + private bool? IsListItemBacker + { + get; set; + } + private int? IndentLevelBacker + { + get; set; + } + #endregion + + #region Public Properties + + public ContainerType ParentContainer + { + get; set; + } + public ListItemType ListItemType + { + get; set; + } + + /// + /// Returns a list of all Pictures in a Paragraph. + /// + /// + /// Returns a list of all Pictures in a Paragraph. + /// + /// pictures = p.Pictures; + /// + /// // Save this document. + /// document.Save(); + /// } + /// ]]> + /// + /// + public List Pictures + { + get + { + var pictures = this.GetPictures( "drawing", "blip", "embed" ); + var shapes = this.GetPictures( "pict", "imagedata", "id" ); + + foreach( Picture pict in shapes ) + { + pictures.Add( pict ); + } + + return pictures; + } + } + + /// + /// Returns a list of Hyperlinks in this Paragraph. + /// + /// + /// + /// // Create a document. + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // Get the first Paragraph in this document. + /// Paragraph p = document.Paragraphs[0]; + /// + /// // Get all of the hyperlinks in this Paragraph. + /// ]]> hyperlinks = paragraph.Hyperlinks; + /// + /// // Change the first hyperlinks text and Uri + /// Hyperlink h0 = hyperlinks[0]; + /// h0.Text = "DocX"; + /// h0.Uri = new Uri("http://docx.codeplex.com"); + /// + /// // Save this document. + /// document.Save(); + /// } + /// + /// + public List Hyperlinks + { + get + { + var hyperlinks = new List(); + + var hyperlink_elements = + ( + from h in Xml.Descendants() + where ( h.Name.LocalName == "hyperlink" || h.Name.LocalName == "instrText" ) + select h + ).ToList(); + + foreach( XElement he in hyperlink_elements ) + { + if( he.Name.LocalName == "hyperlink" ) + { + try + { + var h = new Hyperlink( this.Document, this.PackagePart, he ); + h.PackagePart = this.PackagePart; + hyperlinks.Add( h ); + } + catch( Exception ) + { + } + } + else + { + // Find the parent run, no matter how deeply nested we are. + XElement e = he; + while( e.Name.LocalName != "r" ) + { + e = e.Parent; + } + + // Take every element until we reach w:fldCharType="end" + var hyperlink_runs = new List(); + foreach( XElement r in e.ElementsAfterSelf( XName.Get( "r", DocX.w.NamespaceName ) ) ) + { + // Add this run to the list. + hyperlink_runs.Add( r ); + + var fldChar = r.Descendants( XName.Get( "fldChar", DocX.w.NamespaceName ) ).SingleOrDefault(); + if( fldChar != null ) + { + var fldCharType = fldChar.Attribute( XName.Get( "fldCharType", DocX.w.NamespaceName ) ); + if( fldCharType != null && fldCharType.Value.Equals( "end", StringComparison.CurrentCultureIgnoreCase ) ) + { + try + { + var h = new Hyperlink( Document, he, hyperlink_runs ); + h.PackagePart = this.PackagePart; + hyperlinks.Add( h ); + } + catch( Exception ) + { + } + + break; + } + } + } + } + } + + return hyperlinks; + } + } + + /// + /// The style name of the paragraph. + /// + public string StyleName + { + get + { + var element = this.GetOrCreate_pPr(); + var styleElement = element.Element( XName.Get( "pStyle", DocX.w.NamespaceName ) ); + var attr = styleElement?.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + if ( !string.IsNullOrEmpty( attr?.Value ) ) + { + return attr.Value; + } + return "Normal"; + } + set + { + if( string.IsNullOrEmpty( value ) ) + { + value = "Normal"; + } + var element = this.GetOrCreate_pPr(); + var styleElement = element.Element( XName.Get( "pStyle", DocX.w.NamespaceName ) ); + if( styleElement == null ) + { + element.Add( new XElement( XName.Get( "pStyle", DocX.w.NamespaceName ) ) ); + styleElement = element.Element( XName.Get( "pStyle", DocX.w.NamespaceName ) ); + } + styleElement.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), value ); + } + } + + /// + /// Returns a list of field type DocProperty in this document. + /// + public List DocumentProperties + { + get + { + return docProperties; + } + } + + /// + /// Gets or Sets the Direction of content in this Paragraph. + /// + /// Create a Paragraph with content that flows right to left. Default is left to right. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Create a new Paragraph with the text "Hello World". + /// Paragraph p = document.InsertParagraph("Hello World."); + /// + /// // Make this Paragraph flow right to left. Default is left to right. + /// p.Direction = Direction.RightToLeft; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + /// + public Direction Direction + { + get + { + XElement pPr = GetOrCreate_pPr(); + XElement bidi = pPr.Element( XName.Get( "bidi", DocX.w.NamespaceName ) ); + return bidi == null ? Direction.LeftToRight : Direction.RightToLeft; + } + + set + { + direction = value; + + XElement pPr = GetOrCreate_pPr(); + XElement bidi = pPr.Element( XName.Get( "bidi", DocX.w.NamespaceName ) ); + + if( direction == Direction.RightToLeft ) + { + if( bidi == null ) + pPr.Add( new XElement( XName.Get( "bidi", DocX.w.NamespaceName ) ) ); + } + + else + { + bidi?.Remove(); + } + } + } + + /// + /// Get or set the indentation of the first line of this Paragraph. + /// + /// + /// Indent only the first line of a Paragraph. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Create a new Paragraph. + /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3"); + /// + /// // Indent only the first line of the Paragraph. + /// p.IndentationFirstLine = 2.0f; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + public float IndentationFirstLine + { + get + { + GetOrCreate_pPr(); + XElement ind = GetOrCreate_pPr_ind(); + XAttribute firstLine = ind.Attribute( XName.Get( "firstLine", DocX.w.NamespaceName ) ); + + if( firstLine != null ) + return float.Parse( firstLine.Value ); + + return 0.0f; + } + + set + { + if( IndentationFirstLine != value ) + { + indentationFirstLine = value; + + GetOrCreate_pPr(); + XElement ind = GetOrCreate_pPr_ind(); + + // Paragraph can either be firstLine or hanging (Remove hanging). + XAttribute hanging = ind.Attribute( XName.Get( "hanging", DocX.w.NamespaceName ) ); + hanging?.Remove(); + + string indentation = ( ( indentationFirstLine / 0.1 ) * 57 ).ToString(); + XAttribute firstLine = ind.Attribute( XName.Get( "firstLine", DocX.w.NamespaceName ) ); + if( firstLine != null ) + firstLine.Value = indentation; + else + ind.Add( new XAttribute( XName.Get( "firstLine", DocX.w.NamespaceName ), indentation ) ); + } + } + } + + /// + /// Get or set the indentation of all but the first line of this Paragraph. + /// + /// + /// Indent all but the first line of a Paragraph. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Create a new Paragraph. + /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3"); + /// + /// // Indent all but the first line of the Paragraph. + /// p.IndentationHanging = 1.0f; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + public float IndentationHanging + { + get + { + GetOrCreate_pPr(); + var ind = GetOrCreate_pPr_ind(); + var hanging = ind.Attribute( XName.Get( "hanging", DocX.w.NamespaceName ) ); + + if( hanging != null ) + return float.Parse( hanging.Value ) / 570f; + + return 0.0f; + } + + set + { + if( IndentationHanging != value ) + { + indentationHanging = value; + + GetOrCreate_pPr(); + var ind = GetOrCreate_pPr_ind(); + + // Paragraph can either be firstLine or hanging (Remove firstLine). + var firstLine = ind.Attribute( XName.Get( "firstLine", DocX.w.NamespaceName ) ); + if( firstLine != null ) + { + firstLine.Remove(); + } + + var indentation = ( ( indentationHanging / 0.1 ) * 57 ).ToString(); + var hanging = ind.Attribute( XName.Get( "hanging", DocX.w.NamespaceName ) ); + if( hanging != null ) + { + hanging.Value = indentation; + } + else + { + ind.Add( new XAttribute( XName.Get( "hanging", DocX.w.NamespaceName ), indentation ) ); + } + } + } + } + + /// + /// Set the before indentation in cm for this Paragraph. + /// + /// + /// // Indent an entire Paragraph from the left. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Create a new Paragraph. + /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3"); + /// + /// // Indent this entire Paragraph from the left. + /// p.IndentationBefore = 2.0f; + /// + /// // Save all changes made to this document. + /// document.Save(); + ///} + /// + /// + public float IndentationBefore + { + get + { + GetOrCreate_pPr(); + var ind = GetOrCreate_pPr_ind(); + + var left = ind.Attribute( XName.Get( "left", DocX.w.NamespaceName ) ); + if( left != null ) + return float.Parse( left.Value ) / 570f; + + return 0.0f; + } + + set + { + if( IndentationBefore != value ) + { + indentationBefore = value; + + GetOrCreate_pPr(); + var ind = GetOrCreate_pPr_ind(); + + var indentation = ( ( indentationBefore / 0.1 ) * 57 ).ToString(CultureInfo.GetCultureInfo("en-GB")); + + var left = ind.Attribute( XName.Get( "left", DocX.w.NamespaceName ) ); + if( left != null ) + { + left.Value = indentation; + } + else + { + ind.Add( new XAttribute( XName.Get( "left", DocX.w.NamespaceName ), indentation ) ); + } + } + } + } + + + /// + /// Set the after indentation in cm for this Paragraph. + /// + /// + /// // Indent an entire Paragraph from the right. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Create a new Paragraph. + /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3"); + /// + /// // Make the content of this Paragraph flow right to left. + /// p.Direction = Direction.RightToLeft; + /// + /// // Indent this entire Paragraph from the right. + /// p.IndentationAfter = 2.0f; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + public float IndentationAfter + { + get + { + GetOrCreate_pPr(); + var ind = GetOrCreate_pPr_ind(); + + var right = ind.Attribute( XName.Get( "right", DocX.w.NamespaceName ) ); + if( right != null ) + return float.Parse( right.Value ); + + return 0.0f; + } + + set + { + if( IndentationAfter != value ) + { + indentationAfter = value; + + GetOrCreate_pPr(); + var ind = GetOrCreate_pPr_ind(); + + var indentation = ( ( indentationAfter / 0.1 ) * 57 ).ToString(); + + var right = ind.Attribute( XName.Get( "right", DocX.w.NamespaceName ) ); + if( right != null ) + { + right.Value = indentation; + } + else + { + ind.Add( new XAttribute( XName.Get( "right", DocX.w.NamespaceName ), indentation ) ); + } + } + } + } + + /// + /// Gets or set this Paragraphs text alignment. + /// + public Alignment Alignment + { + get + { + XElement pPr = GetOrCreate_pPr(); + XElement jc = pPr.Element( XName.Get( "jc", DocX.w.NamespaceName ) ); + + if( jc != null ) + { + XAttribute a = jc.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + switch( a.Value.ToLower() ) + { + case "left": + return Xceed.Words.NET.Alignment.left; + case "right": + return Xceed.Words.NET.Alignment.right; + case "center": + return Xceed.Words.NET.Alignment.center; + case "both": + return Xceed.Words.NET.Alignment.both; + } + } + + return Xceed.Words.NET.Alignment.left; + } + + set + { + alignment = value; + + XElement pPr = GetOrCreate_pPr(); + XElement jc = pPr.Element( XName.Get( "jc", DocX.w.NamespaceName ) ); + + if( alignment != Xceed.Words.NET.Alignment.left ) + { + if( jc == null ) + pPr.Add( new XElement( XName.Get( "jc", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), alignment.ToString() ) ) ); + else + jc.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ).Value = alignment.ToString(); + } + + else + { + if( jc != null ) + jc.Remove(); + } + } + } + + /// + /// Gets the text value of this Paragraph. + /// + public string Text + { + // Returns the underlying XElement's Value property. + get + { + try + { + return HelperFunctions.GetText( Xml ); + } + catch( Exception ) + { + return null; + } + } + } + + /// + /// Gets the formatted text value of this Paragraph. + /// + public List MagicText + { + // Returns the underlying XElement's Value property. + get + { + return HelperFunctions.GetFormattedText( Xml ); + } + } + + /// + /// For use with Append() and AppendLine() + /// + /// This Paragraph in curent culture + /// + /// Add a new Paragraph with russian text to this document and then set language of text to local culture. + /// + /// // Load a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph with russian text and set curent local culture to it. + /// Paragraph p = document.InsertParagraph("Привет мир!").CurentCulture(); + /// + /// // Save this document. + /// document.Save(); + /// } + /// + /// + public Paragraph CurentCulture() + { + ApplyTextFormattingProperty( XName.Get( "lang", DocX.w.NamespaceName ), + string.Empty, + new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), CultureInfo.CurrentCulture.Name ) ); + return this; + } + + /// + /// Returns table following the paragraph. Null if the following element isn't table. + /// + public Table FollowingTable + { + get + { + return followingTable; + } + internal set + { + followingTable = value; + } + } + + public float LineSpacing + { + get + { + XElement pPr = GetOrCreate_pPr(); + XElement spacing = pPr.Element( XName.Get( "spacing", DocX.w.NamespaceName ) ); + + if( spacing != null ) + { + XAttribute line = spacing.Attribute( XName.Get( "line", DocX.w.NamespaceName ) ); + if( line != null ) + { + float f; + + if( float.TryParse( line.Value, out f ) ) + return f / 20.0f; + } + } + + return 1.1f * 20.0f; + } + + set + { + Spacing( value ); + } + } + + public float LineSpacingBefore + { + get + { + XElement pPr = GetOrCreate_pPr(); + XElement spacing = pPr.Element( XName.Get( "spacing", DocX.w.NamespaceName ) ); + + if( spacing != null ) + { + XAttribute line = spacing.Attribute( XName.Get( "before", DocX.w.NamespaceName ) ); + if( line != null ) + { + float f; + + if( float.TryParse( line.Value, out f ) ) + return f / 20.0f; + } + } + + return 0.0f; + } + + set + { + SpacingBefore( value ); + } + } + + public float LineSpacingAfter + { + get + { + XElement pPr = GetOrCreate_pPr(); + XElement spacing = pPr.Element( XName.Get( "spacing", DocX.w.NamespaceName ) ); + + if( spacing != null ) + { + XAttribute line = spacing.Attribute( XName.Get( "after", DocX.w.NamespaceName ) ); + if( line != null ) + { + float f; + + if( float.TryParse( line.Value, out f ) ) + return f / 20.0f; + } + } + + return 10.0f; + } + + + set + { + SpacingAfter( value ); + } + } + + public XElement ParagraphNumberProperties + { + get + { + return ParagraphNumberPropertiesBacker ?? ( ParagraphNumberPropertiesBacker = GetParagraphNumberProperties() ); + } + } + + /// + /// Indicates if this paragraph is a list element + /// + public bool IsListItem + { + get + { + IsListItemBacker = IsListItemBacker ?? ( ParagraphNumberProperties != null ); + return ( bool )IsListItemBacker; + } + } + + /// + /// Get the indentation level of the list item + /// + public int? IndentLevel + { + get + { + if( !IsListItem ) + return null; + return IndentLevelBacker ?? ( IndentLevelBacker = int.Parse( ParagraphNumberProperties.Descendants().First( el => el.Name.LocalName == "ilvl" ).GetAttribute( DocX.w + "val" ) ) ); + } + } + + public bool IsKeepWithNext + { + get + { + var pPr = this.GetOrCreate_pPr(); + var keepNext = pPr.Element( XName.Get( "keepNext", DocX.w.NamespaceName ) ); + + return ( keepNext != null ); + } + } + + + #endregion + + #region Constructors + + internal Paragraph( DocX document, XElement xml, int startIndex, ContainerType parentContainerType = ContainerType.None ) : base( document, xml ) + { + _startIndex = startIndex; + _endIndex = startIndex + GetElementTextLength( xml ); + + ParentContainer = parentContainerType; + + RebuildDocProperties(); + + //// Check if this Paragraph references any pStyle elements. + //var stylesElements = xml.Descendants( XName.Get( "pStyle", DocX.w.NamespaceName ) ); + + //// If one or more pStyles are referenced. + //if( stylesElements.Count() > 0 ) + //{ + // Uri style_package_uri = new Uri( "/word/styles.xml", UriKind.Relative ); + // PackagePart styles_document = document.package.GetPart( style_package_uri ); + + // using( TextReader tr = new StreamReader( styles_document.GetStream() ) ) + // { + // XDocument style_document = XDocument.Load( tr ); + // XElement styles_element = style_document.Element( XName.Get( "styles", DocX.w.NamespaceName ) ); + + // var styles_element_ids = stylesElements.Select( e => e.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ).Value ); + + // //foreach(string id in styles_element_ids) + // //{ + // // var style = + // // ( + // // from d in styles_element.Descendants() + // // let styleId = d.Attribute(XName.Get("styleId", DocX.w.NamespaceName)) + // // let type = d.Attribute(XName.Get("type", DocX.w.NamespaceName)) + // // where type != null && type.Value == "paragraph" && styleId != null && styleId.Value == id + // // select d + // // ).First(); + + // // styles.Add(style); + // //} + // } + //} + + _runs = Xml.Elements( XName.Get( "r", DocX.w.NamespaceName ) ).ToList(); + } + + #endregion + + #region Public Methods + + /// + /// Insert a new Table before this Paragraph, this Table can be from this document or another document. + /// + /// The Table t to be inserted. + /// A new Table inserted before this Paragraph. + /// + /// Insert a new Table before this Paragraph. + /// + /// // Place holder for a Table. + /// Table t; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"a.docx")) + /// { + /// // Get the first Table from this document. + /// t = documentA.Tables[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"b.docx")) + /// { + /// // Get the first Paragraph in document b. + /// Paragraph p2 = documentB.Paragraphs[0]; + /// + /// // Insert the Table from document a before this Paragraph. + /// Table newTable = p2.InsertTableBeforeSelf(t); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public override Table InsertTableBeforeSelf( Table t ) + { + t = base.InsertTableBeforeSelf( t ); + t.PackagePart = this.PackagePart; + return t; + } + + /// + /// Insert a new Table into this document before this Paragraph. + /// + /// The number of rows this Table should have. + /// The number of columns this Table should have. + /// A new Table inserted before this Paragraph. + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// //Insert a Paragraph into this document. + /// Paragraph p = document.InsertParagraph("Hello World", false); + /// + /// // Insert a new Table before this Paragraph. + /// Table newTable = p.InsertTableBeforeSelf(2, 2); + /// newTable.Design = TableDesign.LightShadingAccent2; + /// newTable.Alignment = Alignment.center; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public override Table InsertTableBeforeSelf( int rowCount, int columnCount ) + { + return base.InsertTableBeforeSelf( rowCount, columnCount ); + } + + /// + /// Insert a new Table after this Paragraph. + /// + /// The Table t to be inserted. + /// A new Table inserted after this Paragraph. + /// + /// Insert a new Table after this Paragraph. + /// + /// // Place holder for a Table. + /// Table t; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"a.docx")) + /// { + /// // Get the first Table from this document. + /// t = documentA.Tables[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"b.docx")) + /// { + /// // Get the first Paragraph in document b. + /// Paragraph p2 = documentB.Paragraphs[0]; + /// + /// // Insert the Table from document a after this Paragraph. + /// Table newTable = p2.InsertTableAfterSelf(t); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public override Table InsertTableAfterSelf( Table t ) + { + t = base.InsertTableAfterSelf( t ); + t.PackagePart = this.PackagePart; + return t; + } + + /// + /// Insert a new Table into this document after this Paragraph. + /// + /// The number of rows this Table should have. + /// The number of columns this Table should have. + /// A new Table inserted after this Paragraph. + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// //Insert a Paragraph into this document. + /// Paragraph p = document.InsertParagraph("Hello World", false); + /// + /// // Insert a new Table after this Paragraph. + /// Table newTable = p.InsertTableAfterSelf(2, 2); + /// newTable.Design = TableDesign.LightShadingAccent2; + /// newTable.Alignment = Alignment.center; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public override Table InsertTableAfterSelf( int rowCount, int columnCount ) + { + return base.InsertTableAfterSelf( rowCount, columnCount ); + } + + /// + /// Insert a Paragraph before this Paragraph, this Paragraph may have come from the same or another document. + /// + /// The Paragraph to insert. + /// The Paragraph now associated with this document. + /// + /// Take a Paragraph from document a, and insert it into document b before this Paragraph. + /// + /// // Place holder for a Paragraph. + /// Paragraph p; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"a.docx")) + /// { + /// // Get the first paragraph from this document. + /// p = documentA.Paragraphs[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"b.docx")) + /// { + /// // Get the first Paragraph in document b. + /// Paragraph p2 = documentB.Paragraphs[0]; + /// + /// // Insert the Paragraph from document a before this Paragraph. + /// Paragraph newParagraph = p2.InsertParagraphBeforeSelf(p); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public override Paragraph InsertParagraphBeforeSelf( Paragraph p ) + { + var p2 = base.InsertParagraphBeforeSelf( p ); + p2.PackagePart = this.PackagePart; + return p2; + } + + /// + /// Insert a new Paragraph before this Paragraph. + /// + /// The initial text for this new Paragraph. + /// A new Paragraph inserted before this Paragraph. + /// + /// Insert a new paragraph before the first Paragraph in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Paragraph into this document. + /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); + /// + /// p.InsertParagraphBeforeSelf("I was inserted before the next Paragraph."); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphBeforeSelf( string text ) + { + var p = base.InsertParagraphBeforeSelf( text ); + p.PackagePart = this.PackagePart; + return p; + } + + /// + /// Insert a new Paragraph before this Paragraph. + /// + /// The initial text for this new Paragraph. + /// Should this insertion be tracked as a change? + /// A new Paragraph inserted before this Paragraph. + /// + /// Insert a new paragraph before the first Paragraph in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Paragraph into this document. + /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); + /// + /// p.InsertParagraphBeforeSelf("I was inserted before the next Paragraph.", false); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphBeforeSelf( string text, bool trackChanges ) + { + var p = base.InsertParagraphBeforeSelf( text, trackChanges ); + p.PackagePart = this.PackagePart; + return p; + } + + /// + /// Insert a new Paragraph before this Paragraph. + /// + /// The initial text for this new Paragraph. + /// Should this insertion be tracked as a change? + /// The formatting to apply to this insertion. + /// A new Paragraph inserted before this Paragraph. + /// + /// Insert a new paragraph before the first Paragraph in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Paragraph into this document. + /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); + /// + /// Formatting boldFormatting = new Formatting(); + /// boldFormatting.Bold = true; + /// + /// p.InsertParagraphBeforeSelf("I was inserted before the next Paragraph.", false, boldFormatting); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphBeforeSelf( string text, bool trackChanges, Formatting formatting ) + { + var p = base.InsertParagraphBeforeSelf( text, trackChanges, formatting ); + p.PackagePart = this.PackagePart; + return p; + } + + /// + /// Insert a page break before a Paragraph. + /// + /// + /// Insert 2 Paragraphs into a document with a page break between them. + /// + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p1 = document.InsertParagraph("Paragraph 1", false); + /// + /// // Insert a new Paragraph. + /// Paragraph p2 = document.InsertParagraph("Paragraph 2", false); + /// + /// // Insert a page break before Paragraph two. + /// p2.InsertPageBreakBeforeSelf(); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public override void InsertPageBreakBeforeSelf() + { + base.InsertPageBreakBeforeSelf(); + } + + /// + /// Insert a page break after a Paragraph. + /// + /// + /// Insert 2 Paragraphs into a document with a page break between them. + /// + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p1 = document.InsertParagraph("Paragraph 1", false); + /// + /// // Insert a page break after this Paragraph. + /// p1.InsertPageBreakAfterSelf(); + /// + /// // Insert a new Paragraph. + /// Paragraph p2 = document.InsertParagraph("Paragraph 2", false); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public override void InsertPageBreakAfterSelf() + { + base.InsertPageBreakAfterSelf(); + } + + [Obsolete( "Instead use: InsertHyperlink(Hyperlink h, int index)" )] + public Paragraph InsertHyperlink( int index, Hyperlink h ) + { + return InsertHyperlink( h, index ); + } + + /// + /// This function inserts a hyperlink into a Paragraph at a specified character index. + /// + /// The index to insert at. + /// The hyperlink to insert. + /// The Paragraph with the Hyperlink inserted at the specified index. + + public Paragraph InsertHyperlink( Hyperlink h, int index = 0 ) + { + // Convert the path of this mainPart to its equilivant rels file path. + var path = this.PackagePart.Uri.OriginalString.Replace( "/word/", "" ); + var rels_path = new Uri( String.Format( "/word/_rels/{0}.rels", path ), UriKind.Relative ); + + // Check to see if the rels file exists and create it if not. + if( !Document._package.PartExists( rels_path ) ) + { + HelperFunctions.CreateRelsPackagePart( Document, rels_path ); + } + + // Check to see if a rel for this Picture exists, create it if not. + var Id = GetOrGenerateRel( h ); + + XElement h_xml; + if( index == 0 ) + { + // Add this hyperlink as the last element. + Xml.AddFirst( h.Xml ); + + // Extract the picture back out of the DOM. + h_xml = ( XElement )Xml.FirstNode; + } + else + { + // Get the first run effected by this Insert + Run run = GetFirstRunEffectedByEdit( index ); + + if( run == null ) + { + // Add this hyperlink as the last element. + Xml.Add( h.Xml ); + + // Extract the picture back out of the DOM. + h_xml = ( XElement )Xml.LastNode; + } + else + { + // Split this run at the point you want to insert + XElement[] splitRun = Run.SplitRun( run, index ); + + // Replace the origional run. + run.Xml.ReplaceWith + ( + splitRun[ 0 ], + h.Xml, + splitRun[ 1 ] + ); + + // Get the first run effected by this Insert + run = GetFirstRunEffectedByEdit( index ); + + // The picture has to be the next element, extract it back out of the DOM. + h_xml = ( XElement )run.Xml.NextNode; + } + + h_xml.SetAttributeValue( DocX.r + "id", Id ); + } + + return this; + } + + /// + /// Remove the Hyperlink at the provided index. The first hyperlink is at index 0. + /// Using a negative index or an index greater than the index of the last hyperlink will cause an ArgumentOutOfRangeException() to be thrown. + /// + /// The index of the hyperlink to be removed. + /// + /// + /// // Crete a new document. + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Add a Hyperlink into this document. + /// Hyperlink h = document.AddHyperlink("link", new Uri("http://www.google.com")); + /// + /// // Insert a new Paragraph into the document. + /// Paragraph p1 = document.InsertParagraph("AC"); + /// + /// // Insert the hyperlink into this Paragraph. + /// p1.InsertHyperlink(1, h); + /// Assert.IsTrue(p1.Text == "AlinkC"); // Make sure the hyperlink was inserted correctly; + /// + /// // Remove the hyperlink + /// p1.RemoveHyperlink(0); + /// Assert.IsTrue(p1.Text == "AC"); // Make sure the hyperlink was removed correctly; + /// } + /// + /// + public void RemoveHyperlink( int index ) + { + // Dosen't make sense to remove a Hyperlink at a negative index. + if( index < 0 ) + throw new ArgumentOutOfRangeException(); + + // Need somewhere to store the count. + int count = 0; + bool found = false; + RemoveHyperlinkRecursive( Xml, index, ref count, ref found ); + + // If !found then the user tried to remove a hyperlink at an index greater than the last. + if( !found ) + throw new ArgumentOutOfRangeException(); + } + + /// + /// Insert a Paragraph after this Paragraph, this Paragraph may have come from the same or another document. + /// + /// The Paragraph to insert. + /// The Paragraph now associated with this document. + /// + /// Take a Paragraph from document a, and insert it into document b after this Paragraph. + /// + /// // Place holder for a Paragraph. + /// Paragraph p; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"a.docx")) + /// { + /// // Get the first paragraph from this document. + /// p = documentA.Paragraphs[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"b.docx")) + /// { + /// // Get the first Paragraph in document b. + /// Paragraph p2 = documentB.Paragraphs[0]; + /// + /// // Insert the Paragraph from document a after this Paragraph. + /// Paragraph newParagraph = p2.InsertParagraphAfterSelf(p); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public override Paragraph InsertParagraphAfterSelf( Paragraph p ) + { + var p2 = base.InsertParagraphAfterSelf( p ); + p2.PackagePart = this.PackagePart; + return p2; + } + + /// + /// Insert a new Paragraph after this Paragraph. + /// + /// The initial text for this new Paragraph. + /// Should this insertion be tracked as a change? + /// The formatting to apply to this insertion. + /// A new Paragraph inserted after this Paragraph. + /// + /// Insert a new paragraph after the first Paragraph in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Paragraph into this document. + /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); + /// + /// Formatting boldFormatting = new Formatting(); + /// boldFormatting.Bold = true; + /// + /// p.InsertParagraphAfterSelf("I was inserted after the previous Paragraph.", false, boldFormatting); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphAfterSelf( string text, bool trackChanges, Formatting formatting ) + { + var p = base.InsertParagraphAfterSelf( text, trackChanges, formatting ); + p.PackagePart = this.PackagePart; + return p; + } + + /// + /// Insert a new Paragraph after this Paragraph. + /// + /// The initial text for this new Paragraph. + /// Should this insertion be tracked as a change? + /// A new Paragraph inserted after this Paragraph. + /// + /// Insert a new paragraph after the first Paragraph in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Paragraph into this document. + /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); + /// + /// p.InsertParagraphAfterSelf("I was inserted after the previous Paragraph.", false); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphAfterSelf( string text, bool trackChanges ) + { + var p = base.InsertParagraphAfterSelf( text, trackChanges ); + p.PackagePart = this.PackagePart; + return p; + } + + /// + /// Insert a new Paragraph after this Paragraph. + /// + /// The initial text for this new Paragraph. + /// A new Paragraph inserted after this Paragraph. + /// + /// Insert a new paragraph after the first Paragraph in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Paragraph into this document. + /// Paragraph p = document.InsertParagraph("I am a Paragraph", false); + /// + /// p.InsertParagraphAfterSelf("I was inserted after the previous Paragraph."); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphAfterSelf( string text ) + { + var p = base.InsertParagraphAfterSelf( text ); + p.PackagePart = this.PackagePart; + return p; + } + + /// + /// Remove this Paragraph from the document. + /// + /// Should this remove be tracked as a change? + /// + /// Remove a Paragraph from a document and track it as a change. + /// + /// // Create a document using a relative filename. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Create and Insert a new Paragraph into this document. + /// Paragraph p = document.InsertParagraph("Hello", false); + /// + /// // Remove the Paragraph and track this as a change. + /// p.Remove(true); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public void Remove( bool trackChanges ) + { + if( trackChanges ) + { + DateTime now = DateTime.Now.ToUniversalTime(); + + List elements = Xml.Elements().ToList(); + List temp = new List(); + for( int i = 0; i < elements.Count(); i++ ) + { + XElement e = elements[ i ]; + + if( e.Name.LocalName != "del" ) + { + temp.Add( e ); + e.Remove(); + } + + else + { + if( temp.Count() > 0 ) + { + e.AddBeforeSelf( CreateEdit( EditType.del, now, temp.Elements() ) ); + temp.Clear(); + } + } + } + + if( temp.Count() > 0 ) + Xml.Add( CreateEdit( EditType.del, now, temp ) ); + } + + else + { + // If this is the only Paragraph in the Cell then we cannot remove it. + if( Xml.Parent.Name.LocalName == "tc" && Xml.Parent.Elements( XName.Get( "p", DocX.w.NamespaceName ) ).Count() == 1 ) + Xml.Value = string.Empty; + + else + { + // Remove this paragraph from the document + Xml.Remove(); + Xml = null; + } + } + } + + //public Picture InsertPicture(Picture picture) + //{ + // Picture newPicture = picture; + // newPicture.i = new XElement(picture.i); + + // xml.Add(newPicture.i); + // pictures.Add(newPicture); + // return newPicture; + //} + + /// + /// Insert a Picture at the end of this paragraph. + /// + /// A string to describe this Picture. + /// The unique id that identifies the Image this Picture represents. + /// The name of this image. + /// A Picture. + /// + /// + /// // Create a document using a relative filename. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add a new Paragraph to this document. + /// Paragraph p = document.InsertParagraph("Here is Picture 1", false); + /// + /// // Add an Image to this document. + /// Xceed.Words.NET.Image img = document.AddImage(@"Image.jpg"); + /// + /// // Insert pic at the end of Paragraph p. + /// Picture pic = p.InsertPicture(img.Id, "Photo 31415", "A pie I baked."); + /// + /// // Rotate the Picture clockwise by 30 degrees. + /// pic.Rotation = 30; + /// + /// // Resize the Picture. + /// pic.Width = 400; + /// pic.Height = 300; + /// + /// // Set the shape of this Picture to be a cube. + /// pic.SetPictureShape(BasicShapes.cube); + /// + /// // Flip the Picture Horizontally. + /// pic.FlipHorizontal = true; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// Removed to simplify the API. + //public Picture InsertPicture(string imageID, string name, string description) + //{ + // Picture p = CreatePicture(Document, imageID, name, description); + // Xml.Add(p.Xml); + // return p; + //} + + // Removed because it confusses the API. + //public Picture InsertPicture(string imageID) + //{ + // return InsertPicture(imageID, string.Empty, string.Empty); + //} + + //public Picture InsertPicture(int index, Picture picture) + //{ + // Picture p = picture; + // p.i = new XElement(picture.i); + + // Run run = GetFirstRunEffectedByEdit(index); + + // if (run == null) + // xml.Add(p.i); + // else + // { + // // Split this run at the point you want to insert + // XElement[] splitRun = Run.SplitRun(run, index); + + // // Replace the origional run + // run.Xml.ReplaceWith + // ( + // splitRun[0], + // p.i, + // splitRun[1] + // ); + // } + + // // Rebuild the run lookup for this paragraph + // runLookup.Clear(); + // BuildRunLookup(xml); + // DocX.RenumberIDs(document); + // return p; + //} + + /// + /// Insert a Picture into this Paragraph at a specified index. + /// + /// A string to describe this Picture. + /// The unique id that identifies the Image this Picture represents. + /// The name of this image. + /// The index to insert this Picture at. + /// A Picture. + /// + /// + /// // Create a document using a relative filename. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add a new Paragraph to this document. + /// Paragraph p = document.InsertParagraph("Here is Picture 1", false); + /// + /// // Add an Image to this document. + /// Xceed.Words.NET.Image img = document.AddImage(@"Image.jpg"); + /// + /// // Insert pic at the start of Paragraph p. + /// Picture pic = p.InsertPicture(0, img.Id, "Photo 31415", "A pie I baked."); + /// + /// // Rotate the Picture clockwise by 30 degrees. + /// pic.Rotation = 30; + /// + /// // Resize the Picture. + /// pic.Width = 400; + /// pic.Height = 300; + /// + /// // Set the shape of this Picture to be a cube. + /// pic.SetPictureShape(BasicShapes.cube); + /// + /// // Flip the Picture Horizontally. + /// pic.FlipHorizontal = true; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// Removed to simplify API. + //public Picture InsertPicture(int index, string imageID, string name, string description) + //{ + // Picture picture = CreatePicture(Document, imageID, name, description); + + // Run run = GetFirstRunEffectedByEdit(index); + + // if (run == null) + // Xml.Add(picture.Xml); + // else + // { + // // Split this run at the point you want to insert + // XElement[] splitRun = Run.SplitRun(run, index); + + // // Replace the origional run + // run.Xml.ReplaceWith + // ( + // splitRun[0], + // picture.Xml, + // splitRun[1] + // ); + // } + + // HelperFunctions.RenumberIDs(Document); + // return picture; + //} + + // Removed because it confusses the API. + //public Picture InsertPicture(int index, string imageID) + //{ + // return InsertPicture(index, imageID, string.Empty, string.Empty); + //} + + /// + /// Inserts a specified instance of System.String into a Xceed.Words.NET.DocX.Paragraph at a specified index position. + /// + /// + /// + /// // Create a document using a relative filename. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Create a text formatting. + /// Formatting f = new Formatting(); + /// f.FontColor = Color.Red; + /// f.Size = 30; + /// + /// // Iterate through the Paragraphs in this document. + /// foreach (Paragraph p in document.Paragraphs) + /// { + /// // Insert the string "Start: " at the begining of every Paragraph and flag it as a change. + /// p.InsertText("Start: ", true, f); + /// } + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// + /// Inserting tabs using the \t switch. + /// + /// // Create a document using a relative filename. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Create a text formatting. + /// Formatting f = new Formatting(); + /// f.FontColor = Color.Red; + /// f.Size = 30; + /// + /// // Iterate through the paragraphs in this document. + /// foreach (Paragraph p in document.Paragraphs) + /// { + /// // Insert the string "\tEnd" at the end of every paragraph and flag it as a change. + /// p.InsertText("\tEnd", true, f); + /// } + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// + /// + /// The System.String to insert. + /// Flag this insert as a change. + /// The text formatting. + public void InsertText( string value, bool trackChanges = false, Formatting formatting = null ) + { + // Default values for optional parameters must be compile time constants. + // Would have like to write 'public void InsertText(string value, bool trackChanges = false, Formatting formatting = new Formatting()) + if( formatting == null ) + { + formatting = new Formatting(); + } + + var newRuns = HelperFunctions.FormatInput( value, formatting.Xml ); + Xml.Add( newRuns ); + + HelperFunctions.RenumberIDs( Document ); + } + + /// + /// Inserts a specified instance of System.String into a Xceed.Words.NET.DocX.Paragraph at a specified index position. + /// + /// + /// + /// // Create a document using a relative filename. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Create a text formatting. + /// Formatting f = new Formatting(); + /// f.FontColor = Color.Red; + /// f.Size = 30; + /// + /// // Iterate through the Paragraphs in this document. + /// foreach (Paragraph p in document.Paragraphs) + /// { + /// // Insert the string "Start: " at the begining of every Paragraph and flag it as a change. + /// p.InsertText(0, "Start: ", true, f); + /// } + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// + /// Inserting tabs using the \t switch. + /// + /// // Create a document using a relative filename. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Create a text formatting. + /// Formatting f = new Formatting(); + /// f.FontColor = Color.Red; + /// f.Size = 30; + /// + /// // Iterate through the paragraphs in this document. + /// foreach (Paragraph p in document.Paragraphs) + /// { + /// // Insert the string "\tStart:\t" at the begining of every paragraph and flag it as a change. + /// p.InsertText(0, "\tStart:\t", true, f); + /// } + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// + /// + /// The index position of the insertion. + /// The System.String to insert. + /// Flag this insert as a change. + /// The text formatting. + public void InsertText( int index, string value, bool trackChanges = false, Formatting formatting = null ) + { + // Timestamp to mark the start of insert + var now = DateTime.Now; + var insert_datetime = new DateTime( now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc ); + + // Get the first run effected by this Insert + var run = this.GetFirstRunEffectedByEdit( index ); + + if( run == null ) + { + object insert = ( formatting != null ) ? HelperFunctions.FormatInput( value, formatting.Xml ) : HelperFunctions.FormatInput( value, null ); + + if( trackChanges ) + { + insert = CreateEdit( EditType.ins, insert_datetime, insert ); + } + this.Xml.Add( insert ); + } + else + { + object newRuns = null; + var rPr = run.Xml.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + + if( formatting != null ) + { + Formatting oldFormatting = null; + Formatting newFormatting = null; + + if( rPr != null ) + { + oldFormatting = Formatting.Parse( rPr ); + if( oldFormatting != null ) + { + // Clone formatting and apply received formatting + newFormatting = oldFormatting.Clone(); + this.ApplyFormattingFrom( ref newFormatting, formatting ); + } + else + { + newFormatting = formatting; + } + } + else + { + newFormatting = formatting; + } + + newRuns = HelperFunctions.FormatInput( value, newFormatting.Xml ); + } + else + { + newRuns = HelperFunctions.FormatInput( value, rPr ); + } + + // The parent of this Run + var parentElement = run.Xml.Parent; + switch( parentElement.Name.LocalName ) + { + case "ins": + { + // The datetime that this ins was created + var parent_ins_date = DateTime.Parse( parentElement.Attribute( XName.Get( "date", DocX.w.NamespaceName ) ).Value ); + + /* + * Special case: You want to track changes, + * and the first Run effected by this insert + * has a datetime stamp equal to now. + */ + if( trackChanges && parent_ins_date.CompareTo( insert_datetime ) == 0 ) + { + /* + * Inserting into a non edit and this special case, is the same procedure. + */ + goto default; + } + + /* + * If not the special case above, + * then inserting into an ins or a del, is the same procedure. + */ + goto case "del"; + } + + case "del": + { + object insert = newRuns; + if( trackChanges ) + { + insert = CreateEdit( EditType.ins, insert_datetime, newRuns ); + } + + // Split this Edit at the point you want to insert + var splitEdit = SplitEdit( parentElement, index, EditType.ins ); + + // Replace the origional run + parentElement.ReplaceWith + ( + splitEdit[ 0 ], + insert, + splitEdit[ 1 ] + ); + + break; + } + + default: + { + object insert = newRuns; + if( trackChanges && !parentElement.Name.LocalName.Equals( "ins" ) ) + { + insert = CreateEdit( EditType.ins, insert_datetime, newRuns ); + } + // Special case to deal with Page Number elements. + //if (parentElement.Name.LocalName.Equals("fldSimple")) + // parentElement.AddBeforeSelf(insert); + else + { + // Split this run at the point you want to insert + var splitRun = Run.SplitRun( run, index ); + + // Replace the origional run + run.Xml.ReplaceWith + ( + splitRun[ 0 ], + insert, + splitRun[ 1 ] + ); + } + + break; + } + } + } + + HelperFunctions.RenumberIDs( Document ); + } + + /// + /// For use with Append() and AppendLine() + /// + /// The CultureInfo for text + /// This Paragraph in curent culture + /// + /// Add a new Paragraph with russian text to this document and then set language of text to local culture. + /// + /// // Load a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph with russian text and set specific culture to it. + /// Paragraph p = document.InsertParagraph("Привет мир").Culture(CultureInfo.CreateSpecificCulture("ru-RU")); + /// + /// // Save this document. + /// document.Save(); + /// } + /// + /// + public Paragraph Culture( CultureInfo culture ) + { + this.ApplyTextFormattingProperty( XName.Get( "lang", DocX.w.NamespaceName ), + string.Empty, + new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), culture.Name ) ); + return this; + } + + /// + /// Append text to this Paragraph. + /// + /// The text to append. + /// This Paragraph with the new text appened. + /// + /// Add a new Paragraph to this document and then append some text to it. + /// + /// // Load a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph and Append some text to it. + /// Paragraph p = document.InsertParagraph().Append("Hello World!!!"); + /// + /// // Save this document. + /// document.Save(); + /// } + /// + /// + public Paragraph Append( string text ) + { + List newRuns = HelperFunctions.FormatInput( text, null ); + Xml.Add( newRuns ); + + _runs = Xml.Elements( XName.Get( "r", DocX.w.NamespaceName ) ).Reverse().Take( newRuns.Count() ).ToList(); + + return this; + } + + /// + /// Append text to this Paragraph and apply the provided format + /// + /// The text to append. + /// The format to use. + /// This Paragraph with the new text appended. + /// + /// Add a new Paragraph to this document, append some text to it and apply the provided format. + /// + /// // Load a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Prepare format to use + /// Formatting format = new Formatting(); + /// format.Bold = true; + /// format.Size = 18; + /// format.FontColor = Color.Blue; + /// + /// // Insert a new Paragraph and append some text to it with the custom format + /// Paragraph p = document.InsertParagraph().Append("Hello World!!!", format); + /// + /// // Save this document. + /// document.Save(); + /// } + /// + /// + public Paragraph Append( string text, Formatting format ) + { + // Text + Append( text ); + + // Bold + if( format.Bold.HasValue && format.Bold.Value ) + Bold(); + + // CapsStyle + if( format.CapsStyle.HasValue ) + CapsStyle( format.CapsStyle.Value ); + + // FontColor + if( format.FontColor.HasValue ) + Color( format.FontColor.Value ); + + // FontFamily + if( format.FontFamily != null ) + Font( format.FontFamily ); + + // Hidden + if( format.Hidden.HasValue && format.Hidden.Value ) + Hide(); + + // Highlight + if( format.Highlight.HasValue ) + Highlight( format.Highlight.Value ); + + // Italic + if( format.Italic.HasValue && format.Italic.Value ) + Italic(); + + // Kerning + if( format.Kerning.HasValue ) + Kerning( format.Kerning.Value ); + + // Language + if( format.Language != null ) + Culture( format.Language ); + + // Misc + if( format.Misc.HasValue ) + Misc( format.Misc.Value ); + + // PercentageScale + if( format.PercentageScale.HasValue ) + PercentageScale( format.PercentageScale.Value ); + + // Position + if( format.Position.HasValue ) + Position( format.Position.Value ); + + // Script + if( format.Script.HasValue ) + Script( format.Script.Value ); + + // Size + if( format.Size.HasValue ) + FontSize( format.Size.Value ); + + // Spacing + if( format.Spacing.HasValue ) + Spacing( format.Spacing.Value ); + + // StrikeThrough + if( format.StrikeThrough.HasValue ) + StrikeThrough( format.StrikeThrough.Value ); + + // UnderlineColor + if( format.UnderlineColor.HasValue ) + UnderlineColor( format.UnderlineColor.Value ); + + // UnderlineStyle + if( format.UnderlineStyle.HasValue ) + UnderlineStyle( format.UnderlineStyle.Value ); + + return this; + } + + /// + /// Append a hyperlink to a Paragraph. + /// + /// The hyperlink to append. + /// The Paragraph with the hyperlink appended. + /// + /// Creates a Paragraph with some text and a hyperlink. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add a hyperlink to this document. + /// Hyperlink h = document.AddHyperlink("Google", new Uri("http://www.google.com")); + /// + /// // Add a new Paragraph to this document. + /// Paragraph p = document.InsertParagraph(); + /// p.Append("My favourite search engine is "); + /// p.AppendHyperlink(h); + /// p.Append(", I think it's great."); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + public Paragraph AppendHyperlink( Hyperlink h ) + { + // Convert the path of this mainPart to its equilivant rels file path. + var path = this.PackagePart.Uri.OriginalString.Replace( "/word/", "" ); + var rels_path = new Uri( "/word/_rels/" + path + ".rels", UriKind.Relative ); + + // Check to see if the rels file exists and create it if not. + if( !Document._package.PartExists( rels_path ) ) + { + HelperFunctions.CreateRelsPackagePart( Document, rels_path ); + } + + // Check to see if a rel for this Hyperlink exists, create it if not. + var Id = GetOrGenerateRel( h ); + + Xml.Add( h.Xml ); + Xml.Elements().Last().SetAttributeValue( DocX.r + "id", Id ); + + _runs = Xml.Elements().Last().Elements( XName.Get( "r", DocX.w.NamespaceName ) ).ToList(); + + return this; + } + + /// + /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append. + /// + /// The Picture to append. + /// The Paragraph with the Picture now appended. + /// + /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append. + /// + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Add an image to the document. + /// Image i = document.AddImage(@"Image.jpg"); + /// + /// // Create a picture i.e. (A custom view of an image) + /// Picture p = i.CreatePicture(); + /// p.FlipHorizontal = true; + /// p.Rotation = 10; + /// + /// // Create a new Paragraph. + /// Paragraph par = document.InsertParagraph(); + /// + /// // Append content to the Paragraph. + /// par.Append("Here is a cool picture") + /// .AppendPicture(p) + /// .Append(" don't you think so?"); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + public Paragraph AppendPicture( Picture p ) + { + // Convert the path of this mainPart to its equilivant rels file path. + var path = this.PackagePart.Uri.OriginalString.Replace( "/word/", "" ); + var rels_path = new Uri( "/word/_rels/" + path + ".rels", UriKind.Relative ); + + // Check to see if the rels file exists and create it if not. + if( !Document._package.PartExists( rels_path ) ) + { + HelperFunctions.CreateRelsPackagePart( Document, rels_path ); + } + + // Check to see if a rel for this Picture exists, create it if not. + var Id = GetOrGenerateRel( p ); + + // Add the Picture Xml to the end of the Paragragraph Xml. + Xml.Add( p.Xml ); + + // Extract the attribute id from the Pictures Xml. + var a_id = + ( + from e in Xml.Elements().Last().Descendants() + where e.Name.LocalName.Equals( "blip" ) + select e.Attribute( XName.Get( "embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships" ) ) + ).Single(); + + // Set its value to the Pictures relationships id. + a_id.SetValue( Id ); + + // For formatting such as .Bold() + _runs = Xml.Elements( XName.Get( "r", DocX.w.NamespaceName ) ).Reverse().Take( p.Xml.Elements( XName.Get( "r", DocX.w.NamespaceName ) ).Count() ).ToList(); + + return this; + } + + /// + /// Add an equation to a document. + /// + /// The Equation to append. + /// The Paragraph with the Equation now appended. + /// + /// Add an equation to a document. + /// + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Add an equation to the document. + /// document.AddEquation("x=y+z"); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + public Paragraph AppendEquation( String equation ) + { + // Create equation element + XElement oMathPara = + new XElement + ( + XName.Get( "oMathPara", DocX.m.NamespaceName ), + new XElement + ( + XName.Get( "oMath", DocX.m.NamespaceName ), + new XElement + ( + XName.Get( "r", DocX.w.NamespaceName ), + new Formatting() { FontFamily = new Font( "Cambria Math" ) }.Xml, // create formatting + new XElement( XName.Get( "t", DocX.m.NamespaceName ), equation ) // create equation string + ) + ) + ); + + // Add equation element into paragraph xml and update runs collection + Xml.Add( oMathPara ); + _runs = Xml.Elements( XName.Get( "oMathPara", DocX.m.NamespaceName ) ).ToList(); + + // Return paragraph with equation + return this; + } + + /// + /// Insert a Picture into a Paragraph at the given text index. + /// If not index is provided defaults to 0. + /// + /// The Picture to insert. + /// The text index to insert at. + /// The modified Paragraph. + /// + /// + ///Load test document. + ///using (DocX document = DocX.Create("Test.docx")) + ///{ + /// // Add Headers and Footers into this document. + /// document.AddHeaders(); + /// document.AddFooters(); + /// document.DifferentFirstPage = true; + /// document.DifferentOddAndEvenPages = true; + /// + /// // Add an Image to this document. + /// Xceed.Words.NET.Image img = document.AddImage(directory_documents + "purple.png"); + /// + /// // Create a Picture from this Image. + /// Picture pic = img.CreatePicture(); + /// + /// // Main document. + /// Paragraph p0 = document.InsertParagraph("Hello"); + /// p0.InsertPicture(pic, 3); + /// + /// // Header first. + /// Paragraph p1 = document.Headers.first.InsertParagraph("----"); + /// p1.InsertPicture(pic, 2); + /// + /// // Header odd. + /// Paragraph p2 = document.Headers.odd.InsertParagraph("----"); + /// p2.InsertPicture(pic, 2); + /// + /// // Header even. + /// Paragraph p3 = document.Headers.even.InsertParagraph("----"); + /// p3.InsertPicture(pic, 2); + /// + /// // Footer first. + /// Paragraph p4 = document.Footers.first.InsertParagraph("----"); + /// p4.InsertPicture(pic, 2); + /// + /// // Footer odd. + /// Paragraph p5 = document.Footers.odd.InsertParagraph("----"); + /// p5.InsertPicture(pic, 2); + /// + /// // Footer even. + /// Paragraph p6 = document.Footers.even.InsertParagraph("----"); + /// p6.InsertPicture(pic, 2); + /// + /// // Save this document. + /// document.Save(); + ///} + /// + /// + public Paragraph InsertPicture( Picture p, int index = 0 ) + { + // Convert the path of this mainPart to its equilivant rels file path. + var path = this.PackagePart.Uri.OriginalString.Replace( "/word/", "" ); + var rels_path = new Uri( "/word/_rels/" + path + ".rels", UriKind.Relative ); + + // Check to see if the rels file exists and create it if not. + if( !Document._package.PartExists( rels_path ) ) + { + HelperFunctions.CreateRelsPackagePart( Document, rels_path ); + } + + // Check to see if a rel for this Picture exists, create it if not. + var Id = GetOrGenerateRel( p ); + + XElement p_xml; + if( index == 0 ) + { + // Add this hyperlink as the last element. + Xml.AddFirst( p.Xml ); + + // Extract the picture back out of the DOM. + p_xml = ( XElement )Xml.FirstNode; + } + else + { + // Get the first run effected by this Insert + var run = GetFirstRunEffectedByEdit( index ); + if( run == null ) + { + // Add this picture as the last element. + Xml.Add( p.Xml ); + + // Extract the picture back out of the DOM. + p_xml = ( XElement )Xml.LastNode; + } + else + { + // Split this run at the point you want to insert + var splitRun = Run.SplitRun( run, index ); + + // Replace the origional run. + run.Xml.ReplaceWith( splitRun[ 0 ], p.Xml, splitRun[ 1 ] ); + + // Get the first run effected by this Insert + run = GetFirstRunEffectedByEdit( index ); + + // The picture has to be the next element, extract it back out of the DOM. + p_xml = ( XElement )run.Xml.NextNode; + } + } + + // Extract the attribute id from the Pictures Xml. + XAttribute a_id = + ( + from e in p_xml.Descendants() + where e.Name.LocalName.Equals( "blip" ) + select e.Attribute( XName.Get( "embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships" ) ) + ).Single(); + + // Set its value to the Pictures relationships id. + a_id.SetValue( Id ); + + return this; + } + + /// + /// Append text on a new line to this Paragraph. + /// + /// The text to append. + /// This Paragraph with the new text appened. + /// + /// Add a new Paragraph to this document and then append a new line with some text to it. + /// + /// // Load a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph and Append a new line with some text to it. + /// Paragraph p = document.InsertParagraph().AppendLine("Hello World!!!"); + /// + /// // Save this document. + /// document.Save(); + /// } + /// + /// + public Paragraph AppendLine( string text ) + { + return Append( "\n" + text ); + } + + /// + /// Append a new line to this Paragraph. + /// + /// This Paragraph with a new line appeneded. + /// + /// Add a new Paragraph to this document and then append a new line to it. + /// + /// // Load a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph and Append a new line with some text to it. + /// Paragraph p = document.InsertParagraph().AppendLine(); + /// + /// // Save this document. + /// document.Save(); + /// } + /// + /// + public Paragraph AppendLine() + { + return Append( "\n" ); + } + + /// + /// For use with Append() and AppendLine() + /// + /// This Paragraph with the last appended text bold. + /// + /// Append text to this Paragraph and then make it bold. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("Bold").Bold() + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph Bold() + { + ApplyTextFormattingProperty( XName.Get( "b", DocX.w.NamespaceName ), string.Empty, null ); + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// This Paragraph with the last appended text italic. + /// + /// Append text to this Paragraph and then make it italic. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("Italic").Italic() + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph Italic() + { + ApplyTextFormattingProperty( XName.Get( "i", DocX.w.NamespaceName ), string.Empty, null ); + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// A color to use on the appended text. + /// This Paragraph with the last appended text colored. + /// + /// Append text to this Paragraph and then color it. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("Blue").Color(Color.Blue) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph Color( Color c ) + { + ApplyTextFormattingProperty( XName.Get( "color", DocX.w.NamespaceName ), string.Empty, new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), c.ToHex() ) ); + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// The underline style to use for the appended text. + /// This Paragraph with the last appended text underlined. + /// + /// Append text to this Paragraph and then underline it. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("Underlined").UnderlineStyle(UnderlineStyle.doubleLine) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph UnderlineStyle( UnderlineStyle underlineStyle ) + { + string value; + switch( underlineStyle ) + { + case Xceed.Words.NET.UnderlineStyle.none: + value = string.Empty; + break; + case Xceed.Words.NET.UnderlineStyle.singleLine: + value = "single"; + break; + case Xceed.Words.NET.UnderlineStyle.doubleLine: + value = "double"; + break; + default: + value = underlineStyle.ToString(); + break; + } + + ApplyTextFormattingProperty( XName.Get( "u", DocX.w.NamespaceName ), string.Empty, new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), value ) ); + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// The font size to use for the appended text. + /// This Paragraph with the last appended text resized. + /// + /// Append text to this Paragraph and then resize it. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("Big").FontSize(20) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph FontSize( double fontSize ) + { + double tempSize = (int)fontSize*2; + if( tempSize - ( int )tempSize == 0 ) + { + if( !( fontSize > 0 && fontSize < 1639 ) ) + throw new ArgumentException( "Size", "Value must be in the range 0 - 1638" ); + } + + 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 ) ); + + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// The font to use for the appended text. + /// This Paragraph with the last appended text's font changed. + public Paragraph Font (string fontName) + { + return Font(new Font(fontName)); + } + + /// + /// For use with Append() and AppendLine() + /// + /// The font to use for the appended text. + /// This Paragraph with the last appended text's font changed. + /// + /// Append text to this Paragraph and then change its font. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("Times new roman").Font(new FontFamily("Times new roman")) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph Font( Font fontFamily ) + { + ApplyTextFormattingProperty + ( + XName.Get( "rFonts", DocX.w.NamespaceName ), + string.Empty, + new[] + { + new XAttribute(XName.Get("ascii", DocX.w.NamespaceName), fontFamily.Name), + new XAttribute(XName.Get("hAnsi", DocX.w.NamespaceName), fontFamily.Name), + new XAttribute(XName.Get("cs", DocX.w.NamespaceName), fontFamily.Name), + new XAttribute(XName.Get("eastAsia", DocX.w.NamespaceName), fontFamily.Name), + } + ); + + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// The caps style to apply to the last appended text. + /// This Paragraph with the last appended text's caps style changed. + /// + /// Append text to this Paragraph and then set it to full caps. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("Capitalized").CapsStyle(CapsStyle.caps) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph CapsStyle( CapsStyle capsStyle ) + { + switch( capsStyle ) + { + case Xceed.Words.NET.CapsStyle.none: + break; + + default: + { + ApplyTextFormattingProperty( XName.Get( capsStyle.ToString(), DocX.w.NamespaceName ), string.Empty, null ); + break; + } + } + + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// The script style to apply to the last appended text. + /// This Paragraph with the last appended text's script style changed. + /// + /// Append text to this Paragraph and then set it to superscript. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("superscript").Script(Script.superscript) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph Script( Script script ) + { + switch( script ) + { + case Xceed.Words.NET.Script.none: + break; + + default: + { + ApplyTextFormattingProperty( XName.Get( "vertAlign", DocX.w.NamespaceName ), string.Empty, new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), script.ToString() ) ); + break; + } + } + + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + ///The highlight to apply to the last appended text. + /// This Paragraph with the last appended text highlighted. + /// + /// Append text to this Paragraph and then highlight it. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("highlighted").Highlight(Highlight.green) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph Highlight( Highlight highlight ) + { + switch( highlight ) + { + case Xceed.Words.NET.Highlight.none: + break; + + default: + { + ApplyTextFormattingProperty( XName.Get( "highlight", DocX.w.NamespaceName ), string.Empty, new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), highlight.ToString() ) ); + break; + } + } + + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// The miscellaneous property to set. + /// This Paragraph with the last appended text changed by a miscellaneous property. + /// + /// Append text to this Paragraph and then apply a miscellaneous property. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("outlined").Misc(Misc.outline) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph Misc( Misc misc ) + { + switch( misc ) + { + case Xceed.Words.NET.Misc.none: + break; + + case Xceed.Words.NET.Misc.outlineShadow: + { + ApplyTextFormattingProperty( XName.Get( "outline", DocX.w.NamespaceName ), string.Empty, null ); + ApplyTextFormattingProperty( XName.Get( "shadow", DocX.w.NamespaceName ), string.Empty, null ); + + break; + } + + case Xceed.Words.NET.Misc.engrave: + { + ApplyTextFormattingProperty( XName.Get( "imprint", DocX.w.NamespaceName ), string.Empty, null ); + + break; + } + + default: + { + ApplyTextFormattingProperty( XName.Get( misc.ToString(), DocX.w.NamespaceName ), string.Empty, null ); + + break; + } + } + + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// The strike through style to used on the last appended text. + /// This Paragraph with the last appended text striked. + /// + /// Append text to this Paragraph and then strike it. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("striked").StrikeThrough(StrikeThrough.doubleStrike) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph StrikeThrough( StrikeThrough strikeThrough ) + { + string value; + switch( strikeThrough ) + { + case Xceed.Words.NET.StrikeThrough.strike: + value = "strike"; + break; + case Xceed.Words.NET.StrikeThrough.doubleStrike: + value = "dstrike"; + break; + default: + return this; + } + + ApplyTextFormattingProperty( XName.Get( value, DocX.w.NamespaceName ), string.Empty, null ); + + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// The underline color to use, if no underline is set, a single line will be used. + /// This Paragraph with the last appended text underlined in a color. + /// + /// Append text to this Paragraph and then underline it using a color. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("color underlined").UnderlineStyle(UnderlineStyle.dotted).UnderlineColor(Color.Orange) + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph UnderlineColor( Color underlineColor ) + { + foreach( XElement run in _runs ) + { + XElement rPr = run.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + if( rPr == null ) + { + run.AddFirst( new XElement( XName.Get( "rPr", DocX.w.NamespaceName ) ) ); + rPr = run.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + } + + XElement u = rPr.Element( XName.Get( "u", DocX.w.NamespaceName ) ); + if( u == null ) + { + rPr.SetElementValue( XName.Get( "u", DocX.w.NamespaceName ), string.Empty ); + u = rPr.Element( XName.Get( "u", DocX.w.NamespaceName ) ); + u.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), "single" ); + } + + u.SetAttributeValue( XName.Get( "color", DocX.w.NamespaceName ), underlineColor.ToHex() ); + } + + return this; + } + + /// + /// For use with Append() and AppendLine() + /// + /// This Paragraph with the last appended text hidden. + /// + /// Append text to this Paragraph and then hide it. + /// + /// // Create a document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p = document.InsertParagraph(); + /// + /// p.Append("I am ") + /// .Append("hidden").Hide() + /// .Append(" I am not"); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public Paragraph Hide() + { + ApplyTextFormattingProperty( XName.Get( "vanish", DocX.w.NamespaceName ), string.Empty, null ); + + return this; + } + + public Paragraph Spacing( double spacing ) + { + spacing *= 20; + + if( spacing - ( int )spacing == 0 ) + { + if( !( spacing > -1585 && spacing < 1585 ) ) + throw new ArgumentException( "Spacing", "Value must be in the range: -1584 - 1584" ); + } + + else + throw new ArgumentException( "Spacing", "Value must be either a whole or acurate to one decimal, examples: 32, 32.1, 32.2, 32.9" ); + + ApplyTextFormattingProperty( XName.Get( "spacing", DocX.w.NamespaceName ), string.Empty, new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), spacing ) ); + + return this; + } + + public Paragraph SpacingBefore( double spacingBefore ) + { + spacingBefore *= 20; + + var pPr = GetOrCreate_pPr(); + var spacing = pPr.Element( XName.Get( "spacing", DocX.w.NamespaceName ) ); + + if( spacingBefore > 0 ) + { + if( spacing == null ) + { + spacing = new XElement( XName.Get( "spacing", DocX.w.NamespaceName ) ); + pPr.Add( spacing ); + } + + var beforeAttribute = spacing.Attribute( XName.Get( "before", DocX.w.NamespaceName ) ); + + if( beforeAttribute == null ) + spacing.SetAttributeValue( XName.Get( "before", DocX.w.NamespaceName ), spacingBefore ); + else + beforeAttribute.SetValue( spacingBefore ); + } + + if( Math.Abs( spacingBefore ) < 0.1f && spacing != null ) + { + var beforeAttribute = spacing.Attribute( XName.Get( "before", DocX.w.NamespaceName ) ); + beforeAttribute.Remove(); + + if( !spacing.HasAttributes ) + spacing.Remove(); + } + return this; + } + + public Paragraph SpacingAfter( double spacingAfter ) + { + spacingAfter *= 20; + + var pPr = GetOrCreate_pPr(); + var spacing = pPr.Element( XName.Get( "spacing", DocX.w.NamespaceName ) ); + + if( spacingAfter > 0 ) + { + if( spacing == null ) + { + spacing = new XElement( XName.Get( "spacing", DocX.w.NamespaceName ) ); + pPr.Add( spacing ); + } + + var afterAttribute = spacing.Attribute( XName.Get( "after", DocX.w.NamespaceName ) ); + + if( afterAttribute == null ) + spacing.SetAttributeValue( XName.Get( "after", DocX.w.NamespaceName ), spacingAfter ); + else + afterAttribute.SetValue( spacingAfter ); + } + + if( Math.Abs( spacingAfter ) < 0.1f && spacing != null ) + { + var afterAttribute = spacing.Attribute( XName.Get( "after", DocX.w.NamespaceName ) ); + afterAttribute.Remove(); + + if( !spacing.HasAttributes ) + spacing.Remove(); + } + return this; + } + + public Paragraph Kerning( int kerning ) + { + if( !new int?[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72 }.Contains( kerning ) ) + throw new ArgumentOutOfRangeException( "Kerning", "Value must be one of the following: 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48 or 72" ); + + ApplyTextFormattingProperty( XName.Get( "kern", DocX.w.NamespaceName ), string.Empty, new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), kerning * 2 ) ); + return this; + } + + public Paragraph Position( double position ) + { + if( !( position > -1585 && position < 1585 ) ) + throw new ArgumentOutOfRangeException( "Position", "Value must be in the range -1585 - 1585" ); + + ApplyTextFormattingProperty( XName.Get( "position", DocX.w.NamespaceName ), string.Empty, new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), position * 2 ) ); + + return this; + } + + public Paragraph PercentageScale( int percentageScale ) + { + if( !( new int?[] { 200, 150, 100, 90, 80, 66, 50, 33 } ).Contains( percentageScale ) ) + throw new ArgumentOutOfRangeException( "PercentageScale", "Value must be one of the following: 200, 150, 100, 90, 80, 66, 50 or 33" ); + + ApplyTextFormattingProperty( XName.Get( "w", DocX.w.NamespaceName ), string.Empty, new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), percentageScale ) ); + + return this; + } + + /// + /// Append a field of type document property, this field will display the custom property cp, at the end of this paragraph. + /// + /// The custom property to display. + /// The formatting to use for this text. + /// + /// Create, add and display a custom property in a document. + /// + /// // Load a document. + ///using (DocX document = DocX.Create("CustomProperty_Add.docx")) + ///{ + /// // Add a few Custom Properties to this document. + /// document.AddCustomProperty(new CustomProperty("fname", "cathal")); + /// document.AddCustomProperty(new CustomProperty("age", 24)); + /// document.AddCustomProperty(new CustomProperty("male", true)); + /// document.AddCustomProperty(new CustomProperty("newyear2012", new DateTime(2012, 1, 1))); + /// document.AddCustomProperty(new CustomProperty("fav_num", 3.141592)); + /// + /// // Insert a new Paragraph and append a load of DocProperties. + /// Paragraph p = document.InsertParagraph("fname: ") + /// .AppendDocProperty(document.CustomProperties["fname"]) + /// .Append(", age: ") + /// .AppendDocProperty(document.CustomProperties["age"]) + /// .Append(", male: ") + /// .AppendDocProperty(document.CustomProperties["male"]) + /// .Append(", newyear2012: ") + /// .AppendDocProperty(document.CustomProperties["newyear2012"]) + /// .Append(", fav_num: ") + /// .AppendDocProperty(document.CustomProperties["fav_num"]); + /// + /// // Save the changes to the document. + /// document.Save(); + ///} + /// + /// + public Paragraph AppendDocProperty( CustomProperty cp, bool trackChanges = false, Formatting f = null ) + { + this.InsertDocProperty( cp, trackChanges, f ); + return this; + } + + /// + /// Insert a field of type document property, this field will display the custom property cp, at the end of this paragraph. + /// + /// The custom property to display. + /// + /// The formatting to use for this text. + /// + /// Create, add and display a custom property in a document. + /// + /// // Load a document + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Create a custom property. + /// CustomProperty name = new CustomProperty("name", "Cathal Coffey"); + /// + /// // Add this custom property to this document. + /// document.AddCustomProperty(name); + /// + /// // Create a text formatting. + /// Formatting f = new Formatting(); + /// f.Bold = true; + /// f.Size = 14; + /// f.StrikeThrough = StrickThrough.strike; + /// + /// // Insert a new paragraph. + /// Paragraph p = document.InsertParagraph("Author: ", false, f); + /// + /// // Insert a field of type document property to display the custom property name and track this change. + /// p.InsertDocProperty(name, true, f); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public DocProperty InsertDocProperty( CustomProperty cp, bool trackChanges = false, Formatting f = null ) + { + XElement f_xml = null; + if( f != null ) + { + f_xml = f.Xml; + } + + var e = new XElement( XName.Get( "fldSimple", DocX.w.NamespaceName ), + new XAttribute( XName.Get( "instr", DocX.w.NamespaceName ), string.Format( @"DOCPROPERTY {0} \* MERGEFORMAT", cp.Name ) ), + new XElement( XName.Get( "r", DocX.w.NamespaceName ), new XElement( XName.Get( "t", DocX.w.NamespaceName ), f_xml, cp.Value ) ) + ); + + var xml = e; + if( trackChanges ) + { + var now = DateTime.Now; + var insert_datetime = new DateTime( now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc ); + e = CreateEdit( EditType.ins, insert_datetime, e ); + } + + this.Xml.Add( e ); + + return new DocProperty( this.Document, xml ); + } + + /// + /// Removes characters from a Xceed.Words.NET.DocX.Paragraph. + /// + /// + /// + /// // 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. + /// + /// + /// + /// + /// The position to begin deleting characters. + /// The number of characters to delete + /// Track changes + public void RemoveText( int index, int count, bool trackChanges = false ) + { + // Timestamp to mark the start of insert + var now = DateTime.Now; + var remove_datetime = new DateTime( now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc ); + + // The number of characters processed so far + int processed = 0; + + do + { + // Get the first run effected by this Remove + var run = GetFirstRunEffectedByEdit( index, EditType.del ); + + // The parent of this Run + var parentElement = run.Xml.Parent; + switch( parentElement.Name.LocalName ) + { + case "ins": + { + var splitEditBefore = this.SplitEdit( parentElement, index, EditType.del ); + var min = Math.Min( count - processed, run.Xml.ElementsAfterSelf().Sum( e => GetElementTextLength( e ) ) ); + var splitEditAfter = this.SplitEdit( parentElement, index + min, EditType.del ); + + var temp = this.SplitEdit( splitEditBefore[ 1 ], index + min, EditType.del )[ 0 ]; + var middle = Paragraph.CreateEdit( EditType.del, remove_datetime, temp.Elements() ); + processed += Paragraph.GetElementTextLength( middle as XElement ); + + if( !trackChanges ) + { + middle = null; + } + + parentElement.ReplaceWith( splitEditBefore[ 0 ], middle, splitEditAfter[ 1 ] ); + + processed += Paragraph.GetElementTextLength( middle as XElement ); + break; + } + + case "del": + { + if( trackChanges ) + { + // You cannot delete from a deletion, advance processed to the end of this del + processed += Paragraph.GetElementTextLength( parentElement ); + } + else + { + goto case "ins"; + } + break; + } + + default: + { + var splitRunBefore = Run.SplitRun( run, index, EditType.del ); + var min = Math.Min( index + ( count - processed ), run.EndIndex ); + var splitRunAfter = Run.SplitRun( run, min, EditType.del ); + + var middle = Paragraph.CreateEdit( EditType.del, remove_datetime, new List() { Run.SplitRun( new Run( Document, splitRunBefore[ 1 ], run.StartIndex + GetElementTextLength( splitRunBefore[ 0 ] ) ), min, EditType.del )[ 0 ] } ); + processed += Paragraph.GetElementTextLength( middle as XElement ); + + if( !trackChanges ) + { + middle = null; + } + + run.Xml.ReplaceWith( splitRunBefore[ 0 ], middle, splitRunAfter[ 1 ] ); + break; + } + } + + // If after this remove the parent element is empty, remove it. + if( Paragraph.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(); + } + } + } + } + while( processed < count ); + + HelperFunctions.RenumberIDs( Document ); + } + + + /// + /// Removes characters from a Xceed.Words.NET.DocX.Paragraph. + /// + /// + /// + /// // 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 all but the first 2 characters from this Paragraph. + /// p.RemoveText(2, false); + /// } + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + /// + /// + /// The position to begin deleting characters. + /// Track changes + public void RemoveText( int index, bool trackChanges = false ) + { + this.RemoveText( index, Text.Length - index, trackChanges ); + } + + /// + /// Replaces all occurrences of a specified System.String in this instance, with another specified System.String. + /// + /// + /// + /// // 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. + /// + /// + /// + /// + /// + /// + /// A System.String to replace all occurrences of oldValue. + /// A System.String to be replaced. + /// A bitwise OR combination of RegexOption enumeration options. + /// Track changes + /// The formatting to apply to the text being inserted. + /// The formatting that the text must match in order to be replaced. + /// How should formatting be matched? + /// True if the oldValue needs to be escaped, otherwise false. If it represents a valid RegEx pattern this should be false. + /// True if RegEx-like replace should be performed, i.e. if newValue contains RegEx substitutions. Does not perform named-group substitutions (only numbered groups). + public void ReplaceText( string searchValue, + 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 ) + { + var mc = Regex.Matches( this.Text, escapeRegEx ? Regex.Escape( searchValue ) : searchValue, options ); + + // Loop through the matches in reverse order + foreach( Match m in mc.Cast().Reverse() ) + { + // Assume the formatting matches until proven otherwise. + bool formattingMatch = true; + + // Does the user want to match formatting? + if( matchFormatting != null ) + { + // The number of characters processed so far + int processed = 0; + + do + { + // Get the next run effected + var run = GetFirstRunEffectedByEdit( m.Index + processed ); + + // Get this runs properties + var rPr = run.Xml.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + + if( rPr == null ) + { + rPr = new Formatting().Xml; + } + + /* + * Make sure that every formatting element in f.xml is also in this run, + * if this is not true, then their formatting does not match. + */ + if( !HelperFunctions.ContainsEveryChildOf( matchFormatting.Xml, rPr, fo ) ) + { + formattingMatch = false; + break; + } + + // We have processed some characters, so update the counter. + processed += run.Value.Length; + + } while( processed < m.Length ); + } + + // If the formatting matches, do the replace. + if( formattingMatch ) + { + //perform RegEx substitutions. Only named groups are not supported. Everything else is supported. However character escapes are not covered. + if( useRegExSubstitutions && !string.IsNullOrEmpty( newValue ) ) + { + newValue = newValue.Replace( "$&", m.Value ); + if( m.Groups.Count > 0 ) + { + int lastcap = 0; + for( int k = 0; k < m.Groups.Count; k++ ) + { + var g = m.Groups[ k ]; + if( ( g == null ) || ( g.Value == "" ) ) + continue; + newValue = newValue.Replace( "$" + k.ToString(), g.Value ); + lastcap = k; + } + newValue = newValue.Replace( "$+", m.Groups[ lastcap ].Value ); + } + if( m.Index > 0 ) + { + newValue = newValue.Replace( "$`", this.Text.Substring( 0, m.Index ) ); + } + if( ( m.Index + m.Length ) < this.Text.Length ) + { + newValue = newValue.Replace( "$'", this.Text.Substring( m.Index + m.Length ) ); + } + newValue = newValue.Replace( "$_", this.Text ); + newValue = newValue.Replace( "$$", "$" ); + } + + if( !string.IsNullOrEmpty( newValue ) ) + { + this.InsertText( m.Index + m.Length, newValue, trackChanges, newFormatting ); + } + if( m.Length > 0 ) + { + this.RemoveText( m.Index, m.Length, trackChanges ); + } + } + } + } + + public void ReplaceText( string findPattern, Func regexMatchHandler, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch ) + { + var matchCol = Regex.Matches( this.Text, findPattern, options ); + var reversedMatchCol = matchCol.Cast().Reverse(); + + foreach( var match in reversedMatchCol ) + { + var formattingMatch = true; + + if( matchFormatting != null ) + { + int processed = 0; + + while( processed < match.Length ) + { + var run = this.GetFirstRunEffectedByEdit( match.Index + processed ); + var rPr = run.Xml.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + if( rPr == null ) + { + rPr = new Formatting().Xml; + } + + // Make sure that every formatting element in matchFormatting.Xml is also in this run, + // if false => formatting does not match. + if( !HelperFunctions.ContainsEveryChildOf( matchFormatting.Xml, rPr, fo ) ) + { + formattingMatch = false; + break; + } + + processed += run.Value.Length; + } + + // Replace text when formatting matches. + if( formattingMatch ) + { + var newValue = regexMatchHandler.Invoke( match.Groups[ 1 ].Value ); + this.InsertText( match.Index + match.Value.Length, newValue, trackChanges, newFormatting ); + this.RemoveText( match.Index, match.Value.Length, trackChanges ); + } + } + } + } + + /// + /// Find all instances of a string in this paragraph and return their indexes in a List. + /// + /// The string to find + /// A list of indexes. + /// + /// Find all instances of Hello in this document and insert 'don't' in frount of them. + /// + /// // Load a document + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // Loop through the paragraphs in this document. + /// foreach(Paragraph p in document.Paragraphs) + /// { + /// // Find all instances of 'go' in this paragraph. + /// ]]> gos = document.FindAll("go"); + /// + /// /* + /// * Insert 'don't' in frount of every instance of 'go' in this document to produce 'don't go'. + /// * An important trick here is to do the inserting in reverse document order. If you inserted + /// * in document order, every insert would shift the index of the remaining matches. + /// */ + /// gos.Reverse(); + /// foreach (int index in gos) + /// { + /// p.InsertText(index, "don't ", false); + /// } + /// } + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public List FindAll( string str ) + { + return this.FindAll( str, RegexOptions.None ); + } + + /// + /// Find all instances of a string in this paragraph and return their indexes in a List. + /// + /// The string to find + /// The options to use when finding a string match. + /// A list of indexes. + /// + /// Find all instances of Hello in this document and insert 'don't' in frount of them. + /// + /// // Load a document + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // Loop through the paragraphs in this document. + /// foreach(Paragraph p in document.Paragraphs) + /// { + /// // Find all instances of 'go' in this paragraph (Ignore case). + /// ]]> gos = document.FindAll("go", RegexOptions.IgnoreCase); + /// + /// /* + /// * Insert 'don't' in frount of every instance of 'go' in this document to produce 'don't go'. + /// * An important trick here is to do the inserting in reverse document order. If you inserted + /// * in document order, every insert would shift the index of the remaining matches. + /// */ + /// gos.Reverse(); + /// foreach (int index in gos) + /// { + /// p.InsertText(index, "don't ", false); + /// } + /// } + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public List FindAll( string str, RegexOptions options ) + { + var mc = Regex.Matches( this.Text, Regex.Escape( str ), options ); + + var query = + ( + from m in mc.Cast() + select m.Index + ).ToList(); + + return query; + } + + /// + /// Find all unique instances of the given Regex Pattern + /// + /// + /// + /// + public List FindAllByPattern( string str, RegexOptions options ) + { + MatchCollection mc = Regex.Matches( this.Text, str, options ); + + var query = + ( + from m in mc.Cast() + select m.Value + ).ToList(); + + return query; + } + + /// + /// Insert a PageNumber place holder into a Paragraph. + /// This place holder should only be inserted into a Header or Footer Paragraph. + /// Word will not automatically update this field if it is inserted into a document level Paragraph. + /// + /// The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...) + /// The text index to insert this PageNumber place holder at. + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add Headers to the document. + /// document.AddHeaders(); + /// + /// // Get the default Header. + /// Header header = document.Headers.odd; + /// + /// // Insert a Paragraph into the Header. + /// Paragraph p0 = header.InsertParagraph("Page ( of )"); + /// + /// // Insert place holders for PageNumber and PageCount into the Header. + /// // Word will replace these with the correct value for each Page. + /// p0.InsertPageNumber(PageNumberFormat.normal, 6); + /// p0.InsertPageCount(PageNumberFormat.normal, 11); + /// + /// // Save the document. + /// document.Save(); + /// } + /// + /// + /// + /// + /// + public void InsertPageNumber( PageNumberFormat pnf, int index = 0 ) + { + var fldSimple = new XElement( XName.Get( "fldSimple", DocX.w.NamespaceName ) ); + + if( pnf == PageNumberFormat.normal ) + { + fldSimple.Add( new XAttribute( XName.Get( "instr", DocX.w.NamespaceName ), @" PAGE \* MERGEFORMAT " ) ); + } + else + { + fldSimple.Add( new XAttribute( XName.Get( "instr", DocX.w.NamespaceName ), @" PAGE \* ROMAN \* MERGEFORMAT " ) ); + } + + var content = XElement.Parse + ( + @" + + + + 1 + " + ); + + fldSimple.Add( content ); + + if( index == 0 ) + { + Xml.AddFirst( fldSimple ); + } + else + { + var r = GetFirstRunEffectedByEdit( index, EditType.ins ); + var splitEdit = SplitEdit( r.Xml, index, EditType.ins ); + r.Xml.ReplaceWith + ( + splitEdit[ 0 ], + fldSimple, + splitEdit[ 1 ] + ); + } + } + + /// + /// Append a PageNumber place holder onto the end of a Paragraph. + /// + /// The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...) + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add Headers to the document. + /// document.AddHeaders(); + /// + /// // Get the default Header. + /// Header header = document.Headers.odd; + /// + /// // Insert a Paragraph into the Header. + /// Paragraph p0 = header.InsertParagraph(); + /// + /// // Appemd place holders for PageNumber and PageCount into the Header. + /// // Word will replace these with the correct value for each Page. + /// p0.Append("Page ("); + /// p0.AppendPageNumber(PageNumberFormat.normal); + /// p0.Append(" of "); + /// p0.AppendPageCount(PageNumberFormat.normal); + /// p0.Append(")"); + /// + /// // Save the document. + /// document.Save(); + /// } + /// + /// + /// + /// + /// + public void AppendPageNumber( PageNumberFormat pnf ) + { + XElement fldSimple = new XElement( XName.Get( "fldSimple", DocX.w.NamespaceName ) ); + + if( pnf == PageNumberFormat.normal ) + fldSimple.Add( new XAttribute( XName.Get( "instr", DocX.w.NamespaceName ), @" PAGE \* MERGEFORMAT " ) ); + else + fldSimple.Add( new XAttribute( XName.Get( "instr", DocX.w.NamespaceName ), @" PAGE \* ROMAN \* MERGEFORMAT " ) ); + + XElement content = XElement.Parse + ( + @" + + + + 1 + " + ); + + fldSimple.Add( content ); + Xml.Add( fldSimple ); + } + + /// + /// Insert a PageCount place holder into a Paragraph. + /// This place holder should only be inserted into a Header or Footer Paragraph. + /// Word will not automatically update this field if it is inserted into a document level Paragraph. + /// + /// The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...) + /// The text index to insert this PageCount place holder at. + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add Headers to the document. + /// document.AddHeaders(); + /// + /// // Get the default Header. + /// Header header = document.Headers.odd; + /// + /// // Insert a Paragraph into the Header. + /// Paragraph p0 = header.InsertParagraph("Page ( of )"); + /// + /// // Insert place holders for PageNumber and PageCount into the Header. + /// // Word will replace these with the correct value for each Page. + /// p0.InsertPageNumber(PageNumberFormat.normal, 6); + /// p0.InsertPageCount(PageNumberFormat.normal, 11); + /// + /// // Save the document. + /// document.Save(); + /// } + /// + /// + /// + /// + /// + public void InsertPageCount( PageNumberFormat pnf, int index = 0 ) + { + XElement fldSimple = new XElement( XName.Get( "fldSimple", DocX.w.NamespaceName ) ); + + if( pnf == PageNumberFormat.normal ) + fldSimple.Add( new XAttribute( XName.Get( "instr", DocX.w.NamespaceName ), @" NUMPAGES \* MERGEFORMAT " ) ); + else + fldSimple.Add( new XAttribute( XName.Get( "instr", DocX.w.NamespaceName ), @" NUMPAGES \* ROMAN \* MERGEFORMAT " ) ); + + XElement content = XElement.Parse + ( + @" + + + + 1 + " + ); + + fldSimple.Add( content ); + + if( index == 0 ) + Xml.AddFirst( fldSimple ); + else + { + Run r = GetFirstRunEffectedByEdit( index, EditType.ins ); + XElement[] splitEdit = SplitEdit( r.Xml, index, EditType.ins ); + r.Xml.ReplaceWith + ( + splitEdit[ 0 ], + fldSimple, + splitEdit[ 1 ] + ); + } + } + + /// + /// Append a PageCount place holder onto the end of a Paragraph. + /// + /// The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...) + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Add Headers to the document. + /// document.AddHeaders(); + /// + /// // Get the default Header. + /// Header header = document.Headers.odd; + /// + /// // Insert a Paragraph into the Header. + /// Paragraph p0 = header.InsertParagraph(); + /// + /// // Appemd place holders for PageNumber and PageCount into the Header. + /// // Word will replace these with the correct value for each Page. + /// p0.Append("Page ("); + /// p0.AppendPageNumber(PageNumberFormat.normal); + /// p0.Append(" of "); + /// p0.AppendPageCount(PageNumberFormat.normal); + /// p0.Append(")"); + /// + /// // Save the document. + /// document.Save(); + /// } + /// + /// + /// + /// + /// + public void AppendPageCount( PageNumberFormat pnf ) + { + XElement fldSimple = new XElement( XName.Get( "fldSimple", DocX.w.NamespaceName ) ); + + if( pnf == PageNumberFormat.normal ) + fldSimple.Add( new XAttribute( XName.Get( "instr", DocX.w.NamespaceName ), @" NUMPAGES \* MERGEFORMAT " ) ); + else + fldSimple.Add( new XAttribute( XName.Get( "instr", DocX.w.NamespaceName ), @" NUMPAGES \* ROMAN \* MERGEFORMAT " ) ); + + XElement content = XElement.Parse + ( + @" + + + + 1 + " + ); + + fldSimple.Add( content ); + Xml.Add( fldSimple ); + } + + /// + /// Set the Line spacing for this paragraph manually. + /// + /// The type of spacing to be set, can be either Before, After or Line (Standard line spacing). + /// A float value of the amount of spacing. Equals the value that will be set in Word using the "Line and Paragraph spacing" button. + public void SetLineSpacing( LineSpacingType spacingType, float spacingFloat ) + { + var pPr = this.GetOrCreate_pPr(); + var spacingXName = XName.Get( "spacing", DocX.w.NamespaceName ); + var spacing = pPr.Element( spacingXName ); + if( spacing == null ) + { + pPr.Add( new XElement( spacingXName ) ); + spacing = pPr.Element( spacingXName ); + } + + var spacingTypeAttribute = ( spacingType == LineSpacingType.Before ) + ? "before" + : ( spacingType == LineSpacingType.After ) ? "after" : "line"; + spacing.SetAttributeValue( XName.Get( spacingTypeAttribute, DocX.w.NamespaceName ), ( int )( spacingFloat * 240f ) ); + } + + /// + /// Set the Line spacing for this paragraph using the Auto value. + /// + /// The type of spacing to be set automatically. Using Auto will set both Before and After. None will remove any line spacing. + public void SetLineSpacing( LineSpacingTypeAuto spacingTypeAuto ) + { + var pPr = this.GetOrCreate_pPr(); + var spacingXName = XName.Get( "spacing", DocX.w.NamespaceName ); + var spacing = pPr.Element( spacingXName ); + + if( spacingTypeAuto == LineSpacingTypeAuto.None ) + { + if( spacing != null ) + { + spacing.Remove(); + } + } + else + { + if( spacing == null ) + { + pPr.Add( new XElement( spacingXName ) ); + spacing = pPr.Element( spacingXName ); + } + + int spacingValue = 500; + var spacingTypeAttribute = ( spacingTypeAuto == LineSpacingTypeAuto.AutoAfter ) ? "after" : "before"; + var autoSpacingTypeAttribute = ( spacingTypeAuto == LineSpacingTypeAuto.AutoAfter ) ? "afterAutospacing" : "beforeAutospacing"; + + spacing.SetAttributeValue( XName.Get( spacingTypeAttribute, DocX.w.NamespaceName ), spacingValue ); + spacing.SetAttributeValue( XName.Get( autoSpacingTypeAttribute, DocX.w.NamespaceName ), 1 ); + + if( spacingTypeAuto == LineSpacingTypeAuto.Auto ) + { + spacing.SetAttributeValue( XName.Get( "after", DocX.w.NamespaceName ), spacingValue ); + spacing.SetAttributeValue( XName.Get( "afterAutospacing", DocX.w.NamespaceName ), 1 ); + } + } + } + + public Paragraph AppendBookmark( string bookmarkName ) + { + XElement wBookmarkStart = new XElement( + XName.Get( "bookmarkStart", DocX.w.NamespaceName ), + new XAttribute( XName.Get( "id", DocX.w.NamespaceName ), 0 ), + new XAttribute( XName.Get( "name", DocX.w.NamespaceName ), bookmarkName ) ); + Xml.Add( wBookmarkStart ); + + XElement wBookmarkEnd = new XElement( + XName.Get( "bookmarkEnd", DocX.w.NamespaceName ), + new XAttribute( XName.Get( "id", DocX.w.NamespaceName ), 0 ), + new XAttribute( XName.Get( "name", DocX.w.NamespaceName ), bookmarkName ) ); + Xml.Add( wBookmarkEnd ); + + return this; + } + + public bool ValidateBookmark( string bookmarkName ) + { + return GetBookmarks().Any( b => b.Name.Equals( bookmarkName ) ); + } + + public IEnumerable GetBookmarks() + { + return Xml.Descendants( XName.Get( "bookmarkStart", DocX.w.NamespaceName ) ) + .Select( x => x.Attribute( XName.Get( "name", DocX.w.NamespaceName ) ) ) + .Select( x => new Bookmark + { + Name = x.Value, + Paragraph = this + } ); + } + + public void InsertAtBookmark( string toInsert, string bookmarkName ) + { + var bookmark = Xml.Descendants( XName.Get( "bookmarkStart", DocX.w.NamespaceName ) ) + .Where( x => x.Attribute( XName.Get( "name", DocX.w.NamespaceName ) ).Value == bookmarkName ).SingleOrDefault(); + if( bookmark != null ) + { + var run = HelperFunctions.FormatInput( toInsert, null ); + bookmark.AddBeforeSelf( run ); + _runs = Xml.Elements( XName.Get( "r", DocX.w.NamespaceName ) ).ToList(); + HelperFunctions.RenumberIDs( Document ); + } + } + + /// + /// Paragraph that will be kept on the same page as the next paragraph. + /// + /// + /// + public Paragraph KeepWithNextParagraph( bool keepWithNextParagraph = true ) + { + var pPr = GetOrCreate_pPr(); + var keepNextElement = pPr.Element( XName.Get( "keepNext", DocX.w.NamespaceName ) ); + + if( keepNextElement == null && keepWithNextParagraph ) + { + pPr.Add( new XElement( XName.Get( "keepNext", DocX.w.NamespaceName ) ) ); + } + + if( !keepWithNextParagraph && keepNextElement != null ) + { + keepNextElement.Remove(); + } + + return this; + } + + /// + /// Paragraph with lines that will stay together on the same page. + /// + /// + /// + public Paragraph KeepLinesTogether( bool keepLinesTogether = true ) + { + var pPr = GetOrCreate_pPr(); + var keepLinesElement = pPr.Element( XName.Get( "keepLines", DocX.w.NamespaceName ) ); + + if( keepLinesElement == null && keepLinesTogether ) + { + pPr.Add( new XElement( XName.Get( "keepLines", DocX.w.NamespaceName ) ) ); + } + + if( !keepLinesTogether ) + { + keepLinesElement?.Remove(); + } + + return this; + } + + public void ReplaceAtBookmark( string text, string bookmarkName ) + { + var bookmarkStart = this.Xml.Descendants( XName.Get( "bookmarkStart", DocX.w.NamespaceName ) ) + .Where( x => x.Attribute( XName.Get( "name", DocX.w.NamespaceName ) ).Value == bookmarkName ) + .SingleOrDefault(); + if( bookmarkStart == null ) + return; + + var nextNode = bookmarkStart.NextNode; + XElement nextXElement = null; + while( nextNode != null ) + { + nextXElement = nextNode as XElement; + if( ( nextXElement != null ) && + ( nextXElement.Name.NamespaceName == DocX.w.NamespaceName ) && + ( ( nextXElement.Name.LocalName == "r" ) || ( nextXElement.Name.LocalName == "bookmarkEnd" ) ) ) + break; + + nextNode = nextNode.NextNode; + } + + if( nextXElement == null ) + return; + + if( nextXElement.Name.LocalName.Equals( "bookmarkEnd" ) ) + { + this.ReplaceAtBookmark_Core( text, bookmarkStart ); + return; + } + + var tXElement = nextXElement.Elements( XName.Get( "t", DocX.w.NamespaceName ) ).FirstOrDefault(); + if( tXElement == null ) + { + this.ReplaceAtBookmark_Core( text, bookmarkStart ); + return; + } + + tXElement.Value = text; + } + + public void InsertHorizontalLine( string lineType = "single", int size = 6, int space = 1, string color = "auto" ) + { + var pBrXName = XName.Get( "pBdr", DocX.w.NamespaceName ); + var bottomXName = XName.Get( "bottom", DocX.w.NamespaceName ); + + var pPr = this.GetOrCreate_pPr(); + var pBdr = pPr.Element( pBrXName ); + if( pBdr == null ) + { + //Add border + pPr.Add( new XElement( pBrXName ) ); + pBdr = pPr.Element( pBrXName ); + + //Add bottom + pBdr.Add( new XElement( bottomXName ) ); + var bottom = pBdr.Element( bottomXName ); + + //Set bottom's attribute + bottom.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), lineType ); + bottom.SetAttributeValue( XName.Get( "sz", DocX.w.NamespaceName ), size.ToString() ); + bottom.SetAttributeValue( XName.Get( "space", DocX.w.NamespaceName ), space.ToString() ); + bottom.SetAttributeValue( XName.Get( "color", DocX.w.NamespaceName ), color ); + } + } + + #endregion + + #region Internal Methods + + /// + /// If the pPr element doesent exist it is created, either way it is returned by this function. + /// + /// The pPr element for this Paragraph. + internal XElement GetOrCreate_pPr() + { + // Get the element. + var pPr = Xml.Element( XName.Get( "pPr", DocX.w.NamespaceName ) ); + + // If it dosen't exist, create it. + if( pPr == null ) + { + Xml.AddFirst( new XElement( XName.Get( "pPr", DocX.w.NamespaceName ) ) ); + pPr = Xml.Element( XName.Get( "pPr", DocX.w.NamespaceName ) ); + } + + // Return the pPr element for this Paragraph. + return pPr; + } + + /// + /// If the ind element doesent exist it is created, either way it is returned by this function. + /// + /// The ind element for this Paragraphs pPr. + internal XElement GetOrCreate_pPr_ind() + { + // Get the element. + XElement pPr = GetOrCreate_pPr(); + XElement ind = pPr.Element( XName.Get( "ind", DocX.w.NamespaceName ) ); + + // If it dosen't exist, create it. + if( ind == null ) + { + pPr.Add( new XElement( XName.Get( "ind", DocX.w.NamespaceName ) ) ); + ind = pPr.Element( XName.Get( "ind", DocX.w.NamespaceName ) ); + } + + // Return the pPr element for this Paragraph. + return ind; + } + + internal void RemoveHyperlinkRecursive( XElement xml, int index, ref int count, ref bool found ) + { + if( xml.Name.LocalName.Equals( "hyperlink", StringComparison.CurrentCultureIgnoreCase ) ) + { + // This is the hyperlink to be removed. + if( count == index ) + { + found = true; + xml.Remove(); + } + + else + count++; + } + + if( xml.HasElements ) + foreach( XElement e in xml.Elements() ) + if( !found ) + RemoveHyperlinkRecursive( e, index, ref count, ref found ); + } + + /// + /// Create a new Picture. + /// + /// + /// A unique id that identifies an Image embedded in this document. + /// The name of this Picture. + /// The description of this Picture. + /// The width of this Picture. + /// The height of this Picture. + static internal Picture CreatePicture( DocX document, string id, string name, string descr, int width, int height ) + { + var part = document._package.GetPart( document.PackagePart.GetRelationship( id ).TargetUri ); + + var newDocPrIdValue = 1; + var bookmarkIds = new List(); + var bookmarks = document.Xml.Descendants( XName.Get( "bookmarkStart", DocX.wp.NamespaceName ) ); + foreach( var bookmark in bookmarks ) + { + var idAttr = bookmark.Attributes().FirstOrDefault( a => a.Name.LocalName == "id" ); + if( idAttr != null ) + { + bookmarkIds.Add( idAttr.Value ); + } + } + while( bookmarkIds.Contains( newDocPrIdValue.ToString() ) ) + { + ++newDocPrIdValue; + } + + var docPrs = document.Xml.Descendants( XName.Get( "docPr", DocX.wp.NamespaceName ) ); + foreach( var bookmark in docPrs ) + { + var idAttr = bookmark.Attributes().FirstOrDefault( a => a.Name.LocalName == "id" ); + if( idAttr != null ) + { + bookmarkIds.Add( idAttr.Value ); + } + } + while( bookmarkIds.Contains( newDocPrIdValue.ToString() ) ) + { + ++newDocPrIdValue; + } + + int cx, cy; + + using( System.Drawing.Image img = System.Drawing.Image.FromStream( new PackagePartStream( part.GetStream() ) ) ) + { + cx = img.Width * 9526; + cy = img.Height * 9526; + } + + var e = new XElement( DocX.w + "drawing" ); + + var xml = XElement.Parse + ( string.Format( @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ", cx, cy, id, name, descr, newDocPrIdValue.ToString() ) ); + + var picture = new Picture( document, xml, new Image( document, document.PackagePart.GetRelationship( id ) ) ); + if( width > -1 ) + { + picture.Width = width; + } + if( height > -1 ) + { + picture.Height = height; + } + return picture; + } + + /// + /// Creates an Edit either a ins or a del with the specified content and date + /// + /// The type of this edit (ins or del) + /// The time stamp to use for this edit + /// The initial content of this edit + /// + internal static XElement CreateEdit( EditType t, DateTime edit_time, object content ) + { + if( t == EditType.del ) + { + foreach( object o in ( IEnumerable )content ) + { + if( o is XElement ) + { + XElement e = ( o as XElement ); + IEnumerable ts = e.DescendantsAndSelf( XName.Get( "t", DocX.w.NamespaceName ) ); + + for( int i = 0; i < ts.Count(); i++ ) + { + XElement text = ts.ElementAt( i ); + text.ReplaceWith( new XElement( DocX.w + "delText", text.Attributes(), text.Value ) ); + } + } + } + } + + // Check the author in a Try/Catch + // (for the cases where we do not have the rights to access that information) + string author = ""; + try + { + author = WindowsIdentity.GetCurrent().Name; + } + catch( Exception ) + { + // do nothing + } + + if( author.Trim() == "" ) + { + return + ( + new XElement( DocX.w + t.ToString(), + new XAttribute( DocX.w + "id", 0 ), + new XAttribute( DocX.w + "date", edit_time ), + content ) + ); + } + + return + ( + new XElement( DocX.w + t.ToString(), + new XAttribute( DocX.w + "id", 0 ), + new XAttribute( DocX.w + "author", author ), + new XAttribute( DocX.w + "date", edit_time ), + content ) + ); + } + + internal Run GetFirstRunEffectedByEdit( int index, EditType type = EditType.ins ) + { + int len = HelperFunctions.GetText( Xml ).Length; + + // Make sure we are looking within an acceptable index range. + if( index < 0 || ( ( type == EditType.ins && index > len ) || ( type == EditType.del && index >= len ) ) ) + throw new ArgumentOutOfRangeException(); + + // Need some memory that can be updated by the recursive search for the XElement to Split. + int count = 0; + Run theOne = null; + + GetFirstRunEffectedByEditRecursive( Xml, index, ref count, ref theOne, type ); + + return theOne; + } + + internal void GetFirstRunEffectedByEditRecursive( XElement Xml, int index, ref int count, ref Run theOne, EditType type ) + { + count += HelperFunctions.GetSize( Xml ); + + // If the EditType is deletion then we must return the next blah + if( count > 0 && ( ( type == EditType.del && count > index ) || ( type == EditType.ins && count >= index ) ) ) + { + // Correct the index + foreach( XElement e in Xml.ElementsBeforeSelf() ) + { + count -= HelperFunctions.GetSize( e ); + } + + count -= HelperFunctions.GetSize( Xml ); + + // We have found the element, now find the run it belongs to. + while( ( Xml.Name.LocalName != "r" ) && ( Xml.Name.LocalName != "pPr" ) ) + { + Xml = Xml.Parent; + } + + theOne = new Run( Document, Xml, count ); + return; + } + + if( Xml.HasElements ) + { + foreach( XElement e in Xml.Elements() ) + { + if( theOne == null ) + { + this.GetFirstRunEffectedByEditRecursive( e, index, ref count, ref theOne, type ); + } + } + } + } + + /// + static internal int GetElementTextLength( XElement run ) + { + int count = 0; + + if( run == null ) + return count; + + foreach( var d in run.Descendants() ) + { + switch( d.Name.LocalName ) + { + case "tab": + if( d.Parent.Name.LocalName != "tabs" ) + goto case "br"; + break; + case "br": + count++; + break; + case "t": + goto case "delText"; + case "delText": + count += d.Value.Length; + break; + default: + break; + } + } + return count; + } + + internal XElement[] SplitEdit( XElement edit, int index, EditType type ) + { + Run run = GetFirstRunEffectedByEdit( index, type ); + + XElement[] splitRun = Run.SplitRun( run, index, type ); + + XElement splitLeft = new XElement( edit.Name, edit.Attributes(), run.Xml.ElementsBeforeSelf(), splitRun[ 0 ] ); + if( GetElementTextLength( splitLeft ) == 0 ) + splitLeft = null; + + XElement splitRight = new XElement( edit.Name, edit.Attributes(), splitRun[ 1 ], run.Xml.ElementsAfterSelf() ); + if( GetElementTextLength( splitRight ) == 0 ) + splitRight = null; + + return + ( + new XElement[] + { + splitLeft, + splitRight + } + ); + } + + internal string GetOrGenerateRel( Picture p ) + { + string image_uri_string = p._img._pr.TargetUri.OriginalString; + + // Search for a relationship with a TargetUri that points at this Image. + var Id = + ( + from r in this.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ) + where r.TargetUri.OriginalString == image_uri_string + select r.Id + ).SingleOrDefault(); + + // If such a relation dosen't exist, create one. + if( Id == null ) + { + // Check to see if a relationship for this Picture exists and create it if not. + var pr = this.PackagePart.CreateRelationship( p._img._pr.TargetUri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ); + Id = pr.Id; + } + return Id; + } + + internal string GetOrGenerateRel( Hyperlink h ) + { + string image_uri_string = h.Uri.OriginalString; + + // Search for a relationship with a TargetUri that points at this Image. + var Id = + ( + from r in this.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ) + where r.TargetUri.OriginalString == image_uri_string + select r.Id + ).SingleOrDefault(); + + // If such a relation dosen't exist, create one. + if( Id == null ) + { + // Check to see if a relationship for this Picture exists and create it if not. + var pr = this.PackagePart.CreateRelationship( h.Uri, TargetMode.External, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ); + Id = pr.Id; + } + return Id; + } + + internal void ApplyTextFormattingProperty( XName textFormatPropName, string value, object content ) + { + XElement rPr = null; + + if( _runs.Count == 0 ) + { + var pPr = this.Xml.Element( XName.Get( "pPr", DocX.w.NamespaceName ) ); + if( pPr == null ) + { + this.Xml.AddFirst( new XElement( XName.Get( "pPr", DocX.w.NamespaceName ) ) ); + pPr = this.Xml.Element( XName.Get( "pPr", DocX.w.NamespaceName ) ); + } + + rPr = pPr.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + if( rPr == null ) + { + pPr.AddFirst( new XElement( XName.Get( "rPr", DocX.w.NamespaceName ) ) ); + rPr = pPr.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + } + + rPr.SetElementValue( textFormatPropName, value ); + + var lastElement = rPr.Elements( textFormatPropName ).Last(); + // Check if the content is an attribute + if( content as XAttribute != null ) + { + // Add or Update the attribute to the last element + if( lastElement.Attribute( ( ( XAttribute )( content ) ).Name ) == null ) + { + lastElement.Add( content ); + } + else + { + lastElement.Attribute( ( ( XAttribute )( content ) ).Name ).Value = ( ( XAttribute )( content ) ).Value; + } + } + return; + } + + var isFontPropertiesList = false; + var fontProperties = content as IEnumerable; + if( fontProperties != null ) + { + foreach( object property in fontProperties ) + { + isFontPropertiesList = ( property as XAttribute != null ); + } + } + + foreach( XElement run in _runs ) + { + rPr = run.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + if( rPr == null ) + { + run.AddFirst( new XElement( XName.Get( "rPr", DocX.w.NamespaceName ) ) ); + rPr = run.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ); + } + + rPr.SetElementValue( textFormatPropName, value ); + var last = rPr.Elements( textFormatPropName ).Last(); + + if( isFontPropertiesList ) + { + foreach( object property in fontProperties ) + { + if( last.Attribute( ( ( XAttribute )( property ) ).Name ) == null ) + { + last.Add( property ); + } + else + { + last.Attribute( ( ( XAttribute )( property ) ).Name ).Value = ( ( XAttribute )( property ) ).Value; + } + } + } + + + if( content as XAttribute != null )//If content is an attribute + { + if( last.Attribute( ( ( XAttribute )( content ) ).Name ) == null ) + { + last.Add( content ); //Add this attribute if element doesn't have it + } + else + { + last.Attribute( ( ( XAttribute )( content ) ).Name ).Value = ( ( XAttribute )( content ) ).Value; //Apply value only if element already has it + } + } + else + { + //IMPORTANT + //But what to do if it is not? + } + } + } + + #endregion + + #region Private Methods + + private void ApplyFormattingFrom( ref Formatting newFormatting, Formatting sourceFormatting ) + { + //Set the formatting properties of clone based on received formatting. + newFormatting.FontFamily = sourceFormatting.FontFamily; + newFormatting.Language = sourceFormatting.Language; + if( sourceFormatting.Bold.HasValue ) + { + newFormatting.Bold = sourceFormatting.Bold; + } + if( sourceFormatting.CapsStyle.HasValue ) + { + newFormatting.CapsStyle = sourceFormatting.CapsStyle; + } + if( sourceFormatting.FontColor.HasValue ) + { + newFormatting.FontColor = sourceFormatting.FontColor; + } + if( sourceFormatting.Hidden.HasValue ) + { + newFormatting.Hidden = sourceFormatting.Hidden; + } + if( sourceFormatting.Highlight.HasValue ) + { + newFormatting.Highlight = sourceFormatting.Highlight; + } + if( sourceFormatting.Italic.HasValue ) + { + newFormatting.Italic = sourceFormatting.Italic; + } + if( sourceFormatting.Kerning.HasValue ) + { + newFormatting.Kerning = sourceFormatting.Kerning; + } + if( sourceFormatting.Misc.HasValue ) + { + newFormatting.Misc = sourceFormatting.Misc; + } + if( sourceFormatting.PercentageScale.HasValue ) + { + newFormatting.PercentageScale = sourceFormatting.PercentageScale; + } + if( sourceFormatting.Position.HasValue ) + { + newFormatting.Position = sourceFormatting.Position; + } + if( sourceFormatting.Script.HasValue ) + { + newFormatting.Script = sourceFormatting.Script; + } + if( sourceFormatting.Size.HasValue ) + { + newFormatting.Size = sourceFormatting.Size; + } + if( sourceFormatting.Spacing.HasValue ) + { + newFormatting.Spacing = sourceFormatting.Spacing; + } + if( sourceFormatting.StrikeThrough.HasValue ) + { + newFormatting.StrikeThrough = sourceFormatting.StrikeThrough; + } + if( sourceFormatting.UnderlineColor.HasValue ) + { + newFormatting.UnderlineColor = sourceFormatting.UnderlineColor; + } + if( sourceFormatting.UnderlineStyle.HasValue ) + { + newFormatting.UnderlineStyle = sourceFormatting.UnderlineStyle; + } + } + + private void RebuildDocProperties() + { + docProperties = + ( + from xml in Xml.Descendants( XName.Get( "fldSimple", DocX.w.NamespaceName ) ) + select new DocProperty( Document, xml ) + ).ToList(); + } + + private XElement GetParagraphNumberProperties() + { + var numPrNode = Xml.Descendants().FirstOrDefault( el => el.Name.LocalName == "numPr" ); + if( numPrNode != null ) + { + var numIdNode = numPrNode.Descendants().First( numId => numId.Name.LocalName == "numId" ); + var numIdAttribute = numIdNode.Attribute( DocX.w + "val" ); + if( numIdAttribute != null && numIdAttribute.Value.Equals( "0" ) ) + return null; + } + + return numPrNode; + } + + private List GetPictures( string localName, string localNameEquals, string attributeName ) + { + var pictures = + ( + from p in Xml.Descendants() + where ( p.Name.LocalName == localName ) + let id = + ( + from e in p.Descendants() + where e.Name.LocalName.Equals( localNameEquals ) + select e.Attribute( XName.Get( attributeName, "http://schemas.openxmlformats.org/officeDocument/2006/relationships" ) ).Value + ).SingleOrDefault() + where id != null + let img = new Image( this.Document, this.PackagePart.GetRelationship( id ) ) + select new Picture( this.Document, p, img ) + ).ToList(); + + return pictures; + } + + private void ReplaceAtBookmark_Core( string text, XElement bookmark ) + { + var xElementList = HelperFunctions.FormatInput( text, null ); + bookmark.AddAfterSelf( xElementList ); + + _runs = this.Xml.Elements( XName.Get( "r", DocX.w.NamespaceName ) ).ToList(); + + HelperFunctions.RenumberIDs( this.Document ); + } + + #endregion + + } + + public class Run : DocXElement + { + #region Private Members + + // A lookup for the text elements in this paragraph + private Dictionary textLookup = new Dictionary(); + + private int startIndex; + private int endIndex; + private string text; + + #endregion + + #region Public Properties + + /// + /// Gets the start index of this Text (text length before this text) + /// + public int StartIndex + { + get + { + return startIndex; + } + } + + /// + /// Gets the end index of this Text (text length before this text + this texts length) + /// + public int EndIndex + { + get + { + return endIndex; + } + } + + #endregion + + #region Internal Properties + + /// + /// The text value of this text element + /// + internal string Value + { + set + { + text = value; + } + get + { + return text; + } + } + + #endregion + + #region Constructors + + internal Run( DocX document, XElement xml, int startIndex ) + : base( document, xml ) + { + this.startIndex = startIndex; + + // Get the text elements in this run + IEnumerable texts = xml.Descendants(); + + int start = startIndex; + + // Loop through each text in this run + foreach( XElement te in texts ) + { + switch( te.Name.LocalName ) + { + case "tab": + { + textLookup.Add( start + 1, new Text( Document, te, start ) ); + text += "\t"; + start++; + break; + } + case "br": + { + textLookup.Add( start + 1, new Text( Document, te, start ) ); + text += "\n"; + start++; + break; + } + case "t": + goto case "delText"; + case "delText": + { + // Only add strings which are not empty + if( te.Value.Length > 0 ) + { + textLookup.Add( start + te.Value.Length, new Text( Document, te, start ) ); + text += te.Value; + start += te.Value.Length; + } + break; + } + default: + break; + } + } + + endIndex = start; + } + + #endregion + + #region Iternal Methods + + static internal XElement[] SplitRun( Run r, int index, EditType type = EditType.ins ) + { + index = index - r.StartIndex; + + Text t = r.GetFirstTextEffectedByEdit( index, type ); + XElement[] splitText = Text.SplitText( t, index ); + + XElement splitLeft = new XElement( r.Xml.Name, r.Xml.Attributes(), r.Xml.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ), t.Xml.ElementsBeforeSelf().Where( n => n.Name.LocalName != "rPr" ), splitText[ 0 ] ); + if( Paragraph.GetElementTextLength( splitLeft ) == 0 ) + splitLeft = null; + + XElement splitRight = new XElement( r.Xml.Name, r.Xml.Attributes(), r.Xml.Element( XName.Get( "rPr", DocX.w.NamespaceName ) ), splitText[ 1 ], t.Xml.ElementsAfterSelf().Where( n => n.Name.LocalName != "rPr" ) ); + if( Paragraph.GetElementTextLength( splitRight ) == 0 ) + splitRight = null; + + return + ( + new XElement[] + { + splitLeft, + splitRight + } + ); + } + + internal Text GetFirstTextEffectedByEdit( int index, EditType type = EditType.ins ) + { + // Make sure we are looking within an acceptable index range. + if( index < 0 || index > HelperFunctions.GetText( Xml ).Length ) + throw new ArgumentOutOfRangeException(); + + // Need some memory that can be updated by the recursive search for the XElement to Split. + int count = 0; + Text theOne = null; + + GetFirstTextEffectedByEditRecursive( Xml, index, ref count, ref theOne, type ); + + return theOne; + } + + internal void GetFirstTextEffectedByEditRecursive( XElement Xml, int index, ref int count, ref Text theOne, EditType type = EditType.ins ) + { + count += HelperFunctions.GetSize( Xml ); + if( count > 0 && ( ( type == EditType.del && count > index ) || ( type == EditType.ins && count >= index ) ) ) + { + theOne = new Text( Document, Xml, count - HelperFunctions.GetSize( Xml ) ); + return; + } + + if( Xml.HasElements ) + foreach( XElement e in Xml.Elements() ) + if( theOne == null ) + GetFirstTextEffectedByEditRecursive( e, index, ref count, ref theOne ); + } + + #endregion + } + + internal class Text : DocXElement + { + #region Private Members + + private int startIndex; + private int endIndex; + private string text; + + #endregion + + #region Public Properties + + /// + /// Gets the start index of this Text (text length before this text) + /// + public int StartIndex + { + get + { + return startIndex; + } + } + + /// + /// Gets the end index of this Text (text length before this text + this texts length) + /// + public int EndIndex + { + get + { + return endIndex; + } + } + + /// + /// The text value of this text element + /// + public string Value + { + get + { + return text; + } + } + + #endregion + + #region Constructors + + internal Text( DocX document, XElement xml, int startIndex ) + : base( document, xml ) + { + this.startIndex = startIndex; + + switch( Xml.Name.LocalName ) + { + case "t": + { + goto case "delText"; + } + + case "delText": + { + endIndex = startIndex + xml.Value.Length; + text = xml.Value; + break; + } + + case "br": + { + text = "\n"; + endIndex = startIndex + 1; + break; + } + + case "tab": + { + text = "\t"; + endIndex = startIndex + 1; + break; + } + default: + { + break; + } + } + } + + #endregion + + #region Public Methods + + /// + /// If a text element or delText element, starts or ends with a space, + /// it must have the attribute space, otherwise it must not have it. + /// + /// The (t or delText) element check + public static void PreserveSpace( XElement e ) + { + // PreserveSpace should only be used on (t or delText) elements + if( !e.Name.Equals( DocX.w + "t" ) && !e.Name.Equals( DocX.w + "delText" ) ) + throw new ArgumentException( "SplitText can only split elements of type t or delText", "e" ); + + // Check if this w:t contains a space atribute + XAttribute space = e.Attributes().Where( a => a.Name.Equals( XNamespace.Xml + "space" ) ).SingleOrDefault(); + + // This w:t's text begins or ends with whitespace + if( e.Value.StartsWith( " " ) || e.Value.EndsWith( " " ) ) + { + // If this w:t contains no space attribute, add one. + if( space == null ) + e.Add( new XAttribute( XNamespace.Xml + "space", "preserve" ) ); + } + + // This w:t's text does not begin or end with a space + else + { + // If this w:r contains a space attribute, remove it. + if( space != null ) + space.Remove(); + } + } + + #endregion + + #region Internal Methods + + internal static XElement[] SplitText( Text t, int index ) + { + if( index < t.startIndex || index > t.EndIndex ) + throw new ArgumentOutOfRangeException( "index" ); + + XElement splitLeft = null; + XElement splitRight = null; + if( t.Xml.Name.LocalName == "t" || t.Xml.Name.LocalName == "delText" ) + { + // The origional text element, now containing only the text before the index point. + splitLeft = new XElement( t.Xml.Name, t.Xml.Attributes(), t.Xml.Value.Substring( 0, index - t.startIndex ) ); + if( splitLeft.Value.Length == 0 ) + { + splitLeft = null; + } + else + { + Text.PreserveSpace( splitLeft ); + } + + // The origional text element, now containing only the text after the index point. + splitRight = new XElement( t.Xml.Name, t.Xml.Attributes(), t.Xml.Value.Substring( index - t.startIndex, t.Xml.Value.Length - ( index - t.startIndex ) ) ); + if( splitRight.Value.Length == 0 ) + { + splitRight = null; + } + else + { + Text.PreserveSpace( splitRight ); + } + } + + else + { + if( index == t.EndIndex ) + { + splitLeft = t.Xml; + } + else + { + splitRight = t.Xml; + } + } + + return + ( + new XElement[] + { + splitLeft, + splitRight + } + ); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/Picture.cs b/Xceed.Words.NET/Src/Picture.cs new file mode 100644 index 00000000..f9bd8156 --- /dev/null +++ b/Xceed.Words.NET/Src/Picture.cs @@ -0,0 +1,465 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using System.IO.Packaging; + +namespace Xceed.Words.NET +{ + /// + /// Represents a Picture in this document, a Picture is a customized view of an Image. + /// + public class Picture : DocXElement + { + #region Private Members + + private const int EmusInPixel = 9525; + + private string _id; + private string _name; + private string _descr; + private int _cx, _cy; + private uint _rotation; + private bool _hFlip, _vFlip; + private object _pictureShape; + private XElement _xfrm; + private XElement _prstGeom; + + #endregion + + #region Internal Members + + internal Dictionary _picture_rels; + + internal Image _img; + + #endregion + + #region Public Properties + + /// + /// A unique id that identifies an Image embedded in this document. + /// + public string Id + { + get + { + return _id; + } + } + + /// + /// Flip this Picture Horizontally. + /// + public bool FlipHorizontal + { + get + { + return _hFlip; + } + + set + { + _hFlip = value; + + var flipH = _xfrm.Attribute( XName.Get( "flipH" ) ); + if( flipH == null ) + { + _xfrm.Add( new XAttribute( XName.Get( "flipH" ), "0" ) ); + } + + _xfrm.Attribute( XName.Get( "flipH" ) ).Value = _hFlip ? "1" : "0"; + } + } + + /// + /// Flip this Picture Vertically. + /// + public bool FlipVertical + { + get + { + return _vFlip; + } + + set + { + _vFlip = value; + + var flipV = _xfrm.Attribute( XName.Get( "flipV" ) ); + if( flipV == null ) + { + _xfrm.Add( new XAttribute( XName.Get( "flipV" ), "0" ) ); + } + + _xfrm.Attribute( XName.Get( "flipV" ) ).Value = _vFlip ? "1" : "0"; + } + } + + /// + /// The rotation in degrees of this image, actual value = value % 360 + /// + public uint Rotation + { + get + { + return _rotation / 60000; + } + + set + { + _rotation = ( value % 360 ) * 60000; + var xfrm = + ( from d in Xml.Descendants() + where d.Name.LocalName.Equals( "xfrm" ) + select d ).Single(); + + var rot = xfrm.Attribute( XName.Get( "rot" ) ); + if( rot == null ) + { + xfrm.Add( new XAttribute( XName.Get( "rot" ), 0 ) ); + } + + xfrm.Attribute( XName.Get( "rot" ) ).Value = _rotation.ToString(); + } + } + + /// + /// Gets or sets the name of this Image. + /// + public string Name + { + get + { + return _name; + } + + set + { + _name = value; + + foreach( XAttribute a in Xml.Descendants().Attributes( XName.Get( "name" ) ) ) + { + a.Value = _name; + } + } + } + + /// + /// Gets or sets the description for this Image. + /// + public string Description + { + get + { + return _descr; + } + + set + { + _descr = value; + + foreach( XAttribute a in Xml.Descendants().Attributes( XName.Get( "descr" ) ) ) + { + a.Value = _descr; + } + } + } + + /// + /// Returns the name of the image file for the picture. + /// + public string FileName + { + get + { + return _img.FileName; + } + } + + /// + /// Get or sets the Width of this Image. + /// + public int Width + { + get + { + return _cx / EmusInPixel; + } + + set + { + _cx = value * EmusInPixel; + + foreach( XAttribute a in Xml.Descendants().Attributes( XName.Get( "cx" ) ) ) + a.Value = _cx.ToString(); + } + } + + /// + /// Get or sets the height of this Image. + /// + public int Height + { + get + { + return _cy / EmusInPixel; + } + + set + { + _cy = value * EmusInPixel; + + foreach( XAttribute a in Xml.Descendants().Attributes( XName.Get( "cy" ) ) ) + a.Value = _cy.ToString(); + } + } + + #endregion + + #region Constructors + + /// + /// Wraps an XElement as an Image + /// + /// + /// The XElement i to wrap + /// + internal Picture( DocX document, XElement i, Image image ) : base( document, i ) + { + _picture_rels = new Dictionary(); + + _img = image; + + var imageId = + ( + from e in Xml.Descendants() + where e.Name.LocalName.Equals( "blip" ) + select e.Attribute( XName.Get( "embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships" ) ).Value + ).SingleOrDefault(); + + _id = ( imageId != null ) + ? imageId + : ( + from e in Xml.Descendants() + where e.Name.LocalName.Equals( "imagedata" ) + select e.Attribute( XName.Get( "id", "http://schemas.openxmlformats.org/officeDocument/2006/relationships" ) ).Value + ).SingleOrDefault(); + + var nameToFind = + ( + from e in Xml.Descendants() + let a = e.Attribute( XName.Get( "name" ) ) + where ( a != null ) + select a.Value + ).FirstOrDefault(); + + _name = ( nameToFind != null ) + ? nameToFind + : ( + from e in Xml.Descendants() + let a = e.Attribute( XName.Get( "title" ) ) + where ( a != null ) + select a.Value + ).FirstOrDefault(); + + _descr = + ( + from e in Xml.Descendants() + let a = e.Attribute( XName.Get( "descr" ) ) + where ( a != null ) + select a.Value + ).FirstOrDefault(); + + _cx = + ( + from e in Xml.Descendants() + let a = e.Attribute( XName.Get( "cx" ) ) + where ( a != null ) + select int.Parse( a.Value ) + ).FirstOrDefault(); + + if( _cx == 0 ) + { + var style = + ( + from e in Xml.Descendants() + let a = e.Attribute( XName.Get( "style" ) ) + where ( a != null ) + select a + ).FirstOrDefault(); + + if( style != null ) + { + var widthString = style.Value.Substring( style.Value.IndexOf( "width:" ) + 6 ); + var widthValueString = widthString.Substring( 0, widthString.IndexOf( "pt" ) ).Replace( ".", "," ); + var widthDouble = ( double.Parse( widthValueString ) / 72d ) * 914400; + _cx = System.Convert.ToInt32( widthDouble ); + } + } + + _cy = + ( + from e in Xml.Descendants() + let a = e.Attribute( XName.Get( "cy" ) ) + where ( a != null ) + select int.Parse( a.Value ) + ).FirstOrDefault(); + + if( _cy == 0 ) + { + var style = + ( + from e in Xml.Descendants() + let a = e.Attribute( XName.Get( "style" ) ) + where ( a != null ) + select a + ).FirstOrDefault(); + + if( style != null ) + { + var heightString = style.Value.Substring( style.Value.IndexOf( "height:" ) + 7 ); + var heightValueString = heightString.Substring( 0, heightString.IndexOf( "pt" ) ).Replace( ".", "," ); + var heightDouble = ( double.Parse( heightValueString ) / 72d ) * 914400; + _cy = System.Convert.ToInt32( heightDouble ); + } + } + + _xfrm = + ( + from d in Xml.Descendants() + where d.Name.LocalName.Equals( "xfrm" ) + select d + ).SingleOrDefault(); + + _prstGeom = + ( + from d in Xml.Descendants() + where d.Name.LocalName.Equals( "prstGeom" ) + select d + ).SingleOrDefault(); + + if( _xfrm != null ) + { + _rotation = _xfrm.Attribute( XName.Get( "rot" ) ) == null ? 0 : uint.Parse( _xfrm.Attribute( XName.Get( "rot" ) ).Value ); + } + } + + #endregion + + #region Public Methods + + /// + /// Remove this Picture from this document. + /// + public void Remove() + { + Xml.Remove(); + } + + /// + /// Set the shape of this Picture to one in the BasicShapes enumeration. + /// + /// A shape from the BasicShapes enumeration. + public void SetPictureShape( BasicShapes shape ) + { + SetPictureShape( ( object )shape ); + } + + /// + /// Set the shape of this Picture to one in the RectangleShapes enumeration. + /// + /// A shape from the RectangleShapes enumeration. + public void SetPictureShape( RectangleShapes shape ) + { + SetPictureShape( ( object )shape ); + } + + /// + /// Set the shape of this Picture to one in the BlockArrowShapes enumeration. + /// + /// A shape from the BlockArrowShapes enumeration. + public void SetPictureShape( BlockArrowShapes shape ) + { + SetPictureShape( ( object )shape ); + } + + /// + /// Set the shape of this Picture to one in the EquationShapes enumeration. + /// + /// A shape from the EquationShapes enumeration. + public void SetPictureShape( EquationShapes shape ) + { + SetPictureShape( ( object )shape ); + } + + /// + /// Set the shape of this Picture to one in the FlowchartShapes enumeration. + /// + /// A shape from the FlowchartShapes enumeration. + public void SetPictureShape( FlowchartShapes shape ) + { + SetPictureShape( ( object )shape ); + } + + /// + /// Set the shape of this Picture to one in the StarAndBannerShapes enumeration. + /// + /// A shape from the StarAndBannerShapes enumeration. + public void SetPictureShape( StarAndBannerShapes shape ) + { + SetPictureShape( ( object )shape ); + } + + /// + /// Set the shape of this Picture to one in the CalloutShapes enumeration. + /// + /// A shape from the CalloutShapes enumeration. + public void SetPictureShape( CalloutShapes shape ) + { + SetPictureShape( ( object )shape ); + } + + //public void Delete() + //{ + // // Remove xml + // i.Remove(); + + // // Rebuild the image collection for this paragraph + // // Requires that every Image have a link to its paragraph + + //} + + #endregion + + #region Private Methods + + private void SetPictureShape( object shape ) + { + _pictureShape = shape; + + XAttribute prst = _prstGeom.Attribute( XName.Get( "prst" ) ); + if( prst == null ) + { + _prstGeom.Add( new XAttribute( XName.Get( "prst" ), "rectangle" ) ); + } + + _prstGeom.Attribute( XName.Get( "prst" ) ).Value = shape.ToString(); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/Section.cs b/Xceed.Words.NET/Src/Section.cs new file mode 100644 index 00000000..b003c75f --- /dev/null +++ b/Xceed.Words.NET/Src/Section.cs @@ -0,0 +1,34 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System.Collections.Generic; +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + public class Section : Container + { + + public SectionBreakType SectionBreakType; + + internal Section( DocX document, XElement xml ) : base( document, xml ) + { + } + + public List SectionParagraphs + { + get; set; + } + } +} diff --git a/Xceed.Words.NET/Src/Table.cs b/Xceed.Words.NET/Src/Table.cs new file mode 100644 index 00000000..9497641c --- /dev/null +++ b/Xceed.Words.NET/Src/Table.cs @@ -0,0 +1,4035 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using System.IO.Packaging; +using System.IO; +using System.Drawing; +using System.Globalization; +using System.Collections.ObjectModel; + +namespace Xceed.Words.NET +{ + /// + /// Represents a Table in a document. + /// + public class Table : InsertBeforeOrAfter + { + #region Private Members + + private Alignment _alignment; + private AutoFit _autofit; + private float[] _columnWidths; + private TableDesign _design; + /// + /// The custom design\style to apply to this table. + /// + /// + private string _customTableDesignName; + private int _cachedColumnCount = -1; + + #endregion + + #region Public Properties + + /// + /// Returns a list of all Paragraphs inside this container. + /// + /// + public virtual List Paragraphs + { + get + { + var paragraphs = new List(); + + foreach( Row r in Rows ) + paragraphs.AddRange( r.Paragraphs ); + + return paragraphs; + } + } + + /// + /// Returns a list of all Pictures in a Table. + /// + /// + /// Returns a list of all Pictures in a Table. + /// + /// pictures = t.Pictures; + /// + /// // Save this document. + /// document.Save(); + /// } + /// ]]> + /// + /// + public List Pictures + { + get + { + var pictures = new List(); + + foreach( Row r in Rows ) + { + pictures.AddRange( r.Pictures ); + } + + return pictures; + } + } + + /// + /// Get all of the Hyperlinks in this Table. + /// + /// + /// Get all of the Hyperlinks in this Table. + /// + /// // Create a document. + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // Get the first Table in this document. + /// Table t = document.Tables[0]; + /// + /// // Get a list of all Hyperlinks in this Table. + /// List<Hyperlink> hyperlinks = t.Hyperlinks; + /// + /// // Save this document. + /// document.Save(); + /// } + /// + /// + public List Hyperlinks + { + get + { + var hyperlinks = new List(); + + foreach( Row r in Rows ) + { + hyperlinks.AddRange( r.Hyperlinks ); + } + + return hyperlinks; + } + } + + /// + /// Returns the number of rows in this table. + /// + public Int32 RowCount + { + get + { + return this.Xml.Elements( XName.Get( "tr", DocX.w.NamespaceName ) ).Count(); + } + } + + /// + /// Returns the number of columns in this table. + /// + public Int32 ColumnCount + { + get + { + if( this.RowCount == 0 ) + return 0; + if( _cachedColumnCount == -1 ) + { + foreach( var r in this.Rows ) + { + _cachedColumnCount = Math.Max( _cachedColumnCount, r.ColumnCount ); + } + } + return _cachedColumnCount; + } + } + + /// + /// Returns a list of rows in this table. + /// + public List Rows + { + get + { + var rows = + ( + from r in Xml.Elements( XName.Get( "tr", DocX.w.NamespaceName ) ) + select new Row( this, Document, r ) + ).ToList(); + + return rows; + } + } + + public Alignment Alignment + { + get + { + return _alignment; + } + set + { + string alignmentString = string.Empty; + switch( value ) + { + case Alignment.left: + { + alignmentString = "left"; + break; + } + + case Alignment.both: + { + alignmentString = "both"; + break; + } + + + case Alignment.right: + { + alignmentString = "right"; + break; + } + + case Alignment.center: + { + alignmentString = "center"; + break; + } + } + + XElement tblPr = Xml.Descendants( XName.Get( "tblPr", DocX.w.NamespaceName ) ).First(); + XElement jc = tblPr.Descendants( XName.Get( "jc", DocX.w.NamespaceName ) ).FirstOrDefault(); + + jc?.Remove(); + + jc = new XElement( XName.Get( "jc", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), alignmentString ) ); + tblPr.Add( jc ); + _alignment = value; + } + } + + /// + /// Auto size this table according to some rule. + /// + public AutoFit AutoFit + { + get + { + return _autofit; + } + + set + { + string tableAttributeValue = string.Empty; + string columnAttributeValue = string.Empty; + switch( value ) + { + case AutoFit.ColumnWidth: + { + tableAttributeValue = "auto"; + columnAttributeValue = "dxa"; + + // Disable "Automatically resize to fit contents" option + var tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + if( tblPr != null ) + { + var layout = tblPr.Element( XName.Get( "tblLayout", DocX.w.NamespaceName ) ); + if( layout == null ) + { + tblPr.Add( new XElement( XName.Get( "tblLayout", DocX.w.NamespaceName ) ) ); + layout = tblPr.Element( XName.Get( "tblLayout", DocX.w.NamespaceName ) ); + } + + var type = layout.Attribute( XName.Get( "type", DocX.w.NamespaceName ) ); + if( type == null ) + { + layout.Add( new XAttribute( XName.Get( "type", DocX.w.NamespaceName ), String.Empty ) ); + type = layout.Attribute( XName.Get( "type", DocX.w.NamespaceName ) ); + } + + type.Value = "fixed"; + } + + break; + } + + case AutoFit.Contents: + { + tableAttributeValue = columnAttributeValue = "auto"; + break; + } + + case AutoFit.Window: + { + tableAttributeValue = columnAttributeValue = "pct"; + break; + } + + case AutoFit.Fixed: + { + tableAttributeValue = columnAttributeValue = "dxa"; + var tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + var tblLayout = tblPr.Element( XName.Get( "tblLayout", DocX.w.NamespaceName ) ); + + if( tblLayout == null ) + { + var tmp = tblPr.Element( XName.Get( "tblInd", DocX.w.NamespaceName ) ) ?? tblPr.Element( XName.Get( "tblW", DocX.w.NamespaceName ) ); + + tmp.AddAfterSelf( new XElement( XName.Get( "tblLayout", DocX.w.NamespaceName ) ) ); + tmp = tblPr.Element( XName.Get( "tblLayout", DocX.w.NamespaceName ) ); + tmp.SetAttributeValue( XName.Get( "type", DocX.w.NamespaceName ), "fixed" ); + tmp = tblPr.Element( XName.Get( "tblW", DocX.w.NamespaceName ) ); + + Double totalWidth = 0; + foreach( Double columnWidth in ColumnWidths ) + { + totalWidth += columnWidth; + } + + tmp.SetAttributeValue( XName.Get( "w", DocX.w.NamespaceName ), totalWidth.ToString() ); + break; + } + else + { + var types = from d in Xml.Descendants() + let type = d.Attribute( XName.Get( "type", DocX.w.NamespaceName ) ) + where ( d.Name.LocalName == "tblLayout" ) && type != null + select type; + + foreach( XAttribute type in types ) + { + type.Value = "fixed"; + } + + var tmp = tblPr.Element( XName.Get( "tblW", DocX.w.NamespaceName ) ); + + Double totalWidth = 0; + foreach( Double columnWidth in ColumnWidths ) + { + totalWidth += columnWidth; + } + + tmp.SetAttributeValue( XName.Get( "w", DocX.w.NamespaceName ), totalWidth.ToString() ); + break; + } + } + } + + // Set table attributes + var query = from d in Xml.Descendants() + let type = d.Attribute( XName.Get( "type", DocX.w.NamespaceName ) ) + where ( d.Name.LocalName == "tblW" ) && type != null + select type; + + foreach( XAttribute type in query ) + { + type.Value = tableAttributeValue; + } + + // Set column attributes + query = from d in Xml.Descendants() + let type = d.Attribute( XName.Get( "type", DocX.w.NamespaceName ) ) + where ( d.Name.LocalName == "tcW" ) && type != null + select type; + + foreach( XAttribute type in query ) + { + type.Value = columnAttributeValue; + } + + _autofit = value; + } + } + /// + /// The design\style to apply to this table. + /// + public TableDesign Design + { + get + { + return _design; + } + set + { + XElement tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + XElement style = tblPr.Element( XName.Get( "tblStyle", DocX.w.NamespaceName ) ); + if( style == null ) + { + tblPr.Add( new XElement( XName.Get( "tblStyle", DocX.w.NamespaceName ) ) ); + style = tblPr.Element( XName.Get( "tblStyle", DocX.w.NamespaceName ) ); + } + + XAttribute val = style.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + if( val == null ) + { + style.Add( new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), "" ) ); + val = style.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + } + + _design = value; + + if( _design == TableDesign.None ) + { + if( style != null ) + style.Remove(); + } + + if( _design == TableDesign.Custom ) + { + if( string.IsNullOrEmpty( _customTableDesignName ) ) + { + _design = TableDesign.None; + if( style != null ) + style.Remove(); + + } + else + { + val.Value = _customTableDesignName; + } + } + else + { + switch( _design ) + { + case TableDesign.TableNormal: + val.Value = "TableNormal"; + break; + case TableDesign.TableGrid: + val.Value = "TableGrid"; + break; + case TableDesign.LightShading: + val.Value = "LightShading"; + break; + case TableDesign.LightShadingAccent1: + val.Value = "LightShading-Accent1"; + break; + case TableDesign.LightShadingAccent2: + val.Value = "LightShading-Accent2"; + break; + case TableDesign.LightShadingAccent3: + val.Value = "LightShading-Accent3"; + break; + case TableDesign.LightShadingAccent4: + val.Value = "LightShading-Accent4"; + break; + case TableDesign.LightShadingAccent5: + val.Value = "LightShading-Accent5"; + break; + case TableDesign.LightShadingAccent6: + val.Value = "LightShading-Accent6"; + break; + case TableDesign.LightList: + val.Value = "LightList"; + break; + case TableDesign.LightListAccent1: + val.Value = "LightList-Accent1"; + break; + case TableDesign.LightListAccent2: + val.Value = "LightList-Accent2"; + break; + case TableDesign.LightListAccent3: + val.Value = "LightList-Accent3"; + break; + case TableDesign.LightListAccent4: + val.Value = "LightList-Accent4"; + break; + case TableDesign.LightListAccent5: + val.Value = "LightList-Accent5"; + break; + case TableDesign.LightListAccent6: + val.Value = "LightList-Accent6"; + break; + case TableDesign.LightGrid: + val.Value = "LightGrid"; + break; + case TableDesign.LightGridAccent1: + val.Value = "LightGrid-Accent1"; + break; + case TableDesign.LightGridAccent2: + val.Value = "LightGrid-Accent2"; + break; + case TableDesign.LightGridAccent3: + val.Value = "LightGrid-Accent3"; + break; + case TableDesign.LightGridAccent4: + val.Value = "LightGrid-Accent4"; + break; + case TableDesign.LightGridAccent5: + val.Value = "LightGrid-Accent5"; + break; + case TableDesign.LightGridAccent6: + val.Value = "LightGrid-Accent6"; + break; + case TableDesign.MediumShading1: + val.Value = "MediumShading1"; + break; + case TableDesign.MediumShading1Accent1: + val.Value = "MediumShading1-Accent1"; + break; + case TableDesign.MediumShading1Accent2: + val.Value = "MediumShading1-Accent2"; + break; + case TableDesign.MediumShading1Accent3: + val.Value = "MediumShading1-Accent3"; + break; + case TableDesign.MediumShading1Accent4: + val.Value = "MediumShading1-Accent4"; + break; + case TableDesign.MediumShading1Accent5: + val.Value = "MediumShading1-Accent5"; + break; + case TableDesign.MediumShading1Accent6: + val.Value = "MediumShading1-Accent6"; + break; + case TableDesign.MediumShading2: + val.Value = "MediumShading2"; + break; + case TableDesign.MediumShading2Accent1: + val.Value = "MediumShading2-Accent1"; + break; + case TableDesign.MediumShading2Accent2: + val.Value = "MediumShading2-Accent2"; + break; + case TableDesign.MediumShading2Accent3: + val.Value = "MediumShading2-Accent3"; + break; + case TableDesign.MediumShading2Accent4: + val.Value = "MediumShading2-Accent4"; + break; + case TableDesign.MediumShading2Accent5: + val.Value = "MediumShading2-Accent5"; + break; + case TableDesign.MediumShading2Accent6: + val.Value = "MediumShading2-Accent6"; + break; + case TableDesign.MediumList1: + val.Value = "MediumList1"; + break; + case TableDesign.MediumList1Accent1: + val.Value = "MediumList1-Accent1"; + break; + case TableDesign.MediumList1Accent2: + val.Value = "MediumList1-Accent2"; + break; + case TableDesign.MediumList1Accent3: + val.Value = "MediumList1-Accent3"; + break; + case TableDesign.MediumList1Accent4: + val.Value = "MediumList1-Accent4"; + break; + case TableDesign.MediumList1Accent5: + val.Value = "MediumList1-Accent5"; + break; + case TableDesign.MediumList1Accent6: + val.Value = "MediumList1-Accent6"; + break; + case TableDesign.MediumList2: + val.Value = "MediumList2"; + break; + case TableDesign.MediumList2Accent1: + val.Value = "MediumList2-Accent1"; + break; + case TableDesign.MediumList2Accent2: + val.Value = "MediumList2-Accent2"; + break; + case TableDesign.MediumList2Accent3: + val.Value = "MediumList2-Accent3"; + break; + case TableDesign.MediumList2Accent4: + val.Value = "MediumList2-Accent4"; + break; + case TableDesign.MediumList2Accent5: + val.Value = "MediumList2-Accent5"; + break; + case TableDesign.MediumList2Accent6: + val.Value = "MediumList2-Accent6"; + break; + case TableDesign.MediumGrid1: + val.Value = "MediumGrid1"; + break; + case TableDesign.MediumGrid1Accent1: + val.Value = "MediumGrid1-Accent1"; + break; + case TableDesign.MediumGrid1Accent2: + val.Value = "MediumGrid1-Accent2"; + break; + case TableDesign.MediumGrid1Accent3: + val.Value = "MediumGrid1-Accent3"; + break; + case TableDesign.MediumGrid1Accent4: + val.Value = "MediumGrid1-Accent4"; + break; + case TableDesign.MediumGrid1Accent5: + val.Value = "MediumGrid1-Accent5"; + break; + case TableDesign.MediumGrid1Accent6: + val.Value = "MediumGrid1-Accent6"; + break; + case TableDesign.MediumGrid2: + val.Value = "MediumGrid2"; + break; + case TableDesign.MediumGrid2Accent1: + val.Value = "MediumGrid2-Accent1"; + break; + case TableDesign.MediumGrid2Accent2: + val.Value = "MediumGrid2-Accent2"; + break; + case TableDesign.MediumGrid2Accent3: + val.Value = "MediumGrid2-Accent3"; + break; + case TableDesign.MediumGrid2Accent4: + val.Value = "MediumGrid2-Accent4"; + break; + case TableDesign.MediumGrid2Accent5: + val.Value = "MediumGrid2-Accent5"; + break; + case TableDesign.MediumGrid2Accent6: + val.Value = "MediumGrid2-Accent6"; + break; + case TableDesign.MediumGrid3: + val.Value = "MediumGrid3"; + break; + case TableDesign.MediumGrid3Accent1: + val.Value = "MediumGrid3-Accent1"; + break; + case TableDesign.MediumGrid3Accent2: + val.Value = "MediumGrid3-Accent2"; + break; + case TableDesign.MediumGrid3Accent3: + val.Value = "MediumGrid3-Accent3"; + break; + case TableDesign.MediumGrid3Accent4: + val.Value = "MediumGrid3-Accent4"; + break; + case TableDesign.MediumGrid3Accent5: + val.Value = "MediumGrid3-Accent5"; + break; + case TableDesign.MediumGrid3Accent6: + val.Value = "MediumGrid3-Accent6"; + break; + + case TableDesign.DarkList: + val.Value = "DarkList"; + break; + case TableDesign.DarkListAccent1: + val.Value = "DarkList-Accent1"; + break; + case TableDesign.DarkListAccent2: + val.Value = "DarkList-Accent2"; + break; + case TableDesign.DarkListAccent3: + val.Value = "DarkList-Accent3"; + break; + case TableDesign.DarkListAccent4: + val.Value = "DarkList-Accent4"; + break; + case TableDesign.DarkListAccent5: + val.Value = "DarkList-Accent5"; + break; + case TableDesign.DarkListAccent6: + val.Value = "DarkList-Accent6"; + break; + + case TableDesign.ColorfulShading: + val.Value = "ColorfulShading"; + break; + case TableDesign.ColorfulShadingAccent1: + val.Value = "ColorfulShading-Accent1"; + break; + case TableDesign.ColorfulShadingAccent2: + val.Value = "ColorfulShading-Accent2"; + break; + case TableDesign.ColorfulShadingAccent3: + val.Value = "ColorfulShading-Accent3"; + break; + case TableDesign.ColorfulShadingAccent4: + val.Value = "ColorfulShading-Accent4"; + break; + case TableDesign.ColorfulShadingAccent5: + val.Value = "ColorfulShading-Accent5"; + break; + case TableDesign.ColorfulShadingAccent6: + val.Value = "ColorfulShading-Accent6"; + break; + + case TableDesign.ColorfulList: + val.Value = "ColorfulList"; + break; + case TableDesign.ColorfulListAccent1: + val.Value = "ColorfulList-Accent1"; + break; + case TableDesign.ColorfulListAccent2: + val.Value = "ColorfulList-Accent2"; + break; + case TableDesign.ColorfulListAccent3: + val.Value = "ColorfulList-Accent3"; + break; + case TableDesign.ColorfulListAccent4: + val.Value = "ColorfulList-Accent4"; + break; + case TableDesign.ColorfulListAccent5: + val.Value = "ColorfulList-Accent5"; + break; + case TableDesign.ColorfulListAccent6: + val.Value = "ColorfulList-Accent6"; + break; + + case TableDesign.ColorfulGrid: + val.Value = "ColorfulGrid"; + break; + case TableDesign.ColorfulGridAccent1: + val.Value = "ColorfulGrid-Accent1"; + break; + case TableDesign.ColorfulGridAccent2: + val.Value = "ColorfulGrid-Accent2"; + break; + case TableDesign.ColorfulGridAccent3: + val.Value = "ColorfulGrid-Accent3"; + break; + case TableDesign.ColorfulGridAccent4: + val.Value = "ColorfulGrid-Accent4"; + break; + case TableDesign.ColorfulGridAccent5: + val.Value = "ColorfulGrid-Accent5"; + break; + case TableDesign.ColorfulGridAccent6: + val.Value = "ColorfulGrid-Accent6"; + break; + + default: + break; + } + } + + if( Document._styles == null ) + { + PackagePart word_styles = Document._package.GetPart( new Uri( "/word/styles.xml", UriKind.Relative ) ); + using( TextReader tr = new StreamReader( word_styles.GetStream() ) ) + Document._styles = XDocument.Load( tr ); + } + + var tableStyle = + ( + from e in Document._styles.Descendants() + let styleId = e.Attribute( XName.Get( "styleId", DocX.w.NamespaceName ) ) + where ( styleId != null && styleId.Value == val.Value ) + select e + ).FirstOrDefault(); + + if( tableStyle == null ) + { + XDocument external_style_doc = HelperFunctions.DecompressXMLResource( "Xceed.Words.NET.Resources.styles.xml.gz" ); + + var styleElement = + ( + from e in external_style_doc.Descendants() + let styleId = e.Attribute( XName.Get( "styleId", DocX.w.NamespaceName ) ) + where ( styleId != null && styleId.Value == val.Value ) + select e + ).First(); + + Document._styles.Element( XName.Get( "styles", DocX.w.NamespaceName ) ).Add( styleElement ); + } + } + } + + /// + /// Returns the index of this Table. + /// + /// + /// Replace the first table in this document with a new Table. + /// + /// // Load a document into memory. + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // Get the first Table in this document. + /// Table t = document.Tables[0]; + /// + /// // Get the character index of Table t in this document. + /// int index = t.Index; + /// + /// // Remove Table t. + /// t.Remove(); + /// + /// // Insert a new Table at the original index of Table t. + /// Table newTable = document.InsertTable(index, 4, 4); + /// + /// // Set the design of this new Table, so that we can see it. + /// newTable.Design = TableDesign.LightShadingAccent1; + /// + /// // Save all changes made to the document. + /// document.Save(); + /// } // Release this document from memory. + /// + /// + public int Index + { + get + { + int index = 0; + IEnumerable previous = Xml.ElementsBeforeSelf(); + + foreach( XElement e in previous ) + index += Paragraph.GetElementTextLength( e ); + + return index; + } + } + + /// + /// The custom design/style to apply to this table. + /// + public string CustomTableDesignName + { + get + { + return _customTableDesignName; + } + set + { + _customTableDesignName = value; + this.Design = TableDesign.Custom; + } + + } + + /// + /// Gets or sets the value of the Table Caption (Alternate Text Title) of this table. + /// + public string TableCaption + { + get + { + var tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + var caption = tblPr?.Element( XName.Get( "tblCaption", DocX.w.NamespaceName ) ); + + if( caption != null ) + return caption.GetAttribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + return null; + } + set + { + var tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + if( tblPr != null ) + { + var caption = tblPr.Descendants( XName.Get( "tblCaption", DocX.w.NamespaceName ) ).FirstOrDefault(); + if( caption != null ) + { + caption.Remove(); + } + caption = new XElement( XName.Get( "tblCaption", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), value ) ); + tblPr.Add( caption ); + } + } + } + + /// + /// Gets or sets the value of the Table Description (Alternate Text Description) of this table. + /// + public string TableDescription + { + get + { + var tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + var description = tblPr?.Element( XName.Get( "tblDescription", DocX.w.NamespaceName ) ); + + if( description != null ) + return description.GetAttribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + return null; + } + set + { + var tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + if( tblPr != null ) + { + var description = tblPr.Descendants( XName.Get( "tblDescription", DocX.w.NamespaceName ) ).FirstOrDefault(); + description?.Remove(); + description = new XElement( XName.Get( "tblDescription", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), value ) ); + tblPr.Add( description ); + } + } + } + + + public TableLook TableLook + { + get; + set; + } + + #endregion + + #region Constructors + + internal Table( DocX document, XElement xml ) + : base( document, xml ) + { + _autofit = AutoFit.ColumnWidth; + this.Xml = xml; + this.PackagePart = document.PackagePart; + + var properties = xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + + var alignment = properties.Element( XName.Get( "jc", DocX.w.NamespaceName ) ); + if( alignment != null ) + { + var val = alignment.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + if( val != null ) + { + _alignment = (Alignment)Enum.Parse( typeof( Alignment ), val.Value ); + } + } + + var style = properties?.Element( XName.Get( "tblStyle", DocX.w.NamespaceName ) ); + if( style != null ) + { + var val = style.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + if( val != null ) + { + String cleanValue = val.Value.Replace( "-", string.Empty ); + + if( Enum.IsDefined( typeof( TableDesign ), cleanValue ) ) + { + _design = ( TableDesign )Enum.Parse( typeof( TableDesign ), cleanValue ); + } + + else + { + _design = TableDesign.Custom; + } + } + else + { + _design = TableDesign.None; + } + } + else + { + _design = TableDesign.None; + } + + var tableLook = properties?.Element( XName.Get( "tblLook", DocX.w.NamespaceName ) ); + if( tableLook != null ) + { + this.TableLook = new TableLook( tableLook.GetAttribute( XName.Get( "firstRow", DocX.w.NamespaceName ) ) == "1", + tableLook.GetAttribute( XName.Get( "lastRow", DocX.w.NamespaceName ) ) == "1", + tableLook.GetAttribute( XName.Get( "firstColumn", DocX.w.NamespaceName ) ) == "1", + tableLook.GetAttribute( XName.Get( "lastColumn", DocX.w.NamespaceName ) ) == "1", + tableLook.GetAttribute( XName.Get( "noHBand", DocX.w.NamespaceName ) ) == "1", + tableLook.GetAttribute( XName.Get( "noVBand", DocX.w.NamespaceName ) ) == "1" ); + } + } + + #endregion + + #region Public Methods + + /// + /// Merge cells in given column starting with startRow and ending with endRow. + /// + public void MergeCellsInColumn( int columnIndex, int startRow, int endRow ) + { + // Check for valid start and end indexes. + if( columnIndex < 0 || columnIndex >= ColumnCount ) + throw new IndexOutOfRangeException(); + + if( startRow < 0 || endRow <= startRow || endRow >= Rows.Count ) + throw new IndexOutOfRangeException(); + // Foreach each Cell between startIndex and endIndex inclusive. + foreach( Row row in Rows.Where( ( z, i ) => i > startRow && i <= endRow ) ) + { + var c = row.Cells[ columnIndex ]; + var tcPr = c.Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + c.Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = c.Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + var vMerge = tcPr.Element( XName.Get( "vMerge", DocX.w.NamespaceName ) ); + if( vMerge == null ) + { + tcPr.SetElementValue( XName.Get( "vMerge", DocX.w.NamespaceName ), string.Empty ); + vMerge = tcPr.Element( XName.Get( "vMerge", DocX.w.NamespaceName ) ); + } + } + + /* + * Get the tcPr (table cell properties) element for the first cell in this merge, + * null will be returned if no such element exists. + */ + var startRowCellsCount = this.Rows[ startRow ].Cells.Count; + var start_tcPr = ( columnIndex > startRowCellsCount ) + ? this.Rows[ startRow ].Cells[ startRowCellsCount - 1 ].Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ) + : this.Rows[ startRow ].Cells[ columnIndex ].Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( start_tcPr == null ) + { + this.Rows[ startRow ].Cells[ columnIndex ].Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + start_tcPr = this.Rows[ startRow ].Cells[ columnIndex ].Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the gridSpan element of this row, + * null will be returned if no such element exists. + */ + var start_vMerge = start_tcPr.Element( XName.Get( "vMerge", DocX.w.NamespaceName ) ); + if( start_vMerge == null ) + { + start_tcPr.SetElementValue( XName.Get( "vMerge", DocX.w.NamespaceName ), string.Empty ); + start_vMerge = start_tcPr.Element( XName.Get( "vMerge", DocX.w.NamespaceName ) ); + } + + start_vMerge.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), "restart" ); + } + + /// + /// Set the direction of all content in this Table. + /// + /// (Left to Right) or (Right to Left) + /// + /// Set the content direction for all content in a table to RightToLeft. + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // Get the first table in a document. + /// Table table = document.Tables[0]; + /// + /// // Set the content direction for all content in this table to RightToLeft. + /// table.SetDirection(Direction.RightToLeft); + /// + /// // Save all changes made to this document. + /// document.Save(); + /// } + /// + /// + public void SetDirection( Direction direction ) + { + var tblPr = GetOrCreate_tblPr(); + tblPr.Add( new XElement( DocX.w + "bidiVisual" ) ); + + foreach( Row r in Rows ) + { + r.SetDirection( direction ); + } + } + + /// + /// Remove this Table from this document. + /// + /// + /// Remove the first Table from this document. + /// + /// // Load a document into memory. + /// using (DocX document = DocX.Load(@"Test.docx")) + /// { + /// // Get the first Table in this document. + /// Table t = d.Tables[0]; + /// + /// // Remove this Table. + /// t.Remove(); + /// + /// // Save all changes made to the document. + /// document.Save(); + /// } // Release this document from memory. + /// + /// + public void Remove() + { + this.Xml.Remove(); + } + + /// + /// Insert a row at the end of this table. + /// + /// + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Get the first table in this document. + /// Table table = document.Tables[0]; + /// + /// // Insert a new row at the end of this table. + /// Row row = table.InsertRow(); + /// + /// // Loop through each cell in this new row. + /// foreach (Cell c in row.Cells) + /// { + /// // Set the text of each new cell to "Hello". + /// c.Paragraphs[0].InsertText("Hello", false); + /// } + /// + /// // Save the document to a new file. + /// document.SaveAs(@"C:\Example\Test2.docx"); + /// }// Release this document from memory. + /// + /// + /// A new row. + public Row InsertRow() + { + return this.InsertRow( this.RowCount ); + } + + /// + /// Insert a copy of a row at the end of this table. + /// + /// A new row. + public Row InsertRow( Row row ) + { + return this.InsertRow( row, this.RowCount ); + } + + /// + /// Insert a column to the right of a Table. + /// + /// + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Get the first Table in this document. + /// Table table = document.Tables[0]; + /// + /// // Insert a new column to this right of this table. + /// table.InsertColumn(); + /// + /// // Set the new columns text to "Row no." + /// table.Rows[0].Cells[table.ColumnCount - 1].Paragraph.InsertText("Row no.", false); + /// + /// // Loop through each row in the table. + /// for (int i = 1; i < table.Rows.Count; i++) + /// { + /// // The current row. + /// Row row = table.Rows[i]; + /// + /// // The cell in this row that belongs to the new column. + /// Cell cell = row.Cells[table.ColumnCount - 1]; + /// + /// // The first Paragraph that this cell houses. + /// Paragraph p = cell.Paragraphs[0]; + /// + /// // Insert this rows index. + /// p.InsertText(i.ToString(), false); + /// } + /// + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public void InsertColumn() + { + this.InsertColumn( this.ColumnCount, true ); + } + + /// + /// Remove the last row from this Table. + /// + /// + /// Remove the last row from a Table. + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Get the first table in this document. + /// Table table = document.Tables[0]; + /// + /// // Remove the last row from this table. + /// table.RemoveRow(); + /// + /// // Save the document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public void RemoveRow() + { + this.RemoveRow( RowCount - 1 ); + } + + /// + /// Remove a row from this Table. + /// + /// The row to remove. + /// + /// Remove the first row from a Table. + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Get the first table in this document. + /// Table table = document.Tables[0]; + /// + /// // Remove the first row from this table. + /// table.RemoveRow(0); + /// + /// // Save the document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public void RemoveRow( int index ) + { + if( index < 0 || index > RowCount - 1 ) + throw new IndexOutOfRangeException(); + + this.Rows[ index ].Xml.Remove(); + if( this.Rows.Count == 0 ) + { + this.Remove(); + } + } + + /// + /// Remove the last column for this Table. + /// + /// + /// Remove the last column from a Table. + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Get the first table in this document. + /// Table table = document.Tables[0]; + /// + /// // Remove the last column from this table. + /// table.RemoveColumn(); + /// + /// // Save the document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public void RemoveColumn() + { + this.RemoveColumn( this.ColumnCount - 1 ); + } + + /// + /// Remove a column from this Table. + /// + /// The column to remove. + /// + /// Remove the first column from a Table. + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Get the first table in this document. + /// Table table = document.Tables[0]; + /// + /// // Remove the first column from this table. + /// table.RemoveColumn(0); + /// + /// // Save the document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public void RemoveColumn( int index ) + { + if( ( index < 0 ) || ( index > this.ColumnCount - 1 ) ) + throw new IndexOutOfRangeException(); + + foreach( Row r in Rows ) + { + if( r.Cells.Count < this.ColumnCount ) + { + int gridAfterValue = r.GridAfter; + int posIndex = 0; + int currentPos = 0; + + for( int i = 0; i < r.Cells.Count; ++i ) + { + var rowCell = r.Cells[ i ]; + + int gridSpanValue = ( rowCell.GridSpan != 0 ) ? rowCell.GridSpan - 1 : 0; + + // checks to see if index is between the lowest and highest cell value. + if( ( ( index - gridAfterValue ) >= currentPos ) + && ( ( index - gridAfterValue ) <= ( currentPos + gridSpanValue ) ) ) + { + r.Cells[ posIndex ].Xml.Remove(); + break; + } + + ++posIndex; + currentPos += ( gridSpanValue + 1 ); + } + } + else + { + r.Cells[ index ].Xml.Remove(); + } + } + _cachedColumnCount = -1; + } + + /// + /// Insert a row into this table. + /// + /// + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Get the first table in this document. + /// Table table = document.Tables[0]; + /// + /// // Insert a new row at index 1 in this table. + /// Row row = table.InsertRow(1); + /// + /// // Loop through each cell in this new row. + /// foreach (Cell c in row.Cells) + /// { + /// // Set the text of each new cell to "Hello". + /// c.Paragraphs[0].InsertText("Hello", false); + /// } + /// + /// // Save the document to a new file. + /// document.SaveAs(@"C:\Example\Test2.docx"); + /// }// Release this document from memory. + /// + /// + /// Index to insert row at. + /// A new Row + public Row InsertRow( int index ) + { + if( ( index < 0 ) || ( index > this.RowCount ) ) + throw new IndexOutOfRangeException(); + + var content = new List(); + for( int i = 0; i < ColumnCount; i++ ) + { + var cell = ( ( _columnWidths != null ) && ( _columnWidths.Length > i ) ) + ? HelperFunctions.CreateTableCell( _columnWidths[ i ] * 20 ) + : HelperFunctions.CreateTableCell(); + content.Add( cell ); + } + + return this.InsertRow( content, index ); + } + + /// + /// Insert a copy of a row into this table. + /// + /// Row to copy and insert. + /// Index to insert row at. + /// A new Row + public Row InsertRow( Row row, int index ) + { + if( row == null ) + throw new ArgumentNullException( "row" ); + + if( index < 0 || index > RowCount ) + throw new IndexOutOfRangeException(); + + var content = row.Xml.Elements( XName.Get( "tc", DocX.w.NamespaceName ) ).Select( element => HelperFunctions.CloneElement( element ) ).ToList(); + return this.InsertRow( content, index ); + } + + /// + /// Insert a column into a table. + /// + /// The index to insert the column at. + /// The side in which you wish to place the colum : True for right, false for left. + /// + /// Insert a column to the left of a table. + /// + /// // Load a document. + /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) + /// { + /// // Get the first Table in this document. + /// Table table = document.Tables[0]; + /// + /// // Insert a new column to this left of this table. + /// table.InsertColumn(0, false); + /// + /// // Set the new columns text to "Row no." + /// table.Rows[0].Cells[table.ColumnCount - 1].Paragraph.InsertText("Row no.", false); + /// + /// // Loop through each row in the table. + /// for (int i = 1; i < table.Rows.Count; i++) + /// { + /// // The current row. + /// Row row = table.Rows[i]; + /// + /// // The cell in this row that belongs to the new column. + /// Cell cell = row.Cells[table.ColumnCount - 1]; + /// + /// // The first Paragraph that this cell houses. + /// Paragraph p = cell.Paragraphs[0]; + /// + /// // Insert this rows index. + /// p.InsertText(i.ToString(), false); + /// } + /// + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public void InsertColumn( int index, bool direction ) + { + var colCount = this.ColumnCount; + + if( (index <= 0) && (index > colCount ) ) + throw new NullReferenceException( "index should be greater than 0 and smaller or equals to this.ColumnCount." ); + + if( this.RowCount > 0 ) + { + _cachedColumnCount = -1; + foreach( Row r in this.Rows ) + { + // create cell + var cell = HelperFunctions.CreateTableCell(); + + // insert cell + if( r.Cells.Count < colCount ) + { + if( index >= colCount ) + { + this.AddCellToRow( r, cell, r.Cells.Count - 1, direction ); + } + else + { + int gridAfterValue = r.GridAfter; + int currentPosition = 1; + int posIndex = 1; + + foreach( var rowCell in r.Cells ) + { + int gridSpanValue = ( rowCell.GridSpan != 0 ) ? rowCell.GridSpan - 1 : 0; + var tcPr = rowCell.Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + + // Check if the cell have a gridSpan and if the index is between the lowest and highest cell value + if( ( ( index - gridAfterValue ) >= currentPosition ) + && ( ( index - gridAfterValue ) <= ( currentPosition + gridSpanValue ) ) ) + { + var dir = ( direction && ( index == ( currentPosition + gridSpanValue ) ) ); + this.AddCellToRow( r, cell, posIndex - 1, dir ); + break; + } + + ++posIndex; + currentPosition += (gridSpanValue + 1); + } + } + } + else + { + this.AddCellToRow( r, cell, index - 1, direction ); + } + } + } + } + + /// + /// Insert a page break before a Table. + /// + /// + /// Insert a Table and a Paragraph into a document with a page break between them. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Paragraph. + /// Paragraph p1 = document.InsertParagraph("Paragraph", false); + /// + /// // Insert a new Table. + /// Table t1 = document.InsertTable(2, 2); + /// t1.Design = TableDesign.LightShadingAccent1; + /// + /// // Insert a page break before this Table. + /// t1.InsertPageBreakBeforeSelf(); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public override void InsertPageBreakBeforeSelf() + { + base.InsertPageBreakBeforeSelf(); + } + + public void SetWidths( float[] widths ) + { + _columnWidths = widths; + + for( int i = 0; i < this.Rows.Count; ++i ) + { + var row = this.Rows[ i ]; + + for( int j = 0; j < widths.Length; ++j ) + { + if( row.Cells.Count > j ) + { + row.Cells[ j ].Width = widths[ j ]; + } + } + } + } + + public void SetWidthsPercentage( float[] widthsPercentage, float? totalWidth ) + { + if( totalWidth == null ) + totalWidth = this.Document.PageWidth - this.Document.MarginLeft - this.Document.MarginRight; + + List widths = new List( widthsPercentage.Length ); + widthsPercentage.ToList().ForEach( pWidth => { widths.Add( ( pWidth * totalWidth.Value / 100 ) * ( 96 / 72 ) ); } ); + SetWidths( widths.ToArray() ); + } + + /// + /// Insert a page break after a Table. + /// + /// + /// Insert a Table and a Paragraph into a document with a page break between them. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a new Table. + /// Table t1 = document.InsertTable(2, 2); + /// t1.Design = TableDesign.LightShadingAccent1; + /// + /// // Insert a page break after this Table. + /// t1.InsertPageBreakAfterSelf(); + /// + /// // Insert a new Paragraph. + /// Paragraph p1 = document.InsertParagraph("Paragraph", false); + /// + /// // Save this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public override void InsertPageBreakAfterSelf() + { + base.InsertPageBreakAfterSelf(); + } + + /// + /// Insert a new Table before this Table, this Table can be from this document or another document. + /// + /// The Table t to be inserted + /// A new Table inserted before this Table. + /// + /// Insert a new Table before this Table. + /// + /// // Place holder for a Table. + /// Table t; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"a.docx")) + /// { + /// // Get the first Table from this document. + /// t = documentA.Tables[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"b.docx")) + /// { + /// // Get the first Table in document b. + /// Table t2 = documentB.Tables[0]; + /// + /// // Insert the Table from document a before this Table. + /// Table newTable = t2.InsertTableBeforeSelf(t); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public override Table InsertTableBeforeSelf( Table t ) + { + return base.InsertTableBeforeSelf( t ); + } + + /// + /// Insert a new Table into this document before this Table. + /// + /// The number of rows this Table should have. + /// The number of columns this Table should have. + /// A new Table inserted before this Table. + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// //Insert a Table into this document. + /// Table t = document.InsertTable(2, 2); + /// t.Design = TableDesign.LightShadingAccent1; + /// t.Alignment = Alignment.center; + /// + /// // Insert a new Table before this Table. + /// Table newTable = t.InsertTableBeforeSelf(2, 2); + /// newTable.Design = TableDesign.LightShadingAccent2; + /// newTable.Alignment = Alignment.center; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public override Table InsertTableBeforeSelf( int rowCount, int columnCount ) + { + return base.InsertTableBeforeSelf( rowCount, columnCount ); + } + + /// + /// Insert a new Table after this Table, this Table can be from this document or another document. + /// + /// The Table t to be inserted + /// A new Table inserted after this Table. + /// + /// Insert a new Table after this Table. + /// + /// // Place holder for a Table. + /// Table t; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"a.docx")) + /// { + /// // Get the first Table from this document. + /// t = documentA.Tables[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"b.docx")) + /// { + /// // Get the first Table in document b. + /// Table t2 = documentB.Tables[0]; + /// + /// // Insert the Table from document a after this Table. + /// Table newTable = t2.InsertTableAfterSelf(t); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public override Table InsertTableAfterSelf( Table t ) + { + return base.InsertTableAfterSelf( t ); + } + + /// + /// Insert a new Table into this document after this Table. + /// + /// The number of rows this Table should have. + /// The number of columns this Table should have. + /// A new Table inserted before this Table. + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// //Insert a Table into this document. + /// Table t = document.InsertTable(2, 2); + /// t.Design = TableDesign.LightShadingAccent1; + /// t.Alignment = Alignment.center; + /// + /// // Insert a new Table after this Table. + /// Table newTable = t.InsertTableAfterSelf(2, 2); + /// newTable.Design = TableDesign.LightShadingAccent2; + /// newTable.Alignment = Alignment.center; + /// + /// // Save all changes made to this document. + /// document.Save(); + /// }// Release this document from memory. + /// + /// + public override Table InsertTableAfterSelf( int rowCount, int columnCount ) + { + return base.InsertTableAfterSelf( rowCount, columnCount ); + } + + /// + /// Insert a Paragraph before this Table, this Paragraph may have come from the same or another document. + /// + /// The Paragraph to insert. + /// The Paragraph now associated with this document. + /// + /// Take a Paragraph from document a, and insert it into document b before this Table. + /// + /// // Place holder for a Paragraph. + /// Paragraph p; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"a.docx")) + /// { + /// // Get the first paragraph from this document. + /// p = documentA.Paragraphs[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"b.docx")) + /// { + /// // Get the first Table in document b. + /// Table t = documentB.Tables[0]; + /// + /// // Insert the Paragraph from document a before this Table. + /// Paragraph newParagraph = t.InsertParagraphBeforeSelf(p); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public override Paragraph InsertParagraphBeforeSelf( Paragraph p ) + { + return base.InsertParagraphBeforeSelf( p ); + } + + /// + /// Insert a new Paragraph before this Table. + /// + /// The initial text for this new Paragraph. + /// A new Paragraph inserted before this Table. + /// + /// Insert a new Paragraph before the first Table in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Table into this document. + /// Table t = document.InsertTable(2, 2); + /// + /// t.InsertParagraphBeforeSelf("I was inserted before the next Table."); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphBeforeSelf( string text ) + { + return base.InsertParagraphBeforeSelf( text ); + } + + /// + /// Insert a new Paragraph before this Table. + /// + /// The initial text for this new Paragraph. + /// Should this insertion be tracked as a change? + /// A new Paragraph inserted before this Table. + /// + /// Insert a new paragraph before the first Table in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Table into this document. + /// Table t = document.InsertTable(2, 2); + /// + /// t.InsertParagraphBeforeSelf("I was inserted before the next Table.", false); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphBeforeSelf( string text, bool trackChanges ) + { + return base.InsertParagraphBeforeSelf( text, trackChanges ); + } + + /// + /// Insert a new Paragraph before this Table. + /// + /// The initial text for this new Paragraph. + /// Should this insertion be tracked as a change? + /// The formatting to apply to this insertion. + /// A new Paragraph inserted before this Table. + /// + /// Insert a new paragraph before the first Table in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Table into this document. + /// Table t = document.InsertTable(2, 2); + /// + /// Formatting boldFormatting = new Formatting(); + /// boldFormatting.Bold = true; + /// + /// t.InsertParagraphBeforeSelf("I was inserted before the next Table.", false, boldFormatting); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphBeforeSelf( string text, bool trackChanges, Formatting formatting ) + { + return base.InsertParagraphBeforeSelf( text, trackChanges, formatting ); + } + + /// + /// Insert a Paragraph after this Table, this Paragraph may have come from the same or another document. + /// + /// The Paragraph to insert. + /// The Paragraph now associated with this document. + /// + /// Take a Paragraph from document a, and insert it into document b after this Table. + /// + /// // Place holder for a Paragraph. + /// Paragraph p; + /// + /// // Load document a. + /// using (DocX documentA = DocX.Load(@"a.docx")) + /// { + /// // Get the first paragraph from this document. + /// p = documentA.Paragraphs[0]; + /// } + /// + /// // Load document b. + /// using (DocX documentB = DocX.Load(@"b.docx")) + /// { + /// // Get the first Table in document b. + /// Table t = documentB.Tables[0]; + /// + /// // Insert the Paragraph from document a after this Table. + /// Paragraph newParagraph = t.InsertParagraphAfterSelf(p); + /// + /// // Save all changes made to document b. + /// documentB.Save(); + /// }// Release this document from memory. + /// + /// + public override Paragraph InsertParagraphAfterSelf( Paragraph p ) + { + return base.InsertParagraphAfterSelf( p ); + } + + /// + /// Insert a new Paragraph after this Table. + /// + /// The initial text for this new Paragraph. + /// Should this insertion be tracked as a change? + /// The formatting to apply to this insertion. + /// A new Paragraph inserted after this Table. + /// + /// Insert a new paragraph after the first Table in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Table into this document. + /// Table t = document.InsertTable(2, 2); + /// + /// Formatting boldFormatting = new Formatting(); + /// boldFormatting.Bold = true; + /// + /// t.InsertParagraphAfterSelf("I was inserted after the previous Table.", false, boldFormatting); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphAfterSelf( string text, bool trackChanges, Formatting formatting ) + { + return base.InsertParagraphAfterSelf( text, trackChanges, formatting ); + } + + /// + /// Insert a new Paragraph after this Table. + /// + /// The initial text for this new Paragraph. + /// Should this insertion be tracked as a change? + /// A new Paragraph inserted after this Table. + /// + /// Insert a new paragraph after the first Table in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Table into this document. + /// Table t = document.InsertTable(2, 2); + /// + /// t.InsertParagraphAfterSelf("I was inserted after the previous Table.", false); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphAfterSelf( string text, bool trackChanges ) + { + return base.InsertParagraphAfterSelf( text, trackChanges ); + } + + /// + /// Insert a new Paragraph after this Table. + /// + /// The initial text for this new Paragraph. + /// A new Paragraph inserted after this Table. + /// + /// Insert a new Paragraph after the first Table in this document. + /// + /// // Create a new document. + /// using (DocX document = DocX.Create(@"Test.docx")) + /// { + /// // Insert a Table into this document. + /// Table t = document.InsertTable(2, 2); + /// + /// t.InsertParagraphAfterSelf("I was inserted after the previous Table."); + /// + /// // Save all changes made to this new document. + /// document.Save(); + /// }// Release this new document form memory. + /// + /// + public override Paragraph InsertParagraphAfterSelf( string text ) + { + return base.InsertParagraphAfterSelf( text ); + } + + /// + /// Set a table border + /// + /// + /// + /// // Create a new document. + ///using (DocX document = DocX.Create("Test.docx")) + ///{ + /// // Insert a table into this document. + /// Table t = document.InsertTable(3, 3); + /// + /// // Create a large blue border. + /// Border b = new Border(BorderStyle.Tcbs_single, BorderSize.seven, 0, Color.Blue); + /// + /// // Set the tables Top, Bottom, Left and Right Borders to b. + /// t.SetBorder(TableBorderType.Top, b); + /// t.SetBorder(TableBorderType.Bottom, b); + /// t.SetBorder(TableBorderType.Left, b); + /// t.SetBorder(TableBorderType.Right, b); + /// + /// // Save the document. + /// document.Save(); + ///} + /// + /// + /// The table border to set + /// Border object to set the table border + 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. + */ + var tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + if( tblPr == null ) + { + this.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. + */ + var 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 ); + + var 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 + var 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() ); + } + } + + /// + /// Get a table border + /// + /// The table border to get + public Border GetBorder( TableBorderType borderType ) + { + // instance with default border values + var b = new Border(); + + /* + * Get the tblPr (table properties) element for this Table, + * null will be return if no such element exists. + */ + var tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + if( tblPr == null ) + { + // uses default border style + } + + /* + * Get the tblBorders (table borders) element for this Table, + * null will be return if no such element exists. + */ + var tblBorders = tblPr.Element( XName.Get( "tblBorders", DocX.w.NamespaceName ) ); + if( tblBorders == null ) + { + // uses default border style + } + + /* + * Get the 'borderType' (table border) element for this Table, + * null will be return if no such element exists. + */ + string tbordertype = borderType.ToString(); + // only lower the first char of string (because of insideH and insideV) + tbordertype = tbordertype.Substring( 0, 1 ).ToLower() + tbordertype.Substring( 1 ); + + var tblBorderType = tblBorders.Element( XName.Get( tbordertype, DocX.w.NamespaceName ) ); + if( tblBorderType == null ) + { + // uses default border style + } + + // The val attribute is used for the border style + var val = tblBorderType.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + // If val is null, this table contains no border information. + if( val == null ) + { + // uses default border style + } + else + { + try + { + var bordertype = "Tcbs_" + val.Value; + b.Tcbs = ( BorderStyle )Enum.Parse( typeof( BorderStyle ), bordertype ); + } + catch + { + val.Remove(); + // uses default border style + } + } + + // The sz attribute is used for the border size + var sz = tblBorderType.Attribute( XName.Get( "sz", DocX.w.NamespaceName ) ); + // If sz is null, this border contains no size information. + if( sz == null ) + { + // uses default border style + } + else + { + // If sz is not an int, something is wrong with this attributes value, so remove it + int numerical_size; + if( !int.TryParse( sz.Value, out numerical_size ) ) + { + sz.Remove(); + } + else + { + switch( numerical_size ) + { + case 2: + b.Size = BorderSize.one; + break; + case 4: + b.Size = BorderSize.two; + break; + case 6: + b.Size = BorderSize.three; + break; + case 8: + b.Size = BorderSize.four; + break; + case 12: + b.Size = BorderSize.five; + break; + case 18: + b.Size = BorderSize.six; + break; + case 24: + b.Size = BorderSize.seven; + break; + case 36: + b.Size = BorderSize.eight; + break; + case 48: + b.Size = BorderSize.nine; + break; + default: + b.Size = BorderSize.one; + break; + } + } + } + + // The space attribute is used for the border spacing (probably '0') + var space = tblBorderType.Attribute( XName.Get( "space", DocX.w.NamespaceName ) ); + // If space is null, this border contains no space information. + if( space == null ) + { + // uses default border style + } + else + { + // If space is not an int, something is wrong with this attributes value, so remove it + int borderspace; + if( !int.TryParse( space.Value, out borderspace ) ) + { + space.Remove(); + // uses default border style + } + else + { + b.Space = borderspace; + } + } + + // The color attribute is used for the border color + var color = tblBorderType.Attribute( XName.Get( "color", DocX.w.NamespaceName ) ); + if( color == null ) + { + // uses default border style + } + else + { + // If color is not a Color, something is wrong with this attributes value, so remove it + try + { + b.Color = ColorTranslator.FromHtml( string.Format( "#{0}", color.Value ) ); + } + catch + { + color.Remove(); + // uses default border style + } + } + return b; + } + + public Double GetColumnWidth( Int32 columnIndex ) + { + List columnWidths = ColumnWidths; + if( columnWidths == null || columnIndex > columnWidths.Count - 1 ) + return Double.NaN; + + return columnWidths[ columnIndex ]; + } + + public void SetColumnWidth( int columnIndex, double width ) + { + var columnWidths = this.ColumnWidths; + if( columnWidths == null || ( columnIndex > columnWidths.Count - 1 ) ) + { + if( this.Rows.Count == 0 ) + throw new Exception( "There is at least one row required to detect the existing columns." ); + + columnWidths = new List(); + foreach( Cell c in Rows[ Rows.Count - 1 ].Cells ) + { + columnWidths.Add( c.Width ); + } + } + + // check if the columnIndex is valid + if( columnIndex > (columnWidths.Count - 1) ) + throw new Exception( "The index is greather than the available table columns." ); + + // append a new grid if null + var grid = Xml.Element( XName.Get( "tblGrid", DocX.w.NamespaceName ) ); + if( grid == null ) + { + var tblPr = GetOrCreate_tblPr(); + tblPr.AddAfterSelf( new XElement( XName.Get( "tblGrid", DocX.w.NamespaceName ) ) ); + grid = Xml.Element( XName.Get( "tblGrid", DocX.w.NamespaceName ) ); + } + + // remove all existing values + grid?.RemoveAll(); + + // append new column widths + int index = 0; + foreach( var columnWidth in columnWidths ) + { + double newWidth = columnWidth; + if( index == columnIndex ) + { + newWidth = width; + } + + var newColumn = new XElement( XName.Get( "gridCol", DocX.w.NamespaceName ), new XAttribute( XName.Get( "w", DocX.w.NamespaceName ), newWidth ) ); + grid?.Add( newColumn ); + index += 1; + } + + // remove cell widths + foreach( Row row in this.Rows ) + { + foreach( Cell cell in row.Cells ) + { + cell.Width = -1; + } + } + + // set AutoFit to Fixed + this.AutoFit = AutoFit.Fixed; + } + + public List ColumnWidths + { + get + { + var columnWidths = new List(); + + // get the table grid property + XElement grid = Xml.Element( XName.Get( "tblGrid", DocX.w.NamespaceName ) ); + + // get the columns properties + var columns = grid?.Elements( XName.Get( "gridCol", DocX.w.NamespaceName ) ); + if( columns == null ) + return null; + + foreach( var column in columns ) + { + string value = column.GetAttribute( XName.Get( "w", DocX.w.NamespaceName ) ); + columnWidths.Add( Convert.ToDouble( value, new CultureInfo("en-US" ) ) ); + } + + return columnWidths; + } + } + + public void SetTableCellMargin( TableCellMarginType type, double margin ) + { + var tblPr = this.GetOrCreate_tblPr(); + var tblCellMarXName = XName.Get( "tblCellMar", DocX.w.NamespaceName ); + var typeXName = XName.Get( type.ToString(), DocX.w.NamespaceName ); + + var tblCellMar = tblPr.Element( tblCellMarXName ); + if( tblCellMar == null ) + { + tblPr.AddFirst( new XElement( tblCellMarXName ) ); + tblCellMar = tblPr.Element( tblCellMarXName ); + } + + var side = tblCellMar.Element( typeXName ); + if( side == null ) + { + tblCellMar.AddFirst( new XElement( typeXName ) ); + side = tblCellMar.Element( typeXName ); + } + + side.RemoveAttributes(); + // Set value and side for cell Margin + side.Add( new XAttribute( XName.Get( "w", DocX.w.NamespaceName ), margin ) ); + side.Add( new XAttribute( XName.Get( "type", DocX.w.NamespaceName ), "dxa" ) ); + } + + /// + /// Deletes a cell in a row and shift the others to the left. + /// + /// index of the row where a cell will be removed. + /// index of the cell to remove in the row. + public void DeleteAndShiftCellsLeft( int rowIndex, int celIndex ) + { + var trPr = this.Rows[ rowIndex ].Xml.Element( XName.Get( "trPr", DocX.w.NamespaceName ) ); + if( trPr != null ) + { + var gridAfter = trPr.Element( XName.Get( "gridAfter", DocX.w.NamespaceName ) ); + if( gridAfter != null ) + { + var gridAfterValAttr = gridAfter.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + gridAfterValAttr.Value = ( gridAfterValAttr != null ) ? int.Parse( gridAfterValAttr.Value ).ToString() : "1"; + } + else + { + gridAfter.SetAttributeValue( "val", 1 ); + } + } + else + { + var gridAfterXElement = new XElement( XName.Get( "gridAfter", DocX.w.NamespaceName ) ); + var valXAttribute = new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), 1 ); + gridAfterXElement.Add( valXAttribute ); + + var trPrXElement = new XElement( XName.Get( "trPr", DocX.w.NamespaceName ) ); + trPrXElement.Add( gridAfterXElement ); + + this.Rows[ rowIndex ].Xml.AddFirst( trPrXElement ); + } + + if( ( celIndex <= this.ColumnCount ) && ( this.Rows[ rowIndex ].ColumnCount <= this.ColumnCount ) ) + { + this.Rows[ rowIndex ].Cells[ celIndex ].Xml.Remove(); + } + } + + #endregion + + #region Internal Methods + + /// + /// If the tblPr element doesent exist it is created, either way it is returned by this function. + /// + /// The tblPr element for this Table. + internal XElement GetOrCreate_tblPr() + { + // Get the element. + var tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + + // If it dosen't exist, create it. + if( tblPr == null ) + { + this.Xml.AddFirst( new XElement( XName.Get( "tblPr", DocX.w.NamespaceName ) ) ); + tblPr = Xml.Element( XName.Get( "tblPr", DocX.w.NamespaceName ) ); + } + + // Return the pPr element for this Paragraph. + return tblPr; + } + + #endregion + + #region Private Methods + + private Row InsertRow( List content, Int32 index ) + { + Row newRow = new Row( this, Document, new XElement( XName.Get( "tr", DocX.w.NamespaceName ), content ) ); + + XElement rowXml; + if( index == Rows.Count ) + { + rowXml = Rows.Last().Xml; + rowXml.AddAfterSelf( newRow.Xml ); + } + + else + { + rowXml = Rows[ index ].Xml; + rowXml.AddBeforeSelf( newRow.Xml ); + } + + return newRow; + } + + private void AddCellToRow( Row row, XElement cell, int index, bool direction ) + { + if( index >= row.Cells.Count ) + throw new IndexOutOfRangeException( "index is greater or equals to row.Cells.Count." ); + + if( direction ) + { + row.Cells[ index ].Xml.AddAfterSelf( cell ); + } + else + { + row.Cells[ index ].Xml.AddBeforeSelf( cell ); + } + } + + #endregion + } + + /// + /// Represents a single row in a Table. + /// + public class Row : Container + { + #region Internal Members + + internal Table _table; + + #endregion + + #region Public Properties + + /// + /// Calculates columns count in the row, taking spanned cells into account + /// + public Int32 ColumnCount + { + get + { + int gridSpanSum = this.GridAfter; + + // Foreach each Cell between startIndex and endIndex inclusive. + foreach( Cell c in Cells ) + { + if( c.GridSpan != 0 ) + { + gridSpanSum += (c.GridSpan - 1); + } + } + + // return cells count + count of spanned cells + return Cells.Count + gridSpanSum; + } + } + + /// + /// Returns the row.GridAfter => The number of deleted cells in a row. + /// + public int GridAfter + { + get + { + var trPr = this.Xml.Element( XName.Get( "trPr", DocX.w.NamespaceName ) ); + if( trPr != null ) + { + var gridAfter = trPr.Element( XName.Get( "gridAfter", DocX.w.NamespaceName ) ); + var gridAfterAttrVal = gridAfter?.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + if( gridAfterAttrVal != null ) + { + return int.Parse( gridAfterAttrVal.Value ); + } + } + + return 0; + } + } + + /// + /// A list of Cells in this Row. + /// + public List Cells + { + get + { + List cells = + ( + from c in Xml.Elements( XName.Get( "tc", DocX.w.NamespaceName ) ) + select new Cell( this, Document, c ) + ).ToList(); + + return cells; + } + } + + public override ReadOnlyCollection Paragraphs + { + get + { + var paragraphs = + ( + from p in Xml.Descendants( DocX.w + "p" ) + select new Paragraph( Document, p, 0 ) + ).ToList(); + + foreach( Paragraph p in paragraphs ) + { + p.PackagePart = _table.PackagePart; + } + + return paragraphs.AsReadOnly(); + } + } + + /// + /// Height in pixels. + /// + public double Height + { + get + { + /* + * Get the trPr (table row properties) element for this Row, + * null will be return if no such element exists. + */ + XElement trPr = Xml.Element( XName.Get( "trPr", DocX.w.NamespaceName ) ); + + // If trPr is null, this row contains no height information. + // 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 ) ); + + // If trHeight is null, this row contains no height information. + // Get the val attribute for this trHeight element. + XAttribute val = trHeight?.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + // If w is null, this cell contains no width information. + if( val == null ) + return double.NaN; + + // If val is not a double, something is wrong with this attributes value, so remove it and return double.NaN; + double heightInWordUnits; + if( !double.TryParse( val.Value, out heightInWordUnits ) ) + { + val.Remove(); + return double.NaN; + } + + // Using 20 to match DocX._pageSizeMultiplier. + return ( heightInWordUnits / 20 ); + } + + set + { + SetHeight( value, true ); + } + } + + /// + /// Minimum Height in pixels. + /// + public double MinHeight + { + get + { + return Height; + } + set + { + SetHeight( value, false ); + } + } + + public bool TableHeader + { + get + { + XElement trPr = Xml.Element( XName.Get( "trPr", DocX.w.NamespaceName ) ); + XElement tblHeader = trPr?.Element( XName.Get( "tblHeader", DocX.w.NamespaceName ) ); + return tblHeader != null; + } + 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(); + } + } + + /// + /// Allow row to break across pages. + /// Default value is True : Word will break the contents of the row across the pages. + /// When False, the contents of the row will not be split across the pages; it will be entirely moved to the next page. + /// + public bool BreakAcrossPages + { + get + { + var trPr = Xml.Element( XName.Get( "trPr", DocX.w.NamespaceName ) ); + var cantSplit = trPr?.Element( XName.Get( "cantSplit", DocX.w.NamespaceName ) ); + return cantSplit == null; + } + set + { + var trPrXName = XName.Get( "trPr", DocX.w.NamespaceName ); + var cantSplitXName = XName.Get( "cantSplit", DocX.w.NamespaceName ); + + if( value ) + { + var trPr = Xml.Element( trPrXName ); + var cantSplit = trPr?.Element( cantSplitXName ); + if( cantSplit != null ) + cantSplit.Remove(); + } + else + { + var trPr = Xml.Element( trPrXName ); + if( trPr == null ) + { + Xml.SetElementValue( trPrXName, string.Empty ); + trPr = Xml.Element( trPrXName ); + } + var cantSplit = trPr.Element( cantSplitXName ); + if( cantSplit == null ) + { + trPr.SetElementValue( cantSplitXName, string.Empty ); + } + } + } + } + + #endregion + + #region Constructors + + internal Row( Table table, DocX document, XElement xml ) + : base( document, xml ) + { + _table = table; + this.PackagePart = table.PackagePart; + } + + #endregion + + #region Private Methods + + private void SetHeight( double height, bool isHeightExact ) + { + 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 trHeight = trPr.Element( XName.Get( "trHeight", DocX.w.NamespaceName ) ); + if( trHeight == null ) + { + trPr.SetElementValue( XName.Get( "trHeight", DocX.w.NamespaceName ), string.Empty ); + trHeight = trPr.Element( XName.Get( "trHeight", DocX.w.NamespaceName ) ); + } + + // The hRule attribute needs to be set. + trHeight.SetAttributeValue( XName.Get( "hRule", DocX.w.NamespaceName ), isHeightExact ? "exact" : "atLeast" ); + + // Using 20 to match DocX._pageSizeMultiplier. + trHeight.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), ( height * 20 ).ToString() ); + } + + #endregion + + #region Public Methods + + public void Remove() + { + XElement table = Xml.Parent; + + Xml.Remove(); + if( !table.Elements( XName.Get( "tr", DocX.w.NamespaceName ) ).Any() ) + table.Remove(); + } + + /// + /// Merge cells starting with startIndex and ending with endIndex. + /// + public void MergeCells( int startIndex, int endIndex ) + { + // Check for valid start and end indexes. + if( startIndex < 0 || endIndex <= startIndex || endIndex > Cells.Count + 1 ) + throw new IndexOutOfRangeException(); + + // The sum of all merged gridSpans. + int gridSpanSum = 0; + + // Foreach each Cell between startIndex and endIndex inclusive. + foreach( Cell c in Cells.Where( ( z, i ) => i > startIndex && i <= endIndex ) ) + { + XElement tcPr = c.Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + XElement gridSpan = tcPr?.Element( XName.Get( "gridSpan", DocX.w.NamespaceName ) ); + if( gridSpan != null ) + { + XAttribute val = gridSpan.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + int value; + if( val != null && int.TryParse( val.Value, out value ) ) + gridSpanSum += value - 1; + } + + // Add this cells Pragraph to the merge start Cell. + Cells[ startIndex ].Xml.Add( c.Xml.Elements( XName.Get( "p", DocX.w.NamespaceName ) ) ); + + // Remove this Cell. + c.Xml.Remove(); + } + + // Trim cell's paragraphs to remove extra blank lines, if any + int index = 0; + do + { + // If the cell doesn't have multiple paragraphs, leave the loop + if ( Cells[ startIndex ].Paragraphs.Count < 2 ) + break; + + // Remove the last paragraph if it's a blank line, otherwise trimming is done + index = Cells[ startIndex ].Paragraphs.Count - 1; + if ( Cells[ startIndex ].Paragraphs[ index ].Text.Trim() == "" ) + Cells[ startIndex ].Paragraphs[ index ].Remove( false ); + else + break; + } while( true ); + + /* + * 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 = Cells[ startIndex ].Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( start_tcPr == null ) + { + Cells[ startIndex ].Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + start_tcPr = Cells[ startIndex ].Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the gridSpan element of this row, + * null will be returned if no such element exists. + */ + XElement start_gridSpan = start_tcPr.Element( XName.Get( "gridSpan", DocX.w.NamespaceName ) ); + if( start_gridSpan == null ) + { + start_tcPr.SetElementValue( XName.Get( "gridSpan", DocX.w.NamespaceName ), string.Empty ); + start_gridSpan = start_tcPr.Element( XName.Get( "gridSpan", DocX.w.NamespaceName ) ); + } + + /* + * Get the val attribute of this row, + * null will be returned if no such element exists. + */ + XAttribute start_val = start_gridSpan.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + int start_value = 0; + if( start_val != null ) + if( int.TryParse( start_val.Value, out start_value ) ) + gridSpanSum += start_value - 1; + + // Set the val attribute to the number of merged cells. + start_gridSpan.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), ( gridSpanSum + ( endIndex - startIndex + 1 ) ).ToString() ); + } + + #endregion + } + + public class Cell : Container + { + #region Internal Members + + internal Row _row; + + #endregion + + #region Public Properties + + public override ReadOnlyCollection Paragraphs + { + get + { + var paragraphs = base.Paragraphs; + + foreach( Paragraph p in paragraphs ) + { + p.PackagePart = _row._table.PackagePart; + } + + return paragraphs; + } + } + + /// + /// Gets or Sets this Cells vertical alignment. + /// + /// + /// Creates a table with 3 cells and sets the vertical alignment of each to 1 of the 3 available options. + /// + ///// Create a new document. + ///using(DocX document = DocX.Create("Test.docx")) + ///{ + /// // Insert a Table into this document. + /// Table t = document.InsertTable(3, 1); + /// + /// // Set the design of the Table such that we can easily identify cell boundaries. + /// t.Design = TableDesign.TableGrid; + /// + /// // Set the height of the row bigger than default. + /// // We need to be able to see the difference in vertical cell alignment options. + /// t.Rows[0].Height = 100; + /// + /// // Set the vertical alignment of cell0 to top. + /// Cell c0 = t.Rows[0].Cells[0]; + /// c0.InsertParagraph("VerticalAlignment.Top"); + /// c0.VerticalAlignment = VerticalAlignment.Top; + /// + /// // Set the vertical alignment of cell1 to center. + /// Cell c1 = t.Rows[0].Cells[1]; + /// c1.InsertParagraph("VerticalAlignment.Center"); + /// c1.VerticalAlignment = VerticalAlignment.Center; + /// + /// // Set the vertical alignment of cell2 to bottom. + /// Cell c2 = t.Rows[0].Cells[2]; + /// c2.InsertParagraph("VerticalAlignment.Bottom"); + /// c2.VerticalAlignment = VerticalAlignment.Bottom; + /// + /// // Save the document. + /// document.Save(); + ///} + /// + /// + public VerticalAlignment VerticalAlignment + { + get + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + + // If tcPr is null, this cell contains no width information. + // Get the vAlign (table cell vertical alignment) element for this Cell, + // null will be return if no such element exists. + XElement vAlign = tcPr?.Element( XName.Get( "vAlign", DocX.w.NamespaceName ) ); + + // If vAlign is null, this cell contains no vertical alignment information. + // Get the val attribute of the vAlign element. + XAttribute val = vAlign?.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + // If val is null, this cell contains no vAlign information. + if( val == null ) + return VerticalAlignment.Center; + + // If val is not a VerticalAlign enum, something is wrong with this attributes value, so remove it and return VerticalAlignment.Center; + try + { + return ( VerticalAlignment )Enum.Parse( typeof( VerticalAlignment ), val.Value, true ); + } + + catch + { + val.Remove(); + return VerticalAlignment.Center; + } + } + + set + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the vAlign (table cell vertical alignment) element for this Cell, + * null will be return if no such element exists. + */ + XElement vAlign = tcPr.Element( XName.Get( "vAlign", DocX.w.NamespaceName ) ); + if( vAlign == null ) + { + tcPr.SetElementValue( XName.Get( "vAlign", DocX.w.NamespaceName ), string.Empty ); + vAlign = tcPr.Element( XName.Get( "vAlign", DocX.w.NamespaceName ) ); + } + + // Set the VerticalAlignment in 'val' + vAlign.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), value.ToString().ToLower() ); + } + } + + public Color Shading + { + get + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + + // If tcPr is null, this cell contains no Color information. + // Get the shd (table shade) element for this Cell, + // null will be return if no such element exists. + XElement shd = tcPr?.Element( XName.Get( "shd", DocX.w.NamespaceName ) ); + + // If shd is null, this cell contains no Color information. + // Get the w attribute of the tcW element. + XAttribute fill = shd?.Attribute( XName.Get( "fill", DocX.w.NamespaceName ) ); + + // If fill is null, this cell contains no Color information. + if( fill == null ) + return Color.White; + + return ColorTranslator.FromHtml( string.Format( "#{0}", fill.Value ) ); + } + + set + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the shd (table shade) element for this Cell, + * null will be return if no such element exists. + */ + XElement shd = tcPr.Element( XName.Get( "shd", DocX.w.NamespaceName ) ); + if( shd == null ) + { + tcPr.SetElementValue( XName.Get( "shd", DocX.w.NamespaceName ), string.Empty ); + shd = tcPr.Element( XName.Get( "shd", DocX.w.NamespaceName ) ); + } + + // The val attribute needs to be set to clear + shd.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), "clear" ); + + // The color attribute needs to be set to auto + shd.SetAttributeValue( XName.Get( "color", DocX.w.NamespaceName ), "auto" ); + + // The fill attribute needs to be set to the hex for this Color. + shd.SetAttributeValue( XName.Get( "fill", DocX.w.NamespaceName ), value.ToHex() ); + } + } + + /// + /// Width in pixels. + /// + public double Width + { + get + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + + // If tcPr is null, this cell contains no width information. + // Get the tcW (table cell width) element for this Cell, + // null will be return if no such element exists. + XElement tcW = tcPr?.Element( XName.Get( "tcW", DocX.w.NamespaceName ) ); + + // If tcW is null, this cell contains no width information. + // Get the w attribute of the tcW element. + XAttribute w = tcW?.Attribute( XName.Get( "w", DocX.w.NamespaceName ) ); + + // If w is null, this cell contains no width information. + if( w == null ) + return double.NaN; + + // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; + double widthInWordUnits; + if( !double.TryParse( w.Value, out widthInWordUnits ) ) + { + w.Remove(); + return double.NaN; + } + + // Using 20 to match DocX._pageSizeMultiplier. + return ( widthInWordUnits / 20 ); + } + + set + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the tcW (table cell width) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcW = tcPr.Element( XName.Get( "tcW", DocX.w.NamespaceName ) ); + if( tcW == null ) + { + tcPr.SetElementValue( XName.Get( "tcW", DocX.w.NamespaceName ), string.Empty ); + tcW = tcPr.Element( XName.Get( "tcW", DocX.w.NamespaceName ) ); + } + + if( value == -1 ) + { + // remove cell width; due to set on table prop. + tcW.Remove(); + 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" ); + + // Using 20 to match DocX._pageSizeMultiplier. + tcW.SetAttributeValue( XName.Get( "w", DocX.w.NamespaceName ), ( value * 20 ).ToString() ); + } + } + + /// + /// LeftMargin in pixels. + /// + /// + /// + /// // Create a new document. + ///using (DocX document = DocX.Create("Test.docx")) + ///{ + /// // Insert table into this document. + /// Table t = document.InsertTable(3, 3); + /// t.Design = TableDesign.TableGrid; + /// + /// // Get the center cell. + /// Cell center = t.Rows[1].Cells[1]; + /// + /// // Insert some text so that we can see the effect of the Margins. + /// center.Paragraphs[0].Append("Center Cell"); + /// + /// // Set the center cells Left, Margin to 10. + /// center.MarginLeft = 25; + /// + /// // Save the document. + /// document.Save(); + ///} + /// + /// + public double MarginLeft + { + get + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + + // If tcPr is null, this cell contains no width information. + if( tcPr == null ) + return double.NaN; + + /* + * Get the tcMar + * + */ + XElement tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + + // If tcMar is null, this cell contains no margin information. + // Get the left (LeftMargin) element + XElement tcMarLeft = tcMar?.Element( XName.Get( "left", DocX.w.NamespaceName ) ); + + // If tcMarLeft is null, this cell contains no left margin information. + // Get the w attribute of the tcMarLeft element. + XAttribute w = tcMarLeft?.Attribute( XName.Get( "w", DocX.w.NamespaceName ) ); + + // If w is null, this cell contains no width information. + if( w == null ) + return double.NaN; + + // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; + double leftMarginInWordUnits; + if( !double.TryParse( w.Value, out leftMarginInWordUnits ) ) + { + w.Remove(); + return double.NaN; + } + + // Using 20 to match DocX._pageSizeMultiplier. + return ( leftMarginInWordUnits / 20 ); + } + + set + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the tcMar (table cell margin) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + if( tcMar == null ) + { + tcPr.SetElementValue( XName.Get( "tcMar", DocX.w.NamespaceName ), string.Empty ); + tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + } + + /* + * Get the left (table cell left margin) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcMarLeft = tcMar.Element( XName.Get( "left", DocX.w.NamespaceName ) ); + if( tcMarLeft == null ) + { + tcMar.SetElementValue( XName.Get( "left", DocX.w.NamespaceName ), string.Empty ); + tcMarLeft = tcMar.Element( XName.Get( "left", DocX.w.NamespaceName ) ); + } + + // 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. + tcMarLeft.SetAttributeValue( XName.Get( "type", DocX.w.NamespaceName ), "dxa" ); + + // Using 20 to match DocX._pageSizeMultiplier. + tcMarLeft.SetAttributeValue( XName.Get( "w", DocX.w.NamespaceName ), ( value * 20 ).ToString() ); + } + } + + /// + /// RightMargin in pixels. + /// + /// + /// + /// // Create a new document. + ///using (DocX document = DocX.Create("Test.docx")) + ///{ + /// // Insert table into this document. + /// Table t = document.InsertTable(3, 3); + /// t.Design = TableDesign.TableGrid; + /// + /// // Get the center cell. + /// Cell center = t.Rows[1].Cells[1]; + /// + /// // Insert some text so that we can see the effect of the Margins. + /// center.Paragraphs[0].Append("Center Cell"); + /// + /// // Set the center cells Right, Margin to 10. + /// center.MarginRight = 25; + /// + /// // Save the document. + /// document.Save(); + ///} + /// + /// + public double MarginRight + { + get + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + + // If tcPr is null, this cell contains no width information. + if( tcPr == null ) + return double.NaN; + + /* + * Get the tcMar + * + */ + XElement tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + + // If tcMar is null, this cell contains no margin information. + // Get the right (RightMargin) element + XElement tcMarRight = tcMar?.Element( XName.Get( "right", DocX.w.NamespaceName ) ); + + // If tcMarRight is null, this cell contains no right margin information. + // Get the w attribute of the tcMarRight element. + XAttribute w = tcMarRight?.Attribute( XName.Get( "w", DocX.w.NamespaceName ) ); + + // If w is null, this cell contains no width information. + if( w == null ) + return double.NaN; + + // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; + double rightMarginInWordUnits; + if( !double.TryParse( w.Value, out rightMarginInWordUnits ) ) + { + w.Remove(); + return double.NaN; + } + + // Using 20 to match DocX._pageSizeMultiplier. + return ( rightMarginInWordUnits / 20 ); + } + + set + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the tcMar (table cell margin) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + if( tcMar == null ) + { + tcPr.SetElementValue( XName.Get( "tcMar", DocX.w.NamespaceName ), string.Empty ); + tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + } + + /* + * Get the right (table cell right margin) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcMarRight = tcMar.Element( XName.Get( "right", DocX.w.NamespaceName ) ); + if( tcMarRight == null ) + { + tcMar.SetElementValue( XName.Get( "right", DocX.w.NamespaceName ), string.Empty ); + tcMarRight = tcMar.Element( XName.Get( "right", DocX.w.NamespaceName ) ); + } + + // 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. + tcMarRight.SetAttributeValue( XName.Get( "type", DocX.w.NamespaceName ), "dxa" ); + + // Using 20 to match DocX._pageSizeMultiplier. + tcMarRight.SetAttributeValue( XName.Get( "w", DocX.w.NamespaceName ), ( value * 20 ).ToString() ); + } + } + + /// + /// TopMargin in pixels. + /// + /// + /// + /// // Create a new document. + ///using (DocX document = DocX.Create("Test.docx")) + ///{ + /// // Insert table into this document. + /// Table t = document.InsertTable(3, 3); + /// t.Design = TableDesign.TableGrid; + /// + /// // Get the center cell. + /// Cell center = t.Rows[1].Cells[1]; + /// + /// // Insert some text so that we can see the effect of the Margins. + /// center.Paragraphs[0].Append("Center Cell"); + /// + /// // Set the center cells Top, Margin to 10. + /// center.MarginTop = 25; + /// + /// // Save the document. + /// document.Save(); + ///} + /// + /// + public double MarginTop + { + get + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + + // If tcPr is null, this cell contains no width information. + if( tcPr == null ) + return double.NaN; + + /* + * Get the tcMar + * + */ + XElement tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + + // If tcMar is null, this cell contains no margin information. + // Get the top (TopMargin) element + XElement tcMarTop = tcMar?.Element( XName.Get( "top", DocX.w.NamespaceName ) ); + + // If tcMarTop is null, this cell contains no top margin information. + // Get the w attribute of the tcMarTop element. + XAttribute w = tcMarTop?.Attribute( XName.Get( "w", DocX.w.NamespaceName ) ); + + // If w is null, this cell contains no width information. + if( w == null ) + return double.NaN; + + // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; + double topMarginInWordUnits; + if( !double.TryParse( w.Value, out topMarginInWordUnits ) ) + { + w.Remove(); + return double.NaN; + } + + // Using 20 to match DocX._pageSizeMultiplier. + return ( topMarginInWordUnits / 20 ); + } + + set + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the tcMar (table cell margin) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + if( tcMar == null ) + { + tcPr.SetElementValue( XName.Get( "tcMar", DocX.w.NamespaceName ), string.Empty ); + tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + } + + /* + * Get the top (table cell top margin) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcMarTop = tcMar.Element( XName.Get( "top", DocX.w.NamespaceName ) ); + if( tcMarTop == null ) + { + tcMar.SetElementValue( XName.Get( "top", DocX.w.NamespaceName ), string.Empty ); + tcMarTop = tcMar.Element( XName.Get( "top", DocX.w.NamespaceName ) ); + } + + // 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. + tcMarTop.SetAttributeValue( XName.Get( "type", DocX.w.NamespaceName ), "dxa" ); + + // Using 20 to match DocX._pageSizeMultiplier. + tcMarTop.SetAttributeValue( XName.Get( "w", DocX.w.NamespaceName ), ( value * 20 ).ToString() ); + } + } + + /// + /// BottomMargin in pixels. + /// + /// + /// + /// // Create a new document. + ///using (DocX document = DocX.Create("Test.docx")) + ///{ + /// // Insert table into this document. + /// Table t = document.InsertTable(3, 3); + /// t.Design = TableDesign.TableGrid; + /// + /// // Get the center cell. + /// Cell center = t.Rows[1].Cells[1]; + /// + /// // Insert some text so that we can see the effect of the Margins. + /// center.Paragraphs[0].Append("Center Cell"); + /// + /// // Set the center cells Top, Margin to 10. + /// center.MarginBottom = 25; + /// + /// // Save the document. + /// document.Save(); + ///} + /// + /// + public double MarginBottom + { + get + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + + // If tcPr is null, this cell contains no width information. + if( tcPr == null ) + return double.NaN; + + /* + * Get the tcMar + * + */ + XElement tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + + // If tcMar is null, this cell contains no margin information. + // Get the bottom (BottomMargin) element + XElement tcMarBottom = tcMar?.Element( XName.Get( "bottom", DocX.w.NamespaceName ) ); + + // If tcMarBottom is null, this cell contains no bottom margin information. + // Get the w attribute of the tcMarBottom element. + XAttribute w = tcMarBottom?.Attribute( XName.Get( "w", DocX.w.NamespaceName ) ); + + // If w is null, this cell contains no width information. + if( w == null ) + return double.NaN; + + // If w is not a double, something is wrong with this attributes value, so remove it and return double.NaN; + double bottomMarginInWordUnits; + if( !double.TryParse( w.Value, out bottomMarginInWordUnits ) ) + { + w.Remove(); + return double.NaN; + } + + // Using 20 to match DocX._pageSizeMultiplier. + return ( bottomMarginInWordUnits / 20 ); + } + + set + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the tcMar (table cell margin) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + if( tcMar == null ) + { + tcPr.SetElementValue( XName.Get( "tcMar", DocX.w.NamespaceName ), string.Empty ); + tcMar = tcPr.Element( XName.Get( "tcMar", DocX.w.NamespaceName ) ); + } + + /* + * Get the bottom (table cell bottom margin) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcMarBottom = tcMar.Element( XName.Get( "bottom", DocX.w.NamespaceName ) ); + if( tcMarBottom == null ) + { + tcMar.SetElementValue( XName.Get( "bottom", DocX.w.NamespaceName ), string.Empty ); + tcMarBottom = tcMar.Element( XName.Get( "bottom", DocX.w.NamespaceName ) ); + } + + // 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. + tcMarBottom.SetAttributeValue( XName.Get( "type", DocX.w.NamespaceName ), "dxa" ); + + // Using 20 to match DocX._pageSizeMultiplier. + tcMarBottom.SetAttributeValue( XName.Get( "w", DocX.w.NamespaceName ), ( value * 20 ).ToString() ); + } + } + + public Color FillColor + { + get + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + XElement shd = tcPr?.Element( XName.Get( "shd", DocX.w.NamespaceName ) ); + XAttribute fill = shd?.Attribute( XName.Get( "fill", DocX.w.NamespaceName ) ); + if( fill == null ) + return Color.Empty; + + int argb = Int32.Parse( fill.Value.Replace( "#", "" ), NumberStyles.HexNumber ); + return Color.FromArgb( argb ); + } + + set + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the tcW (table cell width) element for this Cell, + * null will be return if no such element exists. + */ + XElement shd = tcPr.Element( XName.Get( "shd", DocX.w.NamespaceName ) ); + if( shd == null ) + { + tcPr.SetElementValue( XName.Get( "shd", DocX.w.NamespaceName ), string.Empty ); + shd = tcPr.Element( XName.Get( "shd", DocX.w.NamespaceName ) ); + } + + shd.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), "clear" ); + shd.SetAttributeValue( XName.Get( "color", DocX.w.NamespaceName ), "auto" ); + shd.SetAttributeValue( XName.Get( "fill", DocX.w.NamespaceName ), value.ToHex() ); + } + } + + public TextDirection TextDirection + { + get + { + var tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + var textDirection = tcPr?.Element( XName.Get( "textDirection", DocX.w.NamespaceName ) ); + var val = textDirection?.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + if( val != null ) + { + TextDirection textDirectionValue; + var success = Enum.TryParse( val.Value, out textDirectionValue ); + if( success ) + return textDirectionValue; + else + { + val.Remove(); + } + } + + return TextDirection.right; + } + + set + { + var tcPrXName = XName.Get( "tcPr", DocX.w.NamespaceName ); + var textDirectionXName = XName.Get( "textDirection", DocX.w.NamespaceName ); + + var tcPr = Xml.Element( tcPrXName ); + if( tcPr == null ) + { + Xml.SetElementValue( tcPrXName, string.Empty ); + tcPr = Xml.Element( tcPrXName ); + } + + var textDirection = tcPr.Element( textDirectionXName ); + if( textDirection == null ) + { + tcPr.SetElementValue( textDirectionXName, string.Empty ); + textDirection = tcPr.Element( textDirectionXName ); + } + + textDirection.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), value.ToString() ); + } + } + + /// + /// Returns the Cell.GridSpan => How many cells are merged. + /// + public int GridSpan + { + get + { + int gridSpanValue = 0; + + var tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + var gridSpan = tcPr?.Element( XName.Get( "gridSpan", DocX.w.NamespaceName ) ); + if( gridSpan != null ) + { + var gridSpanAttrValue = gridSpan.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + + int value; + if( gridSpanAttrValue != null && int.TryParse( gridSpanAttrValue.Value, out value ) ) + gridSpanValue = value; + } + return gridSpanValue; + } + } + + #endregion + + #region Constructors + + internal Cell( Row row, DocX document, XElement xml ) + : base( document, xml ) + { + _row = row; + this.PackagePart = row.PackagePart; + } + + #endregion + + #region Public Methods + + /// + /// Set the table cell border + /// + /// + /// + ///// Create a new document. + ///using (DocX document = DocX.Create("Test.docx")) + ///{ + /// // Insert a table into this document. + /// Table t = document.InsertTable(3, 3); + /// + /// // Get the center cell. + /// Cell center = t.Rows[1].Cells[1]; + /// + /// // Create a large blue border. + /// Border b = new Border(BorderStyle.Tcbs_single, BorderSize.seven, 0, Color.Blue); + /// + /// // Set the center cells Top, Bottom, Left and Right Borders to b. + /// center.SetBorder(TableCellBorderType.Top, b); + /// center.SetBorder(TableCellBorderType.Bottom, b); + /// center.SetBorder(TableCellBorderType.Left, b); + /// center.SetBorder(TableCellBorderType.Right, b); + /// + /// // Save the document. + /// document.Save(); + ///} + /// + /// + /// Table Cell border to set + /// Border object to set the table cell border + public void SetBorder( TableCellBorderType borderType, Border border ) + { + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + Xml.SetElementValue( XName.Get( "tcPr", DocX.w.NamespaceName ), string.Empty ); + tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + } + + /* + * Get the tblBorders (table cell borders) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcBorders = tcPr.Element( XName.Get( "tcBorders", DocX.w.NamespaceName ) ); + if( tcBorders == null ) + { + tcPr.SetElementValue( XName.Get( "tcBorders", DocX.w.NamespaceName ), string.Empty ); + tcBorders = tcPr.Element( XName.Get( "tcBorders", DocX.w.NamespaceName ) ); + } + + /* + * Get the 'borderType' (table cell border) element for this Cell, + * null will be return if no such element exists. + */ + var tcbordertype = borderType.ToString(); + switch( borderType ) + { + case TableCellBorderType.TopLeftToBottomRight: + tcbordertype = "tl2br"; + break; + case TableCellBorderType.TopRightToBottomLeft: + tcbordertype = "tr2bl"; + break; + default: + // only lower the first char of string (because of insideH and insideV) + tcbordertype = tcbordertype.Substring( 0, 1 ).ToLower() + tcbordertype.Substring( 1 ); + break; + } + + XElement tcBorderType = tcBorders.Element( XName.Get( borderType.ToString(), DocX.w.NamespaceName ) ); + if( tcBorderType == null ) + { + tcBorders.SetElementValue( XName.Get( tcbordertype, DocX.w.NamespaceName ), string.Empty ); + tcBorderType = tcBorders.Element( XName.Get( tcbordertype, 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 + tcBorderType.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), borderstyle ); + + 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 + tcBorderType.SetAttributeValue( XName.Get( "sz", DocX.w.NamespaceName ), ( size ).ToString() ); + + // The space attribute is used for the cell spacing (probably '0') + tcBorderType.SetAttributeValue( XName.Get( "space", DocX.w.NamespaceName ), ( border.Space ).ToString() ); + + // The color attribute is used for the border color + tcBorderType.SetAttributeValue( XName.Get( "color", DocX.w.NamespaceName ), border.Color.ToHex() ); + } + + /// + /// Get a table cell border + /// + /// The table cell border to get + public Border GetBorder( TableCellBorderType borderType ) + { + // instance with default border values + var b = new Border(); + + /* + * Get the tcPr (table cell properties) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcPr = Xml.Element( XName.Get( "tcPr", DocX.w.NamespaceName ) ); + if( tcPr == null ) + { + // uses default border style + } + + /* + * Get the tcBorders (table cell borders) element for this Cell, + * null will be return if no such element exists. + */ + XElement tcBorders = tcPr.Element( XName.Get( "tcBorders", DocX.w.NamespaceName ) ); + if( tcBorders == null ) + { + // uses default border style + } + + /* + * Get the 'borderType' (cell border) element for this Cell, + * null will be return if no such element exists. + */ + var tcbordertype = borderType.ToString(); + switch( tcbordertype ) + { + case "TopLeftToBottomRight": + tcbordertype = "tl2br"; + break; + case "TopRightToBottomLeft": + tcbordertype = "tr2bl"; + break; + default: + // only lower the first char of string (because of insideH and insideV) + tcbordertype = tcbordertype.Substring( 0, 1 ).ToLower() + tcbordertype.Substring( 1 ); + break; + } + + XElement tcBorderType = tcBorders.Element( XName.Get( tcbordertype, DocX.w.NamespaceName ) ); + if( tcBorderType == null ) + { + // uses default border style + } + + // The val attribute is used for the border style + XAttribute val = tcBorderType.Attribute( XName.Get( "val", DocX.w.NamespaceName ) ); + // If val is null, this cell contains no border information. + if( val == null ) + { + // uses default border style + } + else + { + try + { + string bordertype = "Tcbs_" + val.Value; + b.Tcbs = ( BorderStyle )Enum.Parse( typeof( BorderStyle ), bordertype ); + } + + catch + { + val.Remove(); + // uses default border style + } + } + + // The sz attribute is used for the border size + XAttribute sz = tcBorderType.Attribute( XName.Get( "sz", DocX.w.NamespaceName ) ); + // If sz is null, this border contains no size information. + if( sz == null ) + { + // uses default border style + } + else + { + // If sz is not an int, something is wrong with this attributes value, so remove it + int numerical_size; + if( !int.TryParse( sz.Value, out numerical_size ) ) + sz.Remove(); + else + { + switch( numerical_size ) + { + case 2: + b.Size = BorderSize.one; + break; + case 4: + b.Size = BorderSize.two; + break; + case 6: + b.Size = BorderSize.three; + break; + case 8: + b.Size = BorderSize.four; + break; + case 12: + b.Size = BorderSize.five; + break; + case 18: + b.Size = BorderSize.six; + break; + case 24: + b.Size = BorderSize.seven; + break; + case 36: + b.Size = BorderSize.eight; + break; + case 48: + b.Size = BorderSize.nine; + break; + default: + b.Size = BorderSize.one; + break; + } + } + } + + // The space attribute is used for the border spacing (probably '0') + XAttribute space = tcBorderType.Attribute( XName.Get( "space", DocX.w.NamespaceName ) ); + // If space is null, this border contains no space information. + if( space == null ) + { + // uses default border style + } + else + { + // If space is not an int, something is wrong with this attributes value, so remove it + int borderspace; + if( !int.TryParse( space.Value, out borderspace ) ) + { + space.Remove(); + // uses default border style + } + else + { + b.Space = borderspace; + } + } + + // The color attribute is used for the border color + XAttribute color = tcBorderType.Attribute( XName.Get( "color", DocX.w.NamespaceName ) ); + if( color == null ) + { + // uses default border style + } + else + { + // If color is not a Color, something is wrong with this attributes value, so remove it + try + { + b.Color = ColorTranslator.FromHtml( string.Format( "#{0}", color.Value ) ); + } + catch + { + color.Remove(); + // uses default border style + } + } + return b; + } + + public override Table InsertTable( int rowCount, int columnCount ) + { + var table = base.InsertTable( rowCount, columnCount ); + table.PackagePart = this.PackagePart; + this.InsertParagraph(); //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; + } + + #endregion + + /// + /// Gets or Sets the fill color of this Cell. + /// + /// + /// + /// // Create a new document. + /// using (DocX document = DocX.Create("Test.docx")) + /// { + /// // Insert a table into this document. + /// Table t = document.InsertTable(3, 3); + /// + /// // Fill the first cell as Blue. + /// t.Rows[0].Cells[0].FillColor = Color.Blue; + /// // Fill the middle cell as Red. + /// t.Rows[1].Cells[1].FillColor = Color.Red; + /// // Fill the last cell as Green. + /// t.Rows[2].Cells[2].FillColor = Color.Green; + /// + /// // Save the document. + /// document.Save(); + /// } + /// + /// + } + + public class TableLook + { + #region Public Properties + + public bool FirstRow + { + get; + set; + } + + public bool LastRow + { + get; + set; + } + + public bool FirstColumn + { + get; + set; + } + + public bool LastColumn + { + get; + set; + } + + public bool NoHorizontalBanding + { + get; + set; + } + + public bool NoVerticalBanding + { + get; + set; + } + + #endregion + + #region Constructors + + public TableLook() + { + } + + public TableLook( bool firstRow, bool lastRow, bool firstColumn, bool lastColumn, bool noHorizontalBanding, bool noVerticalBanding ) + { + this.FirstRow = firstRow; + this.LastRow = lastRow; + this.FirstColumn = firstColumn; + this.LastColumn = lastColumn; + this.NoHorizontalBanding = noHorizontalBanding; + this.NoVerticalBanding = noVerticalBanding; + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/TableOfContents.cs b/Xceed.Words.NET/Src/TableOfContents.cs new file mode 100644 index 00000000..ee4a2ef3 --- /dev/null +++ b/Xceed.Words.NET/Src/TableOfContents.cs @@ -0,0 +1,133 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + /// + /// Represents a table of contents in the document + /// + public class TableOfContents : DocXElement + { + #region Private Constants + + private const string HeaderStyle = "TOCHeading"; + private const int RightTabPos = 9350; + + #endregion + + #region Internal Methods + + internal static TableOfContents CreateTableOfContents( DocX document, string title, TableOfContentsSwitches switches, string headerStyle = null, int lastIncludeLevel = 3, int? rightTabPos = null ) + { + var reader = XmlReader.Create( new StringReader( string.Format( XmlTemplates.TableOfContentsXmlBase, headerStyle ?? HeaderStyle, title, rightTabPos ?? RightTabPos, BuildSwitchString( switches, lastIncludeLevel ) ) ) ); + var xml = XElement.Load( reader ); + return new TableOfContents( document, xml, headerStyle ); + } + + #endregion + + #region Private Methods + + private void InitElement( string elementName, DocX document, string headerStyle = "" ) + { + if( elementName == "updateFields" ) + { + if( document._settings.Descendants().Any( x => x.Name.Equals( DocX.w + elementName ) ) ) + return; + + var element = new XElement( XName.Get( elementName, DocX.w.NamespaceName ), new XAttribute( DocX.w + "val", true ) ); + document._settings.Root.Add( element ); + } + else if( elementName == "styles" ) + { + if( !HasStyle( document, headerStyle, "paragraph" ) ) + { + var reader = XmlReader.Create( new StringReader( string.Format( XmlTemplates.TableOfContentsHeadingStyleBase, headerStyle ?? HeaderStyle ) ) ); + var xml = XElement.Load( reader ); + document._styles.Root.Add( xml ); + } + if( !HasStyle( document, "TOC1", "paragraph" ) ) + { + var reader = XmlReader.Create( new StringReader( string.Format( XmlTemplates.TableOfContentsElementStyleBase, "TOC1", "toc 1" ) ) ); + var xml = XElement.Load( reader ); + document._styles.Root.Add( xml ); + } + if( !HasStyle( document, "TOC2", "paragraph" ) ) + { + var reader = XmlReader.Create( new StringReader( string.Format( XmlTemplates.TableOfContentsElementStyleBase, "TOC2", "toc 2" ) ) ); + var xml = XElement.Load( reader ); + document._styles.Root.Add( xml ); + } + if( !HasStyle( document, "TOC3", "paragraph" ) ) + { + var reader = XmlReader.Create( new StringReader( string.Format( XmlTemplates.TableOfContentsElementStyleBase, "TOC3", "toc 3" ) ) ); + var xml = XElement.Load( reader ); + document._styles.Root.Add( xml ); + } + if( !HasStyle( document, "TOC4", "paragraph" ) ) + { + var reader = XmlReader.Create( new StringReader( string.Format( XmlTemplates.TableOfContentsElementStyleBase, "TOC4", "toc 4" ) ) ); + var xml = XElement.Load( reader ); + document._styles.Root.Add( xml ); + } + if( !HasStyle( document, "Hyperlink", "character" ) ) + { + var reader = XmlReader.Create( new StringReader( string.Format( XmlTemplates.TableOfContentsHyperLinkStyleBase ) ) ); + var xml = XElement.Load( reader ); + document._styles.Root.Add( xml ); + } + } + } + + private bool HasStyle( DocX document, string value, string type ) + { + return document._styles.Descendants().Any( x => x.Name.Equals( DocX.w + "style" ) && ( x.Attribute( DocX.w + "type" ) == null || x.Attribute( DocX.w + "type" ).Value.Equals( type ) ) && x.Attribute( DocX.w + "styleId" ) != null && x.Attribute( DocX.w + "styleId" ).Value.Equals( value ) ); + } + + private static string BuildSwitchString( TableOfContentsSwitches switches, int lastIncludeLevel ) + { + var allSwitches = Enum.GetValues( typeof( TableOfContentsSwitches ) ).Cast(); + var switchString = "TOC"; + foreach( var s in allSwitches.Where( s => s != TableOfContentsSwitches.None && switches.HasFlag( s ) ) ) + { + switchString += " " + s.EnumDescription(); + if( s == TableOfContentsSwitches.O ) + { + switchString += string.Format( " '{0}-{1}'", 1, lastIncludeLevel ); + } + } + + return switchString; + } + + #endregion + + #region Constructor + + private TableOfContents( DocX document, XElement xml, string headerStyle ) + : base( document, xml ) + { + InitElement( "updateFields", document ); + InitElement( "styles", document, headerStyle ); + } + + #endregion + } +} diff --git a/Xceed.Words.NET/Src/_BaseClasses.cs b/Xceed.Words.NET/Src/_BaseClasses.cs new file mode 100644 index 00000000..6b3f89b6 --- /dev/null +++ b/Xceed.Words.NET/Src/_BaseClasses.cs @@ -0,0 +1,377 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.IO.Packaging; +using System.Linq; +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + /// + /// All DocX types are derived from DocXElement. + /// This class contains properties which every element of a DocX must contain. + /// + public abstract class DocXElement + { + #region Private Members + + private PackagePart _mainPart; + + #endregion + + #region Public Properties + + /// + /// This is the actual Xml that gives this element substance. + /// For example, a Paragraphs Xml might look something like the following + ///

+ /// + /// Hello World! + /// + ///

+ ///
+ public XElement Xml { get; set; } + + public PackagePart PackagePart + { + get + { + return _mainPart; + } + set + { + _mainPart = value; + } + } + + #endregion + + #region Internal Properties + + /// + /// This is a reference to the DocX object that this element belongs to. + /// Every DocX element is connected to a document. + /// + internal DocX Document { get; set; } + + #endregion + + #region Constructors + + /// + /// Store both the document and xml so that they can be accessed by derived types. + /// + /// The document that this element belongs to. + /// The Xml that gives this element substance + public DocXElement( DocX document, XElement xml ) + { + this.Document = document; + this.Xml = xml; + } + + #endregion + } + + /// + /// This class provides functions for inserting new DocXElements before or after the current DocXElement. + /// Only certain DocXElements can support these functions without creating invalid documents, at the moment these are Paragraphs and Table. + /// + public abstract class InsertBeforeOrAfter : DocXElement + { + #region Constructors + + public InsertBeforeOrAfter( DocX document, XElement xml ) + : base( document, xml ) + { + } + + #endregion + + #region Public Methods + + public virtual void InsertPageBreakBeforeSelf() + { + XElement p = new XElement + ( + XName.Get( "p", DocX.w.NamespaceName ), + new XElement + ( + XName.Get( "r", DocX.w.NamespaceName ), + new XElement + ( + XName.Get( "br", DocX.w.NamespaceName ), + new XAttribute( XName.Get( "type", DocX.w.NamespaceName ), "page" ) + ) + ) + ); + + Xml.AddBeforeSelf( p ); + } + + public virtual void InsertPageBreakAfterSelf() + { + XElement p = new XElement + ( + XName.Get( "p", DocX.w.NamespaceName ), + new XElement + ( + XName.Get( "r", DocX.w.NamespaceName ), + new XElement + ( + XName.Get( "br", DocX.w.NamespaceName ), + new XAttribute( XName.Get( "type", DocX.w.NamespaceName ), "page" ) + ) + ) + ); + + Xml.AddAfterSelf( p ); + } + + public virtual Paragraph InsertParagraphBeforeSelf( Paragraph p ) + { + Xml.AddBeforeSelf( p.Xml ); + XElement newlyInserted = Xml.ElementsBeforeSelf().First(); + + p.Xml = newlyInserted; + + return p; + } + + public virtual Paragraph InsertParagraphAfterSelf( Paragraph p ) + { + Xml.AddAfterSelf( p.Xml ); + XElement newlyInserted = Xml.ElementsAfterSelf().First(); + + //Dmitchern + if( this as Paragraph != null ) + return new Paragraph( Document, newlyInserted, ( this as Paragraph )._endIndex ); + + p.Xml = newlyInserted; //IMPORTANT: I think we have return new paragraph in any case, but I dont know what to put as startIndex parameter into Paragraph constructor + return p; + } + + public virtual Paragraph InsertParagraphBeforeSelf( string text ) + { + return InsertParagraphBeforeSelf( text, false, new Formatting() ); + } + + public virtual Paragraph InsertParagraphAfterSelf( string text ) + { + return InsertParagraphAfterSelf( text, false, new Formatting() ); + } + + public virtual Paragraph InsertParagraphBeforeSelf( string text, bool trackChanges ) + { + return InsertParagraphBeforeSelf( text, trackChanges, new Formatting() ); + } + + public virtual Paragraph InsertParagraphAfterSelf( string text, bool trackChanges ) + { + return InsertParagraphAfterSelf( text, trackChanges, new Formatting() ); + } + + public virtual Paragraph InsertParagraphBeforeSelf( string text, bool trackChanges, Formatting formatting ) + { + XElement newParagraph = new XElement + ( + XName.Get( "p", DocX.w.NamespaceName ), new XElement( XName.Get( "pPr", DocX.w.NamespaceName ) ), HelperFunctions.FormatInput( text, formatting.Xml ) + ); + + if( trackChanges ) + newParagraph = Paragraph.CreateEdit( EditType.ins, DateTime.Now, newParagraph ); + + Xml.AddBeforeSelf( newParagraph ); + XElement newlyInserted = Xml.ElementsBeforeSelf().Last(); + + return new Paragraph( Document, newlyInserted, -1 ); + } + + public virtual Paragraph InsertParagraphAfterSelf( string text, bool trackChanges, Formatting formatting ) + { + XElement newParagraph = new XElement + ( + XName.Get( "p", DocX.w.NamespaceName ), new XElement( XName.Get( "pPr", DocX.w.NamespaceName ) ), HelperFunctions.FormatInput( text, formatting.Xml ) + ); + + if( trackChanges ) + newParagraph = Paragraph.CreateEdit( EditType.ins, DateTime.Now, newParagraph ); + + Xml.AddAfterSelf( newParagraph ); + XElement newlyInserted = Xml.ElementsAfterSelf().First(); + + Paragraph p = new Paragraph( Document, newlyInserted, -1 ); + + return p; + } + + public virtual Table InsertTableAfterSelf( int rowCount, int columnCount ) + { + var newTable = HelperFunctions.CreateTable( rowCount, columnCount ); + Xml.AddAfterSelf( newTable ); + var newlyInserted = this.Xml.ElementsAfterSelf().First(); + + var table = new Table( this.Document, newlyInserted ); + table.PackagePart = this.PackagePart; + return table; + } + + public virtual Table InsertTableAfterSelf( Table t ) + { + this.Xml.AddAfterSelf( t.Xml ); + var newlyInserted = this.Xml.ElementsAfterSelf().First(); + + var table = new Table( this.Document, newlyInserted ); + table.PackagePart = this.PackagePart; + return table; + } + + public virtual Table InsertTableBeforeSelf( int rowCount, int columnCount ) + { + var newTable = HelperFunctions.CreateTable( rowCount, columnCount ); + this.Xml.AddBeforeSelf( newTable ); + var newlyInserted = this.Xml.ElementsBeforeSelf().Last(); + + var table = new Table( this.Document, newlyInserted ); + table.PackagePart = this.PackagePart; + return table; + } + + public virtual Table InsertTableBeforeSelf( Table t ) + { + this.Xml.AddBeforeSelf( t.Xml ); + var newlyInserted = this.Xml.ElementsBeforeSelf().Last(); + + var table = new Table( this.Document, newlyInserted ); + table.PackagePart = this.PackagePart; + return table; + } + + #endregion + } + + public static class XmlTemplates + { + #region Public Constants + + public const string TableOfContentsXmlBase = @" + + + + + + \ + + + + + + + + + + + + + + + + + {1} + + + + + + + + + + + + + + + + + {3} + + + + + + + + + + + + + + + + + + "; + + public const string TableOfContentsHeadingStyleBase = @" + + + + + + + + + + + + + + + + + "; + + public const string TableOfContentsElementStyleBase = @" + + + + + + + + + + + + + "; + + public const string TableOfContentsHyperLinkStyleBase = @" + + + + + + + + + + + "; + + #endregion + } +} diff --git a/DocX/_Enumerations.cs b/Xceed.Words.NET/Src/_Enumerations.cs similarity index 68% rename from DocX/_Enumerations.cs rename to Xceed.Words.NET/Src/_Enumerations.cs index ab9afd30..cd856656 100644 --- a/DocX/_Enumerations.cs +++ b/Xceed.Words.NET/Src/_Enumerations.cs @@ -1,811 +1,757 @@ -using System; -using System.ComponentModel; - -namespace Novacode -{ - - public enum ListItemType - { - Bulleted, - Numbered - } - - public enum SectionBreakType - { - defaultNextPage, - evenPage, - oddPage, - continuous - } - - - public enum ContainerType - { - None, - TOC, - Section, - Cell, - Table, - Header, - Footer, - Paragraph, - Body - } - - public enum PageNumberFormat - { - normal, - roman - } - - public enum BorderSize - { - one, - two, - three, - four, - five, - six, - seven, - eight, - nine - } - - public enum EditRestrictions - { - none, - readOnly, - forms, - comments, - trackedChanges - } - - /// - /// Table Cell Border styles - /// Added by lckuiper @ 20101117 - /// source: http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.tablecellborders.aspx - /// - public enum BorderStyle - { - Tcbs_none = 0, - Tcbs_single, - Tcbs_thick, - Tcbs_double, - Tcbs_dotted, - Tcbs_dashed, - Tcbs_dotDash, - Tcbs_dotDotDash, - Tcbs_triple, - Tcbs_thinThickSmallGap, - Tcbs_thickThinSmallGap, - Tcbs_thinThickThinSmallGap, - Tcbs_thinThickMediumGap, - Tcbs_thickThinMediumGap, - Tcbs_thinThickThinMediumGap, - Tcbs_thinThickLargeGap, - Tcbs_thickThinLargeGap, - Tcbs_thinThickThinLargeGap, - Tcbs_wave, - Tcbs_doubleWave, - Tcbs_dashSmallGap, - Tcbs_dashDotStroked, - Tcbs_threeDEmboss, - Tcbs_threeDEngrave, - Tcbs_outset, - Tcbs_inset, - Tcbs_nil - } - - /// - /// Table Cell Border Types - /// Added by lckuiper @ 20101117 - /// source: http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.tablecellborders.aspx - /// - public enum TableCellBorderType - { - Top, - Bottom, - Left, - Right, - InsideH, - InsideV, - TopLeftToBottomRight, - TopRightToBottomLeft - } - - /// - /// Table Border Types - /// Added by lckuiper @ 20101117 - /// source: http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.tableborders.aspx - /// - public enum TableBorderType - { - Top, - Bottom, - Left, - Right, - InsideH, - InsideV - } - - // Patch 7398 added by lckuiper on Nov 16th 2010 @ 2:23 PM - public enum VerticalAlignment - { - Top, - Center, - Bottom - }; - - public enum Orientation - { - Portrait, - Landscape - }; - - public enum XmlDocument - { - Main, - HeaderOdd, - HeaderEven, - HeaderFirst, - FooterOdd, - FooterEven, - FooterFirst - }; - - public enum MatchFormattingOptions - { - ExactMatch, - SubsetMatch - }; - - public enum Script - { - superscript, - subscript, - none - } - - public enum Highlight - { - yellow, - green, - cyan, - magenta, - blue, - red, - darkBlue, - darkCyan, - darkGreen, - darkMagenta, - darkRed, - darkYellow, - darkGray, - lightGray, - black, - none - }; - - public enum UnderlineStyle - { - none = 0, - singleLine = 1, - words = 2, - doubleLine = 3, - dotted = 4, - thick = 6, - dash = 7, - dotDash = 9, - dotDotDash = 10, - wave = 11, - dottedHeavy = 20, - dashedHeavy = 23, - dashDotHeavy = 25, - dashDotDotHeavy = 26, - dashLongHeavy = 27, - dashLong = 39, - wavyDouble = 43, - wavyHeavy = 55, - }; - - public enum StrikeThrough - { - none, - strike, - doubleStrike - }; - - public enum Misc - { - none, - shadow, - outline, - outlineShadow, - emboss, - engrave - }; - - /// - /// Change the caps style of text, for use with Append and AppendLine. - /// - public enum CapsStyle - { - /// - /// No caps, make all characters are lowercase. - /// - none, - - /// - /// All caps, make every character uppercase. - /// - caps, - - /// - /// Small caps, make all characters capital but with a small font size. - /// - smallCaps - }; - - /// - /// Designs\Styles that can be applied to a table. - /// - public enum TableDesign - { - Custom, - TableNormal, - TableGrid, - LightShading, - LightShadingAccent1, - LightShadingAccent2, - LightShadingAccent3, - LightShadingAccent4, - LightShadingAccent5, - LightShadingAccent6, - LightList, - LightListAccent1, - LightListAccent2, - LightListAccent3, - LightListAccent4, - LightListAccent5, - LightListAccent6, - LightGrid, - LightGridAccent1, - LightGridAccent2, - LightGridAccent3, - LightGridAccent4, - LightGridAccent5, - LightGridAccent6, - MediumShading1, - MediumShading1Accent1, - MediumShading1Accent2, - MediumShading1Accent3, - MediumShading1Accent4, - MediumShading1Accent5, - MediumShading1Accent6, - MediumShading2, - MediumShading2Accent1, - MediumShading2Accent2, - MediumShading2Accent3, - MediumShading2Accent4, - MediumShading2Accent5, - MediumShading2Accent6, - MediumList1, - MediumList1Accent1, - MediumList1Accent2, - MediumList1Accent3, - MediumList1Accent4, - MediumList1Accent5, - MediumList1Accent6, - MediumList2, - MediumList2Accent1, - MediumList2Accent2, - MediumList2Accent3, - MediumList2Accent4, - MediumList2Accent5, - MediumList2Accent6, - MediumGrid1, - MediumGrid1Accent1, - MediumGrid1Accent2, - MediumGrid1Accent3, - MediumGrid1Accent4, - MediumGrid1Accent5, - MediumGrid1Accent6, - MediumGrid2, - MediumGrid2Accent1, - MediumGrid2Accent2, - MediumGrid2Accent3, - MediumGrid2Accent4, - MediumGrid2Accent5, - MediumGrid2Accent6, - MediumGrid3, - MediumGrid3Accent1, - MediumGrid3Accent2, - MediumGrid3Accent3, - MediumGrid3Accent4, - MediumGrid3Accent5, - MediumGrid3Accent6, - DarkList, - DarkListAccent1, - DarkListAccent2, - DarkListAccent3, - DarkListAccent4, - DarkListAccent5, - DarkListAccent6, - ColorfulShading, - ColorfulShadingAccent1, - ColorfulShadingAccent2, - ColorfulShadingAccent3, - ColorfulShadingAccent4, - ColorfulShadingAccent5, - ColorfulShadingAccent6, - ColorfulList, - ColorfulListAccent1, - ColorfulListAccent2, - ColorfulListAccent3, - ColorfulListAccent4, - ColorfulListAccent5, - ColorfulListAccent6, - ColorfulGrid, - ColorfulGridAccent1, - ColorfulGridAccent2, - ColorfulGridAccent3, - ColorfulGridAccent4, - ColorfulGridAccent5, - ColorfulGridAccent6, - None - }; - - /// - /// How a Table should auto resize. - /// - public enum AutoFit - { - /// - /// Autofit to Table contents. - /// - Contents, - - /// - /// Autofit to Window. - /// - Window, - - /// - /// Autofit to Column width. - /// - ColumnWidth, - /// - /// Autofit to Fixed column width - /// - Fixed - }; - - public enum RectangleShapes - { - rect, - roundRect, - snip1Rect, - snip2SameRect, - snip2DiagRect, - snipRoundRect, - round1Rect, - round2SameRect, - round2DiagRect - }; - - public enum BasicShapes - { - ellipse, - triangle, - rtTriangle, - parallelogram, - trapezoid, - diamond, - pentagon, - hexagon, - heptagon, - octagon, - decagon, - dodecagon, - pie, - chord, - teardrop, - frame, - halfFrame, - corner, - diagStripe, - plus, - plaque, - can, - cube, - bevel, - donut, - noSmoking, - blockArc, - foldedCorner, - smileyFace, - heart, - lightningBolt, - sun, - moon, - cloud, - arc, - backetPair, - bracePair, - leftBracket, - rightBracket, - leftBrace, - rightBrace - }; - - public enum BlockArrowShapes - { - rightArrow, - leftArrow, - upArrow, - downArrow, - leftRightArrow, - upDownArrow, - quadArrow, - leftRightUpArrow, - bentArrow, - uturnArrow, - leftUpArrow, - bentUpArrow, - curvedRightArrow, - curvedLeftArrow, - curvedUpArrow, - curvedDownArrow, - stripedRightArrow, - notchedRightArrow, - homePlate, - chevron, - rightArrowCallout, - downArrowCallout, - leftArrowCallout, - upArrowCallout, - leftRightArrowCallout, - quadArrowCallout, - circularArrow - }; - - public enum EquationShapes - { - mathPlus, - mathMinus, - mathMultiply, - mathDivide, - mathEqual, - mathNotEqual - }; - - public enum FlowchartShapes - { - flowChartProcess, - flowChartAlternateProcess, - flowChartDecision, - flowChartInputOutput, - flowChartPredefinedProcess, - flowChartInternalStorage, - flowChartDocument, - flowChartMultidocument, - flowChartTerminator, - flowChartPreparation, - flowChartManualInput, - flowChartManualOperation, - flowChartConnector, - flowChartOffpageConnector, - flowChartPunchedCard, - flowChartPunchedTape, - flowChartSummingJunction, - flowChartOr, - flowChartCollate, - flowChartSort, - flowChartExtract, - flowChartMerge, - flowChartOnlineStorage, - flowChartDelay, - flowChartMagneticTape, - flowChartMagneticDisk, - flowChartMagneticDrum, - flowChartDisplay - }; - - public enum StarAndBannerShapes - { - irregularSeal1, - irregularSeal2, - star4, - star5, - star6, - star7, - star8, - star10, - star12, - star16, - star24, - star32, - ribbon, - ribbon2, - ellipseRibbon, - ellipseRibbon2, - verticalScroll, - horizontalScroll, - wave, - doubleWave - }; - - public enum CalloutShapes - { - wedgeRectCallout, - wedgeRoundRectCallout, - wedgeEllipseCallout, - cloudCallout, - borderCallout1, - borderCallout2, - borderCallout3, - accentCallout1, - accentCallout2, - accentCallout3, - callout1, - callout2, - callout3, - accentBorderCallout1, - accentBorderCallout2, - accentBorderCallout3 - }; - - /// - /// Text alignment of a Paragraph. - /// - public enum Alignment - { - /// - /// Align Paragraph to the left. - /// - left, - - /// - /// Align Paragraph as centered. - /// - center, - - /// - /// Align Paragraph to the right. - /// - right, - - /// - /// (Justified) Align Paragraph to both the left and right margins, adding extra space between content as necessary. - /// - both - }; - - public enum Direction - { - LeftToRight, - RightToLeft - }; - - /// - /// Paragraph edit types - /// - internal enum EditType - { - /// - /// A ins is a tracked insertion - /// - ins, - - /// - /// A del is tracked deletion - /// - del - } - - /// - /// Custom property types. - /// - internal enum CustomPropertyType - { - /// - /// System.String - /// - Text, - - /// - /// System.DateTime - /// - Date, - - /// - /// System.Int32 - /// - NumberInteger, - - /// - /// System.Double - /// - NumberDecimal, - - /// - /// System.Boolean - /// - YesOrNo - } - - /// - /// Text types in a Run - /// - public enum RunTextType - { - /// - /// System.String - /// - Text, - - /// - /// System.String - /// - DelText, - } - public enum LineSpacingType - { - Line, - Before, - After - } - - public enum LineSpacingTypeAuto - { - AutoBefore, - AutoAfter, - Auto, - None - } - - /// - /// Cell margin for all sides of the table cell. - /// - public enum TableCellMarginType - { - /// - /// The left cell margin. - /// - left, - /// - /// The right cell margin. - /// - right, - /// - /// The bottom cell margin. - /// - bottom, - /// - /// The top cell margin. - /// - top - } - - public enum HeadingType - { - [Description("Heading1")] - Heading1, - - [Description("Heading2")] - Heading2, - - [Description("Heading3")] - Heading3, - - [Description("Heading4")] - Heading4, - - [Description("Heading5")] - Heading5, - - [Description("Heading6")] - Heading6, - - [Description("Heading7")] - Heading7, - - [Description("Heading8")] - Heading8, - - [Description("Heading9")] - Heading9, - - - /* - * The Character Based Headings below do not work in the same way as the headings 1-9 above, but appear on the same list in word. - * I have kept them here for reference in case somebody else things its just a matter of adding them in to gain extra headings - */ - #region Other character (NOT paragraph) based Headings - //[Description("NoSpacing")] - //NoSpacing, - - //[Description("Title")] - //Title, - - //[Description("Subtitle")] - //Subtitle, - - //[Description("Quote")] - //Quote, - - //[Description("IntenseQuote")] - //IntenseQuote, - - //[Description("Emphasis")] - //Emphasis, - - //[Description("IntenseEmphasis")] - //IntenseEmphasis, - - //[Description("Strong")] - //Strong, - - //[Description("ListParagraph")] - //ListParagraph, - - //[Description("SubtleReference")] - //SubtleReference, - - //[Description("IntenseReference")] - //IntenseReference, - - //[Description("BookTitle")] - //BookTitle, - #endregion - - - } - public enum TextDirection - { - btLr, - right - }; - - /// - /// Represents the switches set on a TOC. - /// - [Flags] - public enum TableOfContentsSwitches - { - None = 0 << 0, - [Description("\\a")] - A = 1 << 0, - [Description("\\b")] - B = 1 << 1, - [Description("\\c")] - C = 1 << 2, - [Description("\\d")] - D = 1 << 3, - [Description("\\f")] - F = 1 << 4, - [Description("\\h")] - H = 1 << 5, - [Description("\\l")] - L = 1 << 6, - [Description("\\n")] - N = 1 << 7, - [Description("\\o")] - O = 1 << 8, - [Description("\\p")] - P = 1 << 9, - [Description("\\s")] - S = 1 << 10, - [Description("\\t")] - T = 1 << 11, - [Description("\\u")] - U = 1 << 12, - [Description("\\w")] - W = 1 << 13, - [Description("\\x")] - X = 1 << 14, - [Description("\\z")] - Z = 1 << 15, - } - -} \ No newline at end of file +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System; +using System.ComponentModel; + +namespace Xceed.Words.NET +{ + + public enum ListItemType + { + Bulleted, + Numbered + } + + public enum SectionBreakType + { + defaultNextPage, + evenPage, + oddPage, + continuous + } + + public enum ContainerType + { + None, + TOC, + Section, + Cell, + Table, + Header, + Footer, + Paragraph, + Body + } + + public enum PageNumberFormat + { + normal, + roman + } + + public enum BorderSize + { + one, + two, + three, + four, + five, + six, + seven, + eight, + nine + } + + public enum EditRestrictions + { + none, + readOnly, + forms, + comments, + trackedChanges + } + + /// + /// Table Cell Border styles + /// source: http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.tablecellborders.aspx + /// + public enum BorderStyle + { + Tcbs_none = 0, + Tcbs_single, + Tcbs_thick, + Tcbs_double, + Tcbs_dotted, + Tcbs_dashed, + Tcbs_dotDash, + Tcbs_dotDotDash, + Tcbs_triple, + Tcbs_thinThickSmallGap, + Tcbs_thickThinSmallGap, + Tcbs_thinThickThinSmallGap, + Tcbs_thinThickMediumGap, + Tcbs_thickThinMediumGap, + Tcbs_thinThickThinMediumGap, + Tcbs_thinThickLargeGap, + Tcbs_thickThinLargeGap, + Tcbs_thinThickThinLargeGap, + Tcbs_wave, + Tcbs_doubleWave, + Tcbs_dashSmallGap, + Tcbs_dashDotStroked, + Tcbs_threeDEmboss, + Tcbs_threeDEngrave, + Tcbs_outset, + Tcbs_inset, + Tcbs_nil + } + + /// + /// Table Cell Border Types + /// source: http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.tablecellborders.aspx + /// + public enum TableCellBorderType + { + Top, + Bottom, + Left, + Right, + InsideH, + InsideV, + TopLeftToBottomRight, + TopRightToBottomLeft + } + + /// + /// Table Border Types + /// source: http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.tableborders.aspx + /// + public enum TableBorderType + { + Top, + Bottom, + Left, + Right, + InsideH, + InsideV + } + + public enum VerticalAlignment + { + Top, + Center, + Bottom + }; + + public enum Orientation + { + Portrait, + Landscape + }; + + public enum MatchFormattingOptions + { + ExactMatch, + SubsetMatch + }; + + public enum Script + { + superscript, + subscript, + none + } + + public enum Highlight + { + yellow, + green, + cyan, + magenta, + blue, + red, + darkBlue, + darkCyan, + darkGreen, + darkMagenta, + darkRed, + darkYellow, + darkGray, + lightGray, + black, + none + }; + + public enum UnderlineStyle + { + none = 0, + singleLine = 1, + words = 2, + doubleLine = 3, + dotted = 4, + thick = 6, + dash = 7, + dotDash = 9, + dotDotDash = 10, + wave = 11, + dottedHeavy = 20, + dashedHeavy = 23, + dashDotHeavy = 25, + dashDotDotHeavy = 26, + dashLongHeavy = 27, + dashLong = 39, + wavyDouble = 43, + wavyHeavy = 55 + }; + + public enum StrikeThrough + { + none, + strike, + doubleStrike + }; + + public enum Misc + { + none, + shadow, + outline, + outlineShadow, + emboss, + engrave + }; + + /// + /// Change the caps style of text, for use with Append and AppendLine. + /// + public enum CapsStyle + { + /// + /// No caps, make all characters are lowercase. + /// + none, + /// + /// All caps, make every character uppercase. + /// + caps, + /// + /// Small caps, make all characters capital but with a small font size. + /// + smallCaps + }; + + /// + /// Designs\Styles that can be applied to a table. + /// + public enum TableDesign + { + Custom, + TableNormal, + TableGrid, + LightShading, + LightShadingAccent1, + LightShadingAccent2, + LightShadingAccent3, + LightShadingAccent4, + LightShadingAccent5, + LightShadingAccent6, + LightList, + LightListAccent1, + LightListAccent2, + LightListAccent3, + LightListAccent4, + LightListAccent5, + LightListAccent6, + LightGrid, + LightGridAccent1, + LightGridAccent2, + LightGridAccent3, + LightGridAccent4, + LightGridAccent5, + LightGridAccent6, + MediumShading1, + MediumShading1Accent1, + MediumShading1Accent2, + MediumShading1Accent3, + MediumShading1Accent4, + MediumShading1Accent5, + MediumShading1Accent6, + MediumShading2, + MediumShading2Accent1, + MediumShading2Accent2, + MediumShading2Accent3, + MediumShading2Accent4, + MediumShading2Accent5, + MediumShading2Accent6, + MediumList1, + MediumList1Accent1, + MediumList1Accent2, + MediumList1Accent3, + MediumList1Accent4, + MediumList1Accent5, + MediumList1Accent6, + MediumList2, + MediumList2Accent1, + MediumList2Accent2, + MediumList2Accent3, + MediumList2Accent4, + MediumList2Accent5, + MediumList2Accent6, + MediumGrid1, + MediumGrid1Accent1, + MediumGrid1Accent2, + MediumGrid1Accent3, + MediumGrid1Accent4, + MediumGrid1Accent5, + MediumGrid1Accent6, + MediumGrid2, + MediumGrid2Accent1, + MediumGrid2Accent2, + MediumGrid2Accent3, + MediumGrid2Accent4, + MediumGrid2Accent5, + MediumGrid2Accent6, + MediumGrid3, + MediumGrid3Accent1, + MediumGrid3Accent2, + MediumGrid3Accent3, + MediumGrid3Accent4, + MediumGrid3Accent5, + MediumGrid3Accent6, + DarkList, + DarkListAccent1, + DarkListAccent2, + DarkListAccent3, + DarkListAccent4, + DarkListAccent5, + DarkListAccent6, + ColorfulShading, + ColorfulShadingAccent1, + ColorfulShadingAccent2, + ColorfulShadingAccent3, + ColorfulShadingAccent4, + ColorfulShadingAccent5, + ColorfulShadingAccent6, + ColorfulList, + ColorfulListAccent1, + ColorfulListAccent2, + ColorfulListAccent3, + ColorfulListAccent4, + ColorfulListAccent5, + ColorfulListAccent6, + ColorfulGrid, + ColorfulGridAccent1, + ColorfulGridAccent2, + ColorfulGridAccent3, + ColorfulGridAccent4, + ColorfulGridAccent5, + ColorfulGridAccent6, + None + }; + + /// + /// How a Table should auto resize. + /// + public enum AutoFit + { + Contents, + Window, + ColumnWidth, + Fixed + }; + + public enum RectangleShapes + { + rect, + roundRect, + snip1Rect, + snip2SameRect, + snip2DiagRect, + snipRoundRect, + round1Rect, + round2SameRect, + round2DiagRect + }; + + public enum BasicShapes + { + ellipse, + triangle, + rtTriangle, + parallelogram, + trapezoid, + diamond, + pentagon, + hexagon, + heptagon, + octagon, + decagon, + dodecagon, + pie, + chord, + teardrop, + frame, + halfFrame, + corner, + diagStripe, + plus, + plaque, + can, + cube, + bevel, + donut, + noSmoking, + blockArc, + foldedCorner, + smileyFace, + heart, + lightningBolt, + sun, + moon, + cloud, + arc, + backetPair, + bracePair, + leftBracket, + rightBracket, + leftBrace, + rightBrace + }; + + public enum BlockArrowShapes + { + rightArrow, + leftArrow, + upArrow, + downArrow, + leftRightArrow, + upDownArrow, + quadArrow, + leftRightUpArrow, + bentArrow, + uturnArrow, + leftUpArrow, + bentUpArrow, + curvedRightArrow, + curvedLeftArrow, + curvedUpArrow, + curvedDownArrow, + stripedRightArrow, + notchedRightArrow, + homePlate, + chevron, + rightArrowCallout, + downArrowCallout, + leftArrowCallout, + upArrowCallout, + leftRightArrowCallout, + quadArrowCallout, + circularArrow + }; + + public enum EquationShapes + { + mathPlus, + mathMinus, + mathMultiply, + mathDivide, + mathEqual, + mathNotEqual + }; + + public enum FlowchartShapes + { + flowChartProcess, + flowChartAlternateProcess, + flowChartDecision, + flowChartInputOutput, + flowChartPredefinedProcess, + flowChartInternalStorage, + flowChartDocument, + flowChartMultidocument, + flowChartTerminator, + flowChartPreparation, + flowChartManualInput, + flowChartManualOperation, + flowChartConnector, + flowChartOffpageConnector, + flowChartPunchedCard, + flowChartPunchedTape, + flowChartSummingJunction, + flowChartOr, + flowChartCollate, + flowChartSort, + flowChartExtract, + flowChartMerge, + flowChartOnlineStorage, + flowChartDelay, + flowChartMagneticTape, + flowChartMagneticDisk, + flowChartMagneticDrum, + flowChartDisplay + }; + + public enum StarAndBannerShapes + { + irregularSeal1, + irregularSeal2, + star4, + star5, + star6, + star7, + star8, + star10, + star12, + star16, + star24, + star32, + ribbon, + ribbon2, + ellipseRibbon, + ellipseRibbon2, + verticalScroll, + horizontalScroll, + wave, + doubleWave + }; + + public enum CalloutShapes + { + wedgeRectCallout, + wedgeRoundRectCallout, + wedgeEllipseCallout, + cloudCallout, + borderCallout1, + borderCallout2, + borderCallout3, + accentCallout1, + accentCallout2, + accentCallout3, + callout1, + callout2, + callout3, + accentBorderCallout1, + accentBorderCallout2, + accentBorderCallout3 + }; + + /// + /// Text alignment of a Paragraph. + /// + public enum Alignment + { + /// + /// Align Paragraph to the left. + /// + left, + + /// + /// Align Paragraph as centered. + /// + center, + + /// + /// Align Paragraph to the right. + /// + right, + + /// + /// (Justified) Align Paragraph to both the left and right margins, adding extra space between content as necessary. + /// + both + }; + + public enum Direction + { + LeftToRight, + RightToLeft + }; + + /// + /// Paragraph edit types + /// + internal enum EditType + { + /// + /// A ins is a tracked insertion + /// + ins, + /// + /// A del is tracked deletion + /// + del + } + + /// + /// Custom property types. + /// + internal enum CustomPropertyType + { + /// + /// System.String + /// + Text, + /// + /// System.DateTime + /// + Date, + /// + /// System.Int32 + /// + NumberInteger, + /// + /// System.Double + /// + NumberDecimal, + /// + /// System.Boolean + /// + YesOrNo + } + + /// + /// Text types in a Run + /// + public enum RunTextType + { + /// + /// System.String + /// + Text, + /// + /// System.String + /// + DelText, + } + + public enum LineSpacingType + { + Line, + Before, + After + } + + public enum LineSpacingTypeAuto + { + AutoBefore, + AutoAfter, + Auto, + None + } + + public enum DocumentTypes + { + Document, + Template + } + + public enum HeadingType + { + [Description( "Heading1" )] + Heading1, + + [Description( "Heading2" )] + Heading2, + + [Description( "Heading3" )] + Heading3, + + [Description( "Heading4" )] + Heading4, + + [Description( "Heading5" )] + Heading5, + + [Description( "Heading6" )] + Heading6, + + [Description( "Heading7" )] + Heading7, + + [Description( "Heading8" )] + Heading8, + + [Description( "Heading9" )] + Heading9 + + // The following headings appear in the same list in Word, but they do not work in the same way (they are character based headings, not paragraph based headings) + // NoSpacing + // Title, Subtitle + // Quote, IntenseQuote + // Emphasis, IntenseEmphasis + // Strong + // ListParagraph + // SubtleReference, IntenseReference + // BookTitle + } + + public enum TextDirection + { + btLr, + right + } + + [Flags] + public enum TableOfContentsSwitches + { + None = 0 << 0, + + [Description("\\a")] + A = 1 << 0, + + [Description("\\b")] + B = 1 << 1, + + [Description("\\c")] + C = 1 << 2, + + [Description("\\d")] + D = 1 << 3, + + [Description("\\f")] + F = 1 << 4, + + [Description("\\h")] + H = 1 << 5, + + [Description("\\l")] + L = 1 << 6, + + [Description("\\n")] + N = 1 << 7, + + [Description("\\o")] + O = 1 << 8, + + [Description("\\p")] + P = 1 << 9, + + [Description("\\s")] + S = 1 << 10, + + [Description("\\t")] + T = 1 << 11, + + [Description("\\u")] + U = 1 << 12, + + [Description("\\w")] + W = 1 << 13, + + [Description("\\x")] + X = 1 << 14, + + [Description("\\z")] + Z = 1 << 15 + } + + public enum TableCellMarginType + { + left, + right, + bottom, + top + } +} diff --git a/Xceed.Words.NET/Src/_Extensions.cs b/Xceed.Words.NET/Src/_Extensions.cs new file mode 100644 index 00000000..6e15e093 --- /dev/null +++ b/Xceed.Words.NET/Src/_Extensions.cs @@ -0,0 +1,120 @@ +/************************************************************************************* + + DocX – DocX is the community edition of Xceed Words for .NET + + Copyright (C) 2009-2016 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features and fast professional support, + pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/ + + ***********************************************************************************/ + +using System.Collections.Generic; +using System.Linq; +using System.Drawing; +using System.Xml.Linq; + +namespace Xceed.Words.NET +{ + internal static class Extensions + { + internal static string ToHex( this Color source ) + { + byte red = source.R; + byte green = source.G; + byte blue = source.B; + + string redHex = red.ToString( "X" ); + if( redHex.Length < 2 ) + redHex = "0" + redHex; + + string blueHex = blue.ToString( "X" ); + if( blueHex.Length < 2 ) + blueHex = "0" + blueHex; + + string greenHex = green.ToString( "X" ); + if( greenHex.Length < 2 ) + greenHex = "0" + greenHex; + + return string.Format( "{0}{1}{2}", redHex, greenHex, blueHex ); + } + + public static void Flatten( this XElement e, XName name, List flat ) + { + // Add this element (without its children) to the flat list. + XElement clone = CloneElement( e ); + clone.Elements().Remove(); + + // Filter elements using XName. + if( clone.Name == name ) + flat.Add( clone ); + + // Process the children. + if( e.HasElements ) + foreach( XElement elem in e.Elements( name ) ) // Filter elements using XName + elem.Flatten( name, flat ); + } + + public static string GetAttribute( this XElement el, XName name, string defaultValue = "" ) + { + var attribute = el.Attribute( name ); + if( attribute != null ) + return attribute.Value; + + return defaultValue; + } + + /// + /// Sets margin for all the pages in a DocX document in inches. + /// + /// + /// Margin from the top. -1 for no change. + /// Margin from the bottom. -1 for no change. + /// Margin from the right. -1 for no change. + /// Margin from the left. -1 for no change. + public static void SetMargin( this DocX document, float top, float bottom, float right, float left ) + { + var xNameSpace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; + var tempElement = document.PageLayout.Xml.Descendants( xNameSpace + "pgMar" ); + var multiplier = 1440; + + foreach( var item in tempElement ) + { + if( top != -1 ) + { + item.SetAttributeValue( xNameSpace + "top", multiplier * top ); + } + if( bottom != -1 ) + { + item.SetAttributeValue( xNameSpace + "bottom", multiplier * bottom ); + } + if( right != -1 ) + { + item.SetAttributeValue( xNameSpace + "right", multiplier * right ); + } + if( left != -1 ) + { + item.SetAttributeValue( xNameSpace + "left", multiplier * left ); + } + } + } + + private static XElement CloneElement( XElement element ) + { + return new XElement( element.Name, + element.Attributes(), + element.Nodes().Select( n => + { + XElement e = n as XElement; + if( e != null ) + return CloneElement( e ); + return n; + } + ) + ); + } + } +} diff --git a/DocX/DocX.csproj b/Xceed.Words.NET/Xceed.Words.NET.csproj similarity index 59% rename from DocX/DocX.csproj rename to Xceed.Words.NET/Xceed.Words.NET.csproj index ce419fd8..1753465d 100644 --- a/DocX/DocX.csproj +++ b/Xceed.Words.NET/Xceed.Words.NET.csproj @@ -1,184 +1,163 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {E863D072-AA8B-4108-B5F1-785241B37F67} - Library - Properties - Novacode - DocX - v4.6 - 512 - SAK - SAK - SAK - SAK - - - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\DocX.XML - AllRules.ruleset - CS1591 - false - - - pdbonly - true - bin\Release\ - - - prompt - 4 - AllRules.ruleset - AnyCPU - false - true - bin\Release\DocX.XML - CS1591 - false - - - true - - - KeyWithoutPassword.snk - - - - - - 3.5 - - - - - 3.5 - - - 3.5 - - - - 3.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - - - - - - - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {E863D072-AA8B-4108-B5F1-785241B37F67} + Library + Properties + Xceed.Words.NET + Xceed.Words.NET + v4.0 + 512 + + + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + + true + full + false + bin\Debug\ + TRACE;DEBUG;USING_PDF_DLL + prompt + 4 + bin\Debug\Xceed.Words.NET.XML + AllRules.ruleset + CS1591 + + + none + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + false + + + + + + + + + + 3.5 + + + + + 3.5 + + + 3.5 + + + + 3.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + + + + + \ No newline at end of file diff --git a/Xceed.Words.NET/sn.snk b/Xceed.Words.NET/sn.snk new file mode 100644 index 00000000..1bdc9120 Binary files /dev/null and b/Xceed.Words.NET/sn.snk differ diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index d2f69ae6..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,5 +0,0 @@ -before_build: - - nuget restore DocX.sln -build: - project: DocX.sln - verbosity: minimal \ No newline at end of file