novelWriter 2.6.3__py3-none-any.whl → 2.7__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.
- novelwriter/__init__.py +98 -75
- novelwriter/assets/i18n/nw_cs_CZ.qm +0 -0
- novelwriter/assets/i18n/nw_de_DE.qm +0 -0
- novelwriter/assets/i18n/nw_en_US.qm +0 -0
- novelwriter/assets/i18n/nw_es_419.qm +0 -0
- novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
- novelwriter/assets/i18n/nw_it_IT.qm +0 -0
- novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
- novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
- novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
- novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
- novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_ru_RU.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_de_DE.json +3 -1
- novelwriter/assets/i18n/project_en_GB.json +2 -0
- novelwriter/assets/i18n/project_en_US.json +2 -0
- novelwriter/assets/i18n/project_it_IT.json +2 -0
- novelwriter/assets/i18n/project_ja_JP.json +2 -0
- novelwriter/assets/i18n/project_nb_NO.json +2 -0
- novelwriter/assets/i18n/project_nn_NO.json +5 -0
- novelwriter/assets/i18n/project_pl_PL.json +2 -0
- novelwriter/assets/i18n/project_pt_BR.json +2 -0
- novelwriter/assets/i18n/project_ru_RU.json +2 -0
- novelwriter/assets/i18n/project_zh_CN.json +2 -0
- novelwriter/assets/icons/font_awesome.icons +109 -0
- novelwriter/assets/icons/material_filled_bold.icons +109 -0
- novelwriter/assets/icons/material_filled_normal.icons +109 -0
- novelwriter/assets/icons/material_filled_thin.icons +109 -0
- novelwriter/assets/icons/material_rounded_bold.icons +109 -0
- novelwriter/assets/icons/material_rounded_normal.icons +109 -0
- novelwriter/assets/icons/material_rounded_thin.icons +109 -0
- novelwriter/assets/icons/remix_filled.icons +109 -0
- novelwriter/assets/icons/remix_outline.icons +109 -0
- novelwriter/assets/images/splash.png +0 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/{manual_fr_FR.pdf → manual_fr.pdf} +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/cyberpunk_night.conf +1 -1
- novelwriter/assets/syntax/snazzy.conf +3 -3
- novelwriter/assets/text/credits_en.htm +12 -6
- novelwriter/assets/themes/cyberpunk_night.conf +23 -7
- novelwriter/assets/themes/default_dark.conf +20 -4
- novelwriter/assets/themes/default_light.conf +21 -5
- novelwriter/assets/themes/dracula.conf +20 -4
- novelwriter/assets/themes/snazzy.conf +48 -0
- novelwriter/assets/themes/solarized_dark.conf +24 -8
- novelwriter/assets/themes/solarized_light.conf +22 -6
- novelwriter/common.py +43 -27
- novelwriter/config.py +201 -139
- novelwriter/constants.py +67 -36
- novelwriter/core/buildsettings.py +26 -17
- novelwriter/core/coretools.py +52 -41
- novelwriter/core/docbuild.py +20 -13
- novelwriter/core/document.py +2 -2
- novelwriter/core/index.py +166 -432
- novelwriter/core/indexdata.py +406 -0
- novelwriter/core/item.py +50 -32
- novelwriter/core/itemmodel.py +43 -38
- novelwriter/core/novelmodel.py +225 -0
- novelwriter/core/options.py +1 -1
- novelwriter/core/project.py +24 -25
- novelwriter/core/projectdata.py +47 -29
- novelwriter/core/projectxml.py +18 -8
- novelwriter/core/sessions.py +32 -15
- novelwriter/core/spellcheck.py +4 -3
- novelwriter/core/status.py +12 -15
- novelwriter/core/storage.py +1 -1
- novelwriter/core/tree.py +55 -13
- novelwriter/dialogs/about.py +19 -22
- novelwriter/dialogs/docmerge.py +23 -24
- novelwriter/dialogs/docsplit.py +26 -26
- novelwriter/dialogs/editlabel.py +19 -20
- novelwriter/dialogs/preferences.py +143 -69
- novelwriter/dialogs/projectsettings.py +51 -54
- novelwriter/dialogs/quotes.py +14 -19
- novelwriter/dialogs/wordlist.py +25 -30
- novelwriter/enum.py +8 -0
- novelwriter/error.py +16 -16
- novelwriter/extensions/configlayout.py +24 -20
- novelwriter/extensions/eventfilters.py +9 -5
- novelwriter/extensions/modified.py +34 -15
- novelwriter/extensions/novelselector.py +18 -5
- novelwriter/extensions/pagedsidebar.py +39 -49
- novelwriter/extensions/progressbars.py +10 -8
- novelwriter/extensions/statusled.py +6 -13
- novelwriter/extensions/switch.py +31 -41
- novelwriter/extensions/switchbox.py +8 -3
- novelwriter/extensions/versioninfo.py +4 -4
- novelwriter/formats/shared.py +1 -1
- novelwriter/formats/todocx.py +14 -10
- novelwriter/formats/tohtml.py +7 -5
- novelwriter/formats/tokenizer.py +37 -33
- novelwriter/formats/tomarkdown.py +6 -2
- novelwriter/formats/toodt.py +27 -22
- novelwriter/formats/toqdoc.py +19 -14
- novelwriter/formats/toraw.py +6 -2
- novelwriter/gui/doceditor.py +314 -305
- novelwriter/gui/dochighlight.py +46 -45
- novelwriter/gui/docviewer.py +102 -104
- novelwriter/gui/docviewerpanel.py +47 -51
- novelwriter/gui/editordocument.py +8 -5
- novelwriter/gui/itemdetails.py +11 -14
- novelwriter/gui/mainmenu.py +146 -145
- novelwriter/gui/noveltree.py +246 -406
- novelwriter/gui/outline.py +141 -72
- novelwriter/gui/projtree.py +139 -132
- novelwriter/gui/search.py +34 -31
- novelwriter/gui/sidebar.py +13 -18
- novelwriter/gui/statusbar.py +27 -21
- novelwriter/gui/theme.py +554 -436
- novelwriter/guimain.py +56 -38
- novelwriter/shared.py +32 -23
- novelwriter/splash.py +74 -0
- novelwriter/text/comments.py +70 -0
- novelwriter/text/patterns.py +4 -4
- novelwriter/tools/dictionaries.py +20 -29
- novelwriter/tools/lipsum.py +18 -18
- novelwriter/tools/manusbuild.py +39 -42
- novelwriter/tools/manuscript.py +102 -115
- novelwriter/tools/manussettings.py +129 -102
- novelwriter/tools/noveldetails.py +60 -72
- novelwriter/tools/welcome.py +57 -75
- novelwriter/tools/writingstats.py +112 -102
- novelwriter/types.py +5 -7
- {novelWriter-2.6.3.dist-info → novelwriter-2.7.dist-info}/METADATA +6 -6
- novelwriter-2.7.dist-info/RECORD +162 -0
- {novelWriter-2.6.3.dist-info → novelwriter-2.7.dist-info}/WHEEL +1 -1
- novelWriter-2.6.3.dist-info/RECORD +0 -363
- novelwriter/assets/icons/typicons_dark/README.md +0 -29
- novelwriter/assets/icons/typicons_dark/icons.conf +0 -134
- novelwriter/assets/icons/typicons_dark/mixed_copy.svg +0 -4
- novelwriter/assets/icons/typicons_dark/mixed_document-chapter.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_document-new.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_document-note.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_document-scene.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_document-section.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_document-title.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_edit.svg +0 -4
- novelwriter/assets/icons/typicons_dark/mixed_import.svg +0 -5
- novelwriter/assets/icons/typicons_dark/mixed_input-checked.svg +0 -5
- novelwriter/assets/icons/typicons_dark/mixed_input-none.svg +0 -5
- novelwriter/assets/icons/typicons_dark/mixed_input-unchecked.svg +0 -5
- novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +0 -6
- novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-noveltree-more.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_font.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_panel.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_quote.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_search-case.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_search-preserve.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_search-regex.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_search-word.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +0 -6
- novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +0 -6
- novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +0 -7
- novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +0 -6
- novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +0 -7
- novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +0 -7
- novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +0 -7
- novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_arrow-down-thick-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-forward.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-maximise.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-minimise.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-repeat-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_book-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_book.svg +0 -6
- novelwriter/assets/icons/typicons_dark/typ_bookmark.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_calendar.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_cancel-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_cancel.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chart-bar-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chevron-down.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chevron-left.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chevron-right.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chevron-up.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_cog.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_delete-full.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_delete.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_directions-full.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_document-add.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_document-text.svg +0 -8
- novelwriter/assets/icons/typicons_dark/typ_document.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_export-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_export.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_eye.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_flag.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_folder-open.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_folder.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_globe-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_key.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_lightbulb-full.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_location.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_media-pause-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_media-record-outline.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_media-record.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_minus.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_pencil.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_pin-outline.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_pin.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_plus.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_puzzle.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_refresh.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_search.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_star.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_stopwatch-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-list-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-list.svg +0 -9
- novelwriter/assets/icons/typicons_dark/typ_times.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_trash.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_user.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_warning-full.svg +0 -4
- novelwriter/assets/icons/typicons_light/README.md +0 -29
- novelwriter/assets/icons/typicons_light/icons.conf +0 -134
- novelwriter/assets/icons/typicons_light/mixed_copy.svg +0 -4
- novelwriter/assets/icons/typicons_light/mixed_document-chapter.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_document-new.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_document-note.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_document-scene.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_document-section.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_document-title.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_edit.svg +0 -4
- novelwriter/assets/icons/typicons_light/mixed_import.svg +0 -5
- novelwriter/assets/icons/typicons_light/mixed_input-checked.svg +0 -5
- novelwriter/assets/icons/typicons_light/mixed_input-none.svg +0 -5
- novelwriter/assets/icons/typicons_light/mixed_input-unchecked.svg +0 -5
- novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_search-replace.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_size-height.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_size-width.svg +0 -6
- novelwriter/assets/icons/typicons_light/nw_deco-h0.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h1.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h2.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h3.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h4.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-note.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-noveltree-more.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_font.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_panel.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_quote.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_search-case.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_search-preserve.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_search-regex.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_search-word.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +0 -6
- novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +0 -6
- novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +0 -7
- novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +0 -6
- novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +0 -7
- novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +0 -7
- novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +0 -7
- novelwriter/assets/icons/typicons_light/nw_toolbar.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_arrow-down-thick-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-forward.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-maximise.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-minimise.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-repeat-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_book-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_book.svg +0 -6
- novelwriter/assets/icons/typicons_light/typ_bookmark.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_calendar.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_cancel-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_cancel.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chart-bar-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chevron-down.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chevron-left.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chevron-right.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chevron-up.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_cog.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_delete-full.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_delete.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_directions-full.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_document-add.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_document-text.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_document.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_export-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_export.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_eye.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_flag.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_folder-open.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_folder.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_globe-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_key.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_lightbulb-full.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_location.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_media-pause-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_media-record-outline.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_media-record.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_minus.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_pencil.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_pin-outline.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_pin.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_plus.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_puzzle.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_refresh.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_search-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_search.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_star.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_stopwatch-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-list-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-list.svg +0 -9
- novelwriter/assets/icons/typicons_light/typ_times.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_trash.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_user.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_warning-full.svg +0 -4
- {novelWriter-2.6.3.dist-info → novelwriter-2.7.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.6.3.dist-info → novelwriter-2.7.dist-info/licenses}/LICENSE.md +0 -0
- {novelWriter-2.6.3.dist-info → novelwriter-2.7.dist-info}/top_level.txt +0 -0
novelwriter/config.py
CHANGED
@@ -29,33 +29,64 @@ import json
|
|
29
29
|
import logging
|
30
30
|
import sys
|
31
31
|
|
32
|
-
from datetime import datetime
|
33
32
|
from pathlib import Path
|
34
33
|
from time import time
|
35
|
-
from typing import TYPE_CHECKING
|
34
|
+
from typing import TYPE_CHECKING, Final
|
36
35
|
|
37
|
-
from
|
38
|
-
PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR,
|
39
|
-
QLocale, QStandardPaths, QSysInfo, QTranslator
|
36
|
+
from PyQt6.QtCore import (
|
37
|
+
PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QDate,
|
38
|
+
QDateTime, QLibraryInfo, QLocale, QStandardPaths, QSysInfo, QTranslator
|
40
39
|
)
|
41
|
-
from
|
42
|
-
from
|
40
|
+
from PyQt6.QtGui import QFont, QFontDatabase, QFontMetrics
|
41
|
+
from PyQt6.QtWidgets import QApplication
|
43
42
|
|
44
43
|
from novelwriter.common import (
|
45
44
|
NWConfigParser, checkInt, checkPath, describeFont, fontMatcher,
|
46
|
-
formatTimeStamp
|
45
|
+
formatTimeStamp, processDialogSymbols, simplified
|
47
46
|
)
|
48
|
-
from novelwriter.constants import nwFiles, nwUnicode
|
47
|
+
from novelwriter.constants import nwFiles, nwHtmlUnicode, nwQuotes, nwUnicode
|
49
48
|
from novelwriter.error import formatException, logException
|
50
49
|
|
51
|
-
if TYPE_CHECKING:
|
50
|
+
if TYPE_CHECKING:
|
51
|
+
from datetime import datetime
|
52
|
+
|
52
53
|
from novelwriter.core.projectdata import NWProjectData
|
54
|
+
from novelwriter.splash import NSplashScreen
|
53
55
|
|
54
56
|
logger = logging.getLogger(__name__)
|
55
57
|
|
58
|
+
DEF_GUI = "default"
|
59
|
+
DEF_SYNTAX = "default_light"
|
60
|
+
DEF_ICONS = "material_rounded_normal"
|
61
|
+
DEF_TREECOL = "theme"
|
62
|
+
|
56
63
|
|
57
64
|
class Config:
|
58
65
|
|
66
|
+
__slots__ = (
|
67
|
+
"_appPath", "_appRoot", "_backPath", "_backupPath", "_confPath", "_dLocale", "_dShortDate",
|
68
|
+
"_dShortDateTime", "_dataPath", "_errData", "_hasError", "_homePath", "_lastAuthor",
|
69
|
+
"_manuals", "_nwLangPath", "_qLocale", "_qtLangPath", "_qtTrans", "_recentPaths",
|
70
|
+
"_recentProjects", "_splash", "allowOpenDial", "altDialogClose", "altDialogOpen",
|
71
|
+
"appHandle", "appName", "askBeforeBackup", "askBeforeExit", "autoSaveDoc", "autoSaveProj",
|
72
|
+
"autoScroll", "autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", "dialogLine",
|
73
|
+
"dialogStyle", "doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash",
|
74
|
+
"doReplaceDots", "doReplaceSQuote", "emphLabels", "fmtApostrophe", "fmtDQuoteClose",
|
75
|
+
"fmtDQuoteOpen", "fmtPadAfter", "fmtPadBefore", "fmtPadThin", "fmtSQuoteClose",
|
76
|
+
"fmtSQuoteOpen", "focusWidth", "guiFont", "guiLocale", "guiSyntax", "guiTheme",
|
77
|
+
"hasEnchant", "hideFocusFooter", "hideHScroll", "hideVScroll", "highlightEmph", "hostName",
|
78
|
+
"iconColDocs", "iconColTree", "iconTheme", "incNotesWCount", "isDebug", "kernelVer",
|
79
|
+
"lastNotes", "mainPanePos", "mainWinSize", "memInfo", "narratorBreak", "narratorDialog",
|
80
|
+
"nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows", "outlinePanePos",
|
81
|
+
"prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop", "searchMatchCap",
|
82
|
+
"searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord", "searchRegEx",
|
83
|
+
"searchWord", "showEditToolBar", "showFullPath", "showLineEndings", "showMultiSpaces",
|
84
|
+
"showSessionTime", "showTabsNSpaces", "showViewerPanel", "spellLanguage", "stopWhenIdle",
|
85
|
+
"tabWidth", "textFont", "textMargin", "textWidth", "useCharCount", "userIdleTime",
|
86
|
+
"verPyQtString", "verPyQtValue", "verPyString", "verQtString", "verQtValue",
|
87
|
+
"viewComments", "viewPanePos", "viewSynopsis", "welcomeWinSize",
|
88
|
+
)
|
89
|
+
|
59
90
|
LANG_NW = 1
|
60
91
|
LANG_PROJ = 2
|
61
92
|
|
@@ -64,6 +95,8 @@ class Config:
|
|
64
95
|
# Initialisation
|
65
96
|
# ==============
|
66
97
|
|
98
|
+
self._splash = None
|
99
|
+
|
67
100
|
# Set Application Variables
|
68
101
|
self.appName = "novelWriter"
|
69
102
|
self.appHandle = "novelwriter"
|
@@ -83,10 +116,10 @@ class Config:
|
|
83
116
|
|
84
117
|
self._appPath = Path(__file__).parent.absolute()
|
85
118
|
self._appRoot = self._appPath.parent
|
86
|
-
if
|
87
|
-
# novelWriter is packaged as
|
88
|
-
self.
|
89
|
-
self.
|
119
|
+
if getattr(sys, "frozen", False): # pragma: no cover
|
120
|
+
# novelWriter is packaged as an exe
|
121
|
+
self._appPath = Path(__file__).parent.parent.absolute()
|
122
|
+
self._appRoot = self._appPath
|
90
123
|
|
91
124
|
# Runtime Settings and Variables
|
92
125
|
self._hasError = False # True if the config class encountered an error
|
@@ -95,7 +128,7 @@ class Config:
|
|
95
128
|
# Localisation
|
96
129
|
# Note that these paths must be strings
|
97
130
|
self._nwLangPath = self._appPath / "assets" / "i18n"
|
98
|
-
self._qtLangPath = QLibraryInfo.
|
131
|
+
self._qtLangPath = QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath)
|
99
132
|
|
100
133
|
hasLocale = (self._nwLangPath / f"nw_{QLocale.system().name()}.qm").exists()
|
101
134
|
self._qLocale = QLocale.system() if hasLocale else QLocale("en_GB")
|
@@ -116,25 +149,31 @@ class Config:
|
|
116
149
|
|
117
150
|
self._recentProjects = RecentProjects(self)
|
118
151
|
self._recentPaths = RecentPaths(self)
|
152
|
+
self._lastAuthor = ""
|
119
153
|
|
120
154
|
# General GUI Settings
|
121
155
|
self.guiLocale = self._qLocale.name()
|
122
|
-
self.guiTheme =
|
123
|
-
self.guiSyntax =
|
124
|
-
self.guiFont = QFont()
|
125
|
-
self.
|
126
|
-
self.
|
127
|
-
self.
|
128
|
-
self.
|
129
|
-
self.
|
156
|
+
self.guiTheme = DEF_GUI # GUI theme
|
157
|
+
self.guiSyntax = DEF_SYNTAX # Syntax theme
|
158
|
+
self.guiFont = QFont() # Main GUI font
|
159
|
+
self.hideVScroll = False # Hide vertical scroll bars on main widgets
|
160
|
+
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
|
161
|
+
self.lastNotes = "0x0" # The latest release notes that have been shown
|
162
|
+
self.nativeFont = True # Use native font dialog
|
163
|
+
self.useCharCount = False # Use character count as primary count
|
164
|
+
|
165
|
+
# Icons
|
166
|
+
self.iconTheme = DEF_ICONS # Icons theme
|
167
|
+
self.iconColTree = DEF_TREECOL # Project tree icon colours
|
168
|
+
self.iconColDocs = False # Keep theme colours on documents
|
130
169
|
|
131
170
|
# Size Settings
|
132
|
-
self.
|
133
|
-
self.
|
134
|
-
self.
|
135
|
-
self.
|
136
|
-
self.
|
137
|
-
self.
|
171
|
+
self.mainWinSize = [1200, 650] # Last size of the main GUI window
|
172
|
+
self.welcomeWinSize = [800, 550] # Last size of the welcome window
|
173
|
+
self.prefsWinSize = [700, 615] # Last size of the Preferences dialog
|
174
|
+
self.mainPanePos = [300, 800] # Last position of the main window splitter
|
175
|
+
self.viewPanePos = [500, 150] # Last position of the document viewer splitter
|
176
|
+
self.outlinePanePos = [500, 150] # Last position of the outline panel splitter
|
138
177
|
|
139
178
|
# Project Settings
|
140
179
|
self.autoSaveProj = 60 # Interval for auto-saving project, in seconds
|
@@ -149,6 +188,7 @@ class Config:
|
|
149
188
|
self.textWidth = 700 # Editor text width
|
150
189
|
self.textMargin = 40 # Editor/viewer text margin
|
151
190
|
self.tabWidth = 40 # Editor tabulator width
|
191
|
+
self.cursorWidth = 1 # Editor cursor width
|
152
192
|
|
153
193
|
self.focusWidth = 800 # Focus Mode text width
|
154
194
|
self.hideFocusFooter = False # Hide document footer in Focus Mode
|
@@ -220,7 +260,7 @@ class Config:
|
|
220
260
|
# System and App Information
|
221
261
|
# ==========================
|
222
262
|
|
223
|
-
# Check
|
263
|
+
# Check Qt Versions
|
224
264
|
self.verQtString = QT_VERSION_STR
|
225
265
|
self.verQtValue = QT_VERSION
|
226
266
|
self.verPyQtString = PYQT_VERSION_STR
|
@@ -267,7 +307,12 @@ class Config:
|
|
267
307
|
|
268
308
|
@property
|
269
309
|
def pdfDocs(self) -> Path | None:
|
270
|
-
|
310
|
+
"""Return the local manual PDF file, if any exist."""
|
311
|
+
return self._manuals.get(f"manual_{self.locale.bcp47Name()}", self._manuals.get("manual"))
|
312
|
+
|
313
|
+
@property
|
314
|
+
def nwLangPath(self) -> Path:
|
315
|
+
return self._nwLangPath
|
271
316
|
|
272
317
|
@property
|
273
318
|
def locale(self) -> QLocale:
|
@@ -278,28 +323,9 @@ class Config:
|
|
278
323
|
return self._recentProjects
|
279
324
|
|
280
325
|
@property
|
281
|
-
def
|
282
|
-
|
283
|
-
|
284
|
-
@property
|
285
|
-
def welcomeWinSize(self) -> list[int]:
|
286
|
-
return [int(x*self.guiScale) for x in self._welcomeSize]
|
287
|
-
|
288
|
-
@property
|
289
|
-
def preferencesWinSize(self) -> list[int]:
|
290
|
-
return [int(x*self.guiScale) for x in self._prefsWinSize]
|
291
|
-
|
292
|
-
@property
|
293
|
-
def mainPanePos(self) -> list[int]:
|
294
|
-
return [int(x*self.guiScale) for x in self._mainPanePos]
|
295
|
-
|
296
|
-
@property
|
297
|
-
def viewPanePos(self) -> list[int]:
|
298
|
-
return [int(x*self.guiScale) for x in self._viewPanePos]
|
299
|
-
|
300
|
-
@property
|
301
|
-
def outlinePanePos(self) -> list[int]:
|
302
|
-
return [int(x*self.guiScale) for x in self._outlnPanePos]
|
326
|
+
def lastAuthor(self) -> str:
|
327
|
+
"""Return the last author name used."""
|
328
|
+
return simplified(self._lastAuthor)
|
303
329
|
|
304
330
|
##
|
305
331
|
# Getters
|
@@ -308,68 +334,46 @@ class Config:
|
|
308
334
|
def getTextWidth(self, focusMode: bool = False) -> int:
|
309
335
|
"""Get the text with for the correct editor mode."""
|
310
336
|
if focusMode:
|
311
|
-
return
|
337
|
+
return max(self.focusWidth, 200)
|
312
338
|
else:
|
313
|
-
return
|
314
|
-
|
315
|
-
def getTextMargin(self) -> int:
|
316
|
-
"""Get the scaled text margin."""
|
317
|
-
return self.pxInt(max(self.textMargin, 0))
|
318
|
-
|
319
|
-
def getTabWidth(self) -> int:
|
320
|
-
"""Get the scaled tab width."""
|
321
|
-
return self.pxInt(max(self.tabWidth, 0))
|
339
|
+
return max(self.textWidth, 200)
|
322
340
|
|
323
341
|
##
|
324
342
|
# Setters
|
325
343
|
##
|
326
344
|
|
345
|
+
def setLastAuthor(self, value: str) -> None:
|
346
|
+
"""Set tle last used author name."""
|
347
|
+
self._lastAuthor = simplified(value)
|
348
|
+
return
|
349
|
+
|
327
350
|
def setMainWinSize(self, width: int, height: int) -> None:
|
328
351
|
"""Set the size of the main window, but only if the change is
|
329
352
|
larger than 5 pixels. The OS window manager will sometimes
|
330
353
|
adjust it a bit, and we don't want the main window to shrink or
|
331
354
|
grow each time the app is opened.
|
332
355
|
"""
|
333
|
-
|
334
|
-
|
335
|
-
if abs(self.
|
336
|
-
self.
|
337
|
-
if abs(self._mainWinSize[1] - height) > 5:
|
338
|
-
self._mainWinSize[1] = height
|
356
|
+
if abs(self.mainWinSize[0] - width) > 5:
|
357
|
+
self.mainWinSize[0] = width
|
358
|
+
if abs(self.mainWinSize[1] - height) > 5:
|
359
|
+
self.mainWinSize[1] = height
|
339
360
|
return
|
340
361
|
|
341
362
|
def setWelcomeWinSize(self, width: int, height: int) -> None:
|
342
363
|
"""Set the size of the Preferences dialog window."""
|
343
|
-
self.
|
344
|
-
self._welcomeSize[1] = int(height/self.guiScale)
|
364
|
+
self.welcomeWinSize = [width, height]
|
345
365
|
return
|
346
366
|
|
347
367
|
def setPreferencesWinSize(self, width: int, height: int) -> None:
|
348
368
|
"""Set the size of the Preferences dialog window."""
|
349
|
-
self.
|
350
|
-
self._prefsWinSize[1] = int(height/self.guiScale)
|
351
|
-
return
|
352
|
-
|
353
|
-
def setMainPanePos(self, pos: list[int]) -> None:
|
354
|
-
"""Set the position of the main GUI splitter."""
|
355
|
-
self._mainPanePos = [int(x/self.guiScale) for x in pos]
|
356
|
-
return
|
357
|
-
|
358
|
-
def setViewPanePos(self, pos: list[int]) -> None:
|
359
|
-
"""Set the position of the viewer meta data splitter."""
|
360
|
-
self._viewPanePos = [int(x/self.guiScale) for x in pos]
|
361
|
-
return
|
362
|
-
|
363
|
-
def setOutlinePanePos(self, pos: list[int]) -> None:
|
364
|
-
"""Set the position of the outline details splitter."""
|
365
|
-
self._outlnPanePos = [int(x/self.guiScale) for x in pos]
|
369
|
+
self.prefsWinSize = [width, height]
|
366
370
|
return
|
367
371
|
|
368
372
|
def setLastPath(self, key: str, path: str | Path) -> None:
|
369
373
|
"""Set the last used path. Only the folder is saved, so if the
|
370
374
|
path is not a folder, the parent of the path is used instead.
|
371
375
|
"""
|
372
|
-
if isinstance(path,
|
376
|
+
if isinstance(path, str | Path):
|
373
377
|
path = checkPath(path, self._homePath)
|
374
378
|
if not path.is_dir():
|
375
379
|
path = path.parent
|
@@ -392,13 +396,12 @@ class Config:
|
|
392
396
|
self.guiFont = fontMatcher(font)
|
393
397
|
else:
|
394
398
|
font = QFont()
|
395
|
-
|
396
|
-
if self.osWindows and "Arial" in fontDB.families():
|
399
|
+
if self.osWindows and "Arial" in QFontDatabase.families():
|
397
400
|
# On Windows we default to Arial if possible
|
398
401
|
font.setFamily("Arial")
|
399
402
|
font.setPointSize(10)
|
400
403
|
else:
|
401
|
-
font =
|
404
|
+
font = QFontDatabase.systemFont(QFontDatabase.SystemFont.GeneralFont)
|
402
405
|
self.guiFont = fontMatcher(font)
|
403
406
|
logger.debug("GUI font set to: %s", describeFont(font))
|
404
407
|
QApplication.setFont(self.guiFont)
|
@@ -415,8 +418,7 @@ class Config:
|
|
415
418
|
font.fromString(value)
|
416
419
|
self.textFont = fontMatcher(font)
|
417
420
|
else:
|
418
|
-
|
419
|
-
fontFam = fontDB.families()
|
421
|
+
fontFam = QFontDatabase.families()
|
420
422
|
if self.osWindows and "Arial" in fontFam:
|
421
423
|
font = QFont()
|
422
424
|
font.setFamily("Arial")
|
@@ -426,7 +428,7 @@ class Config:
|
|
426
428
|
font.setFamily("Helvetica")
|
427
429
|
font.setPointSize(12)
|
428
430
|
else:
|
429
|
-
font =
|
431
|
+
font = QFontDatabase.systemFont(QFontDatabase.SystemFont.GeneralFont)
|
430
432
|
self.textFont = fontMatcher(font)
|
431
433
|
logger.debug("Text font set to: %s", describeFont(self.textFont))
|
432
434
|
return
|
@@ -435,14 +437,6 @@ class Config:
|
|
435
437
|
# Methods
|
436
438
|
##
|
437
439
|
|
438
|
-
def pxInt(self, value: int) -> int:
|
439
|
-
"""Scale fixed gui sizes by the screen scale factor."""
|
440
|
-
return int(value*self.guiScale)
|
441
|
-
|
442
|
-
def rpxInt(self, value: int) -> int:
|
443
|
-
"""Un-scale fixed gui sizes by the screen scale factor."""
|
444
|
-
return int(value/self.guiScale)
|
445
|
-
|
446
440
|
def homePath(self) -> Path:
|
447
441
|
"""The user's home folder."""
|
448
442
|
return self._homePath
|
@@ -484,11 +478,16 @@ class Config:
|
|
484
478
|
|
485
479
|
def localDate(self, value: datetime) -> str:
|
486
480
|
"""Return a localised date format."""
|
487
|
-
|
481
|
+
# Explicitly convert the date first, see bug #2325
|
482
|
+
return self._dLocale.toString(QDate(value.year, value.month, value.day), self._dShortDate)
|
488
483
|
|
489
484
|
def localDateTime(self, value: datetime) -> str:
|
490
485
|
"""Return a localised datetime format."""
|
491
|
-
|
486
|
+
# Explicitly convert the datetime first, see bug #2325
|
487
|
+
return self._dLocale.toString(
|
488
|
+
QDateTime(value.year, value.month, value.day, value.hour, value.minute, value.second),
|
489
|
+
self._dShortDateTime,
|
490
|
+
)
|
492
491
|
|
493
492
|
def listLanguages(self, lngSet: int) -> list[tuple[str, str]]:
|
494
493
|
"""List localisation files in the i18n folder. The default GUI
|
@@ -517,20 +516,27 @@ class Config:
|
|
517
516
|
|
518
517
|
return sorted(langList.items(), key=lambda x: x[0])
|
519
518
|
|
519
|
+
def splashMessage(self, message: str) -> None:
|
520
|
+
"""Send a message to the splash screen."""
|
521
|
+
if self._splash:
|
522
|
+
self._splash.showStatus(message)
|
523
|
+
return
|
524
|
+
|
520
525
|
##
|
521
526
|
# Config Actions
|
522
527
|
##
|
523
528
|
|
524
|
-
def initConfig(
|
525
|
-
|
529
|
+
def initConfig(
|
530
|
+
self, confPath: str | Path | None = None, dataPath: str | Path | None = None
|
531
|
+
) -> None:
|
526
532
|
"""Initialise the config class. The manual setting of confPath
|
527
533
|
and dataPath is mainly intended for the test suite.
|
528
534
|
"""
|
529
535
|
logger.debug("Initialising Config ...")
|
530
|
-
if isinstance(confPath,
|
536
|
+
if isinstance(confPath, str | Path):
|
531
537
|
logger.info("Setting alternative config path: %s", confPath)
|
532
538
|
self._confPath = Path(confPath)
|
533
|
-
if isinstance(dataPath,
|
539
|
+
if isinstance(dataPath, str | Path):
|
534
540
|
logger.info("Setting alternative data path: %s", dataPath)
|
535
541
|
self._dataPath = Path(dataPath)
|
536
542
|
|
@@ -562,6 +568,8 @@ class Config:
|
|
562
568
|
|
563
569
|
def initLocalisation(self, nwApp: QApplication) -> None:
|
564
570
|
"""Initialise the localisation of the GUI."""
|
571
|
+
self.splashMessage("Loading localisation ...")
|
572
|
+
|
565
573
|
self._qLocale = QLocale(self.guiLocale)
|
566
574
|
QLocale.setDefault(self._qLocale)
|
567
575
|
self._qtTrans = {}
|
@@ -572,13 +580,13 @@ class Config:
|
|
572
580
|
self._dShortDateTime = self._dLocale.dateTimeFormat(QLocale.FormatType.ShortFormat)
|
573
581
|
|
574
582
|
langList = [
|
575
|
-
(self._qtLangPath, "qtbase"), # Qt
|
583
|
+
(self._qtLangPath, "qtbase"), # Qt
|
576
584
|
(str(self._nwLangPath), "nw"), # novelWriter
|
577
585
|
]
|
578
586
|
for lngPath, lngBase in langList:
|
579
587
|
for lngCode in self._qLocale.uiLanguages():
|
580
588
|
qTrans = QTranslator()
|
581
|
-
lngFile = "
|
589
|
+
lngFile = "{0}_{1}".format(lngBase, lngCode.replace("-", "_"))
|
582
590
|
if lngFile not in self._qtTrans:
|
583
591
|
if qTrans.load(lngFile, lngPath):
|
584
592
|
logger.debug("Loaded: %s.qm", lngFile)
|
@@ -587,8 +595,11 @@ class Config:
|
|
587
595
|
|
588
596
|
return
|
589
597
|
|
590
|
-
def loadConfig(self) -> bool:
|
598
|
+
def loadConfig(self, splash: NSplashScreen | None = None) -> bool:
|
591
599
|
"""Load preferences from file and replace default settings."""
|
600
|
+
self._splash = splash
|
601
|
+
self.splashMessage("Loading user configuration ...")
|
602
|
+
|
592
603
|
logger.debug("Loading config file")
|
593
604
|
|
594
605
|
conf = NWConfigParser()
|
@@ -615,22 +626,26 @@ class Config:
|
|
615
626
|
# Main
|
616
627
|
sec = "Main"
|
617
628
|
self.setGuiFont(conf.rdStr(sec, "font", ""))
|
618
|
-
self.guiTheme
|
619
|
-
self.guiSyntax
|
620
|
-
self.
|
621
|
-
self.
|
622
|
-
self.
|
623
|
-
self.
|
624
|
-
self.
|
629
|
+
self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme)
|
630
|
+
self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax)
|
631
|
+
self.iconTheme = conf.rdStr(sec, "icons", self.iconTheme)
|
632
|
+
self.iconColTree = conf.rdStr(sec, "iconcoltree", self.iconColTree)
|
633
|
+
self.iconColDocs = conf.rdBool(sec, "iconcoldocs", self.iconColDocs)
|
634
|
+
self.guiLocale = conf.rdStr(sec, "localisation", self.guiLocale)
|
635
|
+
self.hideVScroll = conf.rdBool(sec, "hidevscroll", self.hideVScroll)
|
636
|
+
self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll)
|
637
|
+
self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes)
|
638
|
+
self.nativeFont = conf.rdBool(sec, "nativefont", self.nativeFont)
|
639
|
+
self.useCharCount = conf.rdBool(sec, "usecharcount", self.useCharCount)
|
625
640
|
|
626
641
|
# Sizes
|
627
642
|
sec = "Sizes"
|
628
|
-
self.
|
629
|
-
self.
|
630
|
-
self.
|
631
|
-
self.
|
632
|
-
self.
|
633
|
-
self.
|
643
|
+
self.mainWinSize = conf.rdIntList(sec, "mainwindow", self.mainWinSize)
|
644
|
+
self.welcomeWinSize = conf.rdIntList(sec, "welcome", self.welcomeWinSize)
|
645
|
+
self.prefsWinSize = conf.rdIntList(sec, "preferences", self.prefsWinSize)
|
646
|
+
self.mainPanePos = conf.rdIntList(sec, "mainpane", self.mainPanePos)
|
647
|
+
self.viewPanePos = conf.rdIntList(sec, "viewpane", self.viewPanePos)
|
648
|
+
self.outlinePanePos = conf.rdIntList(sec, "outlinepane", self.outlinePanePos)
|
634
649
|
|
635
650
|
# Project
|
636
651
|
sec = "Project"
|
@@ -641,6 +656,7 @@ class Config:
|
|
641
656
|
self.backupOnClose = conf.rdBool(sec, "backuponclose", self.backupOnClose)
|
642
657
|
self.askBeforeBackup = conf.rdBool(sec, "askbeforebackup", self.askBeforeBackup)
|
643
658
|
self.askBeforeExit = conf.rdBool(sec, "askbeforeexit", self.askBeforeExit)
|
659
|
+
self._lastAuthor = conf.rdStr(sec, "lastauthor", self._lastAuthor)
|
644
660
|
|
645
661
|
# Editor
|
646
662
|
sec = "Editor"
|
@@ -648,6 +664,7 @@ class Config:
|
|
648
664
|
self.textWidth = conf.rdInt(sec, "width", self.textWidth)
|
649
665
|
self.textMargin = conf.rdInt(sec, "margin", self.textMargin)
|
650
666
|
self.tabWidth = conf.rdInt(sec, "tabwidth", self.tabWidth)
|
667
|
+
self.cursorWidth = conf.rdInt(sec, "cursorwidth", self.cursorWidth)
|
651
668
|
self.focusWidth = conf.rdInt(sec, "focuswidth", self.focusWidth)
|
652
669
|
self.hideFocusFooter = conf.rdBool(sec, "hidefocusfooter", self.hideFocusFooter)
|
653
670
|
self.doJustify = conf.rdBool(sec, "justify", self.doJustify)
|
@@ -675,9 +692,9 @@ class Config:
|
|
675
692
|
self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath)
|
676
693
|
self.dialogStyle = conf.rdInt(sec, "dialogstyle", self.dialogStyle)
|
677
694
|
self.allowOpenDial = conf.rdBool(sec, "allowopendial", self.allowOpenDial)
|
678
|
-
|
679
|
-
|
680
|
-
|
695
|
+
dialogLine = conf.rdStr(sec, "dialogline", self.dialogLine)
|
696
|
+
narratorBreak = conf.rdStr(sec, "narratorbreak", self.narratorBreak)
|
697
|
+
narratorDialog = conf.rdStr(sec, "narratordialog", self.narratorDialog)
|
681
698
|
self.altDialogOpen = conf.rdStr(sec, "altdialogopen", self.altDialogOpen)
|
682
699
|
self.altDialogClose = conf.rdStr(sec, "altdialogclose", self.altDialogClose)
|
683
700
|
self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph)
|
@@ -704,6 +721,9 @@ class Config:
|
|
704
721
|
# Check Values
|
705
722
|
# ============
|
706
723
|
|
724
|
+
self._prepareFont(self.guiFont, "GUI")
|
725
|
+
self._prepareFont(self.textFont, "document")
|
726
|
+
|
707
727
|
# If we're using straight quotes, disable auto-replace
|
708
728
|
if self.fmtSQuoteOpen == self.fmtSQuoteClose == "'" and self.doReplaceSQuote:
|
709
729
|
logger.info("Using straight single quotes, so disabling auto-replace")
|
@@ -713,6 +733,10 @@ class Config:
|
|
713
733
|
logger.info("Using straight double quotes, so disabling auto-replace")
|
714
734
|
self.doReplaceDQuote = False
|
715
735
|
|
736
|
+
self.dialogLine = processDialogSymbols(dialogLine)
|
737
|
+
self.narratorBreak = narratorBreak if narratorBreak in nwQuotes.DASHES else ""
|
738
|
+
self.narratorDialog = narratorDialog if narratorDialog in nwQuotes.DASHES else ""
|
739
|
+
|
716
740
|
return True
|
717
741
|
|
718
742
|
def saveConfig(self) -> bool:
|
@@ -729,20 +753,24 @@ class Config:
|
|
729
753
|
"font": self.guiFont.toString(),
|
730
754
|
"theme": str(self.guiTheme),
|
731
755
|
"syntax": str(self.guiSyntax),
|
756
|
+
"icons": str(self.iconTheme),
|
757
|
+
"iconcoltree": str(self.iconColTree),
|
758
|
+
"iconcoldocs": str(self.iconColDocs),
|
732
759
|
"localisation": str(self.guiLocale),
|
733
760
|
"hidevscroll": str(self.hideVScroll),
|
734
761
|
"hidehscroll": str(self.hideHScroll),
|
735
762
|
"lastnotes": str(self.lastNotes),
|
736
763
|
"nativefont": str(self.nativeFont),
|
764
|
+
"usecharcount": str(self.useCharCount),
|
737
765
|
}
|
738
766
|
|
739
767
|
conf["Sizes"] = {
|
740
|
-
"mainwindow": self._packList(self.
|
741
|
-
"welcome": self._packList(self.
|
742
|
-
"preferences": self._packList(self.
|
743
|
-
"mainpane": self._packList(self.
|
744
|
-
"viewpane": self._packList(self.
|
745
|
-
"outlinepane": self._packList(self.
|
768
|
+
"mainwindow": self._packList(self.mainWinSize),
|
769
|
+
"welcome": self._packList(self.welcomeWinSize),
|
770
|
+
"preferences": self._packList(self.prefsWinSize),
|
771
|
+
"mainpane": self._packList(self.mainPanePos),
|
772
|
+
"viewpane": self._packList(self.viewPanePos),
|
773
|
+
"outlinepane": self._packList(self.outlinePanePos),
|
746
774
|
}
|
747
775
|
|
748
776
|
conf["Project"] = {
|
@@ -753,6 +781,7 @@ class Config:
|
|
753
781
|
"backuponclose": str(self.backupOnClose),
|
754
782
|
"askbeforebackup": str(self.askBeforeBackup),
|
755
783
|
"askbeforeexit": str(self.askBeforeExit),
|
784
|
+
"lastauthor": str(self._lastAuthor),
|
756
785
|
}
|
757
786
|
|
758
787
|
conf["Editor"] = {
|
@@ -760,6 +789,7 @@ class Config:
|
|
760
789
|
"width": str(self.textWidth),
|
761
790
|
"margin": str(self.textMargin),
|
762
791
|
"tabwidth": str(self.tabWidth),
|
792
|
+
"cursorwidth": str(self.cursorWidth),
|
763
793
|
"focuswidth": str(self.focusWidth),
|
764
794
|
"hidefocusfooter": str(self.hideFocusFooter),
|
765
795
|
"justify": str(self.doJustify),
|
@@ -829,6 +859,11 @@ class Config:
|
|
829
859
|
|
830
860
|
return True
|
831
861
|
|
862
|
+
def finishStartup(self) -> None:
|
863
|
+
"""Call after startup is complete."""
|
864
|
+
self._splash = None
|
865
|
+
return
|
866
|
+
|
832
867
|
##
|
833
868
|
# Internal Functions
|
834
869
|
##
|
@@ -851,6 +886,17 @@ class Config:
|
|
851
886
|
logger.debug("Checking package 'pyenchant': OK")
|
852
887
|
return
|
853
888
|
|
889
|
+
def _prepareFont(self, font: QFont, kind: str) -> None:
|
890
|
+
"""Check Unicode availability in font. This also initialises any
|
891
|
+
alternative character used for missing glyphs. See #2315.
|
892
|
+
"""
|
893
|
+
self.splashMessage(f"Initialising {kind} font: {font.family()}")
|
894
|
+
metrics = QFontMetrics(font)
|
895
|
+
for char in nwHtmlUnicode.U_TO_H.keys():
|
896
|
+
if not metrics.inFont(char): # type: ignore
|
897
|
+
logger.warning("No glyph U+%04x in font", ord(char)) # pragma: no cover
|
898
|
+
return
|
899
|
+
|
854
900
|
|
855
901
|
class RecentProjects:
|
856
902
|
|
@@ -873,9 +919,10 @@ class RecentProjects:
|
|
873
919
|
puuid = str(entry.get("uuid", ""))
|
874
920
|
title = str(entry.get("title", ""))
|
875
921
|
words = checkInt(entry.get("words", 0), 0)
|
922
|
+
chars = checkInt(entry.get("chars", 0), 0)
|
876
923
|
saved = checkInt(entry.get("time", 0), 0)
|
877
924
|
if path and title:
|
878
|
-
self._setEntry(puuid, path, title, words, saved)
|
925
|
+
self._setEntry(puuid, path, title, words, chars, saved)
|
879
926
|
except Exception:
|
880
927
|
logger.error("Could not load recent project cache")
|
881
928
|
logException()
|
@@ -908,7 +955,14 @@ class RecentProjects:
|
|
908
955
|
try:
|
909
956
|
if (remove := self._map.get(data.uuid)) and (remove != str(path)):
|
910
957
|
self.remove(remove)
|
911
|
-
self._setEntry(
|
958
|
+
self._setEntry(
|
959
|
+
data.uuid,
|
960
|
+
str(path),
|
961
|
+
data.name,
|
962
|
+
sum(data.currCounts[:2]),
|
963
|
+
sum(data.currCounts[2:]),
|
964
|
+
int(saved),
|
965
|
+
)
|
912
966
|
self.saveCache()
|
913
967
|
except Exception:
|
914
968
|
pass
|
@@ -921,9 +975,17 @@ class RecentProjects:
|
|
921
975
|
self.saveCache()
|
922
976
|
return
|
923
977
|
|
924
|
-
def _setEntry(
|
978
|
+
def _setEntry(
|
979
|
+
self, puuid: str, path: str, title: str, words: int, chars: int, saved: int
|
980
|
+
) -> None:
|
925
981
|
"""Set an entry in the recent projects record."""
|
926
|
-
self._data[path] = {
|
982
|
+
self._data[path] = {
|
983
|
+
"uuid": puuid,
|
984
|
+
"title": title,
|
985
|
+
"words": words,
|
986
|
+
"chars": chars,
|
987
|
+
"time": saved,
|
988
|
+
}
|
927
989
|
if puuid:
|
928
990
|
self._map[puuid] = path
|
929
991
|
return
|
@@ -931,7 +993,7 @@ class RecentProjects:
|
|
931
993
|
|
932
994
|
class RecentPaths:
|
933
995
|
|
934
|
-
KEYS = ["default", "project", "import", "outline", "stats"]
|
996
|
+
KEYS: Final[list[str]] = ["default", "project", "import", "outline", "stats"]
|
935
997
|
|
936
998
|
def __init__(self, config: Config) -> None:
|
937
999
|
self._conf = config
|