novelWriter 2.4b1__py3-none-any.whl → 2.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/METADATA +5 -6
  2. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/RECORD +79 -83
  3. novelwriter/__init__.py +15 -8
  4. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  5. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  6. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  7. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  8. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  9. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  10. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  11. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  12. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  13. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  14. novelwriter/assets/icons/none.svg +4 -0
  15. novelwriter/assets/icons/typicons_dark/icons.conf +2 -2
  16. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
  17. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
  18. novelwriter/assets/icons/typicons_light/icons.conf +2 -2
  19. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
  20. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
  21. novelwriter/assets/manual.pdf +0 -0
  22. novelwriter/assets/sample.zip +0 -0
  23. novelwriter/common.py +11 -3
  24. novelwriter/config.py +12 -4
  25. novelwriter/core/buildsettings.py +7 -7
  26. novelwriter/core/coretools.py +21 -22
  27. novelwriter/core/docbuild.py +2 -2
  28. novelwriter/core/projectxml.py +1 -1
  29. novelwriter/core/spellcheck.py +3 -3
  30. novelwriter/core/status.py +3 -2
  31. novelwriter/core/tokenizer.py +3 -3
  32. novelwriter/core/toodt.py +333 -356
  33. novelwriter/dialogs/about.py +9 -11
  34. novelwriter/dialogs/docmerge.py +17 -14
  35. novelwriter/dialogs/docsplit.py +14 -12
  36. novelwriter/dialogs/editlabel.py +5 -4
  37. novelwriter/dialogs/preferences.py +29 -34
  38. novelwriter/dialogs/projectsettings.py +31 -28
  39. novelwriter/dialogs/quotes.py +10 -9
  40. novelwriter/dialogs/wordlist.py +17 -14
  41. novelwriter/error.py +14 -12
  42. novelwriter/extensions/circularprogress.py +12 -8
  43. novelwriter/extensions/configlayout.py +1 -3
  44. novelwriter/extensions/modified.py +33 -2
  45. novelwriter/extensions/pagedsidebar.py +16 -14
  46. novelwriter/extensions/simpleprogress.py +3 -1
  47. novelwriter/extensions/statusled.py +3 -1
  48. novelwriter/extensions/switch.py +10 -9
  49. novelwriter/extensions/switchbox.py +14 -13
  50. novelwriter/gui/doceditor.py +205 -246
  51. novelwriter/gui/dochighlight.py +26 -9
  52. novelwriter/gui/docviewer.py +55 -59
  53. novelwriter/gui/docviewerpanel.py +16 -13
  54. novelwriter/gui/editordocument.py +4 -4
  55. novelwriter/gui/itemdetails.py +45 -48
  56. novelwriter/gui/mainmenu.py +2 -2
  57. novelwriter/gui/noveltree.py +23 -21
  58. novelwriter/gui/outline.py +93 -94
  59. novelwriter/gui/projtree.py +32 -30
  60. novelwriter/gui/search.py +75 -29
  61. novelwriter/gui/sidebar.py +24 -28
  62. novelwriter/gui/statusbar.py +14 -14
  63. novelwriter/gui/theme.py +61 -39
  64. novelwriter/guimain.py +37 -33
  65. novelwriter/shared.py +21 -9
  66. novelwriter/text/counting.py +1 -0
  67. novelwriter/tools/dictionaries.py +15 -14
  68. novelwriter/tools/lipsum.py +20 -17
  69. novelwriter/tools/manusbuild.py +44 -35
  70. novelwriter/tools/manuscript.py +112 -112
  71. novelwriter/tools/manussettings.py +91 -98
  72. novelwriter/tools/noveldetails.py +20 -18
  73. novelwriter/tools/welcome.py +51 -48
  74. novelwriter/tools/writingstats.py +61 -55
  75. novelwriter/types.py +90 -0
  76. novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +0 -4
  77. novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +0 -4
  78. novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +0 -4
  79. novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +0 -4
  80. novelwriter/core/__init__.py +0 -3
  81. novelwriter/dialogs/__init__.py +0 -3
  82. novelwriter/extensions/__init__.py +0 -3
  83. novelwriter/gui/__init__.py +0 -3
  84. novelwriter/text/__init__.py +0 -3
  85. novelwriter/tools/__init__.py +0 -3
  86. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/LICENSE.md +0 -0
  87. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/WHEEL +0 -0
  88. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/entry_points.txt +0 -0
  89. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/top_level.txt +0 -0
novelwriter/core/toodt.py CHANGED
@@ -60,8 +60,7 @@ for ns, uri in XML_NS.items():
60
60
 
61
61
  def _mkTag(ns: str, tag: str) -> str:
62
62
  """Assemble namespace and tag name."""
63
- uri = XML_NS.get(ns, "")
64
- if uri:
63
+ if uri := XML_NS.get(ns, ""):
65
64
  return f"{{{uri}}}{tag}"
66
65
  logger.warning("Missing xml namespace '%s'", ns)
67
66
  return tag
@@ -127,9 +126,9 @@ class ToOdt(Tokenizer):
127
126
  self._xBody = ET.Element("") # Office body root
128
127
  self._xText = ET.Element("") # Office text root
129
128
 
130
- self._mainPara = {} # User-accessible paragraph styles
131
- self._autoPara = {} # Auto-generated paragraph styles
132
- self._autoText = {} # Auto-generated text styles
129
+ self._mainPara: dict[str, ODTParagraphStyle] = {} # User-accessible paragraph styles
130
+ self._autoPara: dict[str, ODTParagraphStyle] = {} # Auto-generated paragraph styles
131
+ self._autoText: dict[int, ODTTextStyle] = {} # Auto-generated text styles
133
132
 
134
133
  self._errData = [] # List of errors encountered
135
134
 
@@ -204,10 +203,9 @@ class ToOdt(Tokenizer):
204
203
  def setLanguage(self, language: str | None) -> None:
205
204
  """Set language for the document."""
206
205
  if language:
207
- langBits = language.split("_")
208
- self._dLanguage = langBits[0]
209
- if len(langBits) > 1:
210
- self._dCountry = langBits[1]
206
+ lang, _, country = language.partition("_")
207
+ self._dLanguage = lang or self._dLanguage
208
+ self._dCountry = country or self._dCountry
211
209
  return
212
210
 
213
211
  def setColourHeaders(self, state: bool) -> None:
@@ -408,7 +406,7 @@ class ToOdt(Tokenizer):
408
406
  for tType, _, tText, tFormat, tStyle in self._tokens:
409
407
 
410
408
  # Styles
411
- oStyle = ODTParagraphStyle()
409
+ oStyle = ODTParagraphStyle("New")
412
410
  if tStyle is not None:
413
411
  if tStyle & self.A_LEFT:
414
412
  oStyle.setTextAlign("left")
@@ -515,12 +513,11 @@ class ToOdt(Tokenizer):
515
513
  return
