novelWriter 2.4.2__py3-none-any.whl → 2.4.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: novelWriter
3
- Version: 2.4.2
3
+ Version: 2.4.4
4
4
  Summary: A markdown-like text editor for planning and writing novels
5
5
  Author-email: Veronica Berglyd Olsen <code@vkbo.net>
6
6
  License: GNU General Public License v3
@@ -1,14 +1,14 @@
1
- novelwriter/__init__.py,sha256=UmO-iWGbt0mkX0Qp5ec2ApSn1aDEmkgg-632e_ICZrU,7744
1
+ novelwriter/__init__.py,sha256=_CJImzuDGASfUJUwJ6dCQnZT0pHK8G0tH-0Fa5iouHg,7744
2
2
  novelwriter/common.py,sha256=oarn4-2Ezm595b-dHD4MVrytxMFFB_QhITbTMIKD40M,17440
3
3
  novelwriter/config.py,sha256=Y0c3-0xfmDE-IDcFYW0U_x_WGPMoU2T0sqtNZ8CT4zQ,35841
4
4
  novelwriter/constants.py,sha256=UIxiF-23cB_gmRfxbQPYmObn8Ib-ygm46uOIG329RLY,19818
5
5
  novelwriter/enum.py,sha256=MP-nz3vDRp4bWxXitqjdLWO2_RvrDAlRxngiMON9mb8,3305
6
6
  novelwriter/error.py,sha256=rY3kHVkt7W0MM9iKOBkMY-9qhStlESGlyeOOXwT4BGM,7278
7
7
  novelwriter/guimain.py,sha256=Be32lkJv1ZF-aOSOQTPBfcH7TFrk3KvpLBmwIl20eRc,53477
8
- novelwriter/shared.py,sha256=t-0ZwgnT7KNHDtz4fBV-uPxh9P0Nw1R0Sj-VW4To6sc,14678
8
+ novelwriter/shared.py,sha256=CIzGQcCEAPnFRLRbzPH2m0gcPYDtCZt8PSIdEKKBw7w,15158
9
9
  novelwriter/types.py,sha256=6aP2hZraPEolYqBgj5R_5bah3NgelASBfKol6yYOi4g,3316
10
- novelwriter/assets/manual.pdf,sha256=kMZhZUq4Nl-haKrsBVIjh75k55zEydBMjbUeKfUYKQ8,2691208
11
- novelwriter/assets/sample.zip,sha256=1JF3NFAoBjJIhycpXLPzPTbfTDEiKznKN4O3uX8NI6U,27360
10
+ novelwriter/assets/manual.pdf,sha256=TzPxpJnrik0Na6XaHjrCKctCXCQT-gmga9tysESLrRY,2691197
11
+ novelwriter/assets/sample.zip,sha256=zCNbDDyjElPMp4O37qDJuW_rYkR9-Q_VuEk98q3ZP44,27358
12
12
  novelwriter/assets/i18n/nw_de_DE.qm,sha256=PPBpHJ3M0jL0t4xSY8zr3CKaO0umGW4K4Tb7bj0gtlA,97532
13
13
  novelwriter/assets/i18n/nw_en_US.qm,sha256=sZKjLkT2CcPhGAS3WUgKm9XO3ugbBrx2zbwVyhP7vSE,90470
14
14
  novelwriter/assets/i18n/nw_es_419.qm,sha256=8saaQ1As_hOgBI-oyEIqV5KCmLaMg_ldkOT9Q1uJmaY,99857
@@ -17,7 +17,7 @@ novelwriter/assets/i18n/nw_it_IT.qm,sha256=mRgsonFCjm6bgG2sldQtMrRDAfqNIpiq9ebp1
17
17
  novelwriter/assets/i18n/nw_ja_JP.qm,sha256=kbZKcnRDKralChIDOqsnK8Sn0NdcjlTDf03fOLVPxxY,74895
18
18
  novelwriter/assets/i18n/nw_nb_NO.qm,sha256=cuQLRkvGXIFYsK7a4j1wxKY3H7JQIfjObkVvFbVFt-Q,92928
19
19
  novelwriter/assets/i18n/nw_nl_NL.qm,sha256=4RcFVAWj3PGT4jeivxLEp85HfiSr3FvFCnlmjQRXSRc,96814
20
- novelwriter/assets/i18n/nw_pt_BR.qm,sha256=2pW_7MFG152nN3Yc721qvvcG01XSRTVe21BvvqdBQvk,79257
20
+ novelwriter/assets/i18n/nw_pt_BR.qm,sha256=JNs3XUrVyq2qNxlwSu4em8J8qUi_Wfp_Wom3JtwXWSE,98636
21
21
  novelwriter/assets/i18n/nw_zh_CN.qm,sha256=3q2cSsY3kT7dRggXq-fj8Sank88V_G2RKzjXQY5-3nA,67445
22
22
  novelwriter/assets/i18n/project_de_DE.json,sha256=85ud9rxRHyXm85QDmW_LKcUE8h0L1Bvukaf5Tjt-wpg,2818
23
23
  novelwriter/assets/i18n/project_en_GB.json,sha256=EcQAVEiQgRL3qobuzkPTfOWIxAc3Om-tA7nXUFFXEdI,2483
@@ -29,7 +29,7 @@ novelwriter/assets/i18n/project_ja_JP.json,sha256=8P03f2D9o2TlSxFU5ugRa-DJDeDZr_
29
29
  novelwriter/assets/i18n/project_nb_NO.json,sha256=e8E9c188KRPJfgZa298hDiaLEuhjHMxbRMaIF8HaVew,2298
30
30
  novelwriter/assets/i18n/project_nl_NL.json,sha256=qUEEjLMRtvt9VuNmjb_qOVCXqUCENHskCEyp5YlPMc4,2683
31
31
  novelwriter/assets/i18n/project_nn_NO.json,sha256=7ZfmtFWHcDMiLVqdOEDHQWHbpoC_bv5ESmf_-CoYiks,2250
32
- novelwriter/assets/i18n/project_pt_BR.json,sha256=oZ7jdSF1h-kuGhKYZOWbuwVCRgakgs9HzeMSiLPnTns,2763
32
+ novelwriter/assets/i18n/project_pt_BR.json,sha256=FDxIeSlf3v8AcrWfgwk7UOMRDmb2hWdDoabsBq5rkL8,2763
33
33
  novelwriter/assets/i18n/project_ru_RU.json,sha256=F4QkD6VVDCtGdil7uoXCmuczvUpe9tv-1L-3Eyc8sKE,3699
34
34
  novelwriter/assets/i18n/project_zh_CN.json,sha256=cfl0TsnbISYUvygOw015y0x0REDG97xR0yjyJ85Jm34,2322
35
35
  novelwriter/assets/icons/none.svg,sha256=NRN9vMzohg7Ner71GwPthrCG0uA81TpY8UmKb8-L-pM,251
