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/core/projectdata.py
CHANGED
@@ -34,7 +34,7 @@ from novelwriter.common import (
|
|
34
34
|
)
|
35
35
|
from novelwriter.core.status import NWStatus
|
36
36
|
|
37
|
-
if TYPE_CHECKING:
|
37
|
+
if TYPE_CHECKING:
|
38
38
|
from novelwriter.core.project import NWProject
|
39
39
|
|
40
40
|
logger = logging.getLogger(__name__)
|
@@ -66,13 +66,13 @@ class NWProjectData:
|
|
66
66
|
self._spellLang = None
|
67
67
|
|
68
68
|
# Project Dictionaries
|
69
|
-
self._initCounts = [0, 0]
|
70
|
-
self._currCounts = [0, 0]
|
69
|
+
self._initCounts = [0, 0, 0, 0]
|
70
|
+
self._currCounts = [0, 0, 0, 0]
|
71
71
|
self._lastHandle: dict[str, str | None] = {
|
72
|
-
"editor":
|
73
|
-
"viewer":
|
74
|
-
"
|
75
|
-
"outline":
|
72
|
+
"editor": None,
|
73
|
+
"viewer": None,
|
74
|
+
"novel": None,
|
75
|
+
"outline": None,
|
76
76
|
}
|
77
77
|
self._autoReplace: dict[str, str] = {}
|
78
78
|
self._titleFormat: dict[str, str] = {
|
@@ -148,18 +148,18 @@ class NWProjectData:
|
|
148
148
|
return self._spellLang
|
149
149
|
|
150
150
|
@property
|
151
|
-
def initCounts(self) -> tuple[int, int]:
|
152
|
-
"""Return the initial count of words for novel
|
153
|
-
documents.
|
151
|
+
def initCounts(self) -> tuple[int, int, int, int]:
|
152
|
+
"""Return the initial count of words and characters for novel
|
153
|
+
and note documents.
|
154
154
|
"""
|
155
|
-
return self._initCounts[0], self._initCounts[1]
|
155
|
+
return self._initCounts[0], self._initCounts[1], self._initCounts[2], self._initCounts[3]
|
156
156
|
|
157
157
|
@property
|
158
|
-
def currCounts(self) -> tuple[int, int]:
|
159
|
-
"""Return the current count of words for novel
|
160
|
-
documents.
|
158
|
+
def currCounts(self) -> tuple[int, int, int, int]:
|
159
|
+
"""Return the current count of words and characters for novel
|
160
|
+
and note documents.
|
161
161
|
"""
|
162
|
-
return self._currCounts[0], self._currCounts[1]
|
162
|
+
return self._currCounts[0], self._currCounts[1], self._currCounts[2], self._currCounts[3]
|
163
163
|
|
164
164
|
@property
|
165
165
|
def lastHandle(self) -> dict[str, str | None]:
|
@@ -301,22 +301,40 @@ class NWProjectData:
|
|
301
301
|
self._project.setProjectChanged(True)
|
302
302
|
return
|
303
303
|
|
304
|
-
def setInitCounts(
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
self._initCounts[
|
311
|
-
self._currCounts[
|
304
|
+
def setInitCounts(
|
305
|
+
self, wNovel: Any = None, wNotes: Any = None, cNovel: Any = None, cNotes: Any = None
|
306
|
+
) -> None:
|
307
|
+
"""Set the count totals for novel and note files."""
|
308
|
+
if wNovel is not None:
|
309
|
+
count = checkInt(wNovel, 0)
|
310
|
+
self._initCounts[0] = count
|
311
|
+
self._currCounts[0] = count
|
312
|
+
if wNotes is not None:
|
313
|
+
count = checkInt(wNotes, 0)
|
314
|
+
self._initCounts[1] = count
|
315
|
+
self._currCounts[1] = count
|
316
|
+
if cNovel is not None:
|
317
|
+
count = checkInt(cNovel, 0)
|
318
|
+
self._initCounts[2] = count
|
319
|
+
self._currCounts[2] = count
|
320
|
+
if cNotes is not None:
|
321
|
+
count = checkInt(cNotes, 0)
|
322
|
+
self._initCounts[3] = count
|
323
|
+
self._currCounts[3] = count
|
312
324
|
return
|
313
325
|
|
314
|
-
def setCurrCounts(
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
if
|
319
|
-
self._currCounts[
|
326
|
+
def setCurrCounts(
|
327
|
+
self, wNovel: Any = None, wNotes: Any = None, cNovel: Any = None, cNotes: Any = None
|
328
|
+
) -> None:
|
329
|
+
"""Set the count totals for novel and note files."""
|
330
|
+
if wNovel is not None:
|
331
|
+
self._currCounts[0] = checkInt(wNovel, 0)
|
332
|
+
if wNotes is not None:
|
333
|
+
self._currCounts[1] = checkInt(wNotes, 0)
|
334
|
+
if cNovel is not None:
|
335
|
+
self._currCounts[2] = checkInt(cNovel, 0)
|
336
|
+
if cNotes is not None:
|
337
|
+
self._currCounts[3] = checkInt(cNotes, 0)
|
320
338
|
return
|
321
339
|
|
322
340
|
def setAutoReplace(self, value: dict) -> None:
|
novelwriter/core/projectxml.py
CHANGED
@@ -39,14 +39,14 @@ from novelwriter.common import (
|
|
39
39
|
hexToInt, simplified, xmlIndent, yesNo
|
40
40
|
)
|
41
41
|
|
42
|
-
if TYPE_CHECKING:
|
42
|
+
if TYPE_CHECKING:
|
43
43
|
from novelwriter.core.projectdata import NWProjectData
|
44
44
|
from novelwriter.core.status import NWStatus
|
45
45
|
|
46
46
|
logger = logging.getLogger(__name__)
|
47
47
|
|
48
48
|
FILE_VERSION = "1.5" # The current project file format version
|
49
|
-
FILE_REVISION = "
|
49
|
+
FILE_REVISION = "5" # The current project file format revision
|
50
50
|
HEX_VERSION = 0x0105
|
51
51
|
|
52
52
|
NUM_VERSION = {
|
@@ -109,6 +109,8 @@ class ProjectXMLReader:
|
|
109
109
|
Rev 3: Added TEMPLATE class. 2.3.
|
110
110
|
Rev 4: Added shape attribute to status and importance entry
|
111
111
|
nodes. 2.5.
|
112
|
+
Rev 5: Added novelChars and notesChars attributes to content
|
113
|
+
node. 2.7 RC 1.
|
112
114
|
"""
|
113
115
|
|
114
116
|
def __init__(self, path: str | Path) -> None:
|
@@ -286,9 +288,9 @@ class ProjectXMLReader:
|
|
286
288
|
elif xItem.tag == "spellLang": # Changed to spellChecking in 1.5
|
287
289
|
data.setSpellLang(xItem.text)
|
288
290
|
elif xItem.tag == "novelWordCount": # Moved to content attribute in 1.5
|
289
|
-
data.setInitCounts(
|
291
|
+
data.setInitCounts(wNovel=xItem.text)
|
290
292
|
elif xItem.tag == "notesWordCount": # Moved to content attribute in 1.5
|
291
|
-
data.setInitCounts(
|
293
|
+
data.setInitCounts(wNotes=xItem.text)
|
292
294
|
|
293
295
|
return
|
294
296
|
|
@@ -298,8 +300,13 @@ class ProjectXMLReader:
|
|
298
300
|
"""Parse the content section of the XML file."""
|
299
301
|
logger.debug("Parsing <content> section")
|
300
302
|
|
301
|
-
|
302
|
-
data.setInitCounts(
|
303
|
+
# Moved in 1.5
|
304
|
+
data.setInitCounts(
|
305
|
+
wNovel=xSection.attrib.get("novelWords", None),
|
306
|
+
wNotes=xSection.attrib.get("notesWords", None),
|
307
|
+
cNovel=xSection.attrib.get("novelChars", None),
|
308
|
+
cNotes=xSection.attrib.get("notesChars", None),
|
309
|
+
)
|
303
310
|
|
304
311
|
for xItem in xSection:
|
305
312
|
if xItem.tag != "item":
|
@@ -527,10 +534,13 @@ class ProjectXMLWriter:
|
|
527
534
|
self._packSingleValue(xImport, "entry", label, attrib=attrib)
|
528
535
|
|
529
536
|
# Save Tree Content
|
537
|
+
counts = data.currCounts
|
530
538
|
contAttr = {
|
531
539
|
"items": str(len(content)),
|
532
|
-
"novelWords": str(
|
533
|
-
"notesWords": str(
|
540
|
+
"novelWords": str(counts[0]),
|
541
|
+
"notesWords": str(counts[1]),
|
542
|
+
"novelChars": str(counts[2]),
|
543
|
+
"notesChars": str(counts[3]),
|
534
544
|
}
|
535
545
|
|
536
546
|
xContent = ET.SubElement(xRoot, "content", attrib=contAttr)
|
novelwriter/core/sessions.py
CHANGED
@@ -26,7 +26,6 @@ from __future__ import annotations
|
|
26
26
|
import json
|
27
27
|
import logging
|
28
28
|
|
29
|
-
from collections.abc import Iterable
|
30
29
|
from pathlib import Path
|
31
30
|
from time import time
|
32
31
|
from typing import TYPE_CHECKING
|
@@ -35,7 +34,9 @@ from novelwriter.common import formatTimeStamp
|
|
35
34
|
from novelwriter.constants import nwFiles
|
36
35
|
from novelwriter.error import logException
|
37
36
|
|
38
|
-
if TYPE_CHECKING:
|
37
|
+
if TYPE_CHECKING:
|
38
|
+
from collections.abc import Iterable
|
39
|
+
|
39
40
|
from novelwriter.core.project import NWProject
|
40
41
|
|
41
42
|
logger = logging.getLogger(__name__)
|
@@ -78,29 +79,36 @@ class NWSessionLog:
|
|
78
79
|
return False
|
79
80
|
|
80
81
|
now = time()
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
82
|
+
iWNovel, iWNotes, iCNovel, iCNotes = self._project.data.initCounts
|
83
|
+
cWNovel, cWNotes, cCNovel, cCNotes = self._project.data.currCounts
|
84
|
+
iWTotal = iWNovel + iWNotes
|
85
|
+
iCTotal = iCNovel + iCNotes
|
86
|
+
wDiff = cWNovel + cWNotes - iWTotal
|
87
|
+
cDiff = cCNovel + cCNotes - iCTotal
|
85
88
|
sTime = now - self._start
|
86
89
|
|
87
|
-
logger.info(
|
88
|
-
|
90
|
+
logger.info(
|
91
|
+
"The session lasted %d sec and added %d words abd %d characters",
|
92
|
+
int(sTime), wDiff, cDiff
|
93
|
+
)
|
94
|
+
if sTime < 300 and (wDiff == 0 or cDiff == 0):
|
89
95
|
logger.info("Session too short, skipping log entry")
|
90
96
|
return False
|
91
97
|
|
92
98
|
try:
|
93
99
|
if not sessFile.exists():
|
94
100
|
with open(sessFile, mode="w", encoding="utf-8") as fObj:
|
95
|
-
fObj.write(self.createInitial(
|
101
|
+
fObj.write(self.createInitial(iWTotal))
|
96
102
|
|
97
103
|
with open(sessFile, mode="a+", encoding="utf-8") as fObj:
|
98
104
|
fObj.write(self.createRecord(
|
99
105
|
start=formatTimeStamp(self._start),
|
100
106
|
end=formatTimeStamp(now),
|
101
|
-
novel=
|
102
|
-
notes=
|
103
|
-
idle=round(idleTime)
|
107
|
+
novel=cWNovel,
|
108
|
+
notes=cWNotes,
|
109
|
+
idle=round(idleTime),
|
110
|
+
cnovel=cCNovel,
|
111
|
+
cnotes=cCNotes,
|
104
112
|
))
|
105
113
|
|
106
114
|
except Exception:
|
@@ -128,10 +136,19 @@ class NWSessionLog:
|
|
128
136
|
data = json.dumps({"type": "initial", "offset": total})
|
129
137
|
return f"{data}\n"
|
130
138
|
|
131
|
-
def createRecord(
|
139
|
+
def createRecord(
|
140
|
+
self, start: str, end: str, novel: int, notes: int, idle: int,
|
141
|
+
cnovel: int = 0, cnotes: int = 0,
|
142
|
+
) -> str:
|
132
143
|
"""Low level function to create a log record."""
|
133
144
|
data = json.dumps({
|
134
|
-
"type": "record",
|
135
|
-
"
|
145
|
+
"type": "record",
|
146
|
+
"start": start,
|
147
|
+
"end": end,
|
148
|
+
"novel": novel,
|
149
|
+
"notes": notes,
|
150
|
+
"cnovel": cnovel,
|
151
|
+
"cnotes": cnotes,
|
152
|
+
"idle": idle,
|
136
153
|
})
|
137
154
|
return f"{data}\n"
|
novelwriter/core/spellcheck.py
CHANGED
@@ -27,16 +27,17 @@ from __future__ import annotations
|
|
27
27
|
import json
|
28
28
|
import logging
|
29
29
|
|
30
|
-
from collections.abc import Iterator
|
31
30
|
from pathlib import Path
|
32
31
|
from typing import TYPE_CHECKING
|
33
32
|
|
34
|
-
from
|
33
|
+
from PyQt6.QtCore import QLocale
|
35
34
|
|
36
35
|
from novelwriter.constants import nwFiles
|
37
36
|
from novelwriter.error import logException
|
38
37
|
|
39
|
-
if TYPE_CHECKING:
|
38
|
+
if TYPE_CHECKING:
|
39
|
+
from collections.abc import Iterator
|
40
|
+
|
40
41
|
from novelwriter.core.project import NWProject
|
41
42
|
|
42
43
|
logger = logging.getLogger(__name__)
|
novelwriter/core/status.py
CHANGED
@@ -28,19 +28,18 @@ import dataclasses
|
|
28
28
|
import logging
|
29
29
|
import random
|
30
30
|
|
31
|
-
from
|
32
|
-
from typing import TYPE_CHECKING, Literal
|
31
|
+
from typing import TYPE_CHECKING, Literal, TypeGuard
|
33
32
|
|
34
|
-
from
|
35
|
-
from
|
33
|
+
from PyQt6.QtCore import QPointF, Qt
|
34
|
+
from PyQt6.QtGui import QColor, QIcon, QPainter, QPainterPath, QPixmap, QPolygonF
|
36
35
|
|
37
36
|
from novelwriter import SHARED
|
38
37
|
from novelwriter.common import simplified
|
39
38
|
from novelwriter.enum import nwStatusShape
|
40
39
|
from novelwriter.types import QtPaintAntiAlias, QtTransparent
|
41
40
|
|
42
|
-
if TYPE_CHECKING:
|
43
|
-
from
|
41
|
+
if TYPE_CHECKING:
|
42
|
+
from collections.abc import Iterable
|
44
43
|
|
45
44
|
logger = logging.getLogger(__name__)
|
46
45
|
|
@@ -57,18 +56,16 @@ class StatusEntry:
|
|
57
56
|
@classmethod
|
58
57
|
def duplicate(cls, source: StatusEntry) -> StatusEntry:
|
59
58
|
"""Create a deep copy of the source object."""
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
return
|
59
|
+
status = dataclasses.replace(source)
|
60
|
+
status.color = QColor(source.color)
|
61
|
+
status.icon = QIcon(source.icon)
|
62
|
+
return status
|
64
63
|
|
65
64
|
|
66
65
|
NO_ENTRY = StatusEntry("", QColor(0, 0, 0), nwStatusShape.SQUARE, QIcon(), 0)
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
T_UpdateEntry = list[tuple[str | None, StatusEntry]]
|
71
|
-
T_StatusKind = Literal["s", "i"]
|
67
|
+
T_UpdateEntry = list[tuple[str | None, StatusEntry]]
|
68
|
+
T_StatusKind = Literal["s", "i"]
|
72
69
|
|
73
70
|
|
74
71
|
class NWStatus:
|
@@ -76,7 +73,7 @@ class NWStatus:
|
|
76
73
|
STATUS = "s"
|
77
74
|
IMPORT = "i"
|
78
75
|
|
79
|
-
__slots__ = ("
|
76
|
+
__slots__ = ("_default", "_height", "_prefix", "_store")
|
80
77
|
|
81
78
|
def __init__(self, prefix: T_StatusKind) -> None:
|
82
79
|
self._store: dict[str, StatusEntry] = {}
|
novelwriter/core/storage.py
CHANGED
@@ -40,7 +40,7 @@ from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter
|
|
40
40
|
from novelwriter.core.spellcheck import UserDictionary
|
41
41
|
from novelwriter.error import logException
|
42
42
|
|
43
|
-
if TYPE_CHECKING:
|
43
|
+
if TYPE_CHECKING:
|
44
44
|
from novelwriter.core.project import NWProject
|
45
45
|
|
46
46
|
logger = logging.getLogger(__name__)
|
novelwriter/core/tree.py
CHANGED
@@ -27,20 +27,21 @@ from __future__ import annotations
|
|
27
27
|
import logging
|
28
28
|
import random
|
29
29
|
|
30
|
-
from collections.abc import Iterable, Iterator
|
31
30
|
from pathlib import Path
|
32
31
|
from typing import TYPE_CHECKING, Literal, overload
|
33
32
|
|
34
|
-
from
|
33
|
+
from PyQt6.QtCore import QModelIndex
|
35
34
|
|
36
35
|
from novelwriter import SHARED
|
37
|
-
from novelwriter.constants import nwFiles, nwLabels, trConst
|
36
|
+
from novelwriter.constants import nwFiles, nwLabels, nwStyles, trConst
|
38
37
|
from novelwriter.core.item import NWItem
|
39
38
|
from novelwriter.core.itemmodel import ProjectModel, ProjectNode
|
40
39
|
from novelwriter.enum import nwChange, nwItemClass, nwItemLayout, nwItemType
|
41
40
|
from novelwriter.error import logException
|
42
41
|
|
43
|
-
if TYPE_CHECKING:
|
42
|
+
if TYPE_CHECKING:
|
43
|
+
from collections.abc import Iterable, Iterator
|
44
|
+
|
44
45
|
from novelwriter.core.project import NWProject
|
45
46
|
|
46
47
|
logger = logging.getLogger(__name__)
|
@@ -60,7 +61,7 @@ class NWTree:
|
|
60
61
|
also used for file names.
|
61
62
|
"""
|
62
63
|
|
63
|
-
__slots__ = ("
|
64
|
+
__slots__ = ("_items", "_model", "_nodes", "_project", "_ready", "_trash")
|
64
65
|
|
65
66
|
def __init__(self, project: NWProject) -> None:
|
66
67
|
self._project = project
|
@@ -68,6 +69,7 @@ class NWTree:
|
|
68
69
|
self._items: dict[str, NWItem] = {}
|
69
70
|
self._nodes: dict[str, ProjectNode] = {}
|
70
71
|
self._trash = None
|
72
|
+
self._ready = False
|
71
73
|
logger.debug("Ready: NWTree")
|
72
74
|
return
|
73
75
|
|
@@ -106,6 +108,11 @@ class NWTree:
|
|
106
108
|
# Properties
|
107
109
|
##
|
108
110
|
|
111
|
+
@property
|
112
|
+
def project(self) -> NWProject:
|
113
|
+
"""Return the parent project."""
|
114
|
+
return self._project
|
115
|
+
|
109
116
|
@property
|
110
117
|
def trash(self) -> ProjectNode | None:
|
111
118
|
"""Return trash node, if it exists."""
|
@@ -249,11 +256,37 @@ class NWTree:
|
|
249
256
|
logger.error("Not all items could be added to project tree")
|
250
257
|
|
251
258
|
self._trash = self._getTrashNode()
|
259
|
+
self._ready = True
|
252
260
|
self._model.endInsertRows()
|
253
261
|
self._model.layoutChanged.emit()
|
254
262
|
|
255
263
|
return
|
256
264
|
|
265
|
+
def pickParent(self, sNode: ProjectNode, hLevel: int, isNote: bool) -> tuple[str | None, int]:
|
266
|
+
"""Pick an appropriate parent handle for adding a new item."""
|
267
|
+
if sNode.item.isFolderType() or sNode.item.isRootType():
|
268
|
+
# Always add as a direct child of folders
|
269
|
+
return sNode.item.itemHandle, sNode.childCount()
|
270
|
+
|
271
|
+
pNode = sNode.parent()
|
272
|
+
pLevel = nwStyles.H_LEVEL.get(pNode.item.mainHeading, 0) if pNode else 0
|
273
|
+
|
274
|
+
# Notes are treated as H0, and scenes and sections both as H3
|
275
|
+
sLevel = min(0 if isNote else nwStyles.H_LEVEL.get(sNode.item.mainHeading, 0), 3)
|
276
|
+
|
277
|
+
if pNode and pNode.item.isFileType() and pLevel >= hLevel and sLevel > hLevel:
|
278
|
+
# If the selected item is a smaller heading and the parent heading
|
279
|
+
# is equal or larger, we make it a sibling of the parent (See #2260)
|
280
|
+
return pNode.item.itemParent, pNode.row() + 1
|
281
|
+
|
282
|
+
if sNode.childCount() > 0 and (0 < sLevel < hLevel or isNote):
|
283
|
+
# If the selected item already has child nodes and has a larger
|
284
|
+
# heading or is a note, we make the new item a child
|
285
|
+
return sNode.item.itemHandle, sNode.childCount()
|
286
|
+
|
287
|
+
# The default behaviour is to make the new item a sibling
|
288
|
+
return sNode.item.itemParent, sNode.row() + 1
|
289
|
+
|
257
290
|
def refreshItems(self, items: list[str]) -> None:
|
258
291
|
"""Refresh these items on the GUI. If they are an ordered range,
|
259
292
|
also set the isRange flag to True.
|
@@ -278,6 +311,12 @@ class NWTree:
|
|
278
311
|
self._model.layoutChanged.emit()
|
279
312
|
return
|
280
313
|
|
314
|
+
def novelStructureChanged(self, tHandle: str) -> None:
|
315
|
+
"""Emit a novel structure change signal."""
|
316
|
+
if self._ready:
|
317
|
+
SHARED.novelStructureChanged.emit(tHandle)
|
318
|
+
return
|
319
|
+
|
281
320
|
def checkConsistency(self, prefix: str) -> tuple[int, int]:
|
282
321
|
"""Check the project tree consistency. Also check the content
|
283
322
|
folder and add back files that were discovered but were not
|
@@ -371,16 +410,20 @@ class NWTree:
|
|
371
410
|
|
372
411
|
return True
|
373
412
|
|
374
|
-
def
|
375
|
-
"""Loop over all entries and add up the word counts."""
|
376
|
-
noteWords = 0
|
413
|
+
def sumCounts(self) -> tuple[int, int, int, int]:
|
414
|
+
"""Loop over all entries and add up the word and char counts."""
|
377
415
|
novelWords = 0
|
416
|
+
notesWords = 0
|
417
|
+
novelChars = 0
|
418
|
+
notesChars = 0
|
378
419
|
for item in self._items.values():
|
379
420
|
if item.itemLayout == nwItemLayout.NOTE:
|
380
|
-
|
421
|
+
notesWords += item.wordCount
|
422
|
+
notesChars += item.charCount
|
381
423
|
elif item.itemLayout == nwItemLayout.DOCUMENT:
|
382
424
|
novelWords += item.wordCount
|
383
|
-
|
425
|
+
novelChars += item.charCount
|
426
|
+
return novelWords, notesWords, novelChars, notesChars
|
384
427
|
|
385
428
|
##
|
386
429
|
# Tree Item Methods
|
@@ -388,7 +431,7 @@ class NWTree:
|
|
388
431
|
|
389
432
|
def checkType(self, tHandle: str, itemType: nwItemType) -> bool:
|
390
433
|
"""Check if item exists and is of the specified item type."""
|
391
|
-
if tItem := self
|
434
|
+
if tItem := self[tHandle]:
|
392
435
|
return tItem.itemType == itemType
|
393
436
|
return False
|
394
437
|
|
@@ -406,8 +449,7 @@ class NWTree:
|
|
406
449
|
node = parent
|
407
450
|
else:
|
408
451
|
return path
|
409
|
-
|
410
|
-
logger.error("Max project tree depth reached")
|
452
|
+
logger.error("Max project tree depth reached")
|
411
453
|
return path
|
412
454
|
|
413
455
|
def subTree(self, tHandle: str) -> list[str]:
|
novelwriter/dialogs/about.py
CHANGED
@@ -25,17 +25,21 @@ from __future__ import annotations
|
|
25
25
|
|
26
26
|
import logging
|
27
27
|
|
28
|
-
from
|
29
|
-
|
28
|
+
from typing import TYPE_CHECKING
|
29
|
+
|
30
|
+
from PyQt6.QtWidgets import (
|
30
31
|
QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout, QWidget
|
31
32
|
)
|
32
33
|
|
33
34
|
from novelwriter import CONFIG, SHARED
|
34
|
-
from novelwriter.common import
|
35
|
-
from novelwriter.extensions.configlayout import
|
35
|
+
from novelwriter.common import readTextFile
|
36
|
+
from novelwriter.extensions.configlayout import NColorLabel
|
36
37
|
from novelwriter.extensions.modified import NDialog
|
37
38
|
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
38
|
-
from novelwriter.types import QtAlignRightTop, QtDialogClose
|
39
|
+
from novelwriter.types import QtAlignRightTop, QtDialogClose, QtHexArgb
|
40
|
+
|
41
|
+
if TYPE_CHECKING:
|
42
|
+
from PyQt6.QtGui import QCloseEvent
|
39
43
|
|
40
44
|
logger = logging.getLogger(__name__)
|
41
45
|
|
@@ -49,19 +53,13 @@ class GuiAbout(NDialog):
|
|
49
53
|
self.setObjectName("GuiAbout")
|
50
54
|
|
51
55
|
self.setWindowTitle(self.tr("About novelWriter"))
|
52
|
-
self.resize(
|
53
|
-
|
54
|
-
hA = CONFIG.pxInt(8)
|
55
|
-
hB = CONFIG.pxInt(16)
|
56
|
-
nwH = CONFIG.pxInt(36)
|
57
|
-
nwPx = CONFIG.pxInt(128)
|
56
|
+
self.resize(700, 500)
|
58
57
|
|
59
58
|
# Logo and Banner
|
60
|
-
self.nwImage = SHARED.theme.
|
61
|
-
self.bgColor = QColor(255, 255, 255) if SHARED.theme.isLightTheme else QColor(54, 54, 54)
|
59
|
+
self.nwImage = SHARED.theme.getDecoration("nw-text", h=36)
|
62
60
|
|
63
61
|
self.nwLogo = QLabel(self)
|
64
|
-
self.nwLogo.setPixmap(SHARED.theme.getPixmap("novelwriter", (
|
62
|
+
self.nwLogo.setPixmap(SHARED.theme.getPixmap("novelwriter", (128, 128)))
|
65
63
|
|
66
64
|
self.nwLabel = QLabel(self)
|
67
65
|
self.nwLabel.setPixmap(self.nwImage)
|
@@ -74,14 +72,13 @@ class GuiAbout(NDialog):
|
|
74
72
|
self.nwLicence.setOpenExternalLinks(True)
|
75
73
|
|
76
74
|
# Credits
|
77
|
-
self.lblCredits =
|
75
|
+
self.lblCredits = NColorLabel(
|
78
76
|
self.tr("Credits"), self, scale=1.6, bold=True
|
79
77
|
)
|
80
78
|
|
81
79
|
self.txtCredits = QTextBrowser(self)
|
82
80
|
self.txtCredits.setOpenExternalLinks(True)
|
83
|
-
self.txtCredits.
|
84
|
-
self.txtCredits.setViewportMargins(0, hA, hA, 0)
|
81
|
+
self.txtCredits.setViewportMargins(0, 8, 8, 0)
|
85
82
|
|
86
83
|
# Buttons
|
87
84
|
self.btnBox = QDialogButtonBox(QtDialogClose, self)
|
@@ -89,15 +86,15 @@ class GuiAbout(NDialog):
|
|
89
86
|
|
90
87
|
# Assemble
|
91
88
|
self.innerBox = QVBoxLayout()
|
92
|
-
self.innerBox.addSpacing(
|
89
|
+
self.innerBox.addSpacing(16)
|
93
90
|
self.innerBox.addWidget(self.nwLabel)
|
94
91
|
self.innerBox.addWidget(self.nwInfo)
|
95
|
-
self.innerBox.addSpacing(
|
92
|
+
self.innerBox.addSpacing(8)
|
96
93
|
self.innerBox.addWidget(self.nwLicence)
|
97
|
-
self.innerBox.addSpacing(
|
94
|
+
self.innerBox.addSpacing(8)
|
98
95
|
self.innerBox.addWidget(self.lblCredits)
|
99
96
|
self.innerBox.addWidget(self.txtCredits)
|
100
|
-
self.innerBox.addSpacing(
|
97
|
+
self.innerBox.addSpacing(16)
|
101
98
|
self.innerBox.addWidget(self.btnBox)
|
102
99
|
|
103
100
|
self.outerBox = QHBoxLayout()
|
@@ -142,7 +139,7 @@ class GuiAbout(NDialog):
|
|
142
139
|
|
143
140
|
def _setStyleSheet(self) -> None:
|
144
141
|
"""Set stylesheet text document."""
|
145
|
-
baseCol =
|
142
|
+
baseCol = self.palette().window().color().name(QtHexArgb)
|
146
143
|
self.txtCredits.setStyleSheet(
|
147
144
|
f"QTextBrowser {{border: none; background: {baseCol};}} "
|
148
145
|
)
|