516
514
 
517
515
  def closeDocument(self) -> None:
518
- """Pack the styles of the XML document."""
519
- # Build the auto-generated styles
520
- for styleName, styleObj in self._autoPara.values():
521
- styleObj.packXML(self._xAuto, styleName)
522
- for styleName, styleObj in self._autoText.values():
523
- styleObj.packXML(self._xAuto, styleName)
516
+ """Pack the automatic styles of the XML document."""
517
+ for style in self._autoPara.values():
518
+ style.packXML(self._xAuto)
519
+ for style in self._autoText.values():
520
+ style.packXML(self._xAuto)
524
521
  return
525
522
 
526
523
  def saveFlatXML(self, path: str | Path) -> None:
@@ -551,7 +548,7 @@ class ToOdt(Tokenizer):
551
548
  oVers = _mkTag("office", "version")
552
549
  xSett = ET.Element(oRoot, attrib={oVers: X_VERS})
553
550
 
554
- def putInZip(name, xObj, zipObj):
551
+ def putInZip(name: str, xObj: ET.Element, zipObj: ZipFile) -> None:
555
552
  with zipObj.open(name, mode="w") as fObj:
556
553
  xml = ET.ElementTree(xObj)
557
554
  xml.write(fObj, encoding="utf-8", xml_declaration=True)
@@ -574,10 +571,7 @@ class ToOdt(Tokenizer):
574
571
 
575
572
  def _formatSynopsis(self, text: str, synopsis: bool) -> tuple[str, list[tuple[int, int]]]:
576
573
  """Apply formatting to synopsis lines."""
577
- if synopsis:
578
- name = self._localLookup("Synopsis")
579
- else:
580
- name = self._localLookup("Short Description")
574
+ name = self._localLookup("Synopsis" if synopsis else "Short Description")
581
575
  rTxt = f"{name}: {text}"
582
576
  rFmt = [(0, self.FMT_B_B), (len(name) + 1, self.FMT_B_E)]
583
577
  return rTxt, rFmt
@@ -610,8 +604,7 @@ class ToOdt(Tokenizer):
610
604
  tFmt: Sequence[tuple[int, int]] = [], isHead: bool = False, oLevel: str | None = None
611
605
  ) -> None:
612
606
  """Add a text paragraph to the text XML element."""
613
- tAttr = {}
614
- tAttr[_mkTag("text", "style-name")] = self._paraStyle(styleName, oStyle)
607
+ tAttr = {_mkTag("text", "style-name"): self._paraStyle(styleName, oStyle)}
615
608
  if oLevel is not None:
616
609
  tAttr[_mkTag("text", "outline-level")] = oLevel
617
610
 
@@ -693,54 +686,54 @@ class ToOdt(Tokenizer):
693
686
 
694
687
  return
695
688
 
696
- def _paraStyle(self, parName: str, oStyle: ODTParagraphStyle) -> str:
689
+ def _paraStyle(self, mainName: str, modStyle: ODTParagraphStyle) -> str:
697
690
  """Return a name for a style object."""
698
- refStyle = self._mainPara.get(parName, None)
699
- if refStyle is None:
700
- logger.error("Unknown paragraph style '%s'", parName)
691
+ if not (refStyle := self._mainPara.get(mainName)):
692
+ logger.error("Unknown main paragraph style '%s'", mainName)
701
693
  return "Standard"
702
694
 
703
- if not refStyle.checkNew(oStyle):
704
- return parName
695
+ if not refStyle.checkNew(modStyle):
696
+ # The style is unmodified, so we return the main style
697
+ return mainName
705
698
 
706
- oStyle.setParentStyleName(parName)
707
- pID = oStyle.getID()
708
- if pID in self._autoPara:
709
- return self._autoPara[pID][0]
699
+ # The style is modified, so we check if there already is an
700
+ # identical style with the same parent we can use instead
701
+ modStyle.setParentStyleName(mainName)
702
+ if (pID := modStyle.getID()) in self._autoPara:
703
+ return self._autoPara[pID].name
710
704
 
711
- newName = "P%d" % (len(self._autoPara) + 1)
712
- self._autoPara[pID] = (newName, oStyle)
705
+ # If neither of the above hold, we store it as a new style
706
+ modStyle.setName(f"P{len(self._autoPara)+1:d}")
707
+ self._autoPara[pID] = modStyle
713
708
 
714
- return newName
709
+ return modStyle.name
715
710
 
716
711
  def _textStyle(self, hFmt: int) -> str:
717
712
  """Return a text style for a given style code."""
718
713
  if hFmt in self._autoText:
719
- return self._autoText[hFmt][0]
714
+ return self._autoText[hFmt].name
720
715
 
721
- newName = "T%d" % (len(self._autoText) + 1)
722
- newStyle = ODTTextStyle()
716
+ style = ODTTextStyle(f"T{len(self._autoText)+1:d}")
723
717
  if hFmt & X_BLD:
724
- newStyle.setFontWeight("bold")
718
+ style.setFontWeight("bold")
725
719
  if hFmt & X_ITA:
726
- newStyle.setFontStyle("italic")
720
+ style.setFontStyle("italic")
727
721
  if hFmt & X_DEL:
728
- newStyle.setStrikeStyle("solid")
729
- newStyle.setStrikeType("single")
722
+ style.setStrikeStyle("solid")
723
+ style.setStrikeType("single")
730
724
  if hFmt & X_UND:
731
- newStyle.setUnderlineStyle("solid")
732
- newStyle.setUnderlineWidth("auto")
733
- newStyle.setUnderlineColour("font-color")
725
+ style.setUnderlineStyle("solid")
726
+ style.setUnderlineWidth("auto")
727
+ style.setUnderlineColour("font-color")
734
728
  if hFmt & X_MRK:
735
- newStyle.setBackgroundColor(self._markText)
729
+ style.setBackgroundColour(self._markText)
736
730
  if hFmt & X_SUP:
737
- newStyle.setTextPosition("super")
731
+ style.setTextPosition("super")
738
732
  if hFmt & X_SUB:
739
- newStyle.setTextPosition("sub")
740
-
741
- self._autoText[hFmt] = (newName, newStyle)
733
+ style.setTextPosition("sub")
734
+ self._autoText[hFmt] = style
742
735
 
743
- return newName
736
+ return style.name
744
737
 
745
738
  def _emToCm(self, value: float) -> str:
746
739
  """Converts an em value to centimetres."""
@@ -752,298 +745,254 @@ class ToOdt(Tokenizer):
752
745
 
753
746
  def _pageStyles(self) -> None:
754
747
  """Set the default page style."""
