From 29defce05561279293bcc4a20a1c37c6ff5233a7 Mon Sep 17 00:00:00 2001
From: Mark Kidder <83427558+mark-sil@users.noreply.github.com>
Date: Thu, 2 May 2024 15:40:42 -0400
Subject: [PATCH] LT-21761: Fix indenting for the first line after a Table
(#37)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* LT-21761: Fix indenting for the first line after a Table
The first line of an entry typically uses FirstLineIndent to
indented to the left. When we have multiple paragraphs for an
entry (because the entry contains Tables or Pictures)
then we do not want the line following the Table or Picture to
also be indented to the left. We now create a ‘continuation’
style for paragraphs following a table or picture. It is the
same as the original style except it does not use FirstLineIndent.
---
Src/xWorks/LcmWordGenerator.cs | 75 +++++++++++++++++++++++++++++--
Src/xWorks/WordStylesGenerator.cs | 30 +++++++++++--
2 files changed, 98 insertions(+), 7 deletions(-)
diff --git a/Src/xWorks/LcmWordGenerator.cs b/Src/xWorks/LcmWordGenerator.cs
index dbdb300cb9..958ee86c9f 100644
--- a/Src/xWorks/LcmWordGenerator.cs
+++ b/Src/xWorks/LcmWordGenerator.cs
@@ -428,15 +428,56 @@ public void Append(WP.Table table)
}
///
- /// Appends a new run inside the last paragraph of the doc fragment--creates a new paragraph if none exists or if forceNewParagraph is true.
+ /// Appends a new run inside the last paragraph of the doc fragment--creates a new paragraph if none
+ /// exists or if forceNewParagraph is true.
/// The run will be added to the end of the paragraph.
///
/// The run to append.
/// Even if a paragraph exists, force the creation of a new paragraph.
public void AppendToParagraph(IFragment fragToCopy, OpenXmlElement run, bool forceNewParagraph)
{
+ WP.Paragraph lastPar = null;
+
+ if (forceNewParagraph)
+ {
+ // When forcing a new paragraph use a 'continuation' style for the new paragraph.
+ // The continuation style is based on the style used in the last paragraph.
+ string style = null;
+ WP.Paragraph lastParagraph = DocBody.OfType().LastOrDefault();
+ if (lastParagraph != null)
+ {
+ WP.ParagraphProperties paraProps = lastParagraph.OfType().FirstOrDefault();
+ if (paraProps != null)
+ {
+ ParagraphStyleId styleId = paraProps.OfType().FirstOrDefault();
+ if (styleId != null && styleId.Val != null && styleId.Val.Value != null)
+ {
+ if (styleId.Val.Value.EndsWith(WordStylesGenerator.EntryStyleContinue))
+ {
+ style = styleId.Val.Value;
+ }
+ else
+ {
+ style = styleId.Val.Value + WordStylesGenerator.EntryStyleContinue;
+ }
+ }
+ }
+ }
+
+ lastPar = GetNewParagraph();
+ if (!string.IsNullOrEmpty(style))
+ {
+ WP.ParagraphProperties paragraphProps = new WP.ParagraphProperties(
+ new ParagraphStyleId() { Val = style });
+ lastPar.Append(paragraphProps);
+ }
+ }
+ else
+ {
+ lastPar = GetLastParagraph();
+ }
+
// Deep clone the run b/c of its tree of properties and to maintain styles.
- WP.Paragraph lastPar = forceNewParagraph ? GetNewParagraph() : GetLastParagraph();
lastPar.AppendChild(CloneRun(fragToCopy, run));
}
@@ -1059,12 +1100,19 @@ public void EndTable(IFragmentWriter writer, ConfigurableDictionaryNode config)
}
public void StartEntry(IFragmentWriter writer, ConfigurableDictionaryNode config, string className, Guid entryGuid, int index, RecordClerk clerk)
{
- // Each entry starts a new paragraph, and any entry data added will be added within the same paragraph.
+ // Each entry starts a new paragraph, and any entry data added will usually be added within the same paragraph.
+ // The paragraph will end whenever a data type that cannot be in a paragraph is encounter (Tables or Pictures).
+ // A new 'continuation' paragraph will be started after the Table or Picture if there is other data that still
+ // needs to be added to the entry.
// Create a new paragraph for the entry.
DocFragment wordDoc = ((WordFragmentWriter)writer).WordFragment;
WP.Paragraph entryPar = wordDoc.GetNewParagraph();
WP.ParagraphProperties paragraphProps = new WP.ParagraphProperties(new ParagraphStyleId() {Val = config.Style});
entryPar.Append(paragraphProps);
+
+ // Create the 'continuation' style for the entry. This style will be the same as the style for the entry with the only
+ // difference being that it does not contain the first line indenting (since it is a continuation of the same entry).
+ AddStyles(config, true);
}
public void AddEntryData(IFragmentWriter writer, List pieces)
{
@@ -1313,6 +1361,17 @@ public void AddGlobalStyles(DictionaryConfigurationModel model, ReadOnlyProperty
//WordStylesGenerator.GenerateWordStyleForAudioWs(_styleSheet, cache);
}
public string AddStyles(ConfigurableDictionaryNode node)
+ {
+ return AddStyles(node, false);
+ }
+
+ ///
+ /// Generates styles that are needed by this node and adds them to the dictionary.
+ ///
+ /// If true then generate the 'continuation' style for the node.
+ /// If false then generate the regular (non-continuation) styles for the node.
+ ///
+ public string AddStyles(ConfigurableDictionaryNode node, bool addEntryContinuationStyle)
{
// The css className isn't important for the Word export.
// Styles should be stored in the dictionary based on their stylenames.
@@ -1321,7 +1380,15 @@ public string AddStyles(ConfigurableDictionaryNode node)
lock (_styleDictionary)
{
- var styleContent = WordStylesGenerator.CheckRangeOfStylesForEmpties(WordStylesGenerator.GenerateWordStylesFromConfigurationNode(node, className, _propertyTable));
+ Styles styleContent = null;
+ if (addEntryContinuationStyle)
+ {
+ styleContent = WordStylesGenerator.CheckRangeOfStylesForEmpties(WordStylesGenerator.GenerateContinuationWordStyles(node, _propertyTable));
+ }
+ else
+ {
+ styleContent = WordStylesGenerator.CheckRangeOfStylesForEmpties(WordStylesGenerator.GenerateWordStylesFromConfigurationNode(node, className, _propertyTable));
+ }
if (styleContent == null)
return className;
if (!styleContent.Any())
diff --git a/Src/xWorks/WordStylesGenerator.cs b/Src/xWorks/WordStylesGenerator.cs
index e2ea56a62a..782cf25858 100644
--- a/Src/xWorks/WordStylesGenerator.cs
+++ b/Src/xWorks/WordStylesGenerator.cs
@@ -32,6 +32,7 @@ public class WordStylesGenerator
internal const string WritingSystemPrefix = "writingsystemprefix";
internal const string WritingSystemStyleName = "Writing System Abbreviation";
internal const string PictureAndCaptionTextframeStyle = "Image-Textframe-Style";
+ internal const string EntryStyleContinue = "-Continue";
public static Style GenerateLetterHeaderStyle(
ReadOnlyPropertyTable propertyTable, LcmStyleSheet mediatorStyleSheet)
@@ -86,7 +87,7 @@ internal static Style GenerateWordStyleFromLcmStyleSheet(
ConfigurableDictionaryNode node, ReadOnlyPropertyTable propertyTable)
{
return GenerateWordStyleFromLcmStyleSheet(styleName, wsId, node, propertyTable,
- false);
+ false, true);
}
///
@@ -100,10 +101,11 @@ internal static Style GenerateWordStyleFromLcmStyleSheet(
/// writing system id
/// The configuration node to use for generating paragraph margin in context
/// To retrieve styles
+ /// Indicates if the style returned should include FirstLineIndent.
///
internal static Style GenerateWordStyleFromLcmStyleSheet(
string styleName, int wsId, ConfigurableDictionaryNode node,
- ReadOnlyPropertyTable propertyTable, bool calculateFirstSenseStyle)
+ ReadOnlyPropertyTable propertyTable, bool calculateFirstSenseStyle, bool allowFirstLineIndent)
{
var styleSheet = FontHeightAdjuster.StyleSheetFromPropertyTable(propertyTable);
if (styleSheet == null || !styleSheet.Styles.Contains(styleName))
@@ -182,7 +184,10 @@ internal static Style GenerateWordStyleFromLcmStyleSheet(
hangingIndent = firstLineIndentValue;
}
- parProps.Append(new Indentation() { FirstLine = firstLineIndentValue.ToString() });
+ if (allowFirstLineIndent)
+ {
+ parProps.Append(new Indentation() { FirstLine = firstLineIndentValue.ToString() });
+ }
}
if (exportStyleInfo.HasKeepWithNext)
@@ -581,6 +586,25 @@ private static Styles GenerateWordStylesForWritingSystemPrefix(ConfigurableDicti
return styleRules;
}
+ ///
+ /// Create the 'continuation' style for the entry, which is needed when an entry contains multiple paragraphs. This
+ /// style will be used for all but the first paragraph. It is the same as the style for the first paragraph except
+ /// that it does not contain the first line indenting.
+ ///
+ /// Returns the continuation style.
+ internal static Styles GenerateContinuationWordStyles(
+ ConfigurableDictionaryNode node, ReadOnlyPropertyTable propertyTable)
+ {
+ Style contStyle = GenerateWordStyleFromLcmStyleSheet(node.Style, DefaultStyle, node,
+ propertyTable, false, false);
+ contStyle.StyleName.Val = node.Style + EntryStyleContinue;
+ contStyle.StyleId = node.Style + EntryStyleContinue;
+
+ var retStyles = new Styles();
+ retStyles.AppendChild(contStyle.CloneNode(true));
+ return retStyles;
+ }
+
///
/// Builds the word styles for font info properties using the writing system overrides
///