novelWriter 2.4.4__py3-none-any.whl → 2.5__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 (122) hide show
  1. {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/METADATA +4 -5
  2. {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/RECORD +121 -111
  3. {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +33 -39
  5. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  6. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  7. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  8. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  9. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  10. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  11. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  12. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  13. novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
  14. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  15. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  16. novelwriter/assets/i18n/project_en_GB.json +1 -0
  17. novelwriter/assets/i18n/project_pl_PL.json +116 -0
  18. novelwriter/assets/icons/typicons_dark/icons.conf +2 -0
  19. novelwriter/assets/icons/typicons_dark/nw_font.svg +4 -0
  20. novelwriter/assets/icons/typicons_dark/nw_quote.svg +4 -0
  21. novelwriter/assets/icons/typicons_light/icons.conf +2 -0
  22. novelwriter/assets/icons/typicons_light/nw_font.svg +4 -0
  23. novelwriter/assets/icons/typicons_light/nw_quote.svg +4 -0
  24. novelwriter/assets/manual.pdf +0 -0
  25. novelwriter/assets/sample.zip +0 -0
  26. novelwriter/assets/syntax/cyberpunk_night.conf +5 -3
  27. novelwriter/assets/syntax/default_dark.conf +32 -18
  28. novelwriter/assets/syntax/default_light.conf +24 -10
  29. novelwriter/assets/syntax/dracula.conf +44 -0
  30. novelwriter/assets/syntax/grey_dark.conf +5 -4
  31. novelwriter/assets/syntax/grey_light.conf +5 -4
  32. novelwriter/assets/syntax/light_owl.conf +7 -6
  33. novelwriter/assets/syntax/night_owl.conf +7 -6
  34. novelwriter/assets/syntax/snazzy.conf +42 -0
  35. novelwriter/assets/syntax/solarized_dark.conf +4 -3
  36. novelwriter/assets/syntax/solarized_light.conf +4 -3
  37. novelwriter/assets/syntax/tango.conf +27 -11
  38. novelwriter/assets/syntax/tomorrow.conf +6 -5
  39. novelwriter/assets/syntax/tomorrow_night.conf +7 -6
  40. novelwriter/assets/syntax/tomorrow_night_blue.conf +6 -5
  41. novelwriter/assets/syntax/tomorrow_night_bright.conf +6 -5
  42. novelwriter/assets/syntax/tomorrow_night_eighties.conf +6 -5
  43. novelwriter/assets/text/credits_en.htm +52 -41
  44. novelwriter/assets/themes/cyberpunk_night.conf +3 -0
  45. novelwriter/assets/themes/default_dark.conf +2 -0
  46. novelwriter/assets/themes/default_light.conf +2 -0
  47. novelwriter/assets/themes/dracula.conf +48 -0
  48. novelwriter/assets/themes/solarized_dark.conf +2 -0
  49. novelwriter/assets/themes/solarized_light.conf +2 -0
  50. novelwriter/common.py +33 -12
  51. novelwriter/config.py +184 -98
  52. novelwriter/constants.py +47 -35
  53. novelwriter/core/buildsettings.py +68 -69
  54. novelwriter/core/coretools.py +5 -23
  55. novelwriter/core/docbuild.py +52 -40
  56. novelwriter/core/document.py +3 -5
  57. novelwriter/core/index.py +115 -45
  58. novelwriter/core/item.py +8 -19
  59. novelwriter/core/options.py +2 -4
  60. novelwriter/core/project.py +37 -61
  61. novelwriter/core/projectdata.py +1 -3
  62. novelwriter/core/projectxml.py +12 -15
  63. novelwriter/core/sessions.py +3 -5
  64. novelwriter/core/spellcheck.py +4 -9
  65. novelwriter/core/status.py +211 -164
  66. novelwriter/core/storage.py +0 -8
  67. novelwriter/core/tohtml.py +139 -105
  68. novelwriter/core/tokenizer.py +278 -122
  69. novelwriter/core/{tomd.py → tomarkdown.py} +97 -78
  70. novelwriter/core/toodt.py +257 -166
  71. novelwriter/core/toqdoc.py +419 -0
  72. novelwriter/core/tree.py +5 -7
  73. novelwriter/dialogs/about.py +11 -18
  74. novelwriter/dialogs/docmerge.py +17 -19
  75. novelwriter/dialogs/docsplit.py +17 -19
  76. novelwriter/dialogs/editlabel.py +6 -10
  77. novelwriter/dialogs/preferences.py +200 -164
  78. novelwriter/dialogs/projectsettings.py +225 -189
  79. novelwriter/dialogs/quotes.py +12 -9
  80. novelwriter/dialogs/wordlist.py +9 -15
  81. novelwriter/enum.py +35 -30
  82. novelwriter/error.py +8 -15
  83. novelwriter/extensions/configlayout.py +55 -21
  84. novelwriter/extensions/eventfilters.py +1 -5
  85. novelwriter/extensions/modified.py +58 -14
  86. novelwriter/extensions/novelselector.py +1 -3
  87. novelwriter/extensions/pagedsidebar.py +9 -12
  88. novelwriter/extensions/{circularprogress.py → progressbars.py} +30 -8
  89. novelwriter/extensions/statusled.py +40 -26
  90. novelwriter/extensions/switch.py +4 -6
  91. novelwriter/extensions/switchbox.py +7 -6
  92. novelwriter/extensions/versioninfo.py +3 -9
  93. novelwriter/gui/doceditor.py +120 -139
  94. novelwriter/gui/dochighlight.py +231 -186
  95. novelwriter/gui/docviewer.py +69 -108
  96. novelwriter/gui/docviewerpanel.py +3 -10
  97. novelwriter/gui/editordocument.py +1 -3
  98. novelwriter/gui/itemdetails.py +7 -11
  99. novelwriter/gui/mainmenu.py +22 -18
  100. novelwriter/gui/noveltree.py +11 -24
  101. novelwriter/gui/outline.py +15 -26
  102. novelwriter/gui/projtree.py +35 -60
  103. novelwriter/gui/search.py +10 -3
  104. novelwriter/gui/sidebar.py +2 -6
  105. novelwriter/gui/statusbar.py +29 -37
  106. novelwriter/gui/theme.py +26 -48
  107. novelwriter/guimain.py +162 -160
  108. novelwriter/shared.py +36 -32
  109. novelwriter/text/patterns.py +113 -0
  110. novelwriter/tools/dictionaries.py +10 -20
  111. novelwriter/tools/lipsum.py +10 -16
  112. novelwriter/tools/manusbuild.py +9 -11
  113. novelwriter/tools/manuscript.py +71 -145
  114. novelwriter/tools/manussettings.py +71 -75
  115. novelwriter/tools/noveldetails.py +16 -21
  116. novelwriter/tools/welcome.py +21 -26
  117. novelwriter/tools/writingstats.py +9 -12
  118. novelwriter/types.py +49 -4
  119. novelwriter/extensions/simpleprogress.py +0 -55
  120. {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/LICENSE.md +0 -0
  121. {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/entry_points.txt +0 -0
  122. {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/top_level.txt +0 -0
@@ -1,81 +1,92 @@
1
- <!DOCTYPE html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2
1
  <html>
3
2
  <body>
4
3
 
5
4
  <h3>Main Developer</h3>
6
- <p>Veronica Berglyd Olsen (<a href="https://github.com/vkbo">@vkbo</a>)</p>
5
+
6
+ <p>Veronica Berglyd Olsen</p>
7
7
 
8
8
  <h3>Contributors</h3>
9
9
 
10
- <p>
11
- &nbsp;&bull;&nbsp;<b>Concept:</b> Marian Lückhof (<a href="https://github.com/Number042">@Number042</a>)<br>
12
- &nbsp;&bull;&nbsp;<b>Internationalisation:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
13
- &nbsp;&bull;&nbsp;<b>Setup and Packaging:</b> Rachel Powers (<a href="https://github.com/Ryex">@Ryex</a>)
14
- </p>
10
+ <ul>
11
+ <li><b>Early Concept:</b> Marian Lückhof</li>
12
+ <li><b>Internationalisation:</b> Bruno Meneguello</li>
13
+ <li><b>Setup and Packaging:</b> Rachel Powers</li>
14
+ </ul>
15
+
15
16
  <p>For other contributions, see the project's
16
17
  <a href="https://github.com/vkbo/novelWriter/graphs/contributors">Contributors</a> page.</p>
17
18
 
18
19
  <h3>Artwork</h3>
19
20
 
20
- <p>The artwork on the Welcome dialog was created by <a href="https://louisdurrant.art">Louis Durrant</a>.</p>
21
+ <p>The artwork on the Welcome dialog was created by Louis Durrant.</p>
21
22
 
22
23
  <h3>Translations</h3>
23
24
 
24
25
  <p>The default language is English (UK) with English (US) as an option. These are the original
25
26
  translators for the languages currently available:</p>
26
- <p>
27
- &nbsp;&bull;&nbsp;<b>Dutch:</b> Martijn van der Kleijn (<a href="https://github.com/mvdkleijn">@mvdkleijn</a>)<br>
28
- &nbsp;&bull;&nbsp;<b>French:</b> Jan Lüdke (<a href="https://github.com/jyhelle">@jyhelle</a>)<br>
29
- &nbsp;&bull;&nbsp;<b>German:</b> Myian (<a href="https://github.com/heymyian">@heymyian</a>)<br>
30
- &nbsp;&bull;&nbsp;<b>Italian:</b> Riccardo Mangili<br>
31
- &nbsp;&bull;&nbsp;<b>Japanese:</b> hebekeg (<a href="https://github.com/hebekeg">@hebekeg</a>)<br>
32
- &nbsp;&bull;&nbsp;<b>Latin American Spanish:</b> Tommy Marplatt (<a href="https://github.com/tmarplatt">@tmarplatt</a>)<br>
33
- &nbsp;&bull;&nbsp;<b>Norwegian:</b> Veronica Berglyd Olsen (<a href="https://github.com/vkbo">@vkbo</a>)<br>
34
- &nbsp;&bull;&nbsp;<b>Portuguese:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
35
- &nbsp;&bull;&nbsp;<b>Simplified Chinese:</b> Qianzhi Long (<a href="https://github.com/longqzh">@longqzh</a>)
36
- </p>
27
+
28
+ <ul>
29
+ <li><b>Dutch:</b> Martijn van der Kleijn (mvdkleijn)</li>
30
+ <li><b>French:</b> Jan Lüdke (jyhelle)</li>
31
+ <li><b>German:</b> Myian (HeyMyian)</li>
32
+ <li><b>Italian:</b> Riccardo Mangili</li>
33
+ <li><b>Japanese:</b> hebekeg</li>
34
+ <li><b>Latin American Spanish:</b> Tommy Marplatt (tmarplatt)</li>
35
+ <li><b>Norwegian:</b> Veronica Berglyd Olsen (vkbo)</li>
36
+ <li><b>Polish:</b> Anna Maria Polak (Nauthiz)</li>
37
+ <li><b>Portuguese:</b> Bruno Meneguello (bkmeneguello)</li>
38
+ <li><b>Simplified Chinese:</b> Qianzhi Long (longqzh)</li>
39
+ </ul>
37
40
 
38
41
  <p>Additional larger translation contributions:</p>
39
- <p>
40
- &nbsp;&bull;&nbsp;<b>French:</b> Albert Aribaud (<a href="https://github.com/aaribaud">@aaribaud</a>)
41
- </p>
42
+
43
+ <ul>
44
+ <li><b>French:</b> Albert Aribaud (aaribaud)</li>
45
+ <li><b>Portuguese:</b> Oli Maia (olimaia)</li>
46
+ </ul>
42
47
 
43
48
  <p>Translations are managed on <a href="https://crowdin.com/project/novelwriter">Crowdin</a>, and
44
- more contributions are listed on the project's <a href="https://crowdin.com/project/novelwriter/members">Members</a> page.</p>
49
+ more contributions are listed on the project's Members page.</p>
45
50
 
46
51
  <h3>Libraries</h3>
47
52
 
48
53
  <p>The following libraries are dependencies of novelWriter:</p>
49
- <p>
50
- &nbsp;&bull;&nbsp;<a href="https://www.qt.io">Qt5</a> by Qt Company<br>
51
- &nbsp;&bull;&nbsp;<a href="https://www.riverbankcomputing.com/software/pyqt">PyQt5</a> by Riverbank Computing<br>
52
- &nbsp;&bull;&nbsp;<a href="https://abiword.github.io/enchant">Enchant</a> by Dom Lachowicz<br>
53
- &nbsp;&bull;&nbsp;<a href="https://pyenchant.github.io/pyenchant">PyEnchant</a> by Dimitri Merejkowsky
54
- </p>
54
+
55
+ <ul>
56
+ <li><b>Qt5</b> by Qt Company</li>
57
+ <li><b>PyQt5</b> by Riverbank Computing</li>
58
+ <li><b>Enchant</b> by Dom Lachowicz</li>
59
+ <li><b>PyEnchant</b> by Dimitri Merejkowsky</li>
60
+ </ul>
55
61
 
56
62
  <h3>Assets</h3>
57
63
 
58
64
  <p>Some of the assets bundled with novelWriter were adapted from the following sources:</p>
59
- <p>
60
- &nbsp;&bull;&nbsp;<a href="https://github.com/stephenhutchings/typicons.font">Typicons</a> icons by Stephen Hutchings (CC BY-SA 4.0)<br>
61
- &nbsp;&bull;&nbsp;<a href="https://github.com/chriskempson/base16">Tomorrow</a> syntax themes by Chris Kempson (MIT License)<br>
62
- &nbsp;&bull;&nbsp;<a href="https://github.com/sdras/night-owl-vscode-theme">Owl</a> syntax themes by Sarah Drasner (MIT License)<br>
63
- &nbsp;&bull;&nbsp;<a href="https://github.com/altercation/solarized">Solarized</a> themes by Ethan Schoonover (MIT License)
64
- </p>
65
+
66
+ <ul>
67
+ <li><b>Typicons</b> icons by Stephen Hutchings (CC BY-SA 4.0)</li>
68
+ <li><b>Tomorrow</b> syntax themes by Chris Kempson (MIT License)</li>
69
+ <li><b>Owl</b> syntax themes by Sarah Drasner (MIT License)</li>
70
+ <li><b>Solarized</b> themes by Ethan Schoonover (MIT License)</li>
71
+ <li><b>Cyberpunk Night</b> theme by Anders Lemvigh (CC BY-SA 4.0)</li>
72
+ <li><b>Dracula</b> theme by Zeno Rocha (MIT License)</li>
73
+ <li><b>Snazzy Light</b> theme by Florian Reuschel (MIT License)</li>
74
+ </ul>
65
75
 
66
76
  <h3>Fonts</h3>
67
77
 
68
78
  <p>The font used for the main novelWriter logo, mimetype and text banners is Pridi. Other fonts are
69
79
  used on buttons and icons.</p>
70
- <p>
71
- &nbsp;&bull;&nbsp;Pridi by Cadson Demak (Open Font License, Version 1.1)<br>
72
- &nbsp;&bull;&nbsp;Source Sans Pro by Paul D. Hunt (SIL Open Font License)
73
- </p>
80
+
81
+ <ul>
82
+ <li><b>Pridi</b> by Cadson Demak (Open Font License, Version 1.1)</li>
83
+ <li><b>Source Sans Pro</b> by Paul D. Hunt (SIL Open Font License)</li>
84
+ </ul>
74
85
 
75
86
  <h3>Special Mentions</h3>
76
87
 
77
- <p>Additional thanks to <a href="https://github.com/johnblommers">@johnblommers</a> who was an early user and who has provided a lot
78
- of very useful feedback over the years.</p>
88
+ <p>Additional thanks to John Blommers who was an early user and who has provided a lot of very
89
+ useful feedback over the years.</p>
79
90
 
80
91
  </body>
81
92
  </html>
@@ -24,6 +24,9 @@ link = 77, 77, 255
24
24
  linkvisited = 50, 0, 80
25
25
 
26
26
  [GUI]
27
+ helptext = 97, 97, 97
28
+ fadedtext = 97, 97, 97
29
+ errortext = 255, 77, 77
27
30
  statusnone = 50, 50, 50
28
31
  statussaved = 77, 255, 77
29
32
  statusunsaved = 255, 77, 77
@@ -26,6 +26,8 @@ linkvisited = 102, 153, 204
26
26
 
27
27
  [GUI]
28
28
  helptext = 164, 164, 164
29
+ fadedtext = 148, 148, 148
30
+ errortext = 255, 164, 164
29
31
  statusnone = 150, 152, 150
30
32
  statussaved = 39, 135, 78
31
33
  statusunsaved = 138, 32, 32
@@ -26,6 +26,8 @@ linkvisited = 66, 113, 174
26
26
 
27
27
  [GUI]
28
28
  helptext = 92, 92, 92
29
+ fadedtext = 108, 108, 108
30
+ errortext = 255, 92, 92
29
31
  statusnone = 120, 120, 120
30
32
  statussaved = 200, 15, 39
31
33
  statusunsaved = 2, 133, 37
@@ -0,0 +1,48 @@
1
+ [Main]
2
+ name = Dracula
3
+ description = A dark theme with bright colours
4
+ author = Veronica Berglyd Olsen (adaptation)
5
+ credit = Zeno Rocha
6
+ url = https://draculatheme.com
7
+ license = MIT
8
+ licenseurl = https://github.com/dracula/dracula-theme/blob/main/LICENSE
9
+ icontheme = typicons_dark
10
+
11
+ ##
12
+ # Colours:
13
+ # Background = 282a36 : 40, 42, 54
14
+ # Foreground = f8f8f2 : 248, 248, 242
15
+ # Current Line = 44475A : 68, 71, 90
16
+ # Comment = 6272a4 : 98, 114, 164
17
+ # Cyan = 8be9fd : 139, 233, 253
18
+ # Green = 50fa7b : 80, 250, 123
19
+ # Orange = ffb86c : 255, 184, 108
20
+ # Pink = ff79c6 : 255, 121, 198
21
+ # Purple = bd93f9 : 189, 147, 249
22
+ # Red = ff5555 : 255, 85, 85
23
+ # Yellow = f1fa8c : 241, 250, 140
24
+ ##
25
+
26
+ [Palette]
27
+ window = 68, 71, 90
28
+ windowtext = 248, 248, 242
29
+ base = 40, 42, 54
30
+ alternatebase = 51, 54, 69
31
+ text = 248, 248, 242
32
+ tooltipbase = 241, 250, 140
33
+ tooltiptext = 40, 42, 54
34
+ button = 80, 83, 105
35
+ buttontext = 248, 248, 242
36
+ brighttext = 68, 71, 90
37
+ highlight = 166, 129, 218
38
+ highlightedtext = 248, 248, 242
39
+ link = 139, 233, 253
40
+ linkvisited = 139, 233, 253
41
+
42
+ [GUI]
43
+ helptext = 204, 172, 249
44
+ fadedtext = 98, 114, 164
45
+ errortext = 255, 85, 85
46
+ statusnone = 98, 114, 164
47
+ statussaved = 80, 250, 123
48
+ statusunsaved = 255, 85, 85
@@ -25,6 +25,8 @@ linkvisited = 38, 139, 210
25
25
 
26
26
  [GUI]
27
27
  helptext = 166, 161, 149
28
+ fadedtext = 166, 161, 149
29
+ errortext = 255, 161, 149
28
30
  statusnone = 88, 110, 117
29
31
  statussaved = 42, 161, 152
30
32
  statusunsaved = 203, 75, 22
@@ -25,6 +25,8 @@ linkvisited = 38, 139, 210
25
25
 
26
26
  [GUI]
27
27
  helptext = 78, 91, 95
28
+ fadedtext = 78, 91, 95
29
+ errortext = 255, 91, 95
28
30
  statusnone = 88, 110, 117
29
31
  statussaved = 42, 161, 152
30
32
  statusunsaved = 203, 75, 22
novelwriter/common.py CHANGED
@@ -24,30 +24,32 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
24
24
  from __future__ import annotations
25
25
 
26
26
  import json
27
- import uuid
28
27
  import logging
29
28
  import unicodedata
29
+ import uuid
30
30
  import xml.etree.ElementTree as ET
31
31
 
32
- from typing import TYPE_CHECKING, Any, Literal
33
- from pathlib import Path
34
- from datetime import datetime
35
32
  from configparser import ConfigParser
33
+ from datetime import datetime
34
+ from pathlib import Path
35
+ from typing import TYPE_CHECKING, Any, Literal, TypeVar
36
36
  from urllib.parse import urljoin
37
37
  from urllib.request import pathname2url
38
38
 
39
- from PyQt5.QtGui import QColor, QDesktopServices
40
39
  from PyQt5.QtCore import QCoreApplication, QUrl
40
+ from PyQt5.QtGui import QColor, QDesktopServices, QFont, QFontInfo
41
41
 
42
- from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
43
- from novelwriter.error import logException
44
42
  from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst
43
+ from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
44
+ from novelwriter.error import logException
45
45
 
46
46
  if TYPE_CHECKING: # pragma: no cover
47
47
  from typing import TypeGuard # Requires Python 3.10
48
48
 
49
49
  logger = logging.getLogger(__name__)
50
50
 
51
+ _Type = TypeVar("_Type")
52
+
51
53
 
52
54
  ##
53
55
  # Checker Functions
@@ -172,6 +174,11 @@ def isItemLayout(value: Any) -> TypeGuard[str]:
172
174
  return isinstance(value, str) and value in nwItemLayout.__members__
173
175
 
174
176
 
177
+ def isListInstance(data: Any, check: type[_Type]) -> TypeGuard[list[_Type]]:
178
+ """Check that all items of a list is of a given type."""
179
+ return isinstance(data, list) and all(isinstance(item, check) for item in data)
180
+
181
+
175
182
  def hexToInt(value: Any, default: int = 0) -> int:
176
183
  """Convert a hex string to an integer."""
177
184
  if isinstance(value, str):
@@ -272,6 +279,13 @@ def simplified(text: str) -> str:
272
279
  return " ".join(str(text).strip().split())
273
280
 
274
281
 
282
+ def elide(text: str, length: int) -> str:
283
+ """Elide a piece of text to a maximum length."""
284
+ if len(text) > (cut := max(4, length)):
285
+ return f"{text[:cut-4].rstrip()} ..."
286
+ return text
287
+
288
+
275
289
  def yesNo(value: int | bool | None) -> Literal["yes", "no"]:
276
290
  """Convert a boolean evaluated variable to a yes or no."""
277
291
  return "yes" if value else "no"
@@ -387,6 +401,16 @@ def cssCol(col: QColor, alpha: int | None = None) -> str:
387
401
  return f"rgba({col.red()}, {col.green()}, {col.blue()}, {alpha or col.alpha()})"
388
402
 
389
403
 
404
+ def describeFont(font: QFont) -> str:
405
+ """Describe a font in a way that can be displayed on the GUI."""
406
+ if isinstance(font, QFont):
407
+ info = QFontInfo(font)
408
+ family = info.family()
409
+ styles = [v for v in info.styleName().split() if v not in family]
410
+ return " ".join([f"{info.pointSize()} pt", family] + styles)
411
+ return "Error"
412
+
413
+
390
414
  ##
391
415
  # Encoder Functions
392
416
  ##
@@ -499,12 +523,11 @@ def readTextFile(path: str | Path) -> str:
499
523
 
500
524
 
501
525
  def makeFileNameSafe(text: str) -> str:
502
- """Return a filename safe string.
526
+ """Return a filename-safe string.
503
527
  See: https://unicode.org/reports/tr15/#Norm_Forms
504
528
  """
505
529
  text = unicodedata.normalize("NFKC", text).strip()
506
- allowed = (" ", ".", "-", "_")
507
- return "".join(c for c in text if c.isalnum() or c in allowed)
530
+ return "".join(c for c in text if c.isprintable() and c not in r'\/:*?"<>|')
508
531
 
509
532
 
510
533
  def getFileSize(path: Path) -> int:
@@ -589,5 +612,3 @@ class NWConfigParser(ConfigParser):
589
612
  for i in range(min(len(data), len(result))):
590
613
  result[i] = checkInt(data[i].strip(), result[i])
591
614
  return result
592
-
593
- # END Class NWConfigParser