@@ -290,7 +290,7 @@ novelwriter/dialogs/wordlist.py,sha256=EfjKQn_SZ8qUCXXw5WHgqe6hWLAn02cD23mWUTTax
290
290
  novelwriter/extensions/circularprogress.py,sha256=H0btKccdnvVfijU8ZudYvv4AgrvPYvx7IgznIxASBY0,3856
291
291
  novelwriter/extensions/configlayout.py,sha256=xHUE_HckNwJsfPKZ3hJjAKAYhxzQFRmNCmBrIh6QtTs,9253
292
292
  novelwriter/extensions/eventfilters.py,sha256=XehDoXwsnCvI1D3uieuYu5J3kxZggdV6Teo7Z0xZw7E,2581
293
- novelwriter/extensions/modified.py,sha256=s8HbGumHA0mAspnYo-ADIiwOXkccL-w1ThimxywdlNc,4038
293
+ novelwriter/extensions/modified.py,sha256=KT2Qo3YsZO5dKzjYhA46Kg-T7fCcm6FyhQrmvrNwgSk,4464
294
294
  novelwriter/extensions/novelselector.py,sha256=5ccEDvqrbvrG7khZBrOiJwxsjjRnkFX-A4ZT-lj_z_g,3821
295
295
  novelwriter/extensions/pagedsidebar.py,sha256=X0AYo6oKM7gKr57662v-ZZWUTCVf5AbvIUCoLQai8fk,7369
296
296
  novelwriter/extensions/simpleprogress.py,sha256=13SrFQ9TZTDICyXCdTHeCX0MOtpw4UbBEgxiAmSOjyQ,1836
@@ -298,32 +298,32 @@ novelwriter/extensions/statusled.py,sha256=640phDm3ZcLvM9EC_uwVPjG9LD5W3pAjtoqU4
298
298
  novelwriter/extensions/switch.py,sha256=sZBNX5Wj1qkVA6cHh04GjuWOTbejaatHgLZ5yGzXGv4,4346
299
299
  novelwriter/extensions/switchbox.py,sha256=y6yuoCAZYYL7miaFlC8h5ymtuB0Xyk2AMmxAFYOYPDA,4210
300
300
  novelwriter/extensions/versioninfo.py,sha256=eUJzO6eV6SFXgp71uxr9696rjUQctGm84CA7XqxFhGc,5120
301
- novelwriter/gui/doceditor.py,sha256=9UVaPhA_FnroPK6_K-GraygJYojh208qiJd426g27pc,113840
301
+ novelwriter/gui/doceditor.py,sha256=d96MDOqdLb4y8cR25ah5KGZGvfFADPT33bDBd7O7kzA,114599
302
302
  novelwriter/gui/dochighlight.py,sha256=9-OP0YrMmljOCsdY-rqZe0G27gkBP7Fzk_R_f3iGGVE,17394
303
- novelwriter/gui/docviewer.py,sha256=9KvGhEMLqmqibhdIgJ7lmoQ28oTnOfT08sdlBo4WV24,33107
303
+ novelwriter/gui/docviewer.py,sha256=RcvChY8OA5gxHzNi6l3xj60ua_6nPxSQ75_apIgeyDg,33559
304
304
  novelwriter/gui/docviewerpanel.py,sha256=IcQGLN49MmVGfIPg-8IzLGKYn9DbJqfdXWG6jd_JaAI,20009
305
305
  novelwriter/gui/editordocument.py,sha256=jxODONgq80Kf63lRezzbYtyEelaC-GpvgPEMKQ3m_sg,4116
306
306
  novelwriter/gui/itemdetails.py,sha256=VIfWDtn9g0IRBYSDFT_AhZgluQ0d7sK5C14lENyvzHg,9774
307
307
  novelwriter/gui/mainmenu.py,sha256=iTXNqmhEZqVDA6XkIAhpIq-cc1fF5-rZVe2g9z7v8_c,38707
308
308
  novelwriter/gui/noveltree.py,sha256=F-r6vdgCoIzxFwOI9kvsLEnz7nX2uOs30LOHHijN7NY,27988
309
309
  novelwriter/gui/outline.py,sha256=q0d21UI2r4K4D9jPARKc3ibWsdpiEnartAHfwxE2AgY,42410
310
- novelwriter/gui/projtree.py,sha256=21B1-NJFYf724oIH5xX0b35YX3YX-zxRcLdYopMdRy8,77888
310
+ novelwriter/gui/projtree.py,sha256=lfGkIBAwi71KrnzpdsfpaSGw4rv8JsD5F7TTjDvkcGA,77927
311
311
  novelwriter/gui/search.py,sha256=PYsSIhe77PCuXj1fRXb2_7GF1gxLDv_vyq8JsgW5UfY,12996
312
312
  novelwriter/gui/sidebar.py,sha256=kidGGzXQ5RNQvKuH0kFh-lwoUSlkXffBucEoL15RMd4,6258
313
313
  novelwriter/gui/statusbar.py,sha256=ru-4pyg8owWkwkXGgj5GEupfq9fbIykYwGpomwzaINk,9353
314
- novelwriter/gui/theme.py,sha256=P2EI79WMGulYBhkADqVOWW13DfFOOoCUeBf7Kxku-wM,32670
314
+ novelwriter/gui/theme.py,sha256=ANv1e5KghrB8z-uaHZbc3GZdmcl_or6KOpFhyBbgeX4,32781
315
315
  novelwriter/text/counting.py,sha256=tkWKWS_scPYmBG8xLpIL1KLIjyF2HOlkrloQa5PZmDc,4304
316
- novelwriter/tools/dictionaries.py,sha256=Xy5or2yejJbUv9ptwqsz1-R4pxDYQATiHCZaqorUXdY,9231
316
+ novelwriter/tools/dictionaries.py,sha256=cEdkqXowPZJV9hD01EmYB6PDGsMFYwVQ7QLEt_jthOk,9308
317
317
  novelwriter/tools/lipsum.py,sha256=d-qdRSrXLfTkTdzi7vhjeBlWawwGwWQ9Qd_zRSwzgpQ,4901
318
318
  novelwriter/tools/manusbuild.py,sha256=80kRr4OfvW2lqjhLpnAWO8HiTX7Y3HSivcjT48v_KUE,14101
319
- novelwriter/tools/manuscript.py,sha256=KdQl1xWVSzl9u1TQ1Jb-zWn3jZRwPuRCqh0DY3h1wHs,40236
320
- novelwriter/tools/manussettings.py,sha256=ak4m6cKk8NAg2OmsQJv-x8Ui-jcUtZe-RkyzotXbqRM,55747
319
+ novelwriter/tools/manuscript.py,sha256=lI7xV8KxnuPQt26sN2m-kKORqK3hInepm5Bc8FYhgjk,40510
320
+ novelwriter/tools/manussettings.py,sha256=xMbamo3AKASz2NkJCIQYlvGPXE_rVeJQjxIXz2c57Bg,55754
321
321
  novelwriter/tools/noveldetails.py,sha256=KoENyz0hH3TlXfRCEJvRTZ0h7ruOgTIv85AgCl1Ur5o,18503
