Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 32 additions & 34 deletions Src/xWorks/LcmWordGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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");
Expand Down Expand Up @@ -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
/// <summary>
/// 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.
/// </summary>
public class MasterDocFragment : DocFragment
{
internal MemoryStream MemStr { get; }
internal WordprocessingDocument DocFrag { get; }
internal MainDocumentPart mainDocPart { get; }
internal WP.Body DocBody { get; }

/// <summary>
/// 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.
/// </summary>
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; }

/// <summary>
/// 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.
/// </summary>
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();
}

/// <summary>
/// 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.
/// </summary>
public DocFragment(string str) : this()
{
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -941,7 +946,6 @@ public void Dispose()

public void Flush()
{
WordFragment.MemStr.Flush();
}

public void Insert(IFragment frag)
Expand Down Expand Up @@ -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);

Expand Down
38 changes: 19 additions & 19 deletions Src/xWorks/xWorksTests/LcmWordGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -385,7 +385,7 @@ public void GenerateSenseNumberData()
// 3. Sense number: 2
// 4. Sense number after text: AFT
const string senseNumberTwoRun = "<w:t xml:space=\"preserve\">BEF</w:t></w:r><w:r><w:rPr><w:rStyle w:val=\"Sense Number[lang=en]\" /></w:rPr><w:t xml:space=\"preserve\">2</w:t></w:r><w:r><w:rPr><w:rStyle w:val=\"Sense Number-Context[lang=en]\" /></w:rPr><w:t xml:space=\"preserve\">AFT</w:t></w:r>";
Assert.True(result.mainDocPart.RootElement.OuterXml.Contains(senseNumberTwoRun));
Assert.True(result.DocBody.OuterXml.Contains(senseNumberTwoRun));
}

[Test]
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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 = "<w:t xml:space=\"preserve\">BE4</w:t></w:r><w:r><w:rPr><w:rStyle w:val=\"DisplayNameBase[lang=en]\" /></w:rPr>";
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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, "<w:numId w:val=\"1\" />").Count;
int count2 = Regex.Matches(resultStr, "<w:numId w:val=\"2\" />").Count;
int count3 = Regex.Matches(resultStr, "<w:numId w:val=\"3\" />").Count;
Expand Down Expand Up @@ -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]
Expand Down
Loading