755
- tAttr = {}
756
- tAttr[_mkTag("style", "name")] = "PM1"
757
- if self._isFlat:
758
- xPage = ET.SubElement(self._xAuto, _mkTag("style", "page-layout"), attrib=tAttr)
759
- else:
760
- xPage = ET.SubElement(self._xAut2, _mkTag("style", "page-layout"), attrib=tAttr)
761
-
762
- tAttr = {}
763
- tAttr[_mkTag("fo", "page-width")] = self._mDocWidth
764
- tAttr[_mkTag("fo", "page-height")] = self._mDocHeight
765
- tAttr[_mkTag("fo", "margin-top")] = self._mDocTop
766
- tAttr[_mkTag("fo", "margin-bottom")] = self._mDocBtm
767
- tAttr[_mkTag("fo", "margin-left")] = self._mDocLeft
768
- tAttr[_mkTag("fo", "margin-right")] = self._mDocRight
769
- tAttr[_mkTag("fo", "print-orientation")] = "portrait"
770
- ET.SubElement(xPage, _mkTag("style", "page-layout-properties"), attrib=tAttr)
748
+ xPage = ET.SubElement(
749
+ self._xAuto if self._isFlat else self._xAut2,
750
+ _mkTag("style", "page-layout"),
751
+ attrib={_mkTag("style", "name"): "PM1"}
752
+ )
753
+ ET.SubElement(xPage, _mkTag("style", "page-layout-properties"), attrib={
754
+ _mkTag("fo", "page-width"): self._mDocWidth,
755
+ _mkTag("fo", "page-height"): self._mDocHeight,
756
+ _mkTag("fo", "margin-top"): self._mDocTop,
757
+ _mkTag("fo", "margin-bottom"): self._mDocBtm,
758
+ _mkTag("fo", "margin-left"): self._mDocLeft,
759
+ _mkTag("fo", "margin-right"): self._mDocRight,
760
+ _mkTag("fo", "print-orientation"): "portrait",
761
+ })
771
762
 
772
763
  xHead = ET.SubElement(xPage, _mkTag("style", "header-style"))
773
-
774
- tAttr = {}
775
- tAttr[_mkTag("fo", "min-height")] = "0.600cm"
776
- tAttr[_mkTag("fo", "margin-left")] = "0.000cm"
777
- tAttr[_mkTag("fo", "margin-right")] = "0.000cm"
778
- tAttr[_mkTag("fo", "margin-bottom")] = "0.500cm"
779
- ET.SubElement(xHead, _mkTag("style", "header-footer-properties"), attrib=tAttr)
764
+ ET.SubElement(xHead, _mkTag("style", "header-footer-properties"), attrib={
765
+ _mkTag("fo", "min-height"): "0.600cm",
766
+ _mkTag("fo", "margin-left"): "0.000cm",
767
+ _mkTag("fo", "margin-right"): "0.000cm",
768
+ _mkTag("fo", "margin-bottom"): "0.500cm",
769
+ })
780
770
 
781
771
  return
782
772
 
783
773
  def _defaultStyles(self) -> None:
784
774
  """Set the default styles."""
785
775
  # Add Paragraph Family Style
786
- # ==========================
787
-
788
- tAttr = {}
789
- tAttr[_mkTag("style", "family")] = "paragraph"
790
- xStyl = ET.SubElement(self._xStyl, _mkTag("style", "default-style"), attrib=tAttr)
791
-
792
- tAttr = {}
793
- tAttr[_mkTag("style", "line-break")] = "strict"
794
- tAttr[_mkTag("style", "tab-stop-distance")] = "1.251cm"
795
- tAttr[_mkTag("style", "writing-mode")] = "page"
796
- ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=tAttr)
797
-
798
- tAttr = {}
799
- tAttr[_mkTag("style", "font-name")] = self._textFont
800
- tAttr[_mkTag("fo", "font-family")] = self._fontFamily
801
- tAttr[_mkTag("fo", "font-size")] = self._fSizeText
802
- tAttr[_mkTag("fo", "language")] = self._dLanguage
803
- tAttr[_mkTag("fo", "country")] = self._dCountry
804
- ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=tAttr)
776
+ xStyl = ET.SubElement(self._xStyl, _mkTag("style", "default-style"), attrib={
777
+ _mkTag("style", "family"): "paragraph",
778
+ })
779
+ ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib={
780
+ _mkTag("style", "line-break"): "strict",
781
+ _mkTag("style", "tab-stop-distance"): "1.251cm",
782
+ _mkTag("style", "writing-mode"): "page",
783
+ })
784
+ ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={
785
+ _mkTag("style", "font-name"): self._textFont,
786
+ _mkTag("fo", "font-family"): self._fontFamily,
787
+ _mkTag("fo", "font-size"): self._fSizeText,
788
+ _mkTag("fo", "language"): self._dLanguage,
789
+ _mkTag("fo", "country"): self._dCountry,
790
+ })
805
791
 
806
792
  # Add Standard Paragraph Style
807
- # ============================
808
-
809
- tAttr = {}
810
- tAttr[_mkTag("style", "name")] = "Standard"
811
- tAttr[_mkTag("style", "family")] = "paragraph"
812
- tAttr[_mkTag("style", "class")] = "text"
813
- xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=tAttr)
814
-
815
- tAttr = {}
816
- tAttr[_mkTag("style", "font-name")] = self._textFont
817
- tAttr[_mkTag("fo", "font-family")] = self._fontFamily
818
- tAttr[_mkTag("fo", "font-size")] = self._fSizeText
819
- ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=tAttr)
793
+ xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib={
794
+ _mkTag("style", "name"): "Standard",
795
+ _mkTag("style", "family"): "paragraph",
796
+ _mkTag("style", "class"): "text",
797
+ })
798
+ ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={
799
+ _mkTag("style", "font-name"): self._textFont,
800
+ _mkTag("fo", "font-family"): self._fontFamily,
801
+ _mkTag("fo", "font-size"): self._fSizeText,
802
+ })
820
803
 
821
804
  # Add Default Heading Style
822
- # =========================
823
-
824
- tAttr = {}
825
- tAttr[_mkTag("style", "name")] = "Heading"
826
- tAttr[_mkTag("style", "family")] = "paragraph"
827
- tAttr[_mkTag("style", "parent-style-name")] = "Standard"
828
- tAttr[_mkTag("style", "next-style-name")] = "Text_20_body"
829
- tAttr[_mkTag("style", "class")] = "text"
830
- xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=tAttr)
831
-
832
- tAttr = {}
833
- tAttr[_mkTag("fo", "margin-top")] = self._mTopHead
834
- tAttr[_mkTag("fo", "margin-bottom")] = self._mBotHead
835
- tAttr[_mkTag("fo", "keep-with-next")] = "always"
836
- ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=tAttr)
837
-
838
- tAttr = {}
839
- tAttr[_mkTag("style", "font-name")] = self._textFont
840
- tAttr[_mkTag("fo", "font-family")] = self._fontFamily
841
- tAttr[_mkTag("fo", "font-size")] = self._fSizeHead
842
- ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=tAttr)
805
+ xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib={
806
+ _mkTag("style", "name"): "Heading",
807
+ _mkTag("style", "family"): "paragraph",
808
+ _mkTag("style", "parent-style-name"): "Standard",
809
+ _mkTag("style", "next-style-name"): "Text_20_body",
810
+ _mkTag("style", "class"): "text",
811
+ })
812
+ ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib={
813
+ _mkTag("fo", "margin-top"): self._mTopHead,
814
+ _mkTag("fo", "margin-bottom"): self._mBotHead,
815
+ _mkTag("fo", "keep-with-next"): "always",
816
+ })
817
+ ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={
818
+ _mkTag("style", "font-name"): self._textFont,
819
+ _mkTag("fo", "font-family"): self._fontFamily,
820
+ _mkTag("fo", "font-size"): self._fSizeHead,
821
+ })
843
822
 