322
322
  novelwriter/tools/welcome.py,sha256=BxORHBPjqumEVNZC7SytE3kUasx01GMOKS5QQSagP-M,27954
323
323
  novelwriter/tools/writingstats.py,sha256=IubrbbLB_Qlnwp9B3muKkeD84xtckPvmTax7E4LnI5g,22797
324
- novelWriter-2.4.2.dist-info/LICENSE.md,sha256=2GirkkLrPfQqx7fACKRJjtKJUegKc8067erGvcDVQHM,32197
325
- novelWriter-2.4.2.dist-info/METADATA,sha256=tGVtHnZQbK2spACdq4VUc3ZGspEmvQO9jFT9Oe6t4Sg,2582
326
- novelWriter-2.4.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
327
- novelWriter-2.4.2.dist-info/entry_points.txt,sha256=YDUG1w361LtLsjD3YhxoTDTwM17JA5-nigjC6j5C74A,45
328
- novelWriter-2.4.2.dist-info/top_level.txt,sha256=wFFEucjEeNC_Ap5ULBuEutg5a1Uc0-YO9uFT5L2naNI,12
329
- novelWriter-2.4.2.dist-info/RECORD,,
324
+ novelWriter-2.4.4.dist-info/LICENSE.md,sha256=2GirkkLrPfQqx7fACKRJjtKJUegKc8067erGvcDVQHM,32197
325
+ novelWriter-2.4.4.dist-info/METADATA,sha256=y8mt-5n0Fuv5tb5iMrqkhYyZW_t_w8qFWknSFE3h1AE,2582
326
+ novelWriter-2.4.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
327
+ novelWriter-2.4.4.dist-info/entry_points.txt,sha256=YDUG1w361LtLsjD3YhxoTDTwM17JA5-nigjC6j5C74A,45
328
+ novelWriter-2.4.4.dist-info/top_level.txt,sha256=wFFEucjEeNC_Ap5ULBuEutg5a1Uc0-YO9uFT5L2naNI,12
329
+ novelWriter-2.4.4.dist-info/RECORD,,
novelwriter/__init__.py CHANGED
@@ -47,9 +47,9 @@ __license__ = "GPLv3"
47
47
  __author__ = "Veronica Berglyd Olsen"
48
48
  __maintainer__ = "Veronica Berglyd Olsen"
49
49
  __email__ = "code@vkbo.net"
50
- __version__ = "2.4.2"
51
- __hexversion__ = "0x020402f0"
52
- __date__ = "2024-05-18"
50
+ __version__ = "2.4.4"
51
+ __hexversion__ = "0x020404f0"
52
+ __date__ = "2024-06-12"
53
53
  __status__ = "Stable"
54
54
  __domain__ = "novelwriter.io"
55
55
 
Binary file
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "Synopsis": "Sinopse",
3
3
  "Short Description": "Descrição breve",
4
- "Comment": "Comentários",
4
+ "Comment": "Comentário",
5
5
  "Notes": "Notas",
6
6
  "Tag": "Etiqueta",
7
7
  "Point of View": "Ponto de vista",
@@ -30,87 +30,87 @@
30
30
  "14": "Quatorze",
31
31
  "15": "Quinze",
32
32
  "16": "Dezesseis",
33
- "17": "Dezesete",
33
+ "17": "Dezessete",
34
34
  "18": "Dezoito",
35
35
  "19": "Dezenove",
36
36
  "20": "Vinte",
37
- "21": "Vinte e Um",
38
- "22": "Vinte e Dois",
39
- "23": "Vinte e Três",
40
- "24": "Vinte e Quatro",
41
- "25": "Vinte e Cinco",
42
- "26": "Vinte e Seis",
43
- "27": "Vinte e Sete",
44
- "28": "Vinte e Oito",
45
- "29": "Vinte e Nove",
37
+ "21": "Vinte e um",
38
+ "22": "Vinte e dois",
39
+ "23": "Vinte e três",
40
+ "24": "Vinte e quatro",
41
+ "25": "Vinte e cinco",
42
+ "26": "Vinte e seis",
43
+ "27": "Vinte e sete",
44
+ "28": "Vinte e oito",
45
+ "29": "Vinte e nove",
46
46
  "30": "Trinta",
47
- "31": "Trinta e Um",
48
- "32": "Trinta e Dois",
49
- "33": "Trinta e Três",
50
- "34": "Trinta e Quatro",
51
- "35": "Trinta e Cinco",
52
- "36": "Trinta e Seis",
53
- "37": "Trinta e Sete",
54
- "38": "Trinta e Oito",
55
- "39": "Trinta e Nove",
47
+ "31": "Trinta e um",
48
+ "32": "Trinta e dois",
49
+ "33": "Trinta e três",
50
+ "34": "Trinta e quatro",
51
+ "35": "Trinta e cinco",
52
+ "36": "Trinta e seis",
53
+ "37": "Trinta e sete",
54
+ "38": "Trinta e oito",
55
+ "39": "Trinta e nove",
56
56
  "40": "Quarenta",
57
- "41": "Quarenta e Um",
58
- "42": "Quarenta e Dois",
59
- "43": "Quarenta e Três",
60
- "44": "Quarenta e Quatro",
61
- "45": "Quarenta e Cinco",
62
- "46": "Quarenta e Seis",
63
- "47": "Quarenta e Sete",
64
- "48": "Quarenta e Oito",
65
- "49": "Quarenta e Nove",
57
+ "41": "Quarenta e um",
58
+ "42": "Quarenta e dois",
59
+ "43": "Quarenta e três",
60
+ "44": "Quarenta e quatro",
61
+ "45": "Quarenta e cinco",
62
+ "46": "Quarenta e seis",
63
+ "47": "Quarenta e sete",
64
+ "48": "Quarenta e oito",
65
+ "49": "Quarenta e nove",
66
66
  "50": "Cinquenta",
67
- "51": "Cinquenta e Um",
68
- "52": "Cinquenta e Dois",
69
- "53": "Cinquenta e Três",
70
- "54": "Cinquenta e Quatro",
71
- "55": "Cinquenta e Cinco",
72
- "56": "Cinquenta e Seis",
73
- "57": "Cinquenta e Sete",
74
- "58": "Cinquenta e Oito",
75
- "59": "Cinquenta e Nove",
67
+ "51": "Cinquenta e um",
68
+ "52": "Cinquenta e dois",
69
+ "53": "Cinquenta e três",
70
+ "54": "Cinquenta e quatro",
71
+ "55": "Cinquenta e cinco",
72
+ "56": "Cinquenta e seis",
73
+ "57": "Cinquenta e sete",
74
+ "58": "Cinquenta e oito",
75
+ "59": "Cinquenta e nove",
76
76
  "60": "Sessenta",
