Przeglądaj źródła

Implementation refactored for consistency. Documentation (.chm) file added with lots of code examples.

master
coffeycathal_cp 17 lat temu
rodzic
commit
1dfdfc17b7

+ 0
- 6
DocX.sln Wyświetl plik

EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DF41F5CE-8BCB-40CC-835F-54A3DB7D802F}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DF41F5CE-8BCB-40CC-835F-54A3DB7D802F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Examples", "Examples\Examples.csproj", "{EF2E13CC-B36B-4B5A-AE73-78F5DDCA094E}"
EndProject
Global Global
GlobalSection(TeamFoundationVersionControl) = preSolution GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 3 SccNumberOfProjects = 3
{E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
{E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Any CPU.Build.0 = Release|Any CPU {E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Any CPU.Build.0 = Release|Any CPU
{EF2E13CC-B36B-4B5A-AE73-78F5DDCA094E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF2E13CC-B36B-4B5A-AE73-78F5DDCA094E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF2E13CC-B36B-4B5A-AE73-78F5DDCA094E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF2E13CC-B36B-4B5A-AE73-78F5DDCA094E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

+ 0
- 10
DocX.vssscc Wyświetl plik

""
{
"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"
}

+ 6
- 10
DocX/CustomProperty.cs Wyświetl plik

namespace Novacode namespace Novacode
{ {
/// <summary> /// <summary>
/// Represents a .docx custom property.
/// Represents a document custom property.
/// </summary> /// </summary>
public class CustomProperty public class CustomProperty
{ {
// The underlying XElement which this CustomProperty wraps // The underlying XElement which this CustomProperty wraps
private XElement cp;
private XElement xml;
// This customPropertys name // This customPropertys name
private string name; private string name;
// This customPropertys type // This customPropertys type
/// </summary> /// </summary>
public object Value { get { return value; } } public object Value { get { return value; } }
/// <summary>
/// Wraps a System.Xml.Linq.XElement as an instance of Novacode.DocX.CustomProperty
/// </summary>
/// <param name="cp">The XElement to wrap</param>
public CustomProperty(XElement cp)
internal CustomProperty(XElement xml)
{ {
this.cp = cp;
name = cp.Attribute(XName.Get("name")).Value;
this.xml = xml;
name = xml.Attribute(XName.Get("name")).Value;
XElement p = cp.Elements().SingleOrDefault();
XElement p = xml.Elements().SingleOrDefault();
switch (p.Name.LocalName) switch (p.Name.LocalName)
{ {

+ 669
- 199
DocX/DocX.cs
Plik diff jest za duży
Wyświetl plik


+ 5
- 2
DocX/DocX.csproj Wyświetl plik

<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\DocX.XML</DocumentationFile>
<DocumentationFile>bin\Debug\DocX.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Compile Include="Text.cs" /> <Compile Include="Text.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" />
<None Include="Help\Documentation.chm" />
</ItemGroup>
<ItemGroup>
<Content Include="License\License.html" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

+ 7
- 0
DocX/Enumerations.cs Wyświetl plik

namespace Novacode namespace Novacode
{ {
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, singleLine, doubleLine, thick, dotted, dottedHeavy, dash, dashedHeavy, dashLong, dashLongHeavy, dotDash, dashDotHeavy, dotDotDash, dashDotDotHeavy, wave, wavyHeavy, wavyDouble, words };
public enum StrickThrough { none, strike, doubleStrike };
public enum Misc { none, shadow, outline, outlineShadow, emboss, engrave };
public enum CapsStyle { none, caps, smallCaps };
public enum RectangleShapes public enum RectangleShapes
{ {
rect, rect,

+ 2
- 2
DocX/Extensions.cs Wyświetl plik

namespace Novacode namespace Novacode
{ {
public static class Extensions
internal static class Extensions
{ {
public static string ToHex(this Color source)
internal static string ToHex(this Color source)
{ {
byte red = source.R; byte red = source.R;
byte green = source.G; byte green = source.G;

+ 68
- 9
DocX/Formatting.cs Wyświetl plik

using System.Text; using System.Text;
using System.Xml.Linq; using System.Xml.Linq;
using System.Drawing; using System.Drawing;
namespace Novacode namespace Novacode
{ {
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, singleLine, doubleLine, thick, dotted, dottedHeavy, dash, dashedHeavy, dashLong, dashLongHeavy, dotDash, dashDotHeavy, dotDotDash, dashDotDotHeavy, wave, wavyHeavy, wavyDouble, words};
public enum StrickThrough { none, strike, doubleStrike };
public enum Misc { none, shadow, outline, outlineShadow, emboss, engrave};
public enum CapsStyle { none, caps, smallCaps };
/// <summary>
/// A text formatting.
/// </summary>
public class Formatting public class Formatting
{ {
private XElement rPr; private XElement rPr;
private int? position; private int? position;
private double? spacing; private double? spacing;
/// <summary>
/// A text formatting.
/// </summary>
public Formatting() public Formatting()
{ {
capsStyle = CapsStyle.none; capsStyle = CapsStyle.none;
rPr = new XElement(XName.Get("rPr", DocX.w.NamespaceName)); rPr = new XElement(XName.Get("rPr", DocX.w.NamespaceName));
} }
public XElement Xml
internal XElement Xml
{ {
get get
{ {
} }
} }
/// <summary>
/// This formatting will apply Bold.
/// </summary>
public bool Bold { get { return bold; } set { bold = value;} } public bool Bold { get { return bold; } set { bold = value;} }
/// <summary>
/// This formatting will apply Italic.
/// </summary>
public bool Italic { get { return Italic; } set { italic = value; } } public bool Italic { get { return Italic; } set { italic = value; } }
/// <summary>
/// This formatting will apply StrickThrough.
/// </summary>
public StrickThrough StrikeThrough { get { return strikethrough; } set { strikethrough = value; } } public StrickThrough StrikeThrough { get { return strikethrough; } set { strikethrough = value; } }
/// <summary>
/// The script that this formatting should be, normal, superscript or subscript.
/// </summary>
public Script Script { get { return script; } set { script = value; } } public Script Script { get { return script; } set { script = value; } }
/// <summary>
/// The Size of this text, must be between 0 and 1638.
/// </summary>
public double? Size public double? Size
{ {
get { return size; } get { return size; }
} }
} }
/// <summary>
/// Percentage scale must be one of the following values 200, 150, 100, 90, 80, 66, 50 or 33.
/// </summary>
public int? PercentageScale public int? PercentageScale
{ {
get { return percentageScale; } get { return percentageScale; }
} }
} }
/// <summary>
/// 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.
/// </summary>
public int? Kerning public int? Kerning
{ {
get { return kerning; } get { return kerning; }
} }
} }
/// <summary>
/// Text position must be in the range (-1585 - 1585).
/// </summary>
public int? Position public int? Position
{ {
get { return position; } get { return position; }
} }
} }
/// <summary>
/// Text spacing must be in the range (-1585 - 1585).
/// </summary>
public double? Spacing public double? Spacing
{ {
get { return spacing; } get { return spacing; }
} }
} }
/// <summary>
/// The colour of the text.
/// </summary>
public Color? FontColor { get { return fontColor; } set { fontColor = value; } } public Color? FontColor { get { return fontColor; } set { fontColor = value; } }
/// <summary>
/// Highlight colour.
/// </summary>
public Highlight Highlight { get { return highlight; } set { highlight = value; } } public Highlight Highlight { get { return highlight; } set { highlight = value; } }
/// <summary>
/// The Underline style that this formatting applies.
/// </summary>
public UnderlineStyle UnderlineStyle { get { return underlineStyle; } set { underlineStyle = value; } } public UnderlineStyle UnderlineStyle { get { return underlineStyle; } set { underlineStyle = value; } }
/// <summary>
/// The underline colour.
/// </summary>
public Color? UnderlineColor { get { return underlineColor; } set { underlineColor = value; } } public Color? UnderlineColor { get { return underlineColor; } set { underlineColor = value; } }
/// <summary>
/// Misc settings.
/// </summary>
public Misc Misc { get { return misc; } set { misc = value; } } public Misc Misc { get { return misc; } set { misc = value; } }
/// <summary>
/// Is this text hidden or visible.
/// </summary>
public bool Hidden { get { return hidden; } set { hidden = value; } } public bool Hidden { get { return hidden; } set { hidden = value; } }
/// <summary>
/// Capitalization style.
/// </summary>
public CapsStyle CapsStyle { get { return capsStyle; } set { capsStyle = value; } } public CapsStyle CapsStyle { get { return capsStyle; } set { capsStyle = value; } }
/// <summary>
/// The font familt of this formatting.
/// </summary>
public FontFamily FontFamily { get { return FontFamily; } set { fontFamily = value; } } public FontFamily FontFamily { get { return FontFamily; } set { fontFamily = value; } }
} }

BIN
DocX/Help/Documentation.chm Wyświetl plik


+ 9
- 0
DocX/Image.cs Wyświetl plik

namespace Novacode namespace Novacode
{ {
/// <summary>
/// Represents an Image embedded in a document.
/// </summary>
public class Image public class Image
{ {
/// <summary>
/// A unique id which identifies this Image.
/// </summary>
private string id; private string id;
/// <summary>
/// Returns the id of this Image.
/// </summary>
public string Id public string Id
{ {
get {return id;} get {return id;}

+ 7
- 0
DocX/License/License.html Wyświetl plik

<html>
<body>
<div id="licenseTextHolder" style="margin: 1em">
<span id="ctl00_ctl00_MasterContent_Content_licenseText">Microsoft Public License &#40;Ms-PL&#41;<br /><br />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.<br /><br />1. Definitions<br /><br />The terms &#34;reproduce,&#34; &#34;reproduction,&#34; &#34;derivative works,&#34; and &#34;distribution&#34; have the same meaning here as under U.S. copyright law.<br /><br />A &#34;contribution&#34; is the original software, or any additions or changes to the software.<br /><br />A &#34;contributor&#34; is any person that distributes its contribution under this license.<br /><br />&#34;Licensed patents&#34; are a contributor&#39;s patent claims that read directly on its contribution.<br /><br />2. Grant of Rights<br /><br />&#40;A&#41; 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.<br /><br />&#40;B&#41; 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&#47;or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.<br /><br />3. Conditions and Limitations<br /><br />&#40;A&#41; No Trademark License- This license does not grant you rights to use any contributors&#39; name, logo, or trademarks.<br /><br />&#40;B&#41; 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.<br /><br />&#40;C&#41; If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.<br /><br />&#40;D&#41; 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.<br /><br />&#40;E&#41; The software is licensed &#34;as-is.&#34; 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.</span>
</div>
</body>
</html><!-- @SortOrder 2 -->

+ 388
- 123
DocX/Paragraph.cs Wyświetl plik

namespace Novacode namespace Novacode
{ {
/// <summary> /// <summary>
/// Represents a .docx paragraph.
/// Represents a document paragraph.
/// </summary> /// </summary>
public class Paragraph public class Paragraph
{ {
Dictionary<int, Run> runLookup = new Dictionary<int, Run>(); Dictionary<int, Run> runLookup = new Dictionary<int, Run>();
// The underlying XElement which this Paragraph wraps // The underlying XElement which this Paragraph wraps
private XElement p;
internal XElement xml;
internal int startIndex, endIndex;
// A collection of images in this paragraph // A collection of images in this paragraph
private IEnumerable<Picture> pictures;
public IEnumerable<Picture> Pictures { get { return pictures; } }
private List<Picture> pictures;
/// <summary> /// <summary>
/// Wraps a XElement as a Paragraph.
/// Returns a list of Pictures in this Paragraph.
/// </summary> /// </summary>
/// <param name="p">The XElement to wrap.</param>
internal Paragraph(XElement p)
public List<Picture> Pictures { get { return pictures; } }
internal Paragraph(int startIndex, XElement p)
{ {
this.p = p;
this.startIndex = startIndex;
this.endIndex = startIndex + GetElementTextLength(p);
this.xml = p;
BuildRunLookup(p); BuildRunLookup(p);
// Get all of the images in this document // Get all of the images in this document
pictures = from i in p.Descendants(XName.Get("drawing", DocX.w.NamespaceName))
select new Picture(i);
pictures = (from i in p.Descendants(XName.Get("drawing", DocX.w.NamespaceName))
select new Picture(i)).ToList();
} }
/// <summary> /// <summary>
/// Gets or set this paragraphs text alignment
/// Gets or set this Paragraphs text alignment.
/// </summary> /// </summary>
public Alignment Alignment public Alignment Alignment
{ {
{ {
alignment = value; alignment = value;
XElement pPr = p.Element(XName.Get("pPr", DocX.w.NamespaceName));
XElement pPr = xml.Element(XName.Get("pPr", DocX.w.NamespaceName));
if (alignment != Novacode.Alignment.left) if (alignment != Novacode.Alignment.left)
{ {
if (pPr == null) if (pPr == null)
p.Add(new XElement(XName.Get("pPr", DocX.w.NamespaceName)));
xml.Add(new XElement(XName.Get("pPr", DocX.w.NamespaceName)));
pPr = p.Element(XName.Get("pPr", DocX.w.NamespaceName));
pPr = xml.Element(XName.Get("pPr", DocX.w.NamespaceName));
XElement jc = pPr.Element(XName.Get("jc", DocX.w.NamespaceName)); XElement jc = pPr.Element(XName.Get("jc", DocX.w.NamespaceName));
} }
} }
public void Delete(bool trackChanges)
/// <summary>
/// Remove this Paragraph from the document.
/// </summary>
/// <param name="trackChanges">Should this remove be tracked as a change?</param>
/// <example>
/// Remove a Paragraph from a document and track it as a change.
/// <code>
/// // Load a document using its fully qualified filename.
/// DocX document = DocX.Create(@"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);
///
/// // Close the document.
/// document.Close(true);
/// </code>
/// </example>
public void Remove(bool trackChanges)
{ {
if (trackChanges) if (trackChanges)
{ {
DateTime now = DateTime.Now.ToUniversalTime(); DateTime now = DateTime.Now.ToUniversalTime();
List<XElement> elements = p.Elements().ToList();
List<XElement> elements = xml.Elements().ToList();
List<XElement> temp = new List<XElement>(); List<XElement> temp = new List<XElement>();
for (int i = 0; i < elements.Count(); i++ ) for (int i = 0; i < elements.Count(); i++ )
{ {
} }
if (temp.Count() > 0) if (temp.Count() > 0)
p.Add(CreateEdit(EditType.del, now, temp));
xml.Add(CreateEdit(EditType.del, now, temp));
} }
else else
{ {
// Remove this paragraph from the document // Remove this paragraph from the document
p.Remove();
p = null;
xml.Remove();
xml = null;
runLookup.Clear(); runLookup.Clear();
runLookup = null; runLookup = null;
} }
/// <summary> /// <summary>
/// Gets the value of this Novacode.DocX.Paragraph.
/// Gets the text value of this Paragraph.
/// </summary> /// </summary>
public string Value
public string Text
{ {
// Returns the underlying XElement's Value property. // Returns the underlying XElement's Value property.
get get
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
// Loop through each run in this paragraph // Loop through each run in this paragraph
foreach (XElement r in p.Descendants(XName.Get("r", DocX.w.NamespaceName)))
foreach (XElement r in xml.Descendants(XName.Get("r", DocX.w.NamespaceName)))
{ {
// Loop through each text item in this run // Loop through each text item in this run
foreach (XElement descendant in r.Descendants()) foreach (XElement descendant in r.Descendants())
} }
} }
/// <summary>
/// Insert a Picture into this document at a specified index.
/// </summary>
/// <param name="picture">The Picture to insert.</param>
/// <param name="index">The index to insert at.</param>
/// <example>
/// <code>
/// // Create a document using a relative filename.
/// DocX document = DocX.Create(@"Test.docx");
///
/// // Add an Image to this document.
/// Novacode.Image img = document.AddImage("Image.jpg");
///
/// // Create a Picture, a picture is like a custom view of an Image.
/// Picture pic = new Picture(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;
///
/// // Add a new Paragraph to this document.
/// Paragraph p = document.InsertParagraph("Here is Picture 1", false);
///
/// // Insert pic at the end of Paragraph p.
/// p.InsertPicture(pic, p.Text.Length);
///
/// // Close the document.
/// document.Close(true);
/// </code>
/// </example>
public void InsertPicture(Picture picture, int index) public void InsertPicture(Picture picture, int index)
{ {
Run run = GetFirstRunEffectedByEdit(index); Run run = GetFirstRunEffectedByEdit(index);
if (run == null) if (run == null)
p.Add(picture.i);
xml.Add(picture.i);
else else
{ {
// Split this run at the point you want to insert // Split this run at the point you want to insert
XElement[] splitRun = Run.SplitRun(run, index); XElement[] splitRun = Run.SplitRun(run, index);
// Replace the origional run // Replace the origional run
run.Xml.ReplaceWith
run.xml.ReplaceWith
( (
splitRun[0], splitRun[0],
picture.i, picture.i,
// Rebuild the run lookup for this paragraph // Rebuild the run lookup for this paragraph
runLookup.Clear(); runLookup.Clear();
BuildRunLookup(p);
BuildRunLookup(xml);
DocX.RenumberIDs(); DocX.RenumberIDs();
} }
); );
} }
/// <summary>
/// Return the first Run that will be effected by an edit at the index
/// </summary>
/// <param name="index">The index of this edit</param>
/// <returns>The first Run that will be effected</returns>
public Run GetFirstRunEffectedByEdit(int index)
internal Run GetFirstRunEffectedByEdit(int index)
{ {
foreach (int runEndIndex in runLookup.Keys) foreach (int runEndIndex in runLookup.Keys)
{ {
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
/// <summary>
/// Return the first Run that will be effected by an edit at the index
/// </summary>
/// <param name="index">The index of this edit</param>
/// <returns>The first Run that will be effected</returns>
public Run GetFirstRunEffectedByInsert(int index)
internal Run GetFirstRunEffectedByInsert(int index)
{ {
// This paragraph contains no Runs and insertion is at index 0 // This paragraph contains no Runs and insertion is at index 0
if (runLookup.Keys.Count() == 0 && index == 0) if (runLookup.Keys.Count() == 0 && index == 0)
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
/// <summary>
/// If the value to be inserted contains tab elements or br elements, multiple runs will be inserted.
/// </summary>
/// <param name="text">The text to be inserted, this text can contain the special characters \t (tab) and \n (br)</param>
/// <returns></returns>
private List<XElement> formatInput(string text, XElement rPr)
private List<XElement> FormatInput(string text, XElement rPr)
{ {
// Need to support /n as non breaking space
List<XElement> newRuns = new List<XElement>(); List<XElement> newRuns = new List<XElement>();
XElement tabRun = new XElement(DocX.w + "tab"); XElement tabRun = new XElement(DocX.w + "tab");
{ {
XElement firstText = new XElement(DocX.w + "t", runTexts[0]); XElement firstText = new XElement(DocX.w + "t", runTexts[0]);
Text.PreserveSpace(firstText);
Novacode.Text.PreserveSpace(firstText);
firstRun = new XElement(DocX.w + "r", rPr, firstText); firstRun = new XElement(DocX.w + "r", rPr, firstText);
else else
{ {
// Value begins or ends with a space // Value begins or ends with a space
Text.PreserveSpace(newText);
Novacode.Text.PreserveSpace(newText);
newRun = new XElement(DocX.w + "r", rPr, tabRun, newText); newRun = new XElement(DocX.w + "r", rPr, tabRun, newText);
} }
return newRuns; return newRuns;
} }
/// <summary>
/// Counts the text length of an element
/// </summary>
/// <param name="run">An element</param>
/// <returns>The length of this elements text</returns>
static internal int GetElementTextLength(XElement run) static internal int GetElementTextLength(XElement run)
{ {
int count = 0; int count = 0;
return count; return count;
} }
/// <summary>
/// Splits an edit element at the specified run, at the specified index.
/// </summary>
/// <param name="edit">The edit element to split</param>
/// <param name="run">The run element to split</param>
/// <param name="index">The index to split at</param>
/// <returns></returns>
public XElement[] SplitEdit(XElement edit, int index, EditType type)
internal XElement[] SplitEdit(XElement edit, int index, EditType type)
{ {
Run run; Run run;
if(type == EditType.del) if(type == EditType.del)
XElement[] splitRun = Run.SplitRun(run, index); XElement[] splitRun = Run.SplitRun(run, index);
XElement splitLeft = new XElement(edit.Name, edit.Attributes(), run.Xml.ElementsBeforeSelf(), splitRun[0]);
XElement splitLeft = new XElement(edit.Name, edit.Attributes(), run.xml.ElementsBeforeSelf(), splitRun[0]);
if (GetElementTextLength(splitLeft) == 0) if (GetElementTextLength(splitLeft) == 0)
splitLeft = null; splitLeft = null;
XElement splitRight = new XElement(edit.Name, edit.Attributes(), splitRun[1], run.Xml.ElementsAfterSelf());
XElement splitRight = new XElement(edit.Name, edit.Attributes(), splitRun[1], run.xml.ElementsAfterSelf());
if (GetElementTextLength(splitRight) == 0) if (GetElementTextLength(splitRight) == 0)
splitRight = null; splitRight = null;
); );
} }
public void Insert(int index, string value, bool trackChanges)
/// <summary>
/// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position.
/// </summary>
/// <example>
/// <code>
/// // Load Test.docx.
/// DocX document = DocX.Load(@"C:\Example\Test.docx");
///
/// // 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);
/// }
///
/// // Save changes to this document.
/// document.Close(true);
/// </code>
/// </example>
/// <example>
/// Inserting tabs using the \t switch.
/// <code>
/// // Load Test.docx.
/// DocX document = DocX.Load(@"C:\Example\Test.docx");
///
/// // 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);
/// }
///
/// // Save changes to this document.
/// document.Close(true);
/// </code>
/// </example>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, int, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool, RegexOptions)"/>
/// <param name="index">The index position of the insertion.</param>
/// <param name="value">The System.String to insert.</param>
/// <param name="trackChanges">Flag this insert as a change.</param>
public void InsertText(int index, string value, bool trackChanges)
{ {
Insert(index, value, null, trackChanges);
InsertText(index, value, trackChanges, null);
} }
/// <summary> /// <summary>
/// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position. /// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position.
/// </summary> /// </summary>
/// <example> /// <example>
/// <code>
/// // Description: Simple string insertion
///
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
/// <code>
/// // Load Test.docx.
/// DocX document = DocX.Load(@"C:\Example\Test.docx");
/// ///
/// // Iterate through the paragraphs
/// foreach (Paragraph p in dx.Paragraphs)
/// // 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.Insert(0, "Start: ", true);
/// // Insert the string "End: " at the end of every Paragraph and flag it as a change.
/// p.InsertText("End: ", true);
/// } /// }
/// ///
/// // Save changes to Example.docx
/// dx.Save();
/// // Save changes to this document.
/// document.Close(true);
/// </code> /// </code>
/// </example> /// </example>
/// <example> /// <example>
/// <code>
/// // Description: Inserting tabs using the \t switch
/// Inserting tabs using the \t switch.
/// <code>
/// // Load Test.docx.
/// DocX document = DocX.Load(@"C:\Example\Test.docx");
///
/// // 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);
/// }
///
/// // Save changes to this document.
/// document.Close(true);
/// </code>
/// </example>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, int, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool, RegexOptions)"/>
/// <param name="value">The System.String to insert.</param>
/// <param name="trackChanges">Flag this insert as a change.</param>
public void InsertText(string value, bool trackChanges)
{
InsertText(Text.Length, value, trackChanges, null);
}
/// <summary>
/// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position.
/// </summary>
/// <example>
/// <code>
/// // Load Test.docx.
/// DocX document = DocX.Load(@"C:\Example\Test.docx");
///
/// // Create a text formatting.
/// Formatting f = new Formatting();
/// f.FontColor = Color.Red;
/// f.Size = 30;
/// ///
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
/// // 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 changes to this document.
/// document.Close(true);
/// </code>
/// </example>
/// <example>
/// Inserting tabs using the \t switch.
/// <code>
/// // Load Test.docx.
/// 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 changes to this document.
/// document.Close(true);
/// </code>
/// </example>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, int, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool, RegexOptions)"/>
/// <param name="value">The System.String to insert.</param>
/// <param name="trackChanges">Flag this insert as a change.</param>
/// <param name="formatting">The text formatting.</param>
public void InsertText(string value, bool trackChanges, Formatting formatting)
{
InsertText(Text.Length, value, trackChanges, formatting);
}
/// <summary>
/// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position.
/// </summary>
/// <example>
/// <code>
/// // Load Test.docx.
/// 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 changes to this document.
/// document.Close(true);
/// </code>
/// </example>
/// <example>
/// Inserting tabs using the \t switch.
/// <code>
/// // Load Test.docx.
/// 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
/// foreach (Paragraph p in dx.Paragraphs)
/// // 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. /// // Insert the string "\tStart:\t" at the begining of every paragraph and flag it as a change.
/// p.Insert(0, "\tStart:\t", true);
/// p.InsertText(0, "\tStart:\t", true, f);
/// } /// }
/// ///
/// // Save changes to Example.docx
/// dx.Save();
/// // Save changes to this document.
/// document.Close(true);
/// </code> /// </code>
/// </example> /// </example>
/// <seealso cref="Paragraph.Remove"/>
/// <seealso cref="Paragraph.Replace"/>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, int, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool, RegexOptions)"/>
/// <param name="index">The index position of the insertion.</param> /// <param name="index">The index position of the insertion.</param>
/// <param name="value">The System.String to insert.</param> /// <param name="value">The System.String to insert.</param>
/// <param name="trackChanges">Flag this insert as a change</param>
public void Insert(int index, string value, Formatting formatting, bool trackChanges)
/// <param name="trackChanges">Flag this insert as a change.</param>
/// <param name="formatting">The text formatting.</param>
public void InsertText(int index, string value, bool trackChanges, Formatting formatting)
{ {
// Timestamp to mark the start of insert // Timestamp to mark the start of insert
DateTime now = DateTime.Now; DateTime now = DateTime.Now;
{ {
object insert; object insert;
if (formatting != null) if (formatting != null)
insert = formatInput(value, formatting.Xml);
insert = FormatInput(value, formatting.Xml);
else else
insert = formatInput(value, null);
insert = FormatInput(value, null);
if (trackChanges) if (trackChanges)
insert = CreateEdit(EditType.ins, insert_datetime, insert); insert = CreateEdit(EditType.ins, insert_datetime, insert);
p.Add(insert);
xml.Add(insert);
} }
else else
{ {
object newRuns; object newRuns;
if (formatting != null) if (formatting != null)
newRuns = formatInput(value, formatting.Xml);
newRuns = FormatInput(value, formatting.Xml);
else else
newRuns = formatInput(value, run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)));
newRuns = FormatInput(value, run.xml.Element(XName.Get("rPr", DocX.w.NamespaceName)));
// The parent of this Run // The parent of this Run
XElement parentElement = run.Xml.Parent;
XElement parentElement = run.xml.Parent;
switch (parentElement.Name.LocalName) switch (parentElement.Name.LocalName)
{ {
case "ins": case "ins":
XElement[] splitRun = Run.SplitRun(run, index); XElement[] splitRun = Run.SplitRun(run, index);
// Replace the origional run // Replace the origional run
run.Xml.ReplaceWith
run.xml.ReplaceWith
( (
splitRun[0], splitRun[0],
insert, insert,
// Rebuild the run lookup for this paragraph // Rebuild the run lookup for this paragraph
runLookup.Clear(); runLookup.Clear();
BuildRunLookup(p);
BuildRunLookup(xml);
DocX.RenumberIDs(); DocX.RenumberIDs();
} }
/// </summary> /// </summary>
/// <example> /// <example>
/// <code> /// <code>
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
/// // Load the document Test.docx.
/// DocX document = DocX.Load(@"C:\Example\Test.docx");
/// ///
/// // Iterate through the paragraphs /// // Iterate through the paragraphs
/// foreach (Paragraph p in dx.Paragraphs)
/// foreach (Paragraph p in document.Paragraphs)
/// { /// {
/// // Remove the first two characters from every paragraph /// // Remove the first two characters from every paragraph
/// p.Remove(0, 2);
/// p.RemoveText(0, 2, false);
/// } /// }
/// ///
/// // Save changes to Example.docx
/// dx.Save();
/// // Save changes to this document.
/// document.Close(true);
/// </code> /// </code>
/// </example> /// </example>
/// <seealso cref="Paragraph.Insert"/>
/// <seealso cref="Paragraph.Replace"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool, RegexOptions)"/>
/// <seealso cref="Paragraph.InsertText(string, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
/// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
/// <param name="index">The position to begin deleting characters.</param> /// <param name="index">The position to begin deleting characters.</param>
/// <param name="count">The number of characters to delete</param> /// <param name="count">The number of characters to delete</param>
/// <param name="trackChanges">Track changes</param> /// <param name="trackChanges">Track changes</param>
public void Remove(int index, int count, bool trackChanges)
public void RemoveText(int index, int count, bool trackChanges)
{ {
// Timestamp to mark the start of insert // Timestamp to mark the start of insert
DateTime now = DateTime.Now; DateTime now = DateTime.Now;
Run run = GetFirstRunEffectedByEdit(index + processed); Run run = GetFirstRunEffectedByEdit(index + processed);
// The parent of this Run // The parent of this Run
XElement parentElement = run.Xml.Parent;
XElement parentElement = run.xml.Parent;
switch (parentElement.Name.LocalName) switch (parentElement.Name.LocalName)
{ {
case "ins": case "ins":
{ {
XElement[] splitEditBefore = SplitEdit(parentElement, index + processed, EditType.del); XElement[] splitEditBefore = SplitEdit(parentElement, index + processed, EditType.del);
int min = Math.Min(count - processed, run.Xml.ElementsAfterSelf().Sum(e => GetElementTextLength(e)));
int min = Math.Min(count - processed, run.xml.ElementsAfterSelf().Sum(e => GetElementTextLength(e)));
XElement[] splitEditAfter = SplitEdit(parentElement, index + processed + min, EditType.del); XElement[] splitEditAfter = SplitEdit(parentElement, index + processed + min, EditType.del);
XElement temp = SplitEdit(splitEditBefore[1], index + processed + min, EditType.del)[0]; XElement temp = SplitEdit(splitEditBefore[1], index + processed + min, EditType.del)[0];
if (!trackChanges) if (!trackChanges)
middle = null; middle = null;
run.Xml.ReplaceWith
run.xml.ReplaceWith
( (
splitRunBefore[0], splitRunBefore[0],
middle, middle,
// Rebuild the run lookup // Rebuild the run lookup
runLookup.Clear(); runLookup.Clear();
BuildRunLookup(p);
BuildRunLookup(xml);
DocX.RenumberIDs(); DocX.RenumberIDs();
} }
/// <summary> /// <summary>
/// Replaces all occurrences of a specified System.String in this instance, with another specified System.String.
/// Removes characters from a Novacode.DocX.Paragraph.
/// </summary> /// </summary>
/// <example> /// <example>
/// <code> /// <code>
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
/// // Load the document Test.docx.
/// DocX document = DocX.Load(@"C:\Example\Test.docx");
/// ///
/// // Iterate through the paragraphs /// // Iterate through the paragraphs
/// foreach (Paragraph p in dx.Paragraphs)
/// foreach (Paragraph p in document.Paragraphs)
/// { /// {
/// // Replace all instances of the string "wrong" with the stirng "right"
/// p.Replace("wrong", "right");
/// // Remove all but the first 2 characters from this Paragraph.
/// p.RemoveText(2, false);
/// } /// }
/// ///
/// // Save changes to Example.docx
/// dx.Save();
/// // Save changes to this document.
/// document.Close(true);
/// </code> /// </code>
/// </example> /// </example>
/// <seealso cref="Paragraph.Remove"/>
/// <seealso cref="Paragraph.Insert"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool)"/>
/// <seealso cref="Paragraph.ReplaceText(string, string, bool, RegexOptions)"/>
/// <seealso cref="Paragraph.InsertText(string, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
/// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
/// <param name="index">The position to begin deleting characters.</param>
/// <param name="trackChanges">Track changes</param>
public void RemoveText(int index, bool trackChanges)
{
RemoveText(index, Text.Length - index, trackChanges);
}
/// <summary>
/// Replaces all occurrences of a specified System.String in this instance, with another specified System.String.
/// </summary>
/// <example>
/// <code>
/// // Load the document Test.docx.
/// DocX document = DocX.Load(@"C:\Example.docx");
///
/// // 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.
/// p.ReplaceText("wrong", "right", false, RegexOptions.IgnoreCase);
/// }
///
/// // Save changes to this document.
/// document.Close(true);
/// </code>
/// </example>
/// <seealso cref="Paragraph.RemoveText(int, int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.InsertText(string, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
/// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
/// <param name="newValue">A System.String to replace all occurances of oldValue.</param> /// <param name="newValue">A System.String to replace all occurances of oldValue.</param>
/// <param name="oldValue">A System.String to be replaced.</param> /// <param name="oldValue">A System.String to be replaced.</param>
/// <param name="options">A bitwise OR combination of RegexOption enumeration options.</param> /// <param name="options">A bitwise OR combination of RegexOption enumeration options.</param>
/// <param name="trackChanges">Track changes</param> /// <param name="trackChanges">Track changes</param>
public void Replace(string oldValue, string newValue, bool trackChanges, RegexOptions options)
public void ReplaceText(string oldValue, string newValue, bool trackChanges, RegexOptions options)
{ {
MatchCollection mc = Regex.Matches(this.Value, Regex.Escape(oldValue), options);
MatchCollection mc = Regex.Matches(this.Text, Regex.Escape(oldValue), options);
// Loop through the matches in reverse order // Loop through the matches in reverse order
foreach (Match m in mc.Cast<Match>().Reverse()) foreach (Match m in mc.Cast<Match>().Reverse())
{ {
Insert(m.Index + oldValue.Length, newValue, trackChanges);
Remove(m.Index, m.Length, trackChanges);
InsertText(m.Index + oldValue.Length, newValue, trackChanges);
RemoveText(m.Index, m.Length, trackChanges);
} }
} }
public void Replace(string oldValue, string newValue, bool trackChanges)
/// <summary>
/// Replaces all occurrences of a specified System.String in this instance, with another specified System.String.
/// </summary>
/// <example>
/// <code>
/// // Load the document Test.docx.
/// DocX document = DocX.Load(@"C:\Example.docx");
///
/// // Iterate through the paragraphs in this document.
/// foreach (Paragraph p in document.Paragraphs)
/// {
/// // Replace all instances of the string "wrong" with the string "right".
/// p.ReplaceText("wrong", "right", false);
/// }
///
/// // Save changes to this document.
/// document.Close(true);
/// </code>
/// </example>
/// <seealso cref="Paragraph.RemoveText(int, int, bool)"/>
/// <seealso cref="Paragraph.RemoveText(int, bool)"/>
/// <seealso cref="Paragraph.InsertText(string, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool)"/>
/// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
/// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
/// <param name="newValue">A System.String to replace all occurances of oldValue.</param>
/// <param name="oldValue">A System.String to be replaced.</param>
/// <param name="trackChanges">Track changes</param>
public void ReplaceText(string oldValue, string newValue, bool trackChanges)
{ {
Replace(oldValue, newValue, trackChanges, RegexOptions.None);
ReplaceText(oldValue, newValue, trackChanges, RegexOptions.None);
} }
} }
} }

+ 46
- 0
DocX/Picture.cs Wyświetl plik

namespace Novacode namespace Novacode
{ {
/// <summary>
/// Represents a Picture in this document, a Picture is a customized view of an Image.
/// </summary>
public class Picture public class Picture
{ {
private string id; private string id;
private XElement xfrm; private XElement xfrm;
private XElement prstGeom; private XElement prstGeom;
/// <summary>
/// Create a new Picture.
/// </summary>
/// <param name="id">A unique id that identifies an Image embedded in this document.</param>
/// <param name="name">The name of this Picture.</param>
/// <param name="descr">The description of this Picture.</param>
public Picture(string id, string name, string descr) public Picture(string id, string name, string descr)
{ {
OpenXmlPart part = DocX.mainDocumentPart.GetPartById(id); OpenXmlPart part = DocX.mainDocumentPart.GetPartById(id);
prstGeom.Attribute(XName.Get("prst")).Value = shape.ToString(); prstGeom.Attribute(XName.Get("prst")).Value = shape.ToString();
} }
/// <summary>
/// Set the shape of this Picture to one in the BasicShapes enumeration.
/// </summary>
/// <param name="shape">A shape from the BasicShapes enumeration.</param>
public void SetPictureShape(BasicShapes shape) public void SetPictureShape(BasicShapes shape)
{ {
SetPictureShape((object)shape); SetPictureShape((object)shape);
} }
/// <summary>
/// Set the shape of this Picture to one in the RectangleShapes enumeration.
/// </summary>
/// <param name="shape">A shape from the RectangleShapes enumeration.</param>
public void SetPictureShape(RectangleShapes shape) public void SetPictureShape(RectangleShapes shape)
{ {
SetPictureShape((object)shape); SetPictureShape((object)shape);
} }
/// <summary>
/// Set the shape of this Picture to one in the BlockArrowShapes enumeration.
/// </summary>
/// <param name="shape">A shape from the BlockArrowShapes enumeration.</param>
public void SetPictureShape(BlockArrowShapes shape) public void SetPictureShape(BlockArrowShapes shape)
{ {
SetPictureShape((object)shape); SetPictureShape((object)shape);
} }
/// <summary>
/// Set the shape of this Picture to one in the EquationShapes enumeration.
/// </summary>
/// <param name="shape">A shape from the EquationShapes enumeration.</param>
public void SetPictureShape(EquationShapes shape) public void SetPictureShape(EquationShapes shape)
{ {
SetPictureShape((object)shape); SetPictureShape((object)shape);
} }
/// <summary>
/// Set the shape of this Picture to one in the FlowchartShapes enumeration.
/// </summary>
/// <param name="shape">A shape from the FlowchartShapes enumeration.</param>
public void SetPictureShape(FlowchartShapes shape) public void SetPictureShape(FlowchartShapes shape)
{ {
SetPictureShape((object)shape); SetPictureShape((object)shape);
} }
/// <summary>
/// Set the shape of this Picture to one in the StarAndBannerShapes enumeration.
/// </summary>
/// <param name="shape">A shape from the StarAndBannerShapes enumeration.</param>
public void SetPictureShape(StarAndBannerShapes shape) public void SetPictureShape(StarAndBannerShapes shape)
{ {
SetPictureShape((object)shape); SetPictureShape((object)shape);
} }
/// <summary>
/// Set the shape of this Picture to one in the CalloutShapes enumeration.
/// </summary>
/// <param name="shape">A shape from the CalloutShapes enumeration.</param>
public void SetPictureShape(CalloutShapes shape) public void SetPictureShape(CalloutShapes shape)
{ {
SetPictureShape((object)shape); SetPictureShape((object)shape);
} }
/// <summary>
/// A unique id that identifies an Image embedded in this document.
/// </summary>
public string Id public string Id
{ {
get { return id; } get { return id; }
} }
/// <summary>
/// Flip this Picture Horizontally.
/// </summary>
public bool FlipHorizontal public bool FlipHorizontal
{ {
get { return hFlip; } get { return hFlip; }
} }
} }
/// <summary>
/// Flip this Picture Vertically.
/// </summary>
public bool FlipVertical public bool FlipVertical
{ {
get { return vFlip; } get { return vFlip; }

+ 2
- 2
DocX/Properties/AssemblyInfo.cs Wyświetl plik

// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.2")]
[assembly: AssemblyFileVersion("1.0.0.2")]
[assembly: AssemblyVersion("1.0.0.4")]
[assembly: AssemblyFileVersion("1.0.0.4")]

+ 18
- 41
DocX/Run.cs Wyświetl plik

namespace Novacode namespace Novacode
{ {
public class Run
internal class Run
{ {
// A lookup for the text elements in this paragraph // A lookup for the text elements in this paragraph
Dictionary<int, Text> textLookup = new Dictionary<int, Text>(); Dictionary<int, Text> textLookup = new Dictionary<int, Text>();
private int startIndex; private int startIndex;
private int endIndex; private int endIndex;
private string text; private string text;
private XElement e;
internal XElement xml;
/// <summary> /// <summary>
/// Gets the start index of this Text (text length before this text) /// Gets the start index of this Text (text length before this text)
/// </summary> /// </summary>
private string Value { set { value = text; } get { return text; } } private string Value { set { value = text; } get { return text; } }
/// <summary>
/// The underlying XElement of this run
/// </summary>
public XElement Xml { get { return e; } }
/// <summary>
/// A Run can contain text, delText, br, t and rPr elements
/// </summary>
/// <param name="startIndex">The start index of this run (text length before this run)</param>
/// <param name="endIndex">The end index of this run (text length before this run, plus this runs text length)</param>
/// <param name="runText">The text value of this run</param>
/// <param name="e">The underlying XElement of this run</param>
internal Run(int startIndex, XElement e)
internal Run(int startIndex, XElement xml)
{ {
this.startIndex = startIndex; this.startIndex = startIndex;
this.e = e;
this.xml = xml;
// Get the text elements in this run // Get the text elements in this run
IEnumerable<XElement> texts = e.Descendants();
IEnumerable<XElement> texts = xml.Descendants();
int start = startIndex; int start = startIndex;
// Loop through each text in this run // Loop through each text in this run
foreach (XElement text in texts)
foreach (XElement te in texts)
{ {
switch (text.Name.LocalName)
switch (te.Name.LocalName)
{ {
case "tab": case "tab":
{ {
textLookup.Add(start + 1, new Text(start, text));
Value += "\t";
textLookup.Add(start + 1, new Text(start, te));
text += "\t";
start++; start++;
break; break;
} }
case "br": case "br":
{ {
textLookup.Add(start + 1, new Text(start, text));
Value += "\n";
textLookup.Add(start + 1, new Text(start, te));
text += "\n";
start++; start++;
break; break;
} }
case "delText": case "delText":
{ {
// Only add strings which are not empty // Only add strings which are not empty
if (text.Value.Length > 0)
if (te.Value.Length > 0)
{ {
textLookup.Add(start + text.Value.Length, new Text(start, text));
Value += text.Value;
start += text.Value.Length;
textLookup.Add(start + te.Value.Length, new Text(start, te));
text += te.Value;
start += te.Value.Length;
} }
break; break;
} }
endIndex = start; endIndex = start;
} }
/// <summary>
/// Splits a run element at a specified index
/// </summary>
/// <param name="r">The run element to split</param>
/// <param name="index">The index to split at</param>
/// <returns>A two element array which contains both sides of the split</returns>
static internal XElement[] SplitRun(Run r, int index) static internal XElement[] SplitRun(Run r, int index)
{ {
Text t = r.GetFirstTextEffectedByEdit(index); Text t = r.GetFirstTextEffectedByEdit(index);
XElement[] splitText = Text.SplitText(t, index); XElement[] splitText = Text.SplitText(t, index);
XElement splitLeft = new XElement(r.e.Name, r.e.Attributes(), r.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), t.Xml.ElementsBeforeSelf().Where(n => n.Name.LocalName != "rPr"), splitText[0]);
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) if(Paragraph.GetElementTextLength(splitLeft) == 0)
splitLeft = null; splitLeft = null;
XElement splitRight = new XElement(r.e.Name, r.e.Attributes(), r.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), splitText[1], t.Xml.ElementsAfterSelf().Where(n => n.Name.LocalName != "rPr"));
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) if(Paragraph.GetElementTextLength(splitRight) == 0)
splitRight = null; splitRight = null;
); );
} }
/// <summary>
/// Return the first Run that will be effected by an edit at the index
/// </summary>
/// <param name="index">The index of this edit</param>
/// <returns>The first Run that will be effected</returns>
public Text GetFirstTextEffectedByEdit(int index)
internal Text GetFirstTextEffectedByEdit(int index)
{ {
foreach (int textEndIndex in textLookup.Keys) foreach (int textEndIndex in textLookup.Keys)
{ {

+ 9
- 26
DocX/Text.cs Wyświetl plik

namespace Novacode namespace Novacode
{ {
public class Text
internal class Text
{ {
private int startIndex; private int startIndex;
private int endIndex; private int endIndex;
private string text; private string text;
private XElement e;
internal XElement xml;
/// <summary> /// <summary>
/// Gets the start index of this Text (text length before this text) /// Gets the start index of this Text (text length before this text)
/// </summary> /// </summary>
public string Value { get { return text; } } public string Value { get { return text; } }
/// <summary>
/// The underlying XElement of this run
/// </summary>
public XElement Xml { get { return e; } }
/// <summary>
/// A Text element
/// </summary>
/// <param name="startIndex">The index this text starts at</param>
/// <param name="text">The index this text ends at</param>
/// <param name="e">The underlying xml element that this text wraps</param>
internal Text(int startIndex, XElement e) internal Text(int startIndex, XElement e)
{ {
this.startIndex = startIndex; this.startIndex = startIndex;
this.e = e;
this.xml = e;
switch (e.Name.LocalName) switch (e.Name.LocalName)
{ {
} }
} }
/// <summary>
/// Splits a text element at a specified index
/// </summary>
/// <param name="e">The text element to split</param>
/// <param name="index">The index to split at</param>
/// <returns>A two element array which contains both sides of the split</returns>
public static XElement[] SplitText(Text t, int index)
internal static XElement[] SplitText(Text t, int index)
{ {
if (index < t.startIndex || index > t.EndIndex) if (index < t.startIndex || index > t.EndIndex)
throw new ArgumentOutOfRangeException("index"); throw new ArgumentOutOfRangeException("index");
XElement splitLeft = null, splitRight = null; XElement splitLeft = null, splitRight = null;
if (t.e.Name.LocalName == "t" || t.e.Name.LocalName == "delText")
if (t.xml.Name.LocalName == "t" || t.xml.Name.LocalName == "delText")
{ {
// The origional text element, now containing only the text before the index point. // The origional text element, now containing only the text before the index point.
splitLeft = new XElement(t.e.Name, t.e.Attributes(), t.e.Value.Substring(0, index - t.startIndex));
splitLeft = new XElement(t.xml.Name, t.xml.Attributes(), t.xml.Value.Substring(0, index - t.startIndex));
if (splitLeft.Value.Length == 0) if (splitLeft.Value.Length == 0)
splitLeft = null; splitLeft = null;
else else
PreserveSpace(splitLeft); PreserveSpace(splitLeft);
// The origional text element, now containing only the text after the index point. // The origional text element, now containing only the text after the index point.
splitRight = new XElement(t.e.Name, t.e.Attributes(), t.e.Value.Substring(index - t.startIndex, t.e.Value.Length - (index - t.startIndex)));
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) if (splitRight.Value.Length == 0)
splitRight = null; splitRight = null;
else else
else else
{ {
if (index == t.StartIndex) if (index == t.StartIndex)
splitLeft = t.e;
splitLeft = t.xml;
else else
splitRight = t.e;
splitRight = t.xml;
} }
return return

Ładowanie…
Anuluj
Zapisz