844
823
  # Add Header and Footer Styles
845
- # ============================
846
- tAttr = {}
847
- tAttr[_mkTag("style", "name")] = "Header_20_and_20_Footer"
848
- tAttr[_mkTag("style", "display-name")] = "Header and Footer"
849
- tAttr[_mkTag("style", "family")] = "paragraph"
850
- tAttr[_mkTag("style", "parent-style-name")] = "Standard"
851
- tAttr[_mkTag("style", "class")] = "extra"
852
- ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=tAttr)
824
+ ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib={
825
+ _mkTag("style", "name"): "Header_20_and_20_Footer",
826
+ _mkTag("style", "display-name"): "Header and Footer",
827
+ _mkTag("style", "family"): "paragraph",
828
+ _mkTag("style", "parent-style-name"): "Standard",
829
+ _mkTag("style", "class"): "extra",
830
+ })
853
831
 
854
832
  return
855
833
 
856
834
  def _useableStyles(self) -> None:
857
835
  """Set the usable styles."""
858
836
  # Add Text Body Style
859
- # ===================
860
-
861
- oStyle = ODTParagraphStyle()
862
- oStyle.setDisplayName("Text body")
863
- oStyle.setParentStyleName("Standard")
864
- oStyle.setClass("text")
865
- oStyle.setMarginTop(self._mTopText)
866
- oStyle.setMarginBottom(self._mBotText)
867
- oStyle.setLineHeight(self._fLineHeight)
868
- oStyle.setFontName(self._textFont)
869
- oStyle.setFontFamily(self._fontFamily)
870
- oStyle.setFontSize(self._fSizeText)
871
- oStyle.setTextAlign(self._textAlign)
872
- oStyle.packXML(self._xStyl, "Text_20_body")
873
-
874
- self._mainPara["Text_20_body"] = oStyle
837
+ style = ODTParagraphStyle("Text_20_body")
838
+ style.setDisplayName("Text body")
839
+ style.setParentStyleName("Standard")
840
+ style.setClass("text")
841
+ style.setMarginTop(self._mTopText)
842
+ style.setMarginBottom(self._mBotText)
843
+ style.setLineHeight(self._fLineHeight)
844
+ style.setTextAlign(self._textAlign)
845
+ style.setFontName(self._textFont)
846
+ style.setFontFamily(self._fontFamily)
847
+ style.setFontSize(self._fSizeText)
848
+ style.packXML(self._xStyl)
849
+ self._mainPara[style.name] = style
875
850
 
876
851
  # Add First Line Indent Style
877
- # ===========================
878
-
879
- oStyle = ODTParagraphStyle()
880
- oStyle.setDisplayName("First line indent")
881
- oStyle.setParentStyleName("Text_20_body")
882
- oStyle.setClass("text")
883
- oStyle.setTextIndent(self._fTextIndent)
884
- oStyle.packXML(self._xStyl, "First_20_line_20_indent")
885
-
886
- self._mainPara["First_20_line_20_indent"] = oStyle
852
+ style = ODTParagraphStyle("First_20_line_20_indent")
853
+ style.setDisplayName("First line indent")
854
+ style.setParentStyleName("Text_20_body")
855
+ style.setClass("text")
856
+ style.setTextIndent(self._fTextIndent)
857
+ style.packXML(self._xStyl)
858
+ self._mainPara[style.name] = style
887
859
 
888
860
  # Add Text Meta Style
889
- # ===================
890
-
891
- oStyle = ODTParagraphStyle()
892
- oStyle.setDisplayName("Text Meta")
893
- oStyle.setParentStyleName("Standard")
894
- oStyle.setClass("text")
895
- oStyle.setMarginTop(self._mTopMeta)
896
- oStyle.setMarginBottom(self._mBotMeta)
897
- oStyle.setLineHeight(self._fLineHeight)
898
- oStyle.setFontName(self._textFont)
899
- oStyle.setFontFamily(self._fontFamily)
900
- oStyle.setFontSize(self._fSizeText)
901
- oStyle.setColor(self._colMetaTx)
902
- oStyle.setOpacity(self._opaMetaTx)
903
- oStyle.packXML(self._xStyl, "Text_20_Meta")
904
-
905
- self._mainPara["Text_20_Meta"] = oStyle
861
+ style = ODTParagraphStyle("Text_20_Meta")
862
+ style.setDisplayName("Text Meta")
863
+ style.setParentStyleName("Standard")
864
+ style.setClass("text")
865
+ style.setMarginTop(self._mTopMeta)
866
+ style.setMarginBottom(self._mBotMeta)
867
+ style.setLineHeight(self._fLineHeight)
868
+ style.setFontName(self._textFont)
869
+ style.setFontFamily(self._fontFamily)
870
+ style.setFontSize(self._fSizeText)
871
+ style.setColour(self._colMetaTx)
872
+ style.setOpacity(self._opaMetaTx)
873
+ style.packXML(self._xStyl)
874
+ self._mainPara[style.name] = style
906
875
 
907
876
  # Add Title Style
908
- # ===============
909
-
910
- oStyle = ODTParagraphStyle()
911
- oStyle.setDisplayName("Title")
912
- oStyle.setParentStyleName("Heading")
913
- oStyle.setNextStyleName("Text_20_body")
914
- oStyle.setClass("chapter")
915
- oStyle.setTextAlign("center")
916
- oStyle.setMarginTop(self._mTopTitle)
917
- oStyle.setMarginBottom(self._mBotTitle)
918
- oStyle.setFontName(self._textFont)
919
- oStyle.setFontFamily(self._fontFamily)
920
- oStyle.setFontSize(self._fSizeTitle)
921
- oStyle.setFontWeight("bold")
922
- oStyle.packXML(self._xStyl, "Title")
923
-
924
- self._mainPara["Title"] = oStyle
877
+ style = ODTParagraphStyle("Title")
878
+ style.setDisplayName("Title")
879
+ style.setParentStyleName("Heading")
880
+ style.setNextStyleName("Text_20_body")
881
+ style.setClass("chapter")
882
+ style.setMarginTop(self._mTopTitle)
883
+ style.setMarginBottom(self._mBotTitle)
884
+ style.setTextAlign("center")
885
+ style.setFontName(self._textFont)
886
+ style.setFontFamily(self._fontFamily)
887
+ style.setFontSize(self._fSizeTitle)
888
+ style.setFontWeight("bold")
889
+ style.packXML(self._xStyl)
890
+ self._mainPara[style.name] = style
925
891
 