77
- "61": "Sessenta e Um",
78
- "62": "Sessenta e Dois",
79
- "63": "Sessenta e Três",
80
- "64": "Sessenta e Quatro",
81
- "65": "Sessenta e Cinco",
82
- "66": "Sessenta e Seis",
83
- "67": "Sessenta e Sete",
84
- "68": "Sessenta e Oito",
85
- "69": "Sessenta e Nove",
77
+ "61": "Sessenta e um",
78
+ "62": "Sessenta e dois",
79
+ "63": "Sessenta e três",
80
+ "64": "Sessenta e quatro",
81
+ "65": "Sessenta e cinco",
82
+ "66": "Sessenta e seis",
83
+ "67": "Sessenta e sete",
84
+ "68": "Sessenta e oito",
85
+ "69": "Sessenta e nove",
86
86
  "70": "Setenta",
87
- "71": "Setenta e Um",
88
- "72": "Setenta e Dois",
89
- "73": "Setenta e Três",
90
- "74": "Setenta e Quatro",
91
- "75": "Setenta e Cinco",
92
- "76": "Setenta e Seis",
93
- "77": "Setenta e Sete",
94
- "78": "Setenta e Oito",
95
- "79": "Setenta e Nove",
87
+ "71": "Setenta e um",
88
+ "72": "Setenta e dois",
89
+ "73": "Setenta e três",
90
+ "74": "Setenta e quatro",
91
+ "75": "Setenta e cinco",
92
+ "76": "Setenta e seis",
93
+ "77": "Setenta e sete",
94
+ "78": "Setenta e oito",
95
+ "79": "Setenta e nove",
96
96
  "80": "Oitenta",
97
- "81": "Oitenta e Um",
98
- "82": "Oitenta e Dois",
99
- "83": "Oitenta e Três",
100
- "84": "Oitenta e Quatro",
101
- "85": "Oitenta e Cinco",
102
- "86": "Oitenta e Seis",
103
- "87": "Oitenta e Sete",
104
- "88": "Oitenta e Oito",
105
- "89": "Oitenta e Nove",
97
+ "81": "Oitenta e um",
98
+ "82": "Oitenta e dois",
99
+ "83": "Oitenta e três",
100
+ "84": "Oitenta e quatro",
101
+ "85": "Oitenta e cinco",
102
+ "86": "Oitenta e seis",
103
+ "87": "Oitenta e sete",
104
+ "88": "Oitenta e oito",
105
+ "89": "Oitenta e nove",
106
106
  "90": "Noventa",
107
- "91": "Noventa e Um",
108
- "92": "Noventa e Dois",
109
- "93": "Noventa e Três",
110
- "94": "Noventa e Quatro",
111
- "95": "Noventa e Cinco",
112
- "96": "Noventa e Seis",
113
- "97": "Noventa e Sete",
114
- "98": "Noventa e Oito",
115
- "99": "Noventa e Nove"
107
+ "91": "Noventa e um",
108
+ "92": "Noventa e dois",
109
+ "93": "Noventa e três",
110
+ "94": "Noventa e quatro",
111
+ "95": "Noventa e cinco",
112
+ "96": "Noventa e seis",
113
+ "97": "Noventa e sete",
114
+ "98": "Noventa e oito",
115
+ "99": "Noventa e nove"
116
116
  }
Binary file
Binary file
@@ -27,11 +27,23 @@ from __future__ import annotations
27
27
 
28
28
  from PyQt5.QtCore import QSize, Qt
29
29
  from PyQt5.QtGui import QWheelEvent
30
- from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QToolButton, QWidget
30
+ from PyQt5.QtWidgets import QComboBox, QDialog, QDoubleSpinBox, QSpinBox, QToolButton, QWidget
31
31
 
32
32
  from novelwriter import SHARED
33
33
 
34
34
 
35
+ class NDialog(QDialog):
36
+
37
+ def softDelete(self) -> None:
38
+ """Since calling deleteLater is sometimes not safe from Python,
39
+ as the C++ object can be deleted before the Python process is
40
+ done with the object, we instead set the dialog's parent to None
41
+ so that it gets garbage collected when it runs out of scope.
42
+ """
43
+ self.setParent(None) # type: ignore
44
+ return
45
+
46
+
35
47
  class NComboBox(QComboBox):
36
48
 
37
49
  def __init__(self, parent: QWidget | None = None) -> None:
@@ -43,8 +43,8 @@ from PyQt5.QtCore import (
43
43
  pyqtSignal, pyqtSlot
44
44
  )
45
45
  from PyQt5.QtGui import (
46
- QColor, QCursor, QFont, QKeyEvent, QKeySequence, QMouseEvent, QPalette,
47
- QPixmap, QResizeEvent, QTextBlock, QTextCursor, QTextDocument, QTextOption
46
+ QColor, QCursor, QKeyEvent, QKeySequence, QMouseEvent, QPalette, QPixmap,
47
+ QResizeEvent, QTextBlock, QTextCursor, QTextDocument, QTextOption
48
48
  )
