diff --git a/OfficeIMO.Examples/Program.cs b/OfficeIMO.Examples/Program.cs index cb54607f..39aead47 100644 --- a/OfficeIMO.Examples/Program.cs +++ b/OfficeIMO.Examples/Program.cs @@ -30,6 +30,7 @@ static void Main(string[] args) { BasicDocument.Example_BasicWordWithMarginsInCentimeters(folderPath, false); BasicDocument.Example_BasicWordWithMarginsAndImage(folderPath, false); BasicDocument.Example_BasicWordWithLineSpacing(folderPath, false); + BasicDocument.Example_BasicWordWithSomeParagraphs(folderPath, false); AdvancedDocument.Example_AdvancedWord(folderPath, false); AdvancedDocument.Example_AdvancedWord2(folderPath, false); diff --git a/OfficeIMO.Examples/Word/AdvancedDocument/AdvancedDocument.Create.cs b/OfficeIMO.Examples/Word/AdvancedDocument/AdvancedDocument.Create.cs index 289667f4..3b03ae5b 100644 --- a/OfficeIMO.Examples/Word/AdvancedDocument/AdvancedDocument.Create.cs +++ b/OfficeIMO.Examples/Word/AdvancedDocument/AdvancedDocument.Create.cs @@ -1,4 +1,4 @@ -using System; +using System; using DocumentFormat.OpenXml.Wordprocessing; using OfficeIMO.Word; using Color = SixLabors.ImageSharp.Color; @@ -30,6 +30,9 @@ public static void Example_AdvancedWord(string folderPath, bool openWord) { // lets create a list that will be binded to TOC var wordListToc = document.AddTableOfContentList(WordListStyle.Headings111); + var elements = document.Elements; + Console.WriteLine("Elements count: " + elements.Count); + wordListToc.AddItem("How to add a table to document?"); document.AddParagraph("In the first paragraph I would like to show you how to add a table to the document using one of the 105 built-in styles:"); @@ -47,10 +50,16 @@ public static void Example_AdvancedWord(string folderPath, bool openWord) { var paragraph = document.AddParagraph("Adding lists is similar to ading a table. Just define a list and add list items to it. ").SetText("Remember that you can add anything between list items! "); paragraph.SetColor(Color.Blue).SetText("For example TOC List is just another list, but defining a specific style."); + elements = document.Elements; + Console.WriteLine("Elements count before list: " + elements.Count); + var list = document.AddList(WordListStyle.Bulleted); list.AddItem("First element of list", 0); list.AddItem("Second element of list", 1); + elements = document.Elements; + Console.WriteLine("Elements count after list: " + elements.Count); + var paragraphWithHyperlink = document.AddHyperLink("Go to Evotec Blogs", new Uri("https://evotec.xyz"), true, "URL with tooltip"); // you can also change the hyperlink text, uri later on using properties paragraphWithHyperlink.Hyperlink.Uri = new Uri("https://evotec.xyz/hub"); @@ -95,6 +104,12 @@ public static void Example_AdvancedWord(string folderPath, bool openWord) { // add watermark document.Sections[0].AddWatermark(WordWatermarkStyle.Text, "Draft"); + elements = document.Elements; + Console.WriteLine("Elements count in the end: " + elements.Count); + + var elementsByType = document.ElementsByType; + Console.WriteLine("ElementsByType count in the end: " + elementsByType.Count); + document.Save(openWord); } } diff --git a/OfficeIMO.Examples/Word/BasicDocument/BasicDocument.Create07.cs b/OfficeIMO.Examples/Word/BasicDocument/BasicDocument.Create07.cs new file mode 100644 index 00000000..60fdc52c --- /dev/null +++ b/OfficeIMO.Examples/Word/BasicDocument/BasicDocument.Create07.cs @@ -0,0 +1,27 @@ +using System; +using DocumentFormat.OpenXml.Wordprocessing; +using OfficeIMO.Word; + +namespace OfficeIMO.Examples.Word { + internal static partial class BasicDocument { + public static void Example_BasicWordWithSomeParagraphs(string folderPath, bool openWord) { + Console.WriteLine("[*] Creating standard document with margins"); + string filePath = System.IO.Path.Combine(folderPath, "EmptyDocumentWithSomeParagraphs.docx"); + using (WordDocument document = WordDocument.Create(filePath)) { + document.Settings.FontFamily = "Arial"; + document.Settings.FontSize = 9; + document.AddParagraph("This should be Arial 9"); + + var par = document.AddParagraph("This should be Tahoma 20"); + par.FontFamily = "Tahoma"; + par.AddText("SuperScript").SetVerticalTextAlignment(VerticalPositionValues.Superscript); + par.AddText("Continue 1 "); + par.AddText("Baseline").SetVerticalTextAlignment(VerticalPositionValues.Baseline); + par.AddText("Continue 2 "); + par.AddText("SubScript").SetVerticalTextAlignment(VerticalPositionValues.Subscript); + + document.Save(openWord); + } + } + } +} diff --git a/OfficeIMO.Tests/Documents/NestedTables.docx b/OfficeIMO.Tests/Documents/NestedTables.docx new file mode 100644 index 00000000..ae76ac62 Binary files /dev/null and b/OfficeIMO.Tests/Documents/NestedTables.docx differ diff --git a/OfficeIMO.Tests/Documents/Normal Subscript Superscript.docx b/OfficeIMO.Tests/Documents/Normal Subscript Superscript.docx new file mode 100644 index 00000000..355d8e77 Binary files /dev/null and b/OfficeIMO.Tests/Documents/Normal Subscript Superscript.docx differ diff --git a/OfficeIMO.Tests/Word.BasicDocument.cs b/OfficeIMO.Tests/Word.BasicDocument.cs index 550c18cc..be07f340 100644 --- a/OfficeIMO.Tests/Word.BasicDocument.cs +++ b/OfficeIMO.Tests/Word.BasicDocument.cs @@ -1,4 +1,3 @@ -using System.IO; using OfficeIMO.Word; using Xunit; @@ -36,5 +35,19 @@ public void Test_OpeningWordAndParagraphCountMatches() { //Assert.True(t0.Paragraphs.Count() == 12); } } + + [Fact] + public void Test_AllElements() { + var docs = Directory.GetFiles(_directoryDocuments, "*.docx"); + foreach (var doc in docs) { + using (WordDocument document = WordDocument.Load(doc)) { + var allElements = document.Elements; + Assert.True(allElements.Count > 0); + var allElementsByType = document.ElementsByType; + Assert.True(allElementsByType.Count > 0); + } + + } + } } } diff --git a/OfficeIMO.Tests/Word.Paragraphs.cs b/OfficeIMO.Tests/Word.Paragraphs.cs index 3be1e2eb..7db45567 100644 --- a/OfficeIMO.Tests/Word.Paragraphs.cs +++ b/OfficeIMO.Tests/Word.Paragraphs.cs @@ -439,5 +439,38 @@ public void Test_OpeningDocumentWithCustomStyle() { Assert.Equal(WordParagraphStyles.Custom, document.Paragraphs[1].Style); } } + + [Fact] + public void Test_SubscriptAndSuperscript() { + string filePath = Path.Combine(_directoryDocuments, "Normal Subscript Superscript.docx"); + using (WordDocument document = WordDocument.Load(filePath)) { + Assert.Equal(3, document.Paragraphs.Count); + Assert.Equal(null, document.Paragraphs[0].VerticalTextAlignment); + Assert.Equal(VerticalPositionValues.Subscript, document.Paragraphs[1].VerticalTextAlignment); + Assert.Equal(VerticalPositionValues.Superscript, document.Paragraphs[2].VerticalTextAlignment); + + Assert.True(document.Paragraphs.Count == 3); + + var wordParagraph1 = document.AddParagraph("Subscript").SetVerticalTextAlignment(VerticalPositionValues.Subscript); + var wordParagraph2 = document.AddParagraph("Baseline").SetVerticalTextAlignment(VerticalPositionValues.Baseline); + var wordParagraph3 = document.AddParagraph("Superscript").SetVerticalTextAlignment(VerticalPositionValues.Superscript); + var wordParagraph4 = document.AddParagraph("Normal"); + + Assert.True(document.Paragraphs.Count == 7); + Assert.Equal(document.Paragraphs[3].VerticalTextAlignment, VerticalPositionValues.Subscript); + Assert.Equal(document.Paragraphs[4].VerticalTextAlignment, VerticalPositionValues.Baseline); + Assert.Equal(document.Paragraphs[5].VerticalTextAlignment, VerticalPositionValues.Superscript); + Assert.Equal(document.Paragraphs[6].VerticalTextAlignment, null); + + document.Paragraphs[3].VerticalTextAlignment = null; + Assert.Equal(document.Paragraphs[3].VerticalTextAlignment, null); + document.Paragraphs[4].SetSubScript(); + Assert.Equal(document.Paragraphs[4].VerticalTextAlignment, VerticalPositionValues.Subscript); + document.Paragraphs[5].SetSubScript(); + Assert.Equal(document.Paragraphs[5].VerticalTextAlignment, VerticalPositionValues.Subscript); + document.Paragraphs[6].SetSuperScript(); + Assert.Equal(document.Paragraphs[6].VerticalTextAlignment, VerticalPositionValues.Superscript); + } + } } } diff --git a/OfficeIMO.Tests/Word.TablesNested.cs b/OfficeIMO.Tests/Word.TablesNested.cs index 02b2b077..fb734bc3 100644 --- a/OfficeIMO.Tests/Word.TablesNested.cs +++ b/OfficeIMO.Tests/Word.TablesNested.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using DocumentFormat.OpenXml.Wordprocessing; using OfficeIMO.Word; @@ -106,5 +106,24 @@ public void Test_CreatingWordDocumentWithNestedTables() { document.Save(); } } + + [Fact] + public void Test_ReadingWordDocumentWithNestedTables() { + string filePath = Path.Combine(_directoryDocuments, "NestedTables.docx"); + using (WordDocument document = WordDocument.Load(filePath)) { + Assert.Single(document.Tables); + + var table = document.Tables[0]; + Assert.True(table.HasNestedTables); + Assert.Equal(2, table.NestedTables.Count); + Assert.Equal(9, table.Cells.Count); + Assert.False(table.Cells[1].HasNestedTables); + Assert.True(table.Cells[8].HasNestedTables); + + var cell = table.Cells[0]; + Assert.True(cell.HasNestedTables); + Assert.Single(cell.NestedTables); + } + } } -} \ No newline at end of file +} diff --git a/OfficeIMO.Word/WordBookmark.cs b/OfficeIMO.Word/WordBookmark.cs index 40460ab9..1fa5288a 100644 --- a/OfficeIMO.Word/WordBookmark.cs +++ b/OfficeIMO.Word/WordBookmark.cs @@ -4,7 +4,7 @@ using System.Text; namespace OfficeIMO.Word { - public class WordBookmark { + public class WordBookmark : WordElement { private WordDocument _document; private Paragraph _paragraph; private BookmarkStart _bookmarkStart; diff --git a/OfficeIMO.Word/WordBreak.cs b/OfficeIMO.Word/WordBreak.cs index ced4f234..da9cc40e 100644 --- a/OfficeIMO.Word/WordBreak.cs +++ b/OfficeIMO.Word/WordBreak.cs @@ -1,4 +1,4 @@ -using DocumentFormat.OpenXml.Wordprocessing; +using DocumentFormat.OpenXml.Wordprocessing; using System; using System.Collections.Generic; using System.Linq; @@ -9,7 +9,7 @@ namespace OfficeIMO.Word { /// Represents a break in the text. /// Be it page break, soft break, column or text wrapping /// - public class WordBreak { + public class WordBreak : WordElement { private WordDocument _document; private readonly Paragraph _paragraph; private readonly Run _run; diff --git a/OfficeIMO.Word/WordChart.cs b/OfficeIMO.Word/WordChart.cs index 7873ba32..ba043f9c 100644 --- a/OfficeIMO.Word/WordChart.cs +++ b/OfficeIMO.Word/WordChart.cs @@ -12,7 +12,7 @@ using PlotArea = DocumentFormat.OpenXml.Drawing.Charts.PlotArea; namespace OfficeIMO.Word { - public partial class WordChart { + public partial class WordChart : WordElement { public WordChart(WordDocument document, WordParagraph paragraph, Drawing drawing) { _document = document; _drawing = drawing; diff --git a/OfficeIMO.Word/WordComment.cs b/OfficeIMO.Word/WordComment.cs index ae6f2f13..bdaab9d1 100644 --- a/OfficeIMO.Word/WordComment.cs +++ b/OfficeIMO.Word/WordComment.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,7 +6,7 @@ using DocumentFormat.OpenXml.Wordprocessing; namespace OfficeIMO.Word { - public partial class WordComment { + public partial class WordComment : WordElement { private WordParagraph _paragraph; private readonly WordDocument _document; private readonly Comment _comment; diff --git a/OfficeIMO.Word/WordCoverPage.cs b/OfficeIMO.Word/WordCoverPage.cs index dad941d4..80b9fac3 100644 --- a/OfficeIMO.Word/WordCoverPage.cs +++ b/OfficeIMO.Word/WordCoverPage.cs @@ -1,4 +1,3 @@ -using System; using DocumentFormat.OpenXml.Wordprocessing; namespace OfficeIMO.Word { @@ -19,7 +18,7 @@ public enum CoverPageTemplate { Retrospect } - public partial class WordCoverPage { + public partial class WordCoverPage : WordElement { private readonly WordDocument _document; private readonly SdtBlock _sdtBlock; @@ -32,8 +31,6 @@ public WordCoverPage(WordDocument wordDocument, CoverPageTemplate coverPageTempl _document = wordDocument; _sdtBlock = GetStyle(coverPageTemplate); this._document._wordprocessingDocument.MainDocumentPart.Document.Body.Append(_sdtBlock); - - //this._document._wordprocessingDocument.MainDocumentPart.Document.Body.InsertAt(_sdtBlock, 0); } private SdtBlock GetStyle(CoverPageTemplate template) { diff --git a/OfficeIMO.Word/WordDocument.cs b/OfficeIMO.Word/WordDocument.cs index 537c90b8..ea282bb4 100644 --- a/OfficeIMO.Word/WordDocument.cs +++ b/OfficeIMO.Word/WordDocument.cs @@ -28,36 +28,14 @@ internal int BookmarkId { public WordTableOfContent TableOfContent { get { var sdtBlocks = _document.Body?.ChildElements.OfType() ?? Enumerable.Empty(); - - foreach (var sdtBlock in sdtBlocks) { - var sdtProperties = sdtBlock?.ChildElements.OfType().FirstOrDefault(); - var docPartObject = sdtProperties?.ChildElements.OfType().FirstOrDefault(); - var docPartGallery = docPartObject?.ChildElements.OfType().FirstOrDefault(); - - if (docPartGallery != null && docPartGallery.Val == "Table of Contents") { - return new WordTableOfContent(this, sdtBlock); - } - } - - return null; + return WordSection.ConvertStdBlockToTableOfContent(this, sdtBlocks); } } public WordCoverPage CoverPage { get { var sdtBlocks = _document.Body?.ChildElements.OfType() ?? Enumerable.Empty(); - - foreach (var sdtBlock in sdtBlocks) { - var sdtProperties = sdtBlock?.ChildElements.OfType().FirstOrDefault(); - var docPartObject = sdtProperties?.ChildElements.OfType().FirstOrDefault(); - var docPartGallery = docPartObject?.ChildElements.OfType().FirstOrDefault(); - - if (docPartGallery != null && docPartGallery.Val == "Cover Pages") { - return new WordCoverPage(this, sdtBlock); - } - } - - return null; + return WordSection.ConvertStdBlockToCoverPage(this, sdtBlocks); } } @@ -213,6 +191,35 @@ public List ParagraphsFootNotes { } } + /// + /// List of all elements in the document from all the sections + /// + public List Elements { + get { + List list = new List(); + foreach (var section in this.Sections) { + list.AddRange(section.Elements); + } + return list; + } + } + + /// + /// List of all elements in the document from all the sections by their subtype + /// + public List ElementsByType { + get { + List list = new List(); + foreach (var section in this.Sections) { + list.AddRange(section.ElementsByType); + } + return list; + } + } + + /// + /// List of all PageBreaks in the document from all the sections + /// public List PageBreaks { get { List list = new List(); @@ -259,17 +266,7 @@ public List Comments { get { return WordComment.GetAllComments(this); } } - public List Lists { - get { - return WordSection.GetAllDocumentsLists(this); - //List list = new List(); - //foreach (var section in this.Sections) { - // list.AddRange(section.Lists); - //} - - //return list; - } - } + public List Lists => WordSection.GetAllDocumentsLists(this); /// /// Provides a list of Bookmarks in the document from all the sections diff --git a/OfficeIMO.Word/WordElement.cs b/OfficeIMO.Word/WordElement.cs new file mode 100644 index 00000000..d29f60b2 --- /dev/null +++ b/OfficeIMO.Word/WordElement.cs @@ -0,0 +1,11 @@ +namespace OfficeIMO.Word; + +/// +/// Word element used as base for all Word elements +/// +public class WordElement { + /// + /// Constructor + /// + public WordElement() { } +} diff --git a/OfficeIMO.Word/WordEmbeddedDocument.cs b/OfficeIMO.Word/WordEmbeddedDocument.cs index ebdbb0b4..801f47d8 100644 --- a/OfficeIMO.Word/WordEmbeddedDocument.cs +++ b/OfficeIMO.Word/WordEmbeddedDocument.cs @@ -5,7 +5,7 @@ using DocumentFormat.OpenXml.Wordprocessing; namespace OfficeIMO.Word { - public class WordEmbeddedDocument { + public class WordEmbeddedDocument : WordElement { private string _id; private AltChunk _altChunk; private readonly AlternativeFormatImportPart _altContent; diff --git a/OfficeIMO.Word/WordEndNote.cs b/OfficeIMO.Word/WordEndNote.cs index 708391b7..12ec2252 100644 --- a/OfficeIMO.Word/WordEndNote.cs +++ b/OfficeIMO.Word/WordEndNote.cs @@ -8,7 +8,7 @@ namespace OfficeIMO.Word { - public partial class WordEndNote { + public partial class WordEndNote : WordElement { private readonly WordDocument _document; private readonly Paragraph _paragraph; private readonly Run _run; diff --git a/OfficeIMO.Word/WordEquation.cs b/OfficeIMO.Word/WordEquation.cs index 446c98bf..8b5ebe5c 100644 --- a/OfficeIMO.Word/WordEquation.cs +++ b/OfficeIMO.Word/WordEquation.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,7 +6,7 @@ namespace OfficeIMO.Word { - public class WordEquation { + public class WordEquation : WordElement { private WordDocument _document; private Paragraph _paragraph; private DocumentFormat.OpenXml.Math.Paragraph mathParagraph; diff --git a/OfficeIMO.Word/WordField.cs b/OfficeIMO.Word/WordField.cs index 46102e8d..6f2ba9b5 100644 --- a/OfficeIMO.Word/WordField.cs +++ b/OfficeIMO.Word/WordField.cs @@ -96,7 +96,7 @@ public enum WordFieldFormat { Arabic, } - public partial class WordField { + public partial class WordField : WordElement { private readonly WordDocument _document; private readonly Paragraph _paragraph; private readonly List _runs = new List(); diff --git a/OfficeIMO.Word/WordFootNote.cs b/OfficeIMO.Word/WordFootNote.cs index 242f7388..2959adf5 100644 --- a/OfficeIMO.Word/WordFootNote.cs +++ b/OfficeIMO.Word/WordFootNote.cs @@ -8,7 +8,7 @@ namespace OfficeIMO.Word { - public partial class WordFootNote { + public partial class WordFootNote : WordElement { private WordDocument _document; private readonly Paragraph _paragraph; private readonly Run _run; diff --git a/OfficeIMO.Word/WordHyperLink.cs b/OfficeIMO.Word/WordHyperLink.cs index 027846c3..5a1e6855 100644 --- a/OfficeIMO.Word/WordHyperLink.cs +++ b/OfficeIMO.Word/WordHyperLink.cs @@ -25,7 +25,7 @@ public enum TargetFrame { _blank } - public class WordHyperLink { + public class WordHyperLink : WordElement { private readonly WordDocument _document; private readonly Paragraph _paragraph; internal readonly Hyperlink _hyperlink; diff --git a/OfficeIMO.Word/WordImage.cs b/OfficeIMO.Word/WordImage.cs index e87b510e..5c8f4756 100644 --- a/OfficeIMO.Word/WordImage.cs +++ b/OfficeIMO.Word/WordImage.cs @@ -11,7 +11,7 @@ using DocumentFormat.OpenXml.Office2010.Word.Drawing; namespace OfficeIMO.Word { - public class WordImage { + public class WordImage : WordElement { private const double EnglishMetricUnitsPerInch = 914400; private const double PixelsPerInch = 96; diff --git a/OfficeIMO.Word/WordList.cs b/OfficeIMO.Word/WordList.cs index a3ada783..ad304c2c 100644 --- a/OfficeIMO.Word/WordList.cs +++ b/OfficeIMO.Word/WordList.cs @@ -8,7 +8,7 @@ namespace OfficeIMO.Word; -public class WordList { +public class WordList : WordElement { private readonly WordprocessingDocument _wordprocessingDocument; private readonly WordDocument _document; // private readonly WordSection _section; diff --git a/OfficeIMO.Word/WordParagraph.ParagraphProperties.cs b/OfficeIMO.Word/WordParagraph.ParagraphProperties.cs index be6757fe..bb59fc95 100644 --- a/OfficeIMO.Word/WordParagraph.ParagraphProperties.cs +++ b/OfficeIMO.Word/WordParagraph.ParagraphProperties.cs @@ -306,5 +306,28 @@ public int? LineSpacingAfter { _paragraphProperties.SpacingBetweenLines = spacing; } } + + /// + /// Gets or sets the vertical text alignment - the alignment of the text in the paragraph with respect to the line height. + /// + public VerticalPositionValues? VerticalTextAlignment { + get { + if (_runProperties != null && _runProperties.VerticalTextAlignment != null) { + return _runProperties.VerticalTextAlignment.Val; + } + return null; + } + set { + _runProperties ??= new RunProperties(); + if (value == null) { + if (_runProperties.VerticalTextAlignment == null) { + return; + } + _runProperties.VerticalTextAlignment = null; + } else { + _runProperties.VerticalTextAlignment = new VerticalTextAlignment { Val = value }; + } + } + } } } diff --git a/OfficeIMO.Word/WordParagraph.RunPropertiesMethods.cs b/OfficeIMO.Word/WordParagraph.RunPropertiesMethods.cs index 2194770d..01e24dd8 100644 --- a/OfficeIMO.Word/WordParagraph.RunPropertiesMethods.cs +++ b/OfficeIMO.Word/WordParagraph.RunPropertiesMethods.cs @@ -79,5 +79,32 @@ public WordParagraph SetStyleId(string styleId) { return this; } + /// + /// Set the vertical text alignment + /// + /// + /// + public WordParagraph SetVerticalTextAlignment(VerticalPositionValues? verticalPositionValue) { + VerticalTextAlignment = verticalPositionValue; + return this; + } + + /// + /// Set the text as subscript + /// + /// + public WordParagraph SetSubScript() { + VerticalTextAlignment = VerticalPositionValues.Subscript; + return this; + } + + /// + /// Set the text as superscript + /// + /// + public WordParagraph SetSuperScript() { + VerticalTextAlignment = VerticalPositionValues.Superscript; + return this; + } } } diff --git a/OfficeIMO.Word/WordParagraph.cs b/OfficeIMO.Word/WordParagraph.cs index e76df642..42394880 100644 --- a/OfficeIMO.Word/WordParagraph.cs +++ b/OfficeIMO.Word/WordParagraph.cs @@ -1,10 +1,5 @@ -using System; -using System.Collections.Generic; using DocumentFormat.OpenXml.Wordprocessing; -using System.Linq; -using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Drawing; -using DocumentFormat.OpenXml.Office2016.Drawing.Charts; using Break = DocumentFormat.OpenXml.Wordprocessing.Break; using Hyperlink = DocumentFormat.OpenXml.Wordprocessing.Hyperlink; using OfficeMath = DocumentFormat.OpenXml.Math.OfficeMath; @@ -17,7 +12,7 @@ using Text = DocumentFormat.OpenXml.Wordprocessing.Text; namespace OfficeIMO.Word { - public partial class WordParagraph { + public partial class WordParagraph : WordElement { internal WordDocument _document; internal Paragraph _paragraph; @@ -55,15 +50,21 @@ internal string TopParent { public bool IsLastRun { get { - var runs = _run.Parent.ChildElements.OfType(); - return runs.Last() == _run; + if (_run != null) { + var runs = _run.Parent.ChildElements.OfType(); + return runs.Last() == _run; + } + return false; } } public bool IsFirstRun { get { - var runs = _run.Parent.ChildElements.OfType(); - return runs.First() == _run; + if (_run != null) { + var runs = _run.Parent.ChildElements.OfType(); + return runs.First() == _run; + } + return false; } } @@ -75,6 +76,11 @@ internal RunProperties _runProperties { return null; } + set { + if (_run != null) { + _run.RunProperties = value; + } + } } internal Text _text { diff --git a/OfficeIMO.Word/WordSection.PrivateMethods.cs b/OfficeIMO.Word/WordSection.PrivateMethods.cs index 3c06742e..c725cc9a 100644 --- a/OfficeIMO.Word/WordSection.PrivateMethods.cs +++ b/OfficeIMO.Word/WordSection.PrivateMethods.cs @@ -1,15 +1,11 @@ -using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Text; -using System.Linq; -using DocumentFormat.OpenXml; -using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; namespace OfficeIMO.Word { + /// + /// Section in WordDocument + /// public partial class WordSection { - /// /// Converts tables to WordTables /// @@ -34,27 +30,123 @@ internal static List ConvertTableToWordTable(WordDocument document, I internal static List ConvertStdBlockToWatermark(WordDocument document, IEnumerable sdtBlock) { var list = new List(); foreach (SdtBlock block in sdtBlock) { - var sdtContent = block.SdtContentBlock; - if (sdtContent == null) { - continue; + var watermark = ConvertStdBlockToWatermark(document, block); + if (watermark != null) { + list.Add(watermark); + } + } + return list; + } + + /// + /// Converts SdtBlock to WordWatermark if it's a watermark + /// + /// + /// + /// + internal static WordWatermark ConvertStdBlockToWatermark(WordDocument document, SdtBlock sdtBlock) { + var sdtContent = sdtBlock.SdtContentBlock; + if (sdtContent == null) { + return null; + } + var paragraphs = sdtContent.ChildElements.OfType().FirstOrDefault(); + if (paragraphs == null) { + return null; + } + var run = paragraphs.ChildElements.OfType().FirstOrDefault(); + if (run == null) { + return null; + } + var picture = run.ChildElements.OfType().FirstOrDefault(); + if (picture == null) { + return null; + } + return new WordWatermark(document, sdtBlock); + } + + /// + /// Converts StdBlock to WordCoverPage + /// + /// + /// + /// + internal static WordCoverPage ConvertStdBlockToCoverPage(WordDocument document, IEnumerable sdtBlocks) { + foreach (var sdtBlock in sdtBlocks) { + var sdtProperties = sdtBlock?.ChildElements.OfType().FirstOrDefault(); + var docPartObject = sdtProperties?.ChildElements.OfType().FirstOrDefault(); + var docPartGallery = docPartObject?.ChildElements.OfType().FirstOrDefault(); + + if (docPartGallery != null && docPartGallery.Val == "Cover Pages") { + return new WordCoverPage(document, sdtBlock); } - var paragraphs = sdtContent.ChildElements.OfType().FirstOrDefault(); - if (paragraphs == null) { - continue; + } + + return null; + } + + /// + /// Converts StdBlock to WordTableOfContent + /// + /// + /// + /// + internal static WordTableOfContent ConvertStdBlockToTableOfContent(WordDocument document, IEnumerable sdtBlocks) { + foreach (var sdtBlock in sdtBlocks) { + var sdtProperties = sdtBlock?.ChildElements.OfType().FirstOrDefault(); + var docPartObject = sdtProperties?.ChildElements.OfType().FirstOrDefault(); + var docPartGallery = docPartObject?.ChildElements.OfType().FirstOrDefault(); + + if (docPartGallery != null && docPartGallery.Val == "Table of Contents") { + return new WordTableOfContent(document, sdtBlock); } - var run = paragraphs.ChildElements.OfType().FirstOrDefault(); - if (run == null) { - continue; + } + return null; + } + + /// + /// Converts StdBlock to WordElement + /// + /// + /// + /// + internal static WordElement ConvertStdBlockToWordElements(WordDocument document, SdtBlock sdtBlock) { + var sdtProperties = sdtBlock?.ChildElements.OfType().FirstOrDefault(); + var docPartObject = sdtProperties?.ChildElements.OfType().FirstOrDefault(); + var docPartGallery = docPartObject?.ChildElements.OfType().FirstOrDefault(); + + if (docPartGallery != null && docPartGallery.Val == "Cover Pages") { + return new WordCoverPage(document, sdtBlock); + } else if (docPartGallery != null && docPartGallery.Val == "Table of Contents") { + return new WordTableOfContent(document, sdtBlock); + } else { + var watermark = ConvertStdBlockToWatermark(document, sdtBlock); + if (watermark != null) { + return watermark; + } else { + Debug.WriteLine("Please implement me! " + docPartGallery.Val); } - var picture = run.ChildElements.OfType().FirstOrDefault(); - if (picture == null) { - continue; + } + return null; + } + + /// + /// Converts StdBlock to WordElement + /// + /// + /// + /// + internal static List ConvertStdBlockToWordElements(WordDocument document, IEnumerable sdtBlocks) { + var list = new List(); + foreach (var sdtBlock in sdtBlocks) { + var element = ConvertStdBlockToWordElements(document, sdtBlock); + if (element != null) { + list.Add(element); } - list.Add(new WordWatermark(document, block)); } return list; } + /// /// Converts paragraphs to WordParagraphs /// @@ -63,74 +155,85 @@ internal static List ConvertStdBlockToWatermark(WordDocument docu /// internal static List ConvertParagraphsToWordParagraphs(WordDocument document, IEnumerable paragraphs) { var list = new List(); - Dictionary bookmarks = new Dictionary(); foreach (Paragraph paragraph in paragraphs) { - var childElements = paragraph.ChildElements; - if (childElements.Count == 1 && childElements[0] is ParagraphProperties) { - // basically empty, we still want to track it, but that's about it - list.Add(new WordParagraph(document, paragraph)); - } else if (childElements.Any()) { - List runList = new List(); - bool foundField = false; - foreach (var element in paragraph.ChildElements) { - WordParagraph wordParagraph; - if (element is Run) { - var run = (Run)element; - var fieldChar = run.ChildElements.OfType().FirstOrDefault(); - if (foundField == true) { - if (fieldChar != null && fieldChar.FieldCharType == FieldCharValues.End) { - foundField = false; - runList.Add(run); - wordParagraph = new WordParagraph(document, paragraph, runList); - list.Add(wordParagraph); - } else { + list.AddRange(ConvertParagraphToWordParagraphs(document, paragraph)); + } + + return list; + } + + /// + /// Converts paragraph to WordParagraphs + /// + /// + /// + /// + internal static List ConvertParagraphToWordParagraphs(WordDocument document, Paragraph paragraph) { + var list = new List(); + var childElements = paragraph.ChildElements; + if (childElements.Count == 1 && childElements[0] is ParagraphProperties) { + // basically empty, we still want to track it, but that's about it + list.Add(new WordParagraph(document, paragraph)); + } else if (childElements.Any()) { + List runList = new List(); + bool foundField = false; + foreach (var element in paragraph.ChildElements) { + WordParagraph wordParagraph; + if (element is Run) { + var run = (Run)element; + var fieldChar = run.ChildElements.OfType().FirstOrDefault(); + if (foundField == true) { + if (fieldChar != null && fieldChar.FieldCharType == FieldCharValues.End) { + foundField = false; + runList.Add(run); + wordParagraph = new WordParagraph(document, paragraph, runList); + list.Add(wordParagraph); + } else { + runList.Add(run); + } + } else { + if (fieldChar != null) { + if (fieldChar.FieldCharType == FieldCharValues.Begin) { runList.Add(run); + foundField = true; } } else { - if (fieldChar != null) { - if (fieldChar.FieldCharType == FieldCharValues.Begin) { - runList.Add(run); - foundField = true; - } - } else { - wordParagraph = new WordParagraph(document, paragraph, run); - list.Add(wordParagraph); - } + wordParagraph = new WordParagraph(document, paragraph, run); + list.Add(wordParagraph); } - } else if (element is Hyperlink) { - wordParagraph = new WordParagraph(document, paragraph, (Hyperlink)element); - list.Add(wordParagraph); - } else if (element is SimpleField) { - wordParagraph = new WordParagraph(document, paragraph, (SimpleField)element); - list.Add(wordParagraph); - } else if (element is BookmarkStart) { - wordParagraph = new WordParagraph(document, paragraph, (BookmarkStart)element); - list.Add(wordParagraph); - } else if (element is BookmarkEnd) { - // not needed, we will search for matching bookmark end in the bookmark (i guess) - } else if (element is DocumentFormat.OpenXml.Math.OfficeMath) { - wordParagraph = new WordParagraph(document, paragraph, (DocumentFormat.OpenXml.Math.OfficeMath)element); - list.Add(wordParagraph); - } else if (element is DocumentFormat.OpenXml.Math.Paragraph) { - wordParagraph = new WordParagraph(document, paragraph, (DocumentFormat.OpenXml.Math.Paragraph)element); - list.Add(wordParagraph); - } else if (element is SdtRun) { - list.Add(new WordParagraph(document, paragraph, (SdtRun)element)); - } else if (element is ProofError) { - - } else if (element is ParagraphProperties) { - - } else { - Debug.WriteLine("Please implement me! " + element.GetType().Name); } + } else if (element is Hyperlink) { + wordParagraph = new WordParagraph(document, paragraph, (Hyperlink)element); + list.Add(wordParagraph); + } else if (element is SimpleField) { + wordParagraph = new WordParagraph(document, paragraph, (SimpleField)element); + list.Add(wordParagraph); + } else if (element is BookmarkStart) { + wordParagraph = new WordParagraph(document, paragraph, (BookmarkStart)element); + list.Add(wordParagraph); + } else if (element is BookmarkEnd) { + // not needed, we will search for matching bookmark end in the bookmark (i guess) + } else if (element is DocumentFormat.OpenXml.Math.OfficeMath) { + wordParagraph = new WordParagraph(document, paragraph, (DocumentFormat.OpenXml.Math.OfficeMath)element); + list.Add(wordParagraph); + } else if (element is DocumentFormat.OpenXml.Math.Paragraph) { + wordParagraph = new WordParagraph(document, paragraph, (DocumentFormat.OpenXml.Math.Paragraph)element); + list.Add(wordParagraph); + } else if (element is SdtRun) { + list.Add(new WordParagraph(document, paragraph, (SdtRun)element)); + } else if (element is ProofError) { + + } else if (element is ParagraphProperties) { + + } else { + Debug.WriteLine("Please implement me! " + element.GetType().Name); } - } else { - // add empty word paragraph - list.Add(new WordParagraph(document, paragraph)); } + } else { + // add empty word paragraph + list.Add(new WordParagraph(document, paragraph)); } - return list; } @@ -175,7 +278,6 @@ private List GetParagraphsList() { return ConvertParagraphsToWordParagraphs(_document, dataSections[foundCount]); } - /// /// This method gets all lists for given document (for all sections) /// @@ -290,6 +392,105 @@ private List GetEmbeddedDocumentsList() { return dataSections[foundCount]; } + /// + /// Gets list of word elements in given section + /// + /// + private List GetWordElements() { + Dictionary> dataSections = new Dictionary>(); + var count = 0; + + dataSections[count] = new List(); + var foundCount = -1; + if (_wordprocessingDocument.MainDocumentPart.Document != null) { + if (_wordprocessingDocument.MainDocumentPart.Document.Body != null) { + var listElements = _wordprocessingDocument.MainDocumentPart.Document.Body.ChildElements; + foreach (var element in listElements) { + if (element is Paragraph) { + // converts Paragraph to WordParagraph + Paragraph paragraph = (Paragraph)element; + if (paragraph.ParagraphProperties != null && paragraph.ParagraphProperties.SectionProperties != null) { + if (paragraph.ParagraphProperties.SectionProperties == _sectionProperties) { + foundCount = count; + } + + count++; + dataSections[count] = new List(); + } else { + dataSections[count].AddRange(ConvertParagraphToWordParagraphs(_document, paragraph)); + } + } else if (element is AltChunk) { + // converts AltChunk to WordEmbeddedDocument + WordEmbeddedDocument wordEmbeddedDocument = new WordEmbeddedDocument(_document, (AltChunk)element); + dataSections[count].Add(wordEmbeddedDocument); + } else if (element is SdtBlock) { + // converts SdtBlock to WordElement + dataSections[count].Add(ConvertStdBlockToWordElements(_document, (SdtBlock)element)); + } else if (element is Table) { + // converts Table to WordTable + WordTable wordTable = new WordTable(_document, (Table)element); + dataSections[count].Add(wordTable); + } + } + + var sectionProperties = _wordprocessingDocument.MainDocumentPart.Document.Body.ChildElements.OfType().FirstOrDefault(); + if (sectionProperties == _sectionProperties) { + foundCount = count; + } + } + } + + return dataSections[foundCount]; + } + + /// + /// Gets list of word elements by type in given section + /// + /// + private List GetWordElementsByType() { + var listElements = GetWordElements(); + var additionalElements = new List(); + + foreach (var element in listElements) { + if (element is WordParagraph wordParagraph) { + if (wordParagraph.IsBookmark) { + additionalElements.Add(wordParagraph.Bookmark); + } else if (wordParagraph.IsBreak) { + additionalElements.Add(wordParagraph.Break); + } else if (wordParagraph.IsChart) { + additionalElements.Add(wordParagraph.Chart); + } else if (wordParagraph.IsEndNote) { + additionalElements.Add(wordParagraph.EndNote); + } else if (wordParagraph.IsEquation) { + additionalElements.Add(wordParagraph.Equation); + } else if (wordParagraph.IsField) { + additionalElements.Add(wordParagraph.Field); + } else if (wordParagraph.IsFootNote) { + additionalElements.Add(wordParagraph.FootNote); + } else if (wordParagraph.IsImage) { + additionalElements.Add(wordParagraph.Image); + } else if (wordParagraph.IsListItem) { + additionalElements.Add(wordParagraph); + } else if (wordParagraph.IsPageBreak) { + additionalElements.Add(wordParagraph.PageBreak); + } else if (wordParagraph.IsStructuredDocumentTag) { + additionalElements.Add(wordParagraph.StructuredDocumentTag); + } else if (wordParagraph.IsTab) { + additionalElements.Add(wordParagraph.Tab); + } else if (wordParagraph.IsTextBox) { + additionalElements.Add(wordParagraph.TextBox); + } else if (wordParagraph.IsHyperLink) { + additionalElements.Add(wordParagraph.Hyperlink); + } else { + additionalElements.Add(wordParagraph); + } + } else { + additionalElements.Add(element); + } + } + return additionalElements; + } + /// /// Gets list of watermarks in given section /// @@ -330,7 +531,7 @@ private List GetSdtBlockList() { /// /// This method moves headers and footers and title page to section before it. - /// It also copies copies all other parts of sections (PageSize,PageMargin and others) to section before it. + /// It also copies all other parts of sections (PageSize,PageMargin and others) to section before it. /// This is because headers/footers when applied to section apply to the rest of the document /// unless there are headers/footers on next section. /// On the other hand page size doesn't apply to other sections diff --git a/OfficeIMO.Word/WordSection.cs b/OfficeIMO.Word/WordSection.cs index 29f7e94e..e1c9a945 100644 --- a/OfficeIMO.Word/WordSection.cs +++ b/OfficeIMO.Word/WordSection.cs @@ -7,6 +7,15 @@ namespace OfficeIMO.Word { public partial class WordSection { + /// + /// Provides a list of all elements within the section including paragraphs, tables, images, etc. + /// + public List Elements => GetWordElements(); + + /// + /// Provides a list of all elements within the section including paragraphs, tables, images, etc. + /// + public List ElementsByType => GetWordElementsByType(); /// /// Provides a list of all paragraphs within the section diff --git a/OfficeIMO.Word/WordStructuredDocumentTag.cs b/OfficeIMO.Word/WordStructuredDocumentTag.cs index c2fef2ef..c034e44d 100644 --- a/OfficeIMO.Word/WordStructuredDocumentTag.cs +++ b/OfficeIMO.Word/WordStructuredDocumentTag.cs @@ -1,11 +1,11 @@ -using DocumentFormat.OpenXml.Wordprocessing; +using DocumentFormat.OpenXml.Wordprocessing; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace OfficeIMO.Word { - public class WordStructuredDocumentTag { + public class WordStructuredDocumentTag : WordElement { private WordDocument _document; private Paragraph _paragraph; private SdtRun _stdRun; diff --git a/OfficeIMO.Word/WordTabChar.cs b/OfficeIMO.Word/WordTabChar.cs index 2459acb1..0c5abeea 100644 --- a/OfficeIMO.Word/WordTabChar.cs +++ b/OfficeIMO.Word/WordTabChar.cs @@ -5,7 +5,7 @@ using DocumentFormat.OpenXml.Wordprocessing; namespace OfficeIMO.Word { - public class WordTabChar { + public class WordTabChar : WordElement { private WordDocument _document; private readonly Paragraph _paragraph; private readonly Run _run; diff --git a/OfficeIMO.Word/WordTable.Properties.cs b/OfficeIMO.Word/WordTable.Properties.cs index 569c9f8e..1988fc63 100644 --- a/OfficeIMO.Word/WordTable.Properties.cs +++ b/OfficeIMO.Word/WordTable.Properties.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using DocumentFormat.OpenXml.Wordprocessing; @@ -169,8 +169,7 @@ public List Cells { public bool HasNestedTables { get { foreach (var cell in this.Cells) { - var list = cell._tableCell.Descendants().ToList(); - if (list.Count > 0) { + if (cell.HasNestedTables) { return true; } } @@ -185,10 +184,7 @@ public List NestedTables { get { var listReturn = new List(); foreach (var cell in this.Cells) { - var list = cell._tableCell.Descendants
().ToList(); - foreach (var table in list) { - listReturn.Add(new WordTable(this._document, table)); - } + listReturn.AddRange(cell.NestedTables); } return listReturn; } @@ -224,4 +220,4 @@ public WordTable ParentTable { } } } -} \ No newline at end of file +} diff --git a/OfficeIMO.Word/WordTable.cs b/OfficeIMO.Word/WordTable.cs index ab49283b..2b068cd2 100644 --- a/OfficeIMO.Word/WordTable.cs +++ b/OfficeIMO.Word/WordTable.cs @@ -5,7 +5,7 @@ using DocumentFormat.OpenXml.Wordprocessing; namespace OfficeIMO.Word { - public partial class WordTable { + public partial class WordTable : WordElement { public List Paragraphs { get { List list = new List(); diff --git a/OfficeIMO.Word/WordTableCell.cs b/OfficeIMO.Word/WordTableCell.cs index d738552d..405ca42e 100644 --- a/OfficeIMO.Word/WordTableCell.cs +++ b/OfficeIMO.Word/WordTableCell.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; using DocumentFormat.OpenXml.Wordprocessing; using Color = SixLabors.ImageSharp.Color; @@ -459,5 +454,28 @@ public WordList AddList(WordListStyle style) { wordList.AddList(style); return wordList; } + + /// + /// Gets information whether the cell contains other nested tables + /// + public bool HasNestedTables { + get { + return _tableCell.Descendants
().Count() > 0; + } + } + + /// + /// Get all nested tables in the cell + /// + public List NestedTables { + get { + var listReturn = new List(); + var list = _tableCell.Descendants
().ToList(); + foreach (var table in list) { + listReturn.Add(new WordTable(this._document, table)); + } + return listReturn; + } + } } } diff --git a/OfficeIMO.Word/WordTableOfContent.cs b/OfficeIMO.Word/WordTableOfContent.cs index 6a732f6e..910454d7 100644 --- a/OfficeIMO.Word/WordTableOfContent.cs +++ b/OfficeIMO.Word/WordTableOfContent.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using DocumentFormat.OpenXml.ExtendedProperties; using DocumentFormat.OpenXml.Wordprocessing; namespace OfficeIMO.Word { @@ -11,7 +6,7 @@ public enum TableOfContentStyle { Template2 } - public class WordTableOfContent { + public class WordTableOfContent : WordElement { private readonly WordDocument _document; private readonly SdtBlock _sdtBlock; diff --git a/OfficeIMO.Word/WordTextBox.cs b/OfficeIMO.Word/WordTextBox.cs index 6d853c2d..6a00a670 100644 --- a/OfficeIMO.Word/WordTextBox.cs +++ b/OfficeIMO.Word/WordTextBox.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; namespace OfficeIMO.Word { - public class WordTextBox { + public class WordTextBox : WordElement { private readonly WordDocument _document; private readonly WordParagraph _wordParagraph; private readonly WordHeaderFooter _headerFooter; diff --git a/OfficeIMO.Word/WordWatermark.cs b/OfficeIMO.Word/WordWatermark.cs index 6152c3e4..83856824 100644 --- a/OfficeIMO.Word/WordWatermark.cs +++ b/OfficeIMO.Word/WordWatermark.cs @@ -22,7 +22,7 @@ public enum WordWatermarkStyle { Image } - public class WordWatermark { + public class WordWatermark : WordElement { private WordDocument _document; private SdtBlock _sdtBlock; private WordHeader _wordHeader;