926
892
  # Add Separator Style
927
- # ===================
928
-
929
- oStyle = ODTParagraphStyle()
930
- oStyle.setDisplayName("Separator")
931
- oStyle.setParentStyleName("Standard")
932
- oStyle.setNextStyleName("Text_20_body")
933
- oStyle.setClass("text")
934
- oStyle.setTextAlign("center")
935
- oStyle.setMarginTop(self._mTopText)
936
- oStyle.setMarginBottom(self._mBotText)
937
- oStyle.setLineHeight(self._fLineHeight)
938
- oStyle.setFontName(self._textFont)
939
- oStyle.setFontFamily(self._fontFamily)
940
- oStyle.setFontSize(self._fSizeText)
941
- oStyle.packXML(self._xStyl, "Separator")
942
-
943
- self._mainPara["Separator"] = oStyle
893
+ style = ODTParagraphStyle("Separator")
894
+ style.setDisplayName("Separator")
895
+ style.setParentStyleName("Standard")
896
+ style.setNextStyleName("Text_20_body")
897
+ style.setClass("text")
898
+ style.setMarginTop(self._mTopText)
899
+ style.setMarginBottom(self._mBotText)
900
+ style.setLineHeight(self._fLineHeight)
901
+ style.setTextAlign("center")
902
+ style.setFontName(self._textFont)
903
+ style.setFontFamily(self._fontFamily)
904
+ style.setFontSize(self._fSizeText)
905
+ style.packXML(self._xStyl)
906
+ self._mainPara[style.name] = style
944
907
 
945
908
  # Add Heading 1 Style
946
- # ===================
947
-
948
- oStyle = ODTParagraphStyle()
949
- oStyle.setDisplayName("Heading 1")
950
- oStyle.setParentStyleName("Heading")
951
- oStyle.setNextStyleName("Text_20_body")
952
- oStyle.setOutlineLevel("1")
953
- oStyle.setClass("text")
954
- oStyle.setMarginTop(self._mTopHead1)
955
- oStyle.setMarginBottom(self._mBotHead1)
956
- oStyle.setFontName(self._textFont)
957
- oStyle.setFontFamily(self._fontFamily)
958
- oStyle.setFontSize(self._fSizeHead1)
959
- oStyle.setColor(self._colHead12)
960
- oStyle.setOpacity(self._opaHead12)
961
- oStyle.setFontWeight("bold")
962
- oStyle.packXML(self._xStyl, "Heading_20_1")
963
-
964
- self._mainPara["Heading_20_1"] = oStyle
909
+ style = ODTParagraphStyle("Heading_20_1")
910
+ style.setDisplayName("Heading 1")
911
+ style.setParentStyleName("Heading")
912
+ style.setNextStyleName("Text_20_body")
913
+ style.setOutlineLevel("1")
914
+ style.setClass("text")
915
+ style.setMarginTop(self._mTopHead1)
916
+ style.setMarginBottom(self._mBotHead1)
917
+ style.setFontName(self._textFont)
918
+ style.setFontFamily(self._fontFamily)
919
+ style.setFontSize(self._fSizeHead1)
920
+ style.setFontWeight("bold")
921
+ style.setColour(self._colHead12)
922
+ style.setOpacity(self._opaHead12)
923
+ style.packXML(self._xStyl)
924
+ self._mainPara[style.name] = style
965
925
 
966
926
  # Add Heading 2 Style
967
- # ===================
968
-
969
- oStyle = ODTParagraphStyle()
970
- oStyle.setDisplayName("Heading 2")
971
- oStyle.setParentStyleName("Heading")
972
- oStyle.setNextStyleName("Text_20_body")
973
- oStyle.setOutlineLevel("2")
974
- oStyle.setClass("text")
975
- oStyle.setMarginTop(self._mTopHead2)
976
- oStyle.setMarginBottom(self._mBotHead2)
977
- oStyle.setFontName(self._textFont)
978
- oStyle.setFontFamily(self._fontFamily)
979
- oStyle.setFontSize(self._fSizeHead2)
980
- oStyle.setColor(self._colHead12)
981
- oStyle.setOpacity(self._opaHead12)
982
- oStyle.setFontWeight("bold")
983
- oStyle.packXML(self._xStyl, "Heading_20_2")
984
-
985
- self._mainPara["Heading_20_2"] = oStyle
927
+ style = ODTParagraphStyle("Heading_20_2")
928
+ style.setDisplayName("Heading 2")
929
+ style.setParentStyleName("Heading")
930
+ style.setNextStyleName("Text_20_body")
931
+ style.setOutlineLevel("2")
932
+ style.setClass("text")
933
+ style.setMarginTop(self._mTopHead2)
934
+ style.setMarginBottom(self._mBotHead2)
935
+ style.setFontName(self._textFont)
936
+ style.setFontFamily(self._fontFamily)
937
+ style.setFontSize(self._fSizeHead2)
938
+ style.setFontWeight("bold")
939
+ style.setColour(self._colHead12)
940
+ style.setOpacity(self._opaHead12)
941
+ style.packXML(self._xStyl)
942
+ self._mainPara[style.name] = style
986
943
 
987
944
  # Add Heading 3 Style
988
- # ===================
989
-
990
- oStyle = ODTParagraphStyle()
991
- oStyle.setDisplayName("Heading 3")
992
- oStyle.setParentStyleName("Heading")
993
- oStyle.setNextStyleName("Text_20_body")
994
- oStyle.setOutlineLevel("3")
995
- oStyle.setClass("text")
996
- oStyle.setMarginTop(self._mTopHead3)
997
- oStyle.setMarginBottom(self._mBotHead3)
998
- oStyle.setFontName(self._textFont)
999
- oStyle.setFontFamily(self._fontFamily)
1000
- oStyle.setFontSize(self._fSizeHead3)
1001
- oStyle.setColor(self._colHead34)
1002
- oStyle.setOpacity(self._opaHead34)
1003
- oStyle.setFontWeight("bold")
1004
- oStyle.packXML(self._xStyl, "Heading_20_3")
1005
-
1006
- self._mainPara["Heading_20_3"] = oStyle
945
+ style = ODTParagraphStyle("Heading_20_3")
946
+ style.setDisplayName("Heading 3")
947
+ style.setParentStyleName("Heading")
948
+ style.setNextStyleName("Text_20_body")
949
+ style.setOutlineLevel("3")
950
+ style.setClass("text")
951
+ style.setMarginTop(self._mTopHead3)
952
+ style.setMarginBottom(self._mBotHead3)
953
+ style.setFontName(self._textFont)
954
+ style.setFontFamily(self._fontFamily)
955
+ style.setFontSize(self._fSizeHead3)
956
+ style.setFontWeight("bold")
957
+ style.setColour(self._colHead34)
958
+ style.setOpacity(self._opaHead34)
959
+ style.packXML(self._xStyl)
960
+ self._mainPara[style.name] = style
1007
961
 