49
49
  from PyQt5.QtWidgets import (
50
50
  QAction, QApplication, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit,
@@ -329,10 +329,7 @@ class GuiDocEditor(QPlainTextEdit):
329
329
  SHARED.updateSpellCheckLanguage()
330
330
 
331
331
  # Set font
332
- font = QFont()
333
- font.setFamily(CONFIG.textFont)
334
- font.setPointSize(CONFIG.textSize)
335
- self._qDocument.setDefaultFont(font)
332
+ self.initFont()
336
333
 
337
334
  # Update highlighter settings
338
335
  self._qDocument.syntaxHighlighter.initHighlighter()
@@ -382,6 +379,23 @@ class GuiDocEditor(QPlainTextEdit):
382
379
 
383
380
  return
384
381
 
382
+ def initFont(self) -> None:
383
+ """Set the font of the main widget and sub-widgets. This needs
384
+ special attention since there appears to be a bug in Qt 5.15.3.
385
+ See issues #1862 and #1875.
386
+ """
387
+ font = self.font()
388
+ font.setFamily(CONFIG.textFont)
389
+ font.setPointSize(CONFIG.textSize)
390
+ self.setFont(font)
391
+
392
+ # Reset sub-widget font to GUI font
393
+ self.docHeader.updateFont()
394
+ self.docFooter.updateFont()
395
+ self.docSearch.updateFont()
396
+
397
+ return
398
+
385
399
  def loadText(self, tHandle: str, tLine: int | None = None) -> bool:
386
400
  """Load text from a document into the editor. If we have an I/O
387
401
  error, we must handle this and clear the editor so that we don't
@@ -2396,9 +2410,6 @@ class GuiDocEditSearch(QFrame):
2396
2410
  iSz = SHARED.theme.baseIconSize
2397
2411
  mPx = CONFIG.pxInt(6)
2398
2412
 
2399
- self.boxFont = SHARED.theme.guiFont
2400
- self.boxFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
2401
-
2402
2413
  self.setContentsMargins(0, 0, 0, 0)
2403
2414
  self.setAutoFillBackground(True)
2404
2415
  self.setFrameStyle(QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
@@ -2410,12 +2421,10 @@ class GuiDocEditSearch(QFrame):
2410
2421
  # ==========
2411
2422
 
2412
2423
  self.searchBox = QLineEdit(self)
2413
- self.searchBox.setFont(self.boxFont)
2414
2424
  self.searchBox.setPlaceholderText(self.tr("Search for"))
2415
2425
  self.searchBox.returnPressed.connect(self._doSearch)
2416
2426
 
2417
2427
  self.replaceBox = QLineEdit(self)
2418
- self.replaceBox.setFont(self.boxFont)
2419
2428
  self.replaceBox.setPlaceholderText(self.tr("Replace with"))
2420
2429
  self.replaceBox.returnPressed.connect(self._doReplace)
2421
2430
 
@@ -2425,12 +2434,9 @@ class GuiDocEditSearch(QFrame):
2425
2434
  self.searchOpt.setContentsMargins(0, 0, 0, 0)
2426
2435
 
2427
2436
  self.searchLabel = QLabel(self.tr("Search"), self)
2428
- self.searchLabel.setFont(self.boxFont)
2429
2437
  self.searchLabel.setIndent(CONFIG.pxInt(6))
2430
2438
 
2431
2439
  self.resultLabel = QLabel("?/?", self)
2432
- self.resultLabel.setFont(self.boxFont)
2433
- self.resultLabel.setMinimumWidth(SHARED.theme.getTextWidth("?/?", self.boxFont))
2434
2440
 
2435
2441
  self.toggleCase = QAction(self.tr("Case Sensitive"), self)
2436
2442
  self.toggleCase.setCheckable(True)
@@ -2515,6 +2521,7 @@ class GuiDocEditSearch(QFrame):
2515
2521
  self.replaceButton.setVisible(False)
2516
2522
  self.adjustSize()
2517
2523
 
2524
+ self.updateFont()
2518
2525
  self.updateTheme()
2519
2526
 
2520
2527
  logger.debug("Ready: GuiDocEditSearch")
@@ -2598,7 +2605,9 @@ class GuiDocEditSearch(QFrame):
2598
2605
  numCount = f"{lim:n}+" if (resCount or 0) > lim else f"{resCount:n}"
2599
2606
  sCurrRes = "?" if currRes is None else str(currRes)
2600
2607
  sResCount = "?" if resCount is None else numCount
2601
- minWidth = SHARED.theme.getTextWidth(f"{sResCount}//{sResCount}", self.boxFont)
2608
+ minWidth = SHARED.theme.getTextWidth(
2609
+ f"{sResCount}//{sResCount}", SHARED.theme.guiFontSmall
2610
+ )
2602
2611
  self.resultLabel.setText(f"{sCurrRes}/{sResCount}")
2603
2612
  self.resultLabel.setMinimumWidth(minWidth)
2604
2613
  self.adjustSize()
@@ -2609,6 +2618,18 @@ class GuiDocEditSearch(QFrame):
2609
2618
  # Methods
2610
2619
  ##
2611
2620
 
2621
+ def updateFont(self) -> None:
2622
+ """Update the font settings."""
2623
+ self.setFont(SHARED.theme.guiFont)
2624
+ self.searchBox.setFont(SHARED.theme.guiFontSmall)
2625
+ self.replaceBox.setFont(SHARED.theme.guiFontSmall)
2626
+ self.searchLabel.setFont(SHARED.theme.guiFontSmall)
2627
+ self.resultLabel.setFont(SHARED.theme.guiFontSmall)
2628
+ self.resultLabel.setMinimumWidth(
2629
+ SHARED.theme.getTextWidth("?/?", SHARED.theme.guiFontSmall)
2630
+ )
2631
+ return
2632
+
2612
2633
  def updateTheme(self) -> None:
2613
2634
  """Update theme elements."""
2614
2635
  qPalette = QApplication.palette()
@@ -2793,10 +2814,6 @@ class GuiDocEditHeader(QWidget):
2793
2814
  self.itemTitle.setAlignment(QtAlignCenterTop)
2794
2815
  self.itemTitle.setFixedHeight(iPx)
2795
2816
 
2796
- lblFont = self.itemTitle.font()
2797
- lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
2798
- self.itemTitle.setFont(lblFont)
2799
-
2800
2817
  # Other Widgets
2801
2818
  self.outlineMenu = QMenu(self)
2802
2819
 
@@ -2850,6 +2867,7 @@ class GuiDocEditHeader(QWidget):
2850
2867
  self.setContentsMargins(0, 0, 0, 0)
2851
2868
  self.setMinimumHeight(iPx + 2*mPx)
2852
2869
 
2870
+ self.updateFont()
2853
2871
  self.updateTheme()
2854
2872
 
2855
2873
  logger.debug("Ready: GuiDocEditHeader")
@@ -2888,6 +2906,12 @@ class GuiDocEditHeader(QWidget):
2888
2906
  logger.debug("Document outline updated in %.3f ms", 1000*(time() - tStart))
2889
2907
  return
2890
2908
 
2909
+ def updateFont(self) -> None:
2910
+ """Update the font settings."""
2911
+ self.setFont(SHARED.theme.guiFont)
2912
+ self.itemTitle.setFont(SHARED.theme.guiFontSmall)
2913
+ return
2914
+
2891
2915
  def updateTheme(self) -> None:
2892
2916
  """Update theme elements."""
2893
2917
  self.tbButton.setThemeIcon("menu")
@@ -3001,9 +3025,6 @@ class GuiDocEditFooter(QWidget):
3001
3025
  bSp = CONFIG.pxInt(4)
3002
3026
  hSp = CONFIG.pxInt(6)
3003
3027
 
3004
- lblFont = self.font()
3005
- lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
3006
-
3007
3028
  # Cached Translations
3008
3029
  self._trLineCount = self.tr("Line: {0} ({1})")
3009
3030
  self._trWordCount = self.tr("Words: {0} ({1})")
@@ -3026,7 +3047,6 @@ class GuiDocEditFooter(QWidget):
3026
3047
  self.statusText.setAutoFillBackground(True)
3027
3048
  self.statusText.setFixedHeight(fPx)
3028
3049
  self.statusText.setAlignment(QtAlignLeftTop)
3029
- self.statusText.setFont(lblFont)
3030
3050
 
3031
3051
  # Lines
3032
3052
  self.linesIcon = QLabel("", self)
@@ -3041,7 +3061,6 @@ class GuiDocEditFooter(QWidget):
3041
3061
  self.linesText.setAutoFillBackground(True)
3042
3062
  self.linesText.setFixedHeight(fPx)
3043
3063
  self.linesText.setAlignment(QtAlignLeftTop)
3044
- self.linesText.setFont(lblFont)
3045
3064
 
3046
3065
  # Words
3047
3066
  self.wordsIcon = QLabel("", self)
@@ -3056,7 +3075,6 @@ class GuiDocEditFooter(QWidget):
3056
3075
  self.wordsText.setAutoFillBackground(True)
3057
3076
  self.wordsText.setFixedHeight(fPx)
3058
3077
  self.wordsText.setAlignment(QtAlignLeftTop)
3059
- self.wordsText.setFont(lblFont)
3060
3078
 
3061
3079
  # Assemble Layout
3062
3080
  self.outerBox = QHBoxLayout()
@@ -3079,6 +3097,7 @@ class GuiDocEditFooter(QWidget):
3079
3097
  self.setMinimumHeight(fPx + 2*mPx)
3080
3098
 
3081
3099
  # Fix the Colours
3100
+ self.updateFont()
3082
3101
  self.updateTheme()
3083
3102
 
3084
3103
  # Initialise Info
@@ -3092,6 +3111,14 @@ class GuiDocEditFooter(QWidget):
3092
3111
  # Methods
3093
3112
  ##
3094
3113
 
3114
+ def updateFont(self) -> None:
3115
+ """Update the font settings."""
3116
+ self.setFont(SHARED.theme.guiFont)
3117
+ self.statusText.setFont(SHARED.theme.guiFontSmall)
3118
+ self.linesText.setFont(SHARED.theme.guiFontSmall)
3119
+ self.wordsText.setFont(SHARED.theme.guiFontSmall)
3120
+ return
3121
+
3095
3122
  def updateTheme(self) -> None:
3096
3123
  """Update theme elements."""
3097
3124
  iPx = round(0.9*SHARED.theme.baseIconHeight)
@@ -31,10 +31,7 @@ import logging
31
31
  from enum import Enum
32
32
 
33
33
  from PyQt5.QtCore import QPoint, Qt, QUrl, pyqtSignal, pyqtSlot
34
- from PyQt5.QtGui import (
35
- QCursor, QFont, QMouseEvent, QPalette, QResizeEvent, QTextCursor,
36
- QTextOption
37
- )
34
+ from PyQt5.QtGui import QCursor, QMouseEvent, QPalette, QResizeEvent, QTextCursor, QTextOption
38
35
  from PyQt5.QtWidgets import (
39
36
  QAction, QApplication, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser,
40
37
  QToolButton, QWidget
@@ -141,12 +138,7 @@ class GuiDocViewer(QTextBrowser):
141
138
  def initViewer(self) -> None:
142
139
  """Set editor settings from main config."""
143
140
  self._makeStyleSheet()
144
-
145
- # Set Font
146
- font = QFont()
147
- font.setFamily(CONFIG.textFont)
148
- font.setPointSize(CONFIG.textSize)
149
- self.document().setDefaultFont(font)
141
+ self.initFont()
150
142
 
151
143
  # Set the widget colours to match syntax theme
152
144
  mainPalette = self.palette()
@@ -189,6 +181,22 @@ class GuiDocViewer(QTextBrowser):
189
181
 
190
182
  return
191
183
 
184
+ def initFont(self) -> None:
185
+ """Set the font of the main widget and sub-widgets. This needs
186
+ special attention since there appears to be a bug in Qt 5.15.3.
187
+ See issues #1862 and #1875.
188
+ """
189
+ font = self.font()
190
+ font.setFamily(CONFIG.textFont)
191
+ font.setPointSize(CONFIG.textSize)
192
+ self.setFont(font)
193
+
194
+ # Reset sub-widget font to GUI font
195
+ self.docHeader.updateFont()
196
+ self.docFooter.updateFont()
197
+
198
+ return
199
+
192
200
  def loadText(self, tHandle: str, updateHistory: bool = True) -> bool:
193
201
  """Load text into the viewer from an item handle."""
194
202
  if not SHARED.project.tree.checkType(tHandle, nwItemType.FILE):
@@ -646,10 +654,6 @@ class GuiDocViewHeader(QWidget):
646
654
  self.itemTitle.setAlignment(QtAlignCenterTop)
647
655
  self.itemTitle.setFixedHeight(iPx)
648
656
 
649
- lblFont = self.itemTitle.font()
650
- lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
651
- self.itemTitle.setFont(lblFont)
652
-
653
657
  # Other Widgets
654
658
  self.outlineMenu = QMenu(self)
655
659
 
@@ -700,7 +704,7 @@ class GuiDocViewHeader(QWidget):
700
704
  self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx)
701
705
  self.setMinimumHeight(iPx + 2*mPx)
702
706
 
703
- # Fix the Colours
707
+ self.updateFont()
704
708
  self.updateTheme()
705
709
 
706
710
  logger.debug("Ready: GuiDocViewHeader")
@@ -745,6 +749,12 @@ class GuiDocViewHeader(QWidget):
745
749
  self._docOutline = data
746
750
  return
747
751
 
752
+ def updateFont(self) -> None:
753
+ """Update the font settings."""
754
+ self.setFont(SHARED.theme.guiFont)
755
+ self.itemTitle.setFont(SHARED.theme.guiFontSmall)
756
+ return
757
+
748
758
  def updateTheme(self) -> None:
749
759
  """Update theme elements."""
750
760
  self.outlineButton.setThemeIcon("list")
@@ -886,11 +896,6 @@ class GuiDocViewFooter(QWidget):
886
896
  self.showSynopsis.toggled.connect(self._doToggleSynopsis)
887
897
  self.showSynopsis.setToolTip(self.tr("Show Synopsis Comments"))
888
898
 
889
- lblFont = self.font()
890
- lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
891
- self.showComments.setFont(lblFont)
892
- self.showSynopsis.setFont(lblFont)
893
-
894
899
  # Assemble Layout
895
900
  self.outerBox = QHBoxLayout()
896
901
  self.outerBox.addWidget(self.showHide, 0)
@@ -906,7 +911,7 @@ class GuiDocViewFooter(QWidget):
906
911
  self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx)
907
912
  self.setMinimumHeight(iPx + 2*mPx)
908
913
 
909
- # Fix the Colours
914
+ self.updateFont()
910
915
  self.updateTheme()
911
916
 
912
917
  logger.debug("Ready: GuiDocViewFooter")
@@ -917,6 +922,13 @@ class GuiDocViewFooter(QWidget):
917
922
  # Methods
918
923
  ##
919
924
 
925
+ def updateFont(self) -> None:
926
+ """Update the font settings."""
927
+ self.setFont(SHARED.theme.guiFont)
928
+ self.showComments.setFont(SHARED.theme.guiFontSmall)
929
+ self.showSynopsis.setFont(SHARED.theme.guiFontSmall)
930
+ return
931
+
920
932
  def updateTheme(self) -> None:
921
933
  """Update theme elements."""
922
934
  # Icons
@@ -32,10 +32,8 @@ from enum import Enum
32
32
  from time import time
33
33
  from typing import TYPE_CHECKING
34
34
 
35
- from PyQt5.QtCore import QPoint, QTimer, Qt, pyqtSignal, pyqtSlot
36
- from PyQt5.QtGui import (
37
- QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette
38
- )
35
+ from PyQt5.QtCore import QPoint, Qt, QTimer, pyqtSignal, pyqtSlot
36
+ from PyQt5.QtGui import QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette
39
37
  from PyQt5.QtWidgets import (
40
38
  QAbstractItemView, QAction, QDialog, QFrame, QHBoxLayout, QHeaderView,
41
39
  QLabel, QMenu, QShortcut, QSizePolicy, QTreeWidget, QTreeWidgetItem,
@@ -44,14 +42,14 @@ from PyQt5.QtWidgets import (
44
42
 
45
43
  from novelwriter import CONFIG, SHARED
46
44
  from novelwriter.common import minmax
47
- from novelwriter.constants import nwHeaders, nwUnicode, trConst, nwLabels
45
+ from novelwriter.constants import nwHeaders, nwLabels, nwUnicode, trConst
48
46
  from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter
49
47
  from novelwriter.core.item import NWItem
50
48
  from novelwriter.dialogs.docmerge import GuiDocMerge
51
49
  from novelwriter.dialogs.docsplit import GuiDocSplit
52
50
  from novelwriter.dialogs.editlabel import GuiEditLabel
53
51
  from novelwriter.dialogs.projectsettings import GuiProjectSettings
54
- from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout
52
+ from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType
55
53
  from novelwriter.extensions.modified import NIconToolButton
56
54
  from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
57
55
  from novelwriter.types import QtAlignLeft, QtAlignRight, QtMouseLeft, QtMouseMiddle, QtUserRole
@@ -1830,6 +1828,7 @@ class _TreeContextMenu(QMenu):
1830
1828
 
1831
1829
  def _itemHeader(self) -> None:
1832
1830
  """Check if there is a header that can be used for rename."""
1831
+ SHARED.ensureEditorSaved(self._handle)
1833
1832
  if hItem := SHARED.project.index.getItemHeading(self._handle, "T0001"):
1834
1833
  action = self.addAction(self.tr("Rename to Heading"))
1835
1834
  action.triggered.connect(
novelwriter/gui/theme.py CHANGED
@@ -30,9 +30,7 @@ from math import ceil
30
30
  from pathlib import Path
31
31
 
32
32
  from PyQt5.QtCore import QSize, Qt
33
- from PyQt5.QtGui import (
34
- QPalette, QColor, QIcon, QFont, QFontMetrics, QFontDatabase, QPixmap
35
- )
33
+ from PyQt5.QtGui import QColor, QFont, QFontDatabase, QFontMetrics, QIcon, QPalette, QPixmap
36
34
  from PyQt5.QtWidgets import QApplication
37
35
 
38
36
  from novelwriter import CONFIG
@@ -154,6 +152,8 @@ class GuiTheme:
154
152
  self.guiFont = QApplication.font()
155
153
  self.guiFontB = QApplication.font()
156
154
  self.guiFontB.setBold(True)
155
+ self.guiFontSmall = QApplication.font()
156
+ self.guiFontSmall.setPointSizeF(0.9*self.guiFont.pointSizeF())
157
157
 
158
158
  qMetric = QFontMetrics(self.guiFont)
159
159
  fHeight = qMetric.height()
novelwriter/shared.py CHANGED
@@ -204,6 +204,19 @@ class SharedData(QObject):
204
204
  self._resetIdleTimer()
205
205
  return
206
206
 
207
+ def ensureEditorSaved(self, tHandle: str | None) -> None:
208
+ """Ensure that the editor content is saved. Optionally, only if
209
+ it is a specific handle.
210
+ """
211
+ docEditor = self.mainGui.docEditor
212
+ if (
213
+ self.hasProject and docEditor.docHandle
214
+ and (tHandle is None or tHandle == docEditor.docHandle)
215
+ ):
216
+ logger.debug("Saving editor document before action")
217
+ docEditor.saveText()
218
+ return
219
+
207
220
  def updateSpellCheckLanguage(self, reload: bool = False) -> None:
208
221
  """Update the active spell check language from settings."""
209
222
  from novelwriter import CONFIG
@@ -36,7 +36,7 @@ from PyQt5.QtWidgets import (
36
36
  )
37
37
 
38
38
  from novelwriter import CONFIG, SHARED
39
- from novelwriter.common import formatFileFilter, openExternalPath, formatInt, getFileSize
39
+ from novelwriter.common import formatFileFilter, formatInt, getFileSize, openExternalPath
40
40
  from novelwriter.error import formatException
41
41
  from novelwriter.extensions.modified import NIconToolButton
42
42
  from novelwriter.types import QtDialogClose
@@ -143,11 +143,12 @@ class GuiDictionaries(QDialog):
143
143
  try:
144
144
  import enchant
145
145
  path = Path(enchant.get_user_config_dir())
146
+ self._installPath = Path(path).resolve()
147
+ self._installPath.mkdir(exist_ok=True, parents=True)
146
148
  except Exception:
147
149
  logger.error("Could not get enchant path")
148
150
  return False
149
151
 
150
- self._installPath = Path(path).resolve()
151
152
  if path.is_dir():
152
153
  self.inPath.setText(str(path))
153
154
  hunspell = path / "hunspell"
@@ -199,9 +200,9 @@ class GuiDictionaries(QDialog):
199
200
  if self._installPath:
200
201
  temp = self.huInput.text()
201
202
  if temp and (path := Path(temp)).is_file():
202
- hunspell = self._installPath / "hunspell"
203
- hunspell.mkdir(exist_ok=True)
204
203
  try:
204
+ hunspell = self._installPath / "hunspell"
205
+ hunspell.mkdir(exist_ok=True)
205
206
  nAff, nDic = self._extractDicts(path, hunspell)
206
207
  if nAff == 0 or nDic == 0:
207
208
  self._appendLog(procErr, err=True)
@@ -31,13 +31,13 @@ from time import time
31
31
  from typing import TYPE_CHECKING
32
32
 
33
33
  from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot
34
- from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent
34
+ from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QPalette, QResizeEvent
35
35
  from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
36
36
  from PyQt5.QtWidgets import (
37
- QAbstractItemView, QApplication, QDialog, QFormLayout, QGridLayout,
38
- QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton,
39
- QSizePolicy, QSplitter, QStackedWidget, QTabWidget, QTextBrowser,
40
- QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
37
+ QAbstractItemView, QApplication, QFormLayout, QGridLayout, QHBoxLayout,
38
+ QLabel, QListWidget, QListWidgetItem, QPushButton, QSizePolicy, QSplitter,
39
+ QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget, QTreeWidgetItem,
40
+ QVBoxLayout, QWidget
41
41
  )
42
42
 
43
43
  from novelwriter import CONFIG, SHARED
@@ -48,7 +48,7 @@ from novelwriter.core.tohtml import ToHtml
48
48
  from novelwriter.core.tokenizer import HeadingFormatter
49
49
  from novelwriter.error import logException
50
50
  from novelwriter.extensions.circularprogress import NProgressCircle
51
- from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton
51
+ from novelwriter.extensions.modified import NDialog, NIconToggleButton, NIconToolButton
52
52
  from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
53
53
  from novelwriter.tools.manusbuild import GuiManuscriptBuild
54
54
  from novelwriter.tools.manussettings import GuiBuildSettings
@@ -63,7 +63,7 @@ if TYPE_CHECKING: # pragma: no cover
63
63
  logger = logging.getLogger(__name__)
64
64
 
65
65
 
66
- class GuiManuscript(QDialog):
66
+ class GuiManuscript(NDialog):
67
67
  """GUI Tools: Manuscript Tool
68
68
 
69
69
  The dialog displays all the users build definitions, a preview panel
@@ -285,7 +285,7 @@ class GuiManuscript(QDialog):
285
285
  if isinstance(obj, GuiBuildSettings) and obj.isVisible():
286
286
  obj.close()
287
287
  event.accept()
288
- self.deleteLater()
288
+ self.softDelete()
289
289
  return
290
290
 
291
291
  ##
@@ -343,7 +343,7 @@ class GuiManuscript(QDialog):
343
343
  return
344
344
 
345
345
  # Make sure editor content is saved before we start
346
- SHARED.mainGui.saveDocument()
346
+ SHARED.ensureEditorSaved(None)
347
347
 
348
348
  docBuild = NWBuildDocument(SHARED.project, build)
349
349
  docBuild.setPreviewMode(True)
@@ -761,7 +761,6 @@ class _PreviewWidget(QTextBrowser):
761
761
  self.setPalette(dPalette)
762
762
 
763
763
  self.setMinimumWidth(40*SHARED.theme.textNWidth)
764
- self.setTextFont(CONFIG.textFont, CONFIG.textSize)
765
764
  self.setTabStopDistance(CONFIG.getTabWidth())
766
765
  self.setOpenExternalLinks(False)
767
766
 
@@ -802,6 +801,8 @@ class _PreviewWidget(QTextBrowser):
802
801
  self._updateDocMargins()
803
802
  self._updateBuildAge()
804
803
 
804
+ self.setTextFont(CONFIG.textFont, CONFIG.textSize)
805
+
805
806
  # Age Timer
806
807
  self.ageTimer = QTimer(self)
807
808
  self.ageTimer.setInterval(10000)
@@ -831,12 +832,17 @@ class _PreviewWidget(QTextBrowser):
831
832
  return
832
833
 
833
834
  def setTextFont(self, family: str, size: int) -> None:
834
- """Set the text font properties."""
835
- if family:
836
- font = QFont()
835
+ """Set the text font properties and then reset for sub-widgets.
836
+ This needs special attention since there appears to be a bug in
837
+ Qt 5.15.3. See issues #1862 and #1875.
838
+ """
839
+ if family and size > 4:
840
+ font = self.font()
837
841
  font.setFamily(family)
838
842
  font.setPointSize(size)
839
- self.document().setDefaultFont(font)
843
+ self.setFont(font)
844
+ self.buildProgress.setFont(SHARED.theme.guiFont)
845
+ self.ageLabel.setFont(SHARED.theme.guiFontSmall)
840
846
  return
841
847
 
842
848
  ##
@@ -30,8 +30,8 @@ from typing import TYPE_CHECKING
30
30
  from PyQt5.QtCore import QEvent, Qt, pyqtSignal, pyqtSlot
31
31
  from PyQt5.QtGui import QFont, QIcon, QSyntaxHighlighter, QTextCharFormat, QTextDocument
32
32
  from PyQt5.QtWidgets import (
33
- QAbstractButton, QAbstractItemView, QDialog, QDialogButtonBox, QFontDialog,
34
- QFrame, QGridLayout, QHBoxLayout, QHeaderView, QLabel, QLineEdit, QMenu,
33
+ QAbstractButton, QAbstractItemView, QDialogButtonBox, QFontDialog, QFrame,
34
+ QGridLayout, QHBoxLayout, QHeaderView, QLabel, QLineEdit, QMenu,
35
35
  QPlainTextEdit, QPushButton, QSplitter, QStackedWidget, QTreeWidget,
36
36
  QTreeWidgetItem, QVBoxLayout, QWidget
37
37
  )
@@ -42,7 +42,9 @@ from novelwriter.core.buildsettings import BuildSettings, FilterMode
42
42
  from novelwriter.extensions.configlayout import (
43
43
  NColourLabel, NFixedPage, NScrollableForm, NScrollablePage
44
44
  )
45
- from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NIconToolButton, NSpinBox
45
+ from novelwriter.extensions.modified import (
46
+ NComboBox, NDialog, NDoubleSpinBox, NIconToolButton, NSpinBox
47
+ )
46
48
  from novelwriter.extensions.pagedsidebar import NPagedSideBar
47
49
  from novelwriter.extensions.switch import NSwitch
48
50
  from novelwriter.extensions.switchbox import NSwitchBox
@@ -57,7 +59,7 @@ if TYPE_CHECKING: # pragma: no cover
57
59
  logger = logging.getLogger(__name__)
58
60
 
59
61
 
60
- class GuiBuildSettings(QDialog):
62
+ class GuiBuildSettings(NDialog):
61
63
  """GUI Tools: Manuscript Build Settings Dialog
62
64
 
63
65
  The main tool for configuring manuscript builds. It's a GUI tool for
@@ -199,7 +201,7 @@ class GuiBuildSettings(QDialog):
199
201
  self._askToSaveBuild()
200
202
  self._saveSettings()
201
203
  event.accept()
202
- self.deleteLater()
204
+ self.softDelete()
203
205
  return
204
206
 
205
207
  ##