Skip to content

Commit 1b06dec

Browse files
authored
Merge pull request #11 from Hanzalazia131/AlignementUpdate
Enhancements to the paragraph bullets
2 parents 6e0c295 + cdc4450 commit 1b06dec

File tree

2 files changed

+193
-65
lines changed

2 files changed

+193
-65
lines changed

FileFormat.Words/FileFormat.Words.IElements.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ public class Indentation
2121
public double Hanging { get; set; }
2222
}
2323

24+
public enum ParagraphAlignment
25+
{
26+
Left,
27+
Center,
28+
Right,
29+
Justify
30+
}
31+
2432
/// <summary>
2533
/// Represents a paragraph element in a Word document.
2634
/// </summary>
@@ -49,7 +57,7 @@ public class Paragraph : IElement
4957
/// <summary>
5058
/// Gets or Sets Alignment of the word paragraph
5159
/// </summary>
52-
public string Alignment { get; set; }
60+
public ParagraphAlignment Alignment { get; set; }
5361

5462
/// <summary>
5563
/// Gets or Sets Indentation of the word paragraph
@@ -75,6 +83,16 @@ public class Paragraph : IElement
7583
/// Gets or sets whether the paragraph has numbering.
7684
/// </summary>
7785
public bool IsNumbered { get; set; }
86+
87+
/// <summary>
88+
/// Gets or sets whether the paragraph has numbering.
89+
/// </summary>
90+
public bool IsRoman { get; set; }
91+
92+
/// <summary>
93+
/// Gets or sets whether the paragraph has numbering.
94+
/// </summary>
95+
public bool IsAlphabeticNumber { get; set; }
7896

7997
/// <summary>
8098
/// Initializes a new instance of the <see cref="Paragraph"/> class.

FileFormat.Words/OpenXML.Words.cs

Lines changed: 174 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,6 @@ internal class OwDocument
2121
private MemoryStream _ms;
2222
private PKG.MainDocumentPart _mainPart;
2323
private readonly object _lockObject = new object();
24-
public enum ParagraphAlignment
25-
{
26-
Left,
27-
Center,
28-
Right,
29-
Justify
30-
}
3124
private OwDocument()
3225
{
3326
lock (_lockObject)
@@ -40,6 +33,7 @@ private OwDocument()
4033
_mainPart.Document = new WP.Document();
4134
var tmp = new OT.DefaultTemplate();
4235
tmp.CreateMainDocumentPart(_mainPart);
36+
AddNumberingDefinitions(_pkgDocument);
4337
CreateProperties(_pkgDocument);
4438
}
4539
catch (Exception ex)
@@ -138,35 +132,44 @@ internal WP.Paragraph CreateParagraph(FF.Paragraph ffP)
138132
var paragraphStyleId = new WP.ParagraphStyleId { Val = ffP.Style };
139133
paragraphProperties.Append(paragraphStyleId);
140134

141-
if (Enum.TryParse<ParagraphAlignment>(ffP.Alignment, true, out var alignmentEnum))
142-
{
143-
WP.JustificationValues justificationValue = MapAlignmentToJustification(alignmentEnum);
144-
paragraphProperties.Append(new WP.Justification { Val = justificationValue });
145-
}
135+
WP.JustificationValues justificationValue = MapAlignmentToJustification(ffP.Alignment);
136+
paragraphProperties.Append(new WP.Justification { Val = justificationValue });
137+
146138

147139
if (ffP.Indentation != null)
148140
{
149141
SetIndentation(paragraphProperties, ffP.Indentation);
150142
}
151-
152-
if (ffP.IsNumbered)
153-
{
154-
var numberingProperties = new WP.NumberingProperties
155-
{
156-
NumberingId = new WP.NumberingId { Val = ffP.NumberingId },
157-
NumberingLevelReference = new WP.NumberingLevelReference { Val = ffP.NumberingLevel.Value }
158-
};
159-
paragraphProperties.Append(numberingProperties);
160-
}
161143