1008
962
  # Add Heading 4 Style
1009
- # ===================
1010
-
1011
- oStyle = ODTParagraphStyle()
1012
- oStyle.setDisplayName("Heading 4")
1013
- oStyle.setParentStyleName("Heading")
1014
- oStyle.setNextStyleName("Text_20_body")
1015
- oStyle.setOutlineLevel("4")
1016
- oStyle.setClass("text")
1017
- oStyle.setMarginTop(self._mTopHead4)
1018
- oStyle.setMarginBottom(self._mBotHead4)
1019
- oStyle.setFontName(self._textFont)
1020
- oStyle.setFontFamily(self._fontFamily)
1021
- oStyle.setFontSize(self._fSizeHead4)
1022
- oStyle.setColor(self._colHead34)
1023
- oStyle.setOpacity(self._opaHead34)
1024
- oStyle.setFontWeight("bold")
1025
- oStyle.packXML(self._xStyl, "Heading_20_4")
1026
-
1027
- self._mainPara["Heading_20_4"] = oStyle
963
+ style = ODTParagraphStyle("Heading_20_4")
964
+ style.setDisplayName("Heading 4")
965
+ style.setParentStyleName("Heading")
966
+ style.setNextStyleName("Text_20_body")
967
+ style.setOutlineLevel("4")
968
+ style.setClass("text")
969
+ style.setMarginTop(self._mTopHead4)
970
+ style.setMarginBottom(self._mBotHead4)
971
+ style.setFontName(self._textFont)
972
+ style.setFontFamily(self._fontFamily)
973
+ style.setFontSize(self._fSizeHead4)
974
+ style.setFontWeight("bold")
975
+ style.setColour(self._colHead34)
976
+ style.setOpacity(self._opaHead34)
977
+ style.packXML(self._xStyl)
978
+ self._mainPara[style.name] = style
1028
979
 
1029
980
  # Add Header Style
1030
- # ================
1031
- oStyle = ODTParagraphStyle()
1032
- oStyle.setDisplayName("Header")
1033
- oStyle.setParentStyleName("Header_20_and_20_Footer")
1034
- oStyle.setTextAlign("right")
1035
- oStyle.packXML(self._xStyl, "Header")
1036
-
1037
- self._mainPara["Header"] = oStyle
981
+ style = ODTParagraphStyle("Header")
982
+ style.setDisplayName("Header")
983
+ style.setParentStyleName("Header_20_and_20_Footer")
984
+ style.setTextAlign("right")
985
+ style.packXML(self._xStyl)
986
+ self._mainPara[style.name] = style
1038
987
 
1039
988
  return
1040
989
 
1041
990
  def _writeHeader(self) -> None:
1042
991
  """Write the header elements."""
1043
- tAttr = {}
1044
- tAttr[_mkTag("style", "name")] = "Standard"
1045
- tAttr[_mkTag("style", "page-layout-name")] = "PM1"
1046
- xPage = ET.SubElement(self._xMast, _mkTag("style", "master-page"), attrib=tAttr)
992
+ xPage = ET.SubElement(self._xMast, _mkTag("style", "master-page"), attrib={
993
+ _mkTag("style", "name"): "Standard",
994
+ _mkTag("style", "page-layout-name"): "PM1",
995
+ })
1047
996
 
1048
997
  # Standard Page Header
1049
998
  if self._headerFormat:
@@ -1060,10 +1009,10 @@ class ToOdt(Tokenizer):
1060
1009
  })
1061
1010
  xPar.text = pre
1062
1011
  if page:
1063
- attrib = {_mkTag("text", "select-page"): "current"}
1012
+ attr = {_mkTag("text", "select-page"): "current"}
1064
1013
  if self._pageOffset > 0:
1065
- attrib = {_mkTag("text", "page-adjust"): str(0 - self._pageOffset)}
1066
- xTail = ET.SubElement(xPar, _mkTag("text", "page-number"), attrib=attrib)
1014
+ attr = {_mkTag("text", "page-adjust"): str(0 - self._pageOffset)}
1015
+ xTail = ET.SubElement(xPar, _mkTag("text", "page-number"), attrib=attr)
1067
1016
  xTail.text = "2"
1068
1017
  xTail.tail = post
1069
1018
  else:
@@ -1095,7 +1044,9 @@ class ODTParagraphStyle:
1095
1044
  VALID_CLASS = ["text", "chapter"]
1096
1045
  VALID_WEIGHT = ["normal", "inherit", "bold"]
1097
1046
 
1098
- def __init__(self) -> None:
1047
+ def __init__(self, name: str) -> None:
1048
+
1049
+ self._name = name
1099
1050
 
1100
1051
  # Attributes
1101
1052
  self._mAttr = {
@@ -1131,6 +1082,10 @@ class ODTParagraphStyle:
1131
1082
 
1132
1083
  return
1133
1084
 
1085
+ @property
1086
+ def name(self) -> str:
1087
+ return self._name
1088
+
1134
1089
  ##
1135
1090
  # Checkers
1136
1091
  ##
@@ -1141,23 +1096,36 @@ class ODTParagraphStyle:
1141
1096
  self._pAttr[n][1] is None for n in ["text-align", "margin-left", "margin-right"]
1142
1097
  )
1143
1098
 
1099
+ ##
1100
+ # Setters
1101
+ ##
1102
+
1103
+ def setName(self, name: str) -> None:
1104
+ """Set the paragraph style name."""
1105
+ self._name = name
1106
+ return
1107
+
1144
1108
  ##
1145
1109
  # Attribute Setters
1146
1110
  ##
1147
1111
 
1148
1112
  def setDisplayName(self, value: str | None) -> None:
1113
+ """Set style display name."""
1149
1114
  self._mAttr["display-name"][1] = value
1150
1115
  return
1151
1116
 
1152
1117
  def setParentStyleName(self, value: str | None) -> None:
1118
+ """Set parent style name."""
1153
1119
  self._mAttr["parent-style-name"][1] = value
1154
1120
  return
1155
1121
 
1156
1122
  def setNextStyleName(self, value: str | None) -> None:
1123
+ """Set next style name."""
1157
1124
  self._mAttr["next-style-name"][1] = value
1158
1125
  return
1159
1126
 
1160
1127
  def setOutlineLevel(self, value: str | None) -> None:
1128
+ """Set paragraph outline level."""
1161
1129
  if value in self.VALID_LEVEL:
