Skip to content

Commit

Permalink
Add BasedOn style property and fix duplicate styles (#32)
Browse files Browse the repository at this point in the history
- Add based on property when generating styles from LCM
stylesheet that have based on specified in FLEx. (LT-21769)

- Edit styleDictionary to store individual styles
instead of groups of styles.

- Revise AddStyles so it adds each style one time only,
using the stylenames instead of css classes as the
dictionary keys.

NOTE: In the Word export, the style dictionary should save
each style individually rather than a collection of
styles associated with a given css class.
Otherwise, any given style may be added to the styles xml
multiple times, once for each css class using that style.

Remaining task:
- Homograph-Number style is still being duplicated. It is
handled in a different function and requires its own fix.
  • Loading branch information
aror92 authored Apr 29, 2024
1 parent c9f0c9c commit 442b37a
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 23 deletions.
46 changes: 25 additions & 21 deletions Src/xWorks/LcmWordGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class LcmWordGenerator : ILcmContentGenerator, ILcmStylesGenerator
{
private LcmCache Cache { get; }
private static Styles _styleSheet { get; set; } = new Styles();
private static Dictionary<string, Styles> _styleDictionary = new Dictionary<string, Styles>();
private static Dictionary<string, Style> _styleDictionary = new Dictionary<string, Style>();
private ReadOnlyPropertyTable _propertyTable;
internal const int maxImageHeightInches = 1;
internal const int maxImageWidthInches = 1;
Expand Down Expand Up @@ -129,17 +129,16 @@ public static void SavePublishedDocx(int[] entryHvos, DictionaryPublicationDecor
stylePart = AddStylesPartToPackage(fragment.DocFrag);

// Add generated styles into the stylesheet from the dictionary
foreach (var stylesItem in _styleDictionary.Values)
foreach (var style in _styleDictionary.Values)
{
foreach (var style in stylesItem.Descendants<Style>())
_styleSheet.AppendChild(style.CloneNode(true));
_styleSheet.AppendChild(style.CloneNode(true));
}

// Clone styles from the stylesheet into the word doc's styles xml
stylePart.Styles = ((Styles)_styleSheet.CloneNode(true));

// clear the dictionary
_styleDictionary = new Dictionary<string, Styles>();
_styleDictionary = new Dictionary<string, Style>();

// clear the styleSheet
_styleSheet = new WP.Styles();
Expand Down Expand Up @@ -1301,32 +1300,37 @@ public void AddGlobalStyles(DictionaryConfigurationModel model, ReadOnlyProperty
}
public string AddStyles(ConfigurableDictionaryNode node)
{
// The css className isn't important for the Word export.
// Styles should be stored in the dictionary based on their stylenames.
// Generate all styles that are needed by this class and add them to the dictionary with their stylename as the key.
var className = $".{CssGenerator.GetClassAttributeForConfig(node)}";

lock (_styleDictionary)
{
var styleContent = WordStylesGenerator.CheckRangeOfStylesForEmpties(WordStylesGenerator.GenerateWordStylesFromConfigurationNode(node, className, _propertyTable));
// TODO: for testing, let it return className even if no styles are non-empty. Eventually, probably want to return null in that case?
if (styleContent == null)
return className;
if (!styleContent.Any())
{
return className;
}
if (!_styleDictionary.ContainsKey(className))
{
_styleDictionary[className] = styleContent;
return className;
}
// If the content is the same, then do nothing
if (WordStylesGenerator.AreStylesEquivalent(_styleDictionary[className], styleContent))

foreach (Style style in styleContent.Descendants<Style>())
{
return className;
string styleName = style.StyleId;
if (!_styleDictionary.ContainsKey(styleName))
{
_styleDictionary[styleName] = style;
}
// If the content is the same, we don't need to do anything--the style is alread in the dictionary.
// But if the content is NOT the same, re-name this style and add it to the dictionary.
else if (!WordStylesGenerator.AreStylesEquivalent(_styleDictionary[styleName], style))
{
// Otherwise get a unique but useful style name and re-name the style
styleName = GetBestUniqueNameForNode(_styleDictionary, node);
style.StyleId = styleName;
style.StyleName = new StyleName() { Val = styleName };
_styleDictionary[styleName] = style;
}
}
// Otherwise get a unique but useful class name and re-generate the style with the new name
className = GetBestUniqueNameForNode(_styleDictionary, node);
_styleDictionary[className] = WordStylesGenerator.CheckRangeOfStylesForEmpties(WordStylesGenerator.GenerateWordStylesFromConfigurationNode(node, className, _propertyTable));
//var styleName = _styleDictionary[className].
return className;
}
}
Expand Down Expand Up @@ -1496,7 +1500,7 @@ public static Drawing CreateImage(WordprocessingDocument doc, string filepath, s
/// have the same class name, but different style content. We want this name to be usefully recognizable.
/// </summary>
/// <returns></returns>
public static string GetBestUniqueNameForNode(Dictionary<string, Styles> styles, ConfigurableDictionaryNode node)
public static string GetBestUniqueNameForNode(Dictionary<string, Style> styles, ConfigurableDictionaryNode node)
{
Guard.AgainstNull(node.Parent, "There should not be duplicate class names at the top of tree.");
// First try appending the parent node classname.
Expand Down
9 changes: 7 additions & 2 deletions Src/xWorks/WordStylesGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ internal static Style GenerateWordStyleFromLcmStyleSheet(
var parProps = new ParagraphProperties();
var runProps = new StyleRunProperties();

if (exportStyleInfo.BasedOnStyle?.Name != null)
exportStyle.BasedOn = new BasedOn() { Val = exportStyleInfo.BasedOnStyle.Name };

// Create paragraph and run styles as specified by exportStyleInfo.
// Only if the style to export is a paragraph style should we create paragraph formatting options like indentation, alignment, border, etc.
if (exportStyleInfo.IsParagraphStyle)
Expand Down Expand Up @@ -456,6 +459,7 @@ private static Style GenerateWordStyleFromWsOptions(ConfigurableDictionaryNode c
wsStyle.Append(new BasedOn() { Val = configNode.Style });

wsStyle.StyleId = configNode.Style + wsString;
wsStyle.StyleName = new StyleName(){ Val = wsStyle.StyleId };

if (!IsEmptyStyle(wsStyle))
return wsStyle;
Expand Down Expand Up @@ -561,6 +565,7 @@ private static Styles GenerateWordStylesForWritingSystemPrefix(ConfigurableDicti
var styleRules = new Styles();
var wsRule1 = GetOnlyCharacterStyle(GenerateWordStyleFromLcmStyleSheet(WritingSystemStyleName, 0, configNode, propertyTable));
wsRule1.StyleId = (string.Format("{0}.{1}", baseSelection, WritingSystemPrefix)).Trim('.');
wsRule1.StyleName = new StyleName() { Val = wsRule1.StyleId };
styleRules = AddRange(styleRules, wsRule1);

// TODO: Determine how to handle after content in Word export (can't add content via a style)
Expand Down Expand Up @@ -871,8 +876,8 @@ public static Styles CheckRangeOfStylesForEmpties(Styles rules)
return null;
}

public static bool AreStylesEquivalent(Styles first,
Styles second)
public static bool AreStylesEquivalent(Style first,
Style second)
{
// OuterXml gets the markup that represents the current element and all of its child elements.
// All styles and style specification added to the styles element will be its children;
Expand Down

0 comments on commit 442b37a

Please sign in to comment.