162-
if (ffP.IsBullet)
144+
if (ffP.IsNumbered || ffP.IsBullet || ffP.IsRoman || ffP.IsAlphabeticNumber)
163145
{
164-
var bulletProperties = new WP.NumberingProperties
146+
var numberingProperties = new WP.NumberingProperties();
147+
var numberingId = new WP.NumberingId();
148+
var numberingLevelReference = new WP.NumberingLevelReference();
149+
150+
if (ffP.IsBullet)
151+
{
152+
numberingId.Val = 1;
153+
numberingLevelReference.Val = ffP.NumberingLevel ?? 0;
154+
}
155+
else if (ffP.IsNumbered)
165156
{
166-
NumberingId = new WP.NumberingId { Val = 1 },
167-
NumberingLevelReference = new WP.NumberingLevelReference { Val = 0 }
168-
};
169-
paragraphProperties.Append(bulletProperties);
157+
numberingId.Val = ffP.NumberingId <= 1 || ffP.NumberingId == null ? 2 : ffP.NumberingId;
158+
numberingLevelReference.Val = ffP.NumberingLevel ?? 0;
159+
}
160+
else if (ffP.IsAlphabeticNumber)
161+
{
162+
numberingId.Val = ffP.NumberingId <= 2 || ffP.NumberingId == null ? 3 : ffP.NumberingId;
163+
numberingLevelReference.Val = ffP.NumberingLevel ?? 0;
164+
}
165+
else if (ffP.IsRoman)
166+
{
167+
numberingId.Val = ffP.NumberingId <= 3 || ffP.NumberingId == null ? 4 : ffP.NumberingId;
168+
numberingLevelReference.Val = ffP.NumberingLevel ?? 0;
169+
}
170+
171+
numberingProperties.Append(numberingId, numberingLevelReference);
172+
paragraphProperties.Append(numberingProperties);
170173
}
171174
wpParagraph.Append(paragraphProperties);
172175
}
@@ -232,6 +235,74 @@ internal WP.Paragraph CreateParagraph(FF.Paragraph ffP)
232235
}
233236
}
234237

