diff --git a/Src/xWorks/LcmWordGenerator.cs b/Src/xWorks/LcmWordGenerator.cs
index e4e2ec3fc6..117e67fe98 100644
--- a/Src/xWorks/LcmWordGenerator.cs
+++ b/Src/xWorks/LcmWordGenerator.cs
@@ -45,7 +45,7 @@ public class LcmWordGenerator : ILcmContentGenerator, ILcmStylesGenerator
private ReadOnlyPropertyTable _propertyTable;
public static bool IsBidi { get; private set; }
- private static DocFragment MasterFragment { get; set; }
+ private static MasterDocFragment MasterFragment { get; set; }
public LcmWordGenerator(LcmCache cache)
{
@@ -63,7 +63,7 @@ public static void SavePublishedDocx(int[] entryHvos, DictionaryPublicationDecor
{
using (MemoryStream mem = new MemoryStream())
{
- MasterFragment = new DocFragment(mem);
+ MasterFragment = new MasterDocFragment(mem);
var entryCount = entryHvos.Length;
var cssPath = System.IO.Path.ChangeExtension(filePath, "css");
@@ -346,50 +346,55 @@ internal static IFragment GenerateLetterHeaderIfNeeded(ICmObject entry, ref stri
return DocFragment.GenerateLetterHeaderDocFragment(headerTextBuilder.ToString(), WordStylesGenerator.LetterHeadingDisplayName, firstHeader, wsString);
}
- /*
- * DocFragment Region
- */
- #region DocFragment class
- public class DocFragment : IFragment
+ #region MasterDocFragment class
+ ///
+ /// The MasterDocFragment contains the data to write to a docx file. Regular
+ /// DocFragments that are used to build the MasterDocFragment do not need
+ /// this data.
+ ///
+ public class MasterDocFragment : DocFragment
{
internal MemoryStream MemStr { get; }
internal WordprocessingDocument DocFrag { get; }
internal MainDocumentPart mainDocPart { get; }
- internal WP.Body DocBody { get; }
///
- /// Constructs a new memory stream and creates an empty doc fragment
- /// that writes to that stream.
+ /// Initializes the memory stream from the argument and creates
+ /// an empty master doc fragment that writes to that stream.
///
- public DocFragment()
+ public MasterDocFragment(MemoryStream str)
{
- MemStr = new MemoryStream();
- DocFrag = WordprocessingDocument.Open(MemStr, true);
+ MemStr = str;
+ DocFrag = WordprocessingDocument.Open(str, true);
// Initialize the document and body.
mainDocPart = DocFrag.AddMainDocumentPart();
mainDocPart.Document = new WP.Document();
- DocBody = mainDocPart.Document.AppendChild(new WP.Body());
+ mainDocPart.Document.AppendChild(DocBody);
}
+ }
+ #endregion MasterDocFragment class
+
+ /*
+ * DocFragment Region
+ */
+ #region DocFragment class
+ public class DocFragment : IFragment
+ {
+ internal WP.Body DocBody { get; }
+
///
- /// Initializes the memory stream from the argument and creates
- /// an empty doc fragment that writes to that stream.
+ /// Constructs an empty doc fragment that has a Body.
///
- public DocFragment(MemoryStream str)
+ public DocFragment()
{
- MemStr = str;
- DocFrag = WordprocessingDocument.Open(str, true);
-
- // Initialize the document and body.
- mainDocPart = DocFrag.AddMainDocumentPart();
- mainDocPart.Document = new WP.Document();
- DocBody = mainDocPart.Document.AppendChild(new WP.Body());
+ DocBody = new WP.Body();
}
///
- /// Constructs a new memory stream and creates a non-empty doc fragment,
- /// containing the given string, that writes to that stream.
+ /// Constructs a non-empty doc fragment that has a Body which
+ /// contains the given string.
///
public DocFragment(string str) : this()
{
@@ -688,7 +693,7 @@ public void AppendSpace()
public bool IsNullOrEmpty()
{
// A docbody with no children is an empty document.
- if (MemStr == null || DocFrag == null || DocBody == null || !DocBody.HasChildren)
+ if (DocBody == null || !DocBody.HasChildren)
{
return true;
}
@@ -941,7 +946,6 @@ public void Dispose()
public void Flush()
{
- WordFragment.MemStr.Flush();
}
public void Insert(IFragment frag)
@@ -1775,12 +1779,6 @@ public IFragment AddImage(ConfigurableDictionaryNode config, ConfiguredLcmGenera
// calculate the maximum image height from the configuration
var maxHeight = config.Model.Pictures?.Height ?? (picOpts?.MaximumHeight ?? 1.0f);
Drawing image = CreateImage(srcAttribute, partId, maxWidth, maxHeight);
-
- if (imageFrag.DocFrag.MainDocumentPart is null || imageFrag.DocFrag.MainDocumentPart.Document.Body is null)
- {
- throw new ArgumentNullException("MainDocumentPart and/or Body is null.");
- }
-
Run imgRun = new Run();
imgRun.AppendChild(image);
diff --git a/Src/xWorks/xWorksTests/LcmWordGeneratorTests.cs b/Src/xWorks/xWorksTests/LcmWordGeneratorTests.cs
index e5a02c007d..ac6dd31e81 100644
--- a/Src/xWorks/xWorksTests/LcmWordGeneratorTests.cs
+++ b/Src/xWorks/xWorksTests/LcmWordGeneratorTests.cs
@@ -240,8 +240,8 @@ public void GenerateWordDocForEntry_OneSenseWithGlossGeneratesCorrectResult()
//SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(entry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
Console.WriteLine(result);
- AssertThatXmlIn.String(result.mainDocPart.RootElement.OuterXml).HasSpecifiedNumberOfMatchesForXpath(
- "/w:document/w:body/w:p/w:r/w:t[text()='gloss']",
+ AssertThatXmlIn.String(result.DocBody.OuterXml).HasSpecifiedNumberOfMatchesForXpath(
+ "/w:body/w:p/w:r/w:t[text()='gloss']",
1,
WordNamespaceManager);
}
@@ -275,8 +275,8 @@ public void GenerateWordDocForEntry_LineBreaksInBeforeContentWork()
//SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(entry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
Console.WriteLine(result);
- AssertThatXmlIn.String(result?.mainDocPart.RootElement?.OuterXml).HasSpecifiedNumberOfMatchesForXpath(
- "/w:document/w:body/w:p/w:r/w:br[@w:type='textWrapping']",
+ AssertThatXmlIn.String(result?.DocBody?.OuterXml).HasSpecifiedNumberOfMatchesForXpath(
+ "/w:body/w:p/w:r/w:br[@w:type='textWrapping']",
2,
WordNamespaceManager);
}
@@ -327,8 +327,8 @@ public void GenerateUniqueStyleName()
//SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(entry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
- Assert.True(result.mainDocPart.RootElement.OuterXml.Contains("Gloss[lang=en]"));
- Assert.True(result.mainDocPart.RootElement.OuterXml.Contains("Gloss2[lang=en]"));
+ Assert.True(result.DocBody.OuterXml.Contains("Gloss[lang=en]"));
+ Assert.True(result.DocBody.OuterXml.Contains("Gloss2[lang=en]"));
}
[Test]
@@ -385,7 +385,7 @@ public void GenerateSenseNumberData()
// 3. Sense number: 2
// 4. Sense number after text: AFT
const string senseNumberTwoRun = "BEF2AFT";
- Assert.True(result.mainDocPart.RootElement.OuterXml.Contains(senseNumberTwoRun));
+ Assert.True(result.DocBody.OuterXml.Contains(senseNumberTwoRun));
}
[Test]
@@ -438,7 +438,7 @@ public void GenerateBeforeBetweenAfterContent()
//SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
- var outXml = result.mainDocPart.RootElement.OuterXml;
+ var outXml = result.DocBody.OuterXml;
// Before text 'BE1' is before sense number '1' for 'gloss'.
const string beforeFirstSense =
@@ -520,7 +520,7 @@ public void GenerateBeforeBetweenAfterContentWithWSAbbreviation()
//SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
- var outXml = result.mainDocPart.RootElement.OuterXml;
+ var outXml = result.DocBody.OuterXml;
// Before text 'BE3' is after the sense number '1' and before the english abbreviation, which is before 'gloss'.
const string beforeAbbreviation =
@@ -576,7 +576,7 @@ public void GeneratePropertyData()
//SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(entry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
- var outXml = result.mainDocPart.RootElement.OuterXml;
+ var outXml = result.DocBody.OuterXml;
// The property before text 'BE4' is first, followed by the style that is applied to the property, 'DisplayNameBase'.
const string beforeAndStyle = "BE4";
@@ -641,7 +641,7 @@ public void EmbeddedStylesHaveNoExtraSpace()
//SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
- var outXml = result.mainDocPart.RootElement.OuterXml;
+ var outXml = result.DocBody.OuterXml;
// Verify that AREYOUCRAZY appears only once in the output.
var betweenCount = Regex.Matches(outXml, "AREYOUCRAZY").Count;
@@ -688,8 +688,8 @@ public void ReferenceParagraphDisplayNames()
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
// Assert that the references to the paragraph styles use the display names, not the style names.
- Assert.True(result.mainDocPart.RootElement.OuterXml.Contains(MainEntryParagraphDisplayName));
- Assert.True(result.mainDocPart.RootElement.OuterXml.Contains(SensesParagraphDisplayName));
+ Assert.True(result.DocBody.OuterXml.Contains(MainEntryParagraphDisplayName));
+ Assert.True(result.DocBody.OuterXml.Contains(SensesParagraphDisplayName));
}
[Test]
@@ -751,8 +751,8 @@ public void GenerateParagraphForSensesAndSubSenses()
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
// There should be 5 paragraphs, one for the main entry, one for each sense, and one for each subsense.
- AssertThatXmlIn.String(result.mainDocPart.RootElement.OuterXml).HasSpecifiedNumberOfMatchesForXpath(
- "/w:document/w:body/w:p",
+ AssertThatXmlIn.String(result.DocBody.OuterXml).HasSpecifiedNumberOfMatchesForXpath(
+ "/w:body/w:p",
5,
WordNamespaceManager);
}
@@ -815,7 +815,7 @@ public void GenerateBulletsAndNumbering()
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
// There should be two instances of the bulletId and one instance for each of the numberId's.
- string resultStr = result.mainDocPart.RootElement.OuterXml;
+ string resultStr = result.DocBody.OuterXml;
int count1 = Regex.Matches(resultStr, "").Count;
int count2 = Regex.Matches(resultStr, "").Count;
int count3 = Regex.Matches(resultStr, "").Count;
@@ -888,13 +888,13 @@ public void GenerateContinueParagraph()
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
// There should be 3 paragraph styles, one for the main entry, one for the sense, and one for the continuation of the main entry.
- AssertThatXmlIn.String(result.mainDocPart.RootElement.OuterXml).HasSpecifiedNumberOfMatchesForXpath(
- "/w:document/w:body/w:p/w:pPr/w:pStyle",
+ AssertThatXmlIn.String(result.DocBody.OuterXml).HasSpecifiedNumberOfMatchesForXpath(
+ "/w:body/w:p/w:pPr/w:pStyle",
3,
WordNamespaceManager);
// Assert that the continuation paragraph uses the continuation style.
- Assert.True(result.mainDocPart.RootElement.OuterXml.Contains(MainEntryParagraphDisplayName + WordStylesGenerator.EntryStyleContinue));
+ Assert.True(result.DocBody.OuterXml.Contains(MainEntryParagraphDisplayName + WordStylesGenerator.EntryStyleContinue));
}
[Test]