1162
1130
  self._mAttr["default-outline-level"][1] = value
1163
1131
  else:
@@ -1165,6 +1133,7 @@ class ODTParagraphStyle:
1165
1133
  return
1166
1134
 
1167
1135
  def setClass(self, value: str | None) -> None:
1136
+ """Set paragraph class."""
1168
1137
  if value in self.VALID_CLASS:
1169
1138
  self._mAttr["class"][1] = value
1170
1139
  else:
@@ -1176,30 +1145,37 @@ class ODTParagraphStyle:
1176
1145
  ##
1177
1146
 
1178
1147
  def setMarginTop(self, value: str | None) -> None:
1148
+ """Set paragraph top margin."""
1179
1149
  self._pAttr["margin-top"][1] = value
1180
1150
  return
1181
1151
 
1182
1152
  def setMarginBottom(self, value: str | None) -> None:
1153
+ """Set paragraph bottom margin."""
1183
1154
  self._pAttr["margin-bottom"][1] = value
1184
1155
  return
1185
1156
 
1186
1157
  def setMarginLeft(self, value: str | None) -> None:
1158
+ """Set paragraph left margin."""
1187
1159
  self._pAttr["margin-left"][1] = value
1188
1160
  return
1189
1161
 
1190
1162
  def setMarginRight(self, value: str | None) -> None:
1163
+ """Set paragraph right margin."""
1191
1164
  self._pAttr["margin-right"][1] = value
1192
1165
  return
1193
1166
 
1194
1167
  def setTextIndent(self, value: str | None) -> None:
1168
+ """Set text indentation."""
1195
1169
  self._pAttr["text-indent"][1] = value
1196
1170
  return
1197
1171
 
1198
1172
  def setLineHeight(self, value: str | None) -> None:
1173
+ """Set line height."""
1199
1174
  self._pAttr["line-height"][1] = value
1200
1175
  return
1201
1176
 
1202
1177
  def setTextAlign(self, value: str | None) -> None:
1178
+ """Set paragraph text alignment."""
1203
1179
  if value in self.VALID_ALIGN:
1204
1180
  self._pAttr["text-align"][1] = value
1205
1181
  else:
@@ -1207,6 +1183,7 @@ class ODTParagraphStyle:
1207
1183
  return
1208
1184
 
1209
1185
  def setBreakBefore(self, value: str | None) -> None:
1186
+ """Set page break before policy."""
1210
1187
  if value in self.VALID_BREAK:
1211
1188
  self._pAttr["break-before"][1] = value
1212
1189
  else:
@@ -1214,6 +1191,7 @@ class ODTParagraphStyle:
1214
1191
  return
1215
1192
 
1216
1193
  def setBreakAfter(self, value: str | None) -> None:
1194
+ """Set page break after policy."""
1217
1195
  if value in self.VALID_BREAK:
1218
1196
  self._pAttr["break-after"][1] = value
1219
1197
  else:
@@ -1225,29 +1203,35 @@ class ODTParagraphStyle:
1225
1203
  ##
1226
1204
 
1227
1205
  def setFontName(self, value: str | None) -> None:
1206
+ """Set font name."""
1228
1207
  self._tAttr["font-name"][1] = value
1229
1208
  return
1230
1209
 
1231
1210
  def setFontFamily(self, value: str | None) -> None:
1211
+ """Set font family."""
1232
1212
  self._tAttr["font-family"][1] = value
1233
1213
  return
1234
1214
 
1235
1215
  def setFontSize(self, value: str | None) -> None:
1216
+ """Set font size."""
1236
1217
  self._tAttr["font-size"][1] = value
1237
1218
  return
1238
1219
 
1239
1220
  def setFontWeight(self, value: str | None) -> None:
1221
+ """Set font weight."""
1240
1222
  if value in self.VALID_WEIGHT:
1241
1223
  self._tAttr["font-weight"][1] = value
1242
1224
  else:
1243
1225
  self._tAttr["font-weight"][1] = None
1244
1226
  return
1245
1227
 
1246
- def setColor(self, value: str | None) -> None:
1228
+ def setColour(self, value: str | None) -> None:
1229
+ """Set text colour."""
1247
1230
  self._tAttr["color"][1] = value
1248
1231
  return
1249
1232
 
1250
1233
  def setOpacity(self, value: str | None) -> None:
1234
+ """Set text opacity."""
1251
1235
  self._tAttr["opacity"][1] = value
1252
1236
  return
1253
1237
 
@@ -1256,54 +1240,41 @@ class ODTParagraphStyle:
1256
1240
  ##
1257
1241
 
1258
1242
  def checkNew(self, style: ODTParagraphStyle) -> bool:
