Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BasedOn style property and fix duplicate styles #32

Merged
merged 2 commits into from
Apr 29, 2024
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
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
Loading