238+
internal void AddNumberingDefinitions(PKG.WordprocessingDocument pkgDocument)
239+
{
240+
PKG.NumberingDefinitionsPart numberingPart = pkgDocument.MainDocumentPart.NumberingDefinitionsPart;
241+
if (numberingPart == null)
242+
{
243+
numberingPart = pkgDocument.MainDocumentPart.AddNewPart<PKG.NumberingDefinitionsPart>();
244+
}
245+
246+
WP.Numbering numbering = new WP.Numbering();
247+
248+
WP.AbstractNum abstractNumBulleted = new WP.AbstractNum() { AbstractNumberId = 1 };
249+
WP.AbstractNum abstractNumNumbered = new WP.AbstractNum() { AbstractNumberId = 2 };
250+
WP.AbstractNum abstractNumLetter = new WP.AbstractNum() { AbstractNumberId = 3 };
251+
WP.AbstractNum abstractNumRoman = new WP.AbstractNum() { AbstractNumberId = 4 };
252+
string numberingStyle = "%1.";
253+
for (int i = 0; i < 9; i++)
254+
{
255+
for(int j = 0; j < i; j++)
256+
{
257+
numberingStyle += $"%{i + 1}.";
258+
}
259+
abstractNumBulleted.Append(CreateLevel(i, WP.NumberFormatValues.Bullet, "•"));
260+
abstractNumNumbered.Append(CreateLevel(i, WP.NumberFormatValues.Decimal, numberingStyle));
261+
abstractNumLetter.Append(CreateLevel(i, WP.NumberFormatValues.LowerLetter, $"%{ i + 1 }."));
262+
abstractNumRoman.Append(CreateLevel(i, WP.NumberFormatValues.LowerRoman, $"%{i + 1}."));
263+
}
264+
265+
numbering.Append(abstractNumBulleted);
266+
numbering.Append(abstractNumNumbered);
267+
numbering.Append(abstractNumLetter);
268+
numbering.Append(abstractNumRoman);
269+
270+
WP.NumberingInstance numInstanceBulleted = new WP.NumberingInstance() { NumberID = 1 };
271+
numInstanceBulleted.Append(new WP.AbstractNumId() { Val = abstractNumBulleted.AbstractNumberId });
272+
273+
WP.NumberingInstance numInstanceNumbered = new WP.NumberingInstance() { NumberID = 2 };
274+
numInstanceNumbered.Append(new WP.AbstractNumId() { Val = abstractNumNumbered.AbstractNumberId });
275+
276+
WP.NumberingInstance numInstanceLetter = new WP.NumberingInstance() { NumberID = 3 };
277+
numInstanceLetter.Append(new WP.AbstractNumId() { Val = abstractNumLetter.AbstractNumberId });
278+
279+
WP.NumberingInstance numInstanceRoman = new WP.NumberingInstance() { NumberID = 4 };
280+
numInstanceRoman.Append(new WP.AbstractNumId() { Val = abstractNumRoman.AbstractNumberId });
281+
282+
numbering.Append(numInstanceBulleted);
283+
numbering.Append(numInstanceNumbered);
284+
numbering.Append(numInstanceLetter);
285+
numbering.Append(numInstanceRoman);
286+
287+
numberingPart.Numbering = numbering;
288+
}
289+
290+
private WP.Level CreateLevel(int levelIndex, WP.NumberFormatValues numFormatVal, string levelTextVal)
291+
{
292+
WP.Level level = new WP.Level(
293+
new WP.StartNumberingValue() { Val = 1 },
294+
new WP.NumberingFormat() { Val = numFormatVal },
295+
new WP.LevelText() { Val = levelTextVal },
296+
new WP.LevelJustification() { Val = WP.LevelJustificationValues.Left }
297+
)
298+
{ LevelIndex = levelIndex };
299+
if (numFormatVal == WP.NumberFormatValues.Bullet)
300+
{
301+
level.RemoveAllChildren<WP.StartNumberingValue>();
302+
}
303+
return level;
304+
}
305+
235306
private void SetIndentation(WP.ParagraphProperties paragraphProperties, FF.Indentation ffIndentation)
236307
{
237308
var indentation = new WP.Indentation();
@@ -259,17 +330,17 @@ private void SetIndentation(WP.ParagraphProperties paragraphProperties, FF.Inden
259330
paragraphProperties.Append(indentation);
260331
}
261332

262-
private WP.JustificationValues MapAlignmentToJustification(ParagraphAlignment alignment)
333+
private WP.JustificationValues MapAlignmentToJustification(FF.ParagraphAlignment alignment)
263334
{
264335
switch (alignment)
265336
{
266-
case ParagraphAlignment.Left:
337+
case FF.ParagraphAlignment.Left:
267338
return WP.JustificationValues.Left;
268-
case ParagraphAlignment.Center:
339+
case FF.ParagraphAlignment.Center:
269340
return WP.JustificationValues.Center;
270-
case ParagraphAlignment.Right:
341+
case FF.ParagraphAlignment.Right:
271342
return WP.JustificationValues.Right;
272-
case ParagraphAlignment.Justify:
343+
case FF.ParagraphAlignment.Justify:
273344
return WP.JustificationValues.Both;
274345
default:
275346
return WP.JustificationValues.Left;
@@ -540,43 +611,82 @@ internal FF.Paragraph LoadParagraph(WP.Paragraph wpPara, int id)
540611
if (paraStyleId != null)
541612
{
542613
if (paraStyleId.Val != null) ffP.Style = paraStyleId.Val.Value;
614+
}
615+
}
616+
var numberingProperties = wpPara.ParagraphProperties?.NumberingProperties;
617+
if (numberingProperties != null)
618+
{
619+
var numIdVal = numberingProperties.NumberingId?.Val;
620+
var levelVal = numberingProperties.NumberingLevelReference?.Val;
543621

544-
if (IsBulletStyle(paraStyleId.Val.Value))
622+
// Check if there's a valid numbering id and level reference
623+
if (numIdVal.HasValue && levelVal.HasValue)
624+
{
625+
// Get the numbering part from the document
626+
var numberingPart = _pkgDocument.MainDocumentPart.NumberingDefinitionsPart;
627+
if (numberingPart != null)
545628
{
546-
ffP.IsBullet = true;
629+
// Look for the AbstractNum that matches the numIdVal
630+
var abstractNum = numberingPart.Numbering.Elements<WP.AbstractNum>()
631+
.FirstOrDefault(a => a.AbstractNumberId.Value == numIdVal.Value);
632+
633+
if (abstractNum != null)
634+
{
635+
// Get the level corresponding to the levelVal
636+
var level = abstractNum.Elements<WP.Level>()
637+
.FirstOrDefault(l => l.LevelIndex.Value == levelVal.Value);
638+
639+
// If the level's numbering format is bullet, set IsBullet to true
640+
if (level != null && level.NumberingFormat != null && level.NumberingFormat.Val.Value == WP.NumberFormatValues.Bullet)
641+
{
642+
ffP.IsBullet = true;
643+
ffP.NumberingLevel = levelVal.Value;
644+
}
645+
else if (level != null && level.NumberingFormat != null && level.NumberingFormat.Val.Value == WP.NumberFormatValues.LowerLetter)
646+
{
647+
ffP.IsAlphabeticNumber = true;
648+
ffP.NumberingLevel = levelVal.Value;
649+
}
650+
else if (level != null && level.NumberingFormat != null && level.NumberingFormat.Val.Value == WP.NumberFormatValues.LowerRoman)
651+
{
652+
ffP.IsAlphabeticNumber = true;
653+
ffP.NumberingLevel = levelVal.Value;
654+
}
655+
// If the level's numbering format is not bullet, it's a numbered list
656+
else if (level != null)
657+
{
658+
ffP.IsNumbered = true;
659+
ffP.NumberingLevel = levelVal.Value;
660+
ffP.NumberingId = numIdVal.Value;
661+
}
662+
}
547663
}
548664
}
549-
var numberingProperties = paraProps.Elements<WP.NumberingProperties>().FirstOrDefault();
550-
if (numberingProperties != null)
551-
{
552-
ffP.IsNumbered = true;
553-
ffP.NumberingId = numberingProperties.NumberingId?.Val ?? 0;
554-
ffP.NumberingLevel = numberingProperties.NumberingLevelReference?.Val ?? 0;
555-
}
556665
}
557666
var justificationElement = paraProps.Elements<WP.Justification>().FirstOrDefault();
558667
if (justificationElement != null)
559668
{
560669
ffP.Alignment = MapJustificationToAlignment(justificationElement.Val);
561670
}
562671
var Indentation = paraProps.Elements<WP.Indentation>().FirstOrDefault();
563-
if (Indentation.Left != null)
564-
{
565-
ffP.Indentation.Left = int.Parse(Indentation.Left);
566-
}
567-
if (Indentation.Right != null)
568-
{
569-
ffP.Indentation.Right = int.Parse(Indentation.Right);
570-
}
571-
if (Indentation.Hanging != null)
572-
{
573-
ffP.Indentation.Hanging = int.Parse(Indentation.Hanging);
574-
}
575-
if (Indentation.FirstLine != null)
576-
{
577-
ffP.Indentation.FirstLine = int.Parse(Indentation.FirstLine);
672+
if (Indentation != null) {
673+
if (Indentation.Left != null)
674+
{
675+
ffP.Indentation.Left = int.Parse(Indentation.Left);
676+
}
677+
if (Indentation.Right != null)
678+
{
679+
ffP.Indentation.Right = int.Parse(Indentation.Right);
680+
}
681+
if (Indentation.Hanging != null)
682+
{
683+
ffP.Indentation.Hanging = int.Parse(Indentation.Hanging);
684+
}
685+
if (Indentation.FirstLine != null)
686+
{
687+
ffP.Indentation.FirstLine = int.Parse(Indentation.FirstLine);
688+
}
578689
}
579-
580690
var runs = wpPara.Elements<WP.Run>();
581691

582692
foreach (var wpR in runs)
@@ -613,20 +723,20 @@ private bool IsBulletStyle(string styleId)
613723
return styleId == "BulletStyle";
614724
}
615725

616-
private string MapJustificationToAlignment(WP.JustificationValues justificationValue)
726+
private FF.ParagraphAlignment MapJustificationToAlignment(WP.JustificationValues justificationValue)
617727
{
618728
switch (justificationValue)
619729
{
620730
case WP.JustificationValues.Left:
621-
return "Left";
731+
return FF.ParagraphAlignment.Left;
622732
case WP.JustificationValues.Center:
623-
return "Center";
733+
return FF.ParagraphAlignment.Center;
624734
case WP.JustificationValues.Right:
625-
return "Right";
735+
return FF.ParagraphAlignment.Right;
626736
case WP.JustificationValues.Both:
627-
return "Justify";
737+
return FF.ParagraphAlignment.Justify;
628738
default:
629-
return "Left";
739+
return FF.ParagraphAlignment.Left;
630740
}
631741
}
632742

0 commit comments

Comments
 (0)