1259
- """Check if there are new settings in refStyle that differ from
1260
- those in the current object.
1243
+ """Check if there are new settings in style that differ from
1244
+ those in this object. Unset styles are ignored as they can be
1245
+ inherited from the parent style.
1261
1246
  """
1262
- for name, (_, aVal) in style._mAttr.items():
1263
- if aVal is not None and aVal != self._mAttr[name][1]:
1264
- return True
1265
- for name, (_, aVal) in style._pAttr.items():
1266
- if aVal is not None and aVal != self._pAttr[name][1]:
1267
- return True
1268
- for name, (_, aVal) in style._tAttr.items():
1269
- if aVal is not None and aVal != self._tAttr[name][1]:
1270
- return True
1247
+ if any(v and v != self._mAttr[m][1] for m, (_, v) in style._mAttr.items()):
1248
+ return True
1249
+ if any(v and v != self._pAttr[m][1] for m, (_, v) in style._pAttr.items()):
1250
+ return True
1251
+ if any(v and v != self._tAttr[m][1] for m, (_, v) in style._tAttr.items()):
1252
+ return True
1271
1253
  return False
1272
1254
 
1273
1255
  def getID(self) -> str:
1274
1256
  """Generate a unique ID from the settings."""
1275
- string = (
1257
+ return sha256((
1276
1258
  f"Paragraph:Main:{str(self._mAttr)}:"
1277
1259
  f"Paragraph:Para:{str(self._pAttr)}:"
1278
1260
  f"Paragraph:Text:{str(self._tAttr)}:"
1279
- )
1280
- return sha256(string.encode()).hexdigest()
1261
+ ).encode()).hexdigest()
1281
1262
 
1282
- def packXML(self, xParent: ET.Element, name: str) -> None:
1263
+ def packXML(self, xParent: ET.Element) -> None:
1283
1264
  """Pack the content into an xml element."""
1284
- attr = {}
1285
- attr[_mkTag("style", "name")] = name
1286
- attr[_mkTag("style", "family")] = "paragraph"
1287
- for aName, (aNm, aVal) in self._mAttr.items():
1288
- if aVal is not None:
1289
- attr[_mkTag(aNm, aName)] = aVal
1290
-
1265
+ attr = {
1266
+ _mkTag("style", "name"): self._name,
1267
+ _mkTag("style", "family"): "paragraph",
1268
+ }
1269
+ attr.update(
1270
+ {_mkTag(n, m): v for m, (n, v) in self._mAttr.items() if v}
1271
+ )
1291
1272
  xEntry = ET.SubElement(xParent, _mkTag("style", "style"), attrib=attr)
1292
1273
 
1293
- attr = {}
1294
- for aName, (aNm, aVal) in self._pAttr.items():
1295
- if aVal is not None:
1296
- attr[_mkTag(aNm, aName)] = aVal
1297
-
1298
- if attr:
1274
+ if attr := {_mkTag(n, m): v for m, (n, v) in self._pAttr.items() if v}:
1299
1275
  ET.SubElement(xEntry, _mkTag("style", "paragraph-properties"), attrib=attr)
1300
1276
 
1301
- attr = {}
1302
- for aName, (aNm, aVal) in self._tAttr.items():
1303
- if aVal is not None:
1304
- attr[_mkTag(aNm, aName)] = aVal
1305
-
1306
- if attr:
1277
+ if attr := {_mkTag(n, m): v for m, (n, v) in self._tAttr.items() if v}:
1307
1278
  ET.SubElement(xEntry, _mkTag("style", "text-properties"), attrib=attr)
1308
1279
 
1309
1280
  return
@@ -1324,8 +1295,8 @@ class ODTTextStyle:
1324
1295
  VALID_LWIDTH = ["auto"]
1325
1296
  VALID_LCOL = ["font-color"]
1326
1297
 
1327
- def __init__(self) -> None:
1328
- # Text Attributes
1298
+ def __init__(self, name: str) -> None:
1299
+ self._name = name
1329
1300
  self._tAttr = {
1330
1301
  "font-weight": ["fo", None],
1331
1302
  "font-style": ["fo", None],
@@ -1339,11 +1310,16 @@ class ODTTextStyle:
1339
1310
  }
1340
1311
  return
1341
1312
 
1313
+ @property
1314
+ def name(self) -> str:
1315
+ return self._name
1316
+
1342
1317
  ##
1343
1318
  # Setters
1344
1319
  ##
1345
1320
 
1346
1321
  def setFontWeight(self, value: str | None) -> None:
1322
+ """Set text font weight."""
1347
1323
  if value in self.VALID_WEIGHT:
1348
1324
  self._tAttr["font-weight"][1] = value
1349
1325
  else:
@@ -1351,13 +1327,15 @@ class ODTTextStyle:
1351
1327
  return
1352
1328
 
1353
1329
  def setFontStyle(self, value: str | None) -> None:
1330
+ """Set text font style."""
1354
1331
  if value in self.VALID_STYLE:
1355
1332
  self._tAttr["font-style"][1] = value
1356
1333
  else:
1357
1334
  self._tAttr["font-style"][1] = None
1358
1335
  return
1359
1336
 
1360
- def setBackgroundColor(self, value: str | None) -> None:
1337
+ def setBackgroundColour(self, value: str | None) -> None:
1338
+ """Set text background colour."""
1361
1339
  if value and len(value) == 7 and value[0] == "#":
1362
1340
  self._tAttr["background-color"][1] = value
1363
1341
  else:
@@ -1365,6 +1343,7 @@ class ODTTextStyle:
1365
1343
  return
1366
1344
 
1367
1345
  def setTextPosition(self, value: str | None) -> None:
1346
+ """Set text vertical position."""
1368
1347
  if value in self.VALID_POS:
1369
1348
  self._tAttr["text-position"][1] = f"{value} 58%"
1370
1349
  else:
@@ -1372,6 +1351,7 @@ class ODTTextStyle:
1372
1351
  return
1373
1352
 
1374
1353
  def setStrikeStyle(self, value: str | None) -> None:
1354
+ """Set text line-trough style."""
1375
1355
  if value in self.VALID_LSTYLE:
1376
1356
  self._tAttr["text-line-through-style"][1] = value
1377
1357
  else:
@@ -1379,6 +1359,7 @@ class ODTTextStyle:
1379
1359
  return
1380
1360
 
1381
1361
  def setStrikeType(self, value: str | None) -> None:
1362
+ """Set text line-through type."""
1382
1363
  if value in self.VALID_LTYPE:
1383
1364
  self._tAttr["text-line-through-type"][1] = value
1384
1365
  else:
@@ -1386,6 +1367,7 @@ class ODTTextStyle:
1386
1367
  return
1387
1368
 
1388
1369
  def setUnderlineStyle(self, value: str | None) -> None:
1370
+ """Set text underline style."""
1389
1371
  if value in self.VALID_LSTYLE:
1390
1372
  self._tAttr["text-underline-style"][1] = value
1391
1373
  else:
@@ -1393,6 +1375,7 @@ class ODTTextStyle:
1393
1375
  return
1394
1376
 
1395
1377
  def setUnderlineWidth(self, value: str | None) -> None:
1378
+ """Set text underline width."""
1396
1379
  if value in self.VALID_LWIDTH:
1397
1380
  self._tAttr["text-underline-width"][1] = value
1398
1381
  else:
@@ -1400,6 +1383,7 @@ class ODTTextStyle:
1400
1383
  return
1401
1384
 
1402
1385
  def setUnderlineColour(self, value: str | None) -> None:
1386
+ """Set text underline colour."""
1403
1387
  if value in self.VALID_LCOL:
1404
1388
  self._tAttr["text-underline-color"][1] = value
1405
1389
  else:
@@ -1410,21 +1394,14 @@ class ODTTextStyle:
1410
1394
  # Methods
1411
1395
  ##
1412
1396
 
1413
- def packXML(self, xParent: ET.Element, name: str) -> None:
1397
+ def packXML(self, xParent: ET.Element) -> None:
1414
1398
  """Pack the content into an xml element."""
1415
- attr = {}
1416
- attr[_mkTag("style", "name")] = name
1417
- attr[_mkTag("style", "family")] = "text"
1418
- xEntry = ET.SubElement(xParent, _mkTag("style", "style"), attrib=attr)
1419
-
1420
- attr = {}
1421
- for aName, (aNm, aVal) in self._tAttr.items():
1422
- if aVal is not None:
1423
- attr[_mkTag(aNm, aName)] = aVal
1424
-
1425
- if attr:
1399
+ xEntry = ET.SubElement(xParent, _mkTag("style", "style"), attrib={
1400
+ _mkTag("style", "name"): self._name,
1401
+ _mkTag("style", "family"): "text",
1402
+ })
1403
+ if attr := {_mkTag(n, m): v for m, (n, v) in self._tAttr.items() if v}:
1426
1404
  ET.SubElement(xEntry, _mkTag("style", "text-properties"), attrib=attr)
1427
-
1428
1405
  return
1429
1406
 
1430
1407
  # END Class ODTTextStyle