From 832787c7b4fb382bf3001e83efb779283f846d1a Mon Sep 17 00:00:00 2001 From: Mark Kidder <83427558+mark-sil@users.noreply.github.com> Date: Thu, 2 May 2024 15:00:36 -0400 Subject: [PATCH 1/2] LT-21674: Use Dictionary-Context style for Before/After (#39) Change-Id: I3c558a1a9337dfa2bf11ae21133fb49df2461f14 --- Src/xWorks/LcmWordGenerator.cs | 44 ++++++++++++++++++++----------- Src/xWorks/WordStylesGenerator.cs | 5 ++++ 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/Src/xWorks/LcmWordGenerator.cs b/Src/xWorks/LcmWordGenerator.cs index 9c4a236771..dbdb300cb9 100644 --- a/Src/xWorks/LcmWordGenerator.cs +++ b/Src/xWorks/LcmWordGenerator.cs @@ -665,21 +665,15 @@ config.DictionaryNodeOptions is IParaOption && // Add Before text, if it is not going to be displayed in it's own paragraph. if (!displayEachInAParagraph && !string.IsNullOrEmpty(config.Before)) { - WP.Text txt = new WP.Text(config.Before); - txt.Space = SpaceProcessingModeValues.Preserve; - var beforeRun = new WP.Run(txt); + var beforeRun = CreateBeforeAfterBetweenRun(config.Before); ((DocFragment)elementContent).DocBody.PrependChild(beforeRun); } // Add After text, if it is not going to be displayed in it's own paragraph. if (!displayEachInAParagraph && !string.IsNullOrEmpty(config.After)) { - WP.Text txt = new WP.Text(config.After); - txt.Space = SpaceProcessingModeValues.Preserve; - var afterRun = new WP.Run(txt); + var afterRun = CreateBeforeAfterBetweenRun(config.After); ((DocFragment)elementContent).DocBody.Append(afterRun); - // To be consistent with the xhtml output, only the after text uses the same style. - DocFragment.LinkStyleOrInheritParentStyle(elementContent, config); } return elementContent; @@ -778,7 +772,8 @@ config.DictionaryNodeOptions is IParaOption && !eachInAParagraph && !string.IsNullOrEmpty(config.Between)) { - ((DocFragment)collData).Append(config.Between); + var betweenRun = CreateBeforeAfterBetweenRun(config.Between); + ((DocFragment)collData).DocBody.Append(betweenRun); } collData.Append(content); @@ -1253,18 +1248,14 @@ public IFragment WriteProcessedSenses(bool isBlock, IFragment senseContent, Conf // Add Before text for the sharedGramInfo. if (!string.IsNullOrEmpty(config.Before)) { - WP.Text txt = new WP.Text(config.Before); - txt.Space = SpaceProcessingModeValues.Preserve; - var beforeRun = new WP.Run(txt); + var beforeRun = CreateBeforeAfterBetweenRun(config.Before); ((DocFragment)sharedGramInfo).DocBody.PrependChild(beforeRun); } // Add After text for the sharedGramInfo. if (!string.IsNullOrEmpty(config.After)) { - WP.Text txt = new WP.Text(config.After); - txt.Space = SpaceProcessingModeValues.Preserve; - var afterRun = new WP.Run(txt); + var afterRun = CreateBeforeAfterBetweenRun(config.After); ((DocFragment)sharedGramInfo).DocBody.Append(afterRun); } @@ -1303,6 +1294,10 @@ public void AddGlobalStyles(DictionaryConfigurationModel model, ReadOnlyProperty if (letterHeaderStyle != null) _styleSheet.Append(letterHeaderStyle); + var beforeAfterBetweenStyle = WordStylesGenerator.GenerateBeforeAfterBetweenStyle(propertyTable); + if (beforeAfterBetweenStyle != null) + _styleSheet.Append(beforeAfterBetweenStyle); + Styles defaultStyles = WordStylesGenerator.GetDefaultWordStyles(propertyTable, propStyleSheet, model); if (defaultStyles != null) { @@ -1533,5 +1528,24 @@ public static string GetBestUniqueNameForNode(Dictionary styles, } return className; } + + /// + /// Creates a BeforeAfterBetween run using the text provided and using the BeforeAfterBetween style. + /// + /// Text for the run. + /// The BeforeAfterBetween run. + private WP.Run CreateBeforeAfterBetweenRun(string text) + { + WP.Run run = new WP.Run(); + WP.RunProperties runProps = + new WP.RunProperties(new RunStyle() { Val = WordStylesGenerator.BeforeAfterBetweenStyleName }); + run.Append(runProps); + + WP.Text txt = new WP.Text(text); + txt.Space = SpaceProcessingModeValues.Preserve; + run.Append(txt); + + return run; + } } } diff --git a/Src/xWorks/WordStylesGenerator.cs b/Src/xWorks/WordStylesGenerator.cs index 90ddcfb63e..e2ea56a62a 100644 --- a/Src/xWorks/WordStylesGenerator.cs +++ b/Src/xWorks/WordStylesGenerator.cs @@ -39,6 +39,11 @@ public static Style GenerateLetterHeaderStyle( return GenerateWordStyleFromLcmStyleSheet(LetterHeadingStyleName, 0, propertyTable); } + public static Style GenerateBeforeAfterBetweenStyle(ReadOnlyPropertyTable propertyTable) + { + return GenerateWordStyleFromLcmStyleSheet(BeforeAfterBetweenStyleName, 0, propertyTable); + } + public static Styles GetDefaultWordStyles(ReadOnlyPropertyTable propertyTable, LcmStyleSheet propStyleSheet, DictionaryConfigurationModel model) { var styles = new Styles(); 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 2/2] 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 ///