novelWriter 2.6.2__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 +92 -56
- 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 +15 -18
- novelwriter/gui/mainmenu.py +147 -146
- novelwriter/gui/noveltree.py +246 -406
- novelwriter/gui/outline.py +145 -76
- 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 +114 -127
- 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.2.dist-info → novelwriter-2.7.dist-info}/METADATA +6 -6
- novelwriter-2.7.dist-info/RECORD +162 -0
- {novelWriter-2.6.2.dist-info → novelwriter-2.7.dist-info}/WHEEL +1 -1
- novelWriter-2.6.2.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.2.dist-info → novelwriter-2.7.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.6.2.dist-info → novelwriter-2.7.dist-info/licenses}/LICENSE.md +0 -0
- {novelWriter-2.6.2.dist-info → novelwriter-2.7.dist-info}/top_level.txt +0 -0
novelwriter/core/itemmodel.py
CHANGED
@@ -28,8 +28,8 @@ import logging
|
|
28
28
|
|
29
29
|
from typing import TYPE_CHECKING
|
30
30
|
|
31
|
-
from
|
32
|
-
from
|
31
|
+
from PyQt6.QtCore import QAbstractItemModel, QMimeData, QModelIndex, Qt
|
32
|
+
from PyQt6.QtGui import QFont, QIcon
|
33
33
|
|
34
34
|
from novelwriter.common import decodeMimeHandles, encodeMimeHandles, minmax
|
35
35
|
from novelwriter.constants import nwConst
|
@@ -37,7 +37,7 @@ from novelwriter.core.item import NWItem
|
|
37
37
|
from novelwriter.enum import nwItemClass
|
38
38
|
from novelwriter.types import QtAlignRight
|
39
39
|
|
40
|
-
if TYPE_CHECKING:
|
40
|
+
if TYPE_CHECKING:
|
41
41
|
from novelwriter.core.tree import NWTree
|
42
42
|
|
43
43
|
logger = logging.getLogger(__name__)
|
@@ -45,24 +45,24 @@ logger = logging.getLogger(__name__)
|
|
45
45
|
INV_ROOT = "invisibleRoot"
|
46
46
|
C_FACTOR = 0x0100
|
47
47
|
|
48
|
-
C_LABEL_TEXT
|
49
|
-
C_LABEL_ICON
|
50
|
-
C_LABEL_FONT
|
51
|
-
C_COUNT_TEXT
|
52
|
-
C_COUNT_ICON
|
53
|
-
C_COUNT_ALIGN
|
54
|
-
C_ACTIVE_ICON
|
55
|
-
C_ACTIVE_TIP
|
56
|
-
|
57
|
-
|
48
|
+
C_LABEL_TEXT = 0x0000 | Qt.ItemDataRole.DisplayRole
|
49
|
+
C_LABEL_ICON = 0x0000 | Qt.ItemDataRole.DecorationRole
|
50
|
+
C_LABEL_FONT = 0x0000 | Qt.ItemDataRole.FontRole
|
51
|
+
C_COUNT_TEXT = 0x0100 | Qt.ItemDataRole.DisplayRole
|
52
|
+
C_COUNT_ICON = 0x0100 | Qt.ItemDataRole.DecorationRole
|
53
|
+
C_COUNT_ALIGN = 0x0100 | Qt.ItemDataRole.TextAlignmentRole
|
54
|
+
C_ACTIVE_ICON = 0x0200 | Qt.ItemDataRole.DecorationRole
|
55
|
+
C_ACTIVE_TIP = 0x0200 | Qt.ItemDataRole.ToolTipRole
|
56
|
+
C_ACTIVE_ACCESS = 0x0200 | Qt.ItemDataRole.AccessibleTextRole
|
57
|
+
C_STATUS_ICON = 0x0300 | Qt.ItemDataRole.DecorationRole
|
58
|
+
C_STATUS_TIP = 0x0300 | Qt.ItemDataRole.ToolTipRole
|
59
|
+
C_STATUS_ACCESS = 0x0300 | Qt.ItemDataRole.AccessibleTextRole
|
58
60
|
|
59
61
|
NODE_FLAGS = Qt.ItemFlag.ItemIsEnabled
|
60
62
|
NODE_FLAGS |= Qt.ItemFlag.ItemIsSelectable
|
61
63
|
NODE_FLAGS |= Qt.ItemFlag.ItemIsDropEnabled
|
62
64
|
|
63
|
-
|
64
|
-
# Requires Python 3.10
|
65
|
-
T_NodeData = str | QIcon | QFont | Qt.AlignmentFlag | None
|
65
|
+
T_NodeData = str | QIcon | QFont | Qt.AlignmentFlag | None
|
66
66
|
|
67
67
|
|
68
68
|
class ProjectNode:
|
@@ -91,7 +91,7 @@ class ProjectNode:
|
|
91
91
|
C_ACTIVE = 2
|
92
92
|
C_STATUS = 3
|
93
93
|
|
94
|
-
__slots__ = ("
|
94
|
+
__slots__ = ("_cache", "_children", "_count", "_flags", "_item", "_parent", "_row")
|
95
95
|
|
96
96
|
def __init__(self, item: NWItem) -> None:
|
97
97
|
self._item = item
|
@@ -152,19 +152,21 @@ class ProjectNode:
|
|
152
152
|
|
153
153
|
# Active
|
154
154
|
aText, aIcon = self._item.getActiveStatus()
|
155
|
-
self._cache[C_ACTIVE_TIP] = aText
|
156
155
|
self._cache[C_ACTIVE_ICON] = aIcon
|
156
|
+
self._cache[C_ACTIVE_TIP] = aText
|
157
|
+
self._cache[C_ACTIVE_ACCESS] = aText
|
157
158
|
|
158
159
|
# Status
|
159
160
|
sText, sIcon = self._item.getImportStatus()
|
160
|
-
self._cache[C_STATUS_TIP] = sText
|
161
161
|
self._cache[C_STATUS_ICON] = sIcon
|
162
|
+
self._cache[C_STATUS_TIP] = sText
|
163
|
+
self._cache[C_STATUS_ACCESS] = sText
|
162
164
|
|
163
165
|
return
|
164
166
|
|
165
167
|
def updateCount(self, propagate: bool = True) -> None:
|
166
168
|
"""Update counts, and propagate upwards in the tree."""
|
167
|
-
self._count = self._item.
|
169
|
+
self._count = self._item.mainCount + sum(c._count for c in self._children) # noqa: SLF001
|
168
170
|
self._cache[C_COUNT_TEXT] = f"{self._count:n}"
|
169
171
|
if propagate and (parent := self._parent):
|
170
172
|
parent.updateCount()
|
@@ -195,7 +197,7 @@ class ProjectNode:
|
|
195
197
|
return self._parent
|
196
198
|
|
197
199
|
def child(self, row: int) -> ProjectNode | None:
|
198
|
-
"""Return a child
|
200
|
+
"""Return a child of the node."""
|
199
201
|
if 0 <= row < len(self._children):
|
200
202
|
return self._children[row]
|
201
203
|
return None
|
@@ -220,6 +222,7 @@ class ProjectNode:
|
|
220
222
|
child._row = len(self._children)
|
221
223
|
self._children.append(child)
|
222
224
|
self._refreshChildrenPos()
|
225
|
+
self._item.notifyNovelStructureChange()
|
223
226
|
return
|
224
227
|
|
225
228
|
def takeChild(self, pos: int) -> ProjectNode | None:
|
@@ -228,6 +231,7 @@ class ProjectNode:
|
|
228
231
|
node = self._children.pop(pos)
|
229
232
|
self._refreshChildrenPos()
|
230
233
|
self.updateCount()
|
234
|
+
self._item.notifyNovelStructureChange()
|
231
235
|
return node
|
232
236
|
return None
|
233
237
|
|
@@ -238,6 +242,7 @@ class ProjectNode:
|
|
238
242
|
node = self._children.pop(source)
|
239
243
|
self._children.insert(target, node)
|
240
244
|
self._refreshChildrenPos()
|
245
|
+
self._item.notifyNovelStructureChange()
|
241
246
|
return
|
242
247
|
|
243
248
|
def setExpanded(self, state: bool) -> None:
|
@@ -256,13 +261,13 @@ class ProjectNode:
|
|
256
261
|
"""Recursively add all nodes to a list."""
|
257
262
|
for node in self._children:
|
258
263
|
children.append(node)
|
259
|
-
node._recursiveAppendChildren(children)
|
264
|
+
node._recursiveAppendChildren(children) # noqa: SLF001
|
260
265
|
return
|
261
266
|
|
262
267
|
def _refreshChildrenPos(self) -> None:
|
263
268
|
"""Update the row value on all children."""
|
264
269
|
for n, child in enumerate(self._children):
|
265
|
-
child._row = n
|
270
|
+
child._row = n # noqa: SLF001
|
266
271
|
child.item.setOrder(n)
|
267
272
|
return
|
268
273
|
|
@@ -289,12 +294,12 @@ class ProjectModel(QAbstractItemModel):
|
|
289
294
|
methods needed primarily by the project tree GUI component.
|
290
295
|
"""
|
291
296
|
|
292
|
-
__slots__ = ("
|
297
|
+
__slots__ = ("_root", "_tree")
|
293
298
|
|
294
299
|
def __init__(self, tree: NWTree) -> None:
|
295
300
|
super().__init__()
|
296
301
|
self._tree = tree
|
297
|
-
self._root = ProjectNode(NWItem(tree.
|
302
|
+
self._root = ProjectNode(NWItem(tree.project, INV_ROOT))
|
298
303
|
self._root.item.setName("Invisible Root")
|
299
304
|
logger.debug("Ready: ProjectModel")
|
300
305
|
return
|
@@ -332,8 +337,9 @@ class ProjectModel(QAbstractItemModel):
|
|
332
337
|
return self.createIndex(parent.row(), 0, parent)
|
333
338
|
return QModelIndex()
|
334
339
|
|
335
|
-
def index(self, row: int, column: int, parent: QModelIndex =
|
336
|
-
"""
|
340
|
+
def index(self, row: int, column: int, parent: QModelIndex | None = None) -> QModelIndex:
|
341
|
+
"""Get the index of a child item of a parent."""
|
342
|
+
parent = parent or QModelIndex()
|
337
343
|
if self.hasIndex(row, column, parent):
|
338
344
|
node: ProjectNode = parent.internalPointer() if parent.isValid() else self._root
|
339
345
|
if child := node.child(row):
|
@@ -389,10 +395,10 @@ class ProjectModel(QAbstractItemModel):
|
|
389
395
|
) -> bool:
|
390
396
|
"""Process mime data drop."""
|
391
397
|
if self.canDropMimeData(data, action, row, column, parent):
|
392
|
-
items = [
|
393
|
-
|
394
|
-
if (index := self.indexFromHandle(handle)).isValid()
|
395
|
-
|
398
|
+
items = [
|
399
|
+
index for handle in decodeMimeHandles(data)
|
400
|
+
if (index := self.indexFromHandle(handle)).isValid()
|
401
|
+
]
|
396
402
|
self.multiMove(items, parent, row)
|
397
403
|
return True
|
398
404
|
return False
|
@@ -488,7 +494,7 @@ class ProjectModel(QAbstractItemModel):
|
|
488
494
|
if temp := self.removeChild(index.parent(), index.row()):
|
489
495
|
self.insertChild(temp, target, pos)
|
490
496
|
for child in reversed(node.allChildren()):
|
491
|
-
node._updateRelationships(child)
|
497
|
+
node._updateRelationships(child) # noqa: SLF001
|
492
498
|
child.item.notifyToRefresh()
|
493
499
|
node.item.notifyToRefresh()
|
494
500
|
return
|
@@ -499,16 +505,15 @@ class ProjectModel(QAbstractItemModel):
|
|
499
505
|
|
500
506
|
def clear(self) -> None:
|
501
507
|
"""Clear the project model."""
|
502
|
-
self._root.
|
508
|
+
self._root.children.clear()
|
503
509
|
return
|
504
510
|
|
505
511
|
def allExpanded(self) -> list[QModelIndex]:
|
506
512
|
"""Return a list of all expanded items."""
|
507
|
-
|
508
|
-
|
509
|
-
if node.
|
510
|
-
|
511
|
-
return expanded
|
513
|
+
return [
|
514
|
+
self.createIndex(node.row(), 0, node) for node in self._root.allChildren()
|
515
|
+
if node.item.isExpanded
|
516
|
+
]
|
512
517
|
|
513
518
|
def trashSelection(self, indices: list[QModelIndex]) -> bool:
|
514
519
|
"""Check if a selection of indices are all in trash or not."""
|
@@ -0,0 +1,225 @@
|
|
1
|
+
"""
|
2
|
+
novelWriter – Novel Model
|
3
|
+
=========================
|
4
|
+
|
5
|
+
File History:
|
6
|
+
Created: 2025-02-22 [2.7b1] NovelModel
|
7
|
+
|
8
|
+
This file is a part of novelWriter
|
9
|
+
Copyright (C) 2025 Veronica Berglyd Olsen and novelWriter contributors
|
10
|
+
|
11
|
+
This program is free software: you can redistribute it and/or modify
|
12
|
+
it under the terms of the GNU General Public License as published by
|
13
|
+
the Free Software Foundation, either version 3 of the License, or
|
14
|
+
(at your option) any later version.
|
15
|
+
|
16
|
+
This program is distributed in the hope that it will be useful, but
|
17
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
19
|
+
General Public License for more details.
|
20
|
+
|
21
|
+
You should have received a copy of the GNU General Public License
|
22
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
23
|
+
"""
|
24
|
+
from __future__ import annotations
|
25
|
+
|
26
|
+
import logging
|
27
|
+
|
28
|
+
from typing import TYPE_CHECKING
|
29
|
+
|
30
|
+
from PyQt6.QtCore import QAbstractTableModel, QModelIndex, Qt
|
31
|
+
from PyQt6.QtGui import QIcon, QPixmap
|
32
|
+
|
33
|
+
from novelwriter import SHARED
|
34
|
+
from novelwriter.constants import nwKeyWords, nwLabels, nwStyles, trConst
|
35
|
+
from novelwriter.enum import nwNovelExtra
|
36
|
+
from novelwriter.types import QtAlignRight
|
37
|
+
|
38
|
+
if TYPE_CHECKING:
|
39
|
+
from novelwriter.core.indexdata import IndexHeading, IndexNode
|
40
|
+
|
41
|
+
logger = logging.getLogger(__name__)
|
42
|
+
|
43
|
+
C_FACTOR = 0x0100
|
44
|
+
|
45
|
+
R_TEXT = Qt.ItemDataRole.DisplayRole
|
46
|
+
R_ICON = Qt.ItemDataRole.DecorationRole
|
47
|
+
R_ALIGN = Qt.ItemDataRole.TextAlignmentRole
|
48
|
+
R_TIP = Qt.ItemDataRole.ToolTipRole
|
49
|
+
R_ACCESS = Qt.ItemDataRole.AccessibleTextRole
|
50
|
+
R_HANDLE = 0xff01
|
51
|
+
R_KEY = 0xff02
|
52
|
+
|
53
|
+
T_NodeData = str | QIcon | QPixmap | Qt.AlignmentFlag | None
|
54
|
+
|
55
|
+
|
56
|
+
class NovelModel(QAbstractTableModel):
|
57
|
+
|
58
|
+
__slots__ = ("_columns", "_extraKey", "_extraLabel", "_more", "_rows")
|
59
|
+
|
60
|
+
def __init__(self) -> None:
|
61
|
+
super().__init__()
|
62
|
+
self._rows: list[dict[int, T_NodeData]] = []
|
63
|
+
self._more = SHARED.theme.getIcon("more_arrow")
|
64
|
+
self._columns = 3
|
65
|
+
self._extraKey = ""
|
66
|
+
self._extraLabel = ""
|
67
|
+
return
|
68
|
+
|
69
|
+
def __del__(self) -> None: # pragma: no cover
|
70
|
+
logger.debug("Delete: NovelModel")
|
71
|
+
return
|
72
|
+
|
73
|
+
##
|
74
|
+
# Properties
|
75
|
+
##
|
76
|
+
|
77
|
+
@property
|
78
|
+
def columns(self) -> int:
|
79
|
+
"""Return the number of columns."""
|
80
|
+
return self._columns
|
81
|
+
|
82
|
+
##
|
83
|
+
# Setters
|
84
|
+
##
|
85
|
+
|
86
|
+
def setExtraColumn(self, extra: nwNovelExtra) -> None:
|
87
|
+
"""Set extra data column settings."""
|
88
|
+
match extra:
|
89
|
+
case nwNovelExtra.HIDDEN:
|
90
|
+
self._columns = 3
|
91
|
+
self._extraKey = ""
|
92
|
+
self._extraLabel = ""
|
93
|
+
case nwNovelExtra.POV:
|
94
|
+
self._columns = 4
|
95
|
+
self._extraKey = nwKeyWords.POV_KEY
|
96
|
+
self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
|
97
|
+
case nwNovelExtra.FOCUS:
|
98
|
+
self._columns = 4
|
99
|
+
self._extraKey = nwKeyWords.FOCUS_KEY
|
100
|
+
self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])
|
101
|
+
case nwNovelExtra.PLOT:
|
102
|
+
self._columns = 4
|
103
|
+
self._extraKey = nwKeyWords.PLOT_KEY
|
104
|
+
self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY])
|
105
|
+
return
|
106
|
+
|
107
|
+
##
|
108
|
+
# Model Interface
|
109
|
+
##
|
110
|
+
|
111
|
+
def rowCount(self, index: QModelIndex) -> int:
|
112
|
+
"""Return the number of rows."""
|
113
|
+
return len(self._rows)
|
114
|
+
|
115
|
+
def columnCount(self, index: QModelIndex) -> int:
|
116
|
+
"""Return the number of columns."""
|
117
|
+
return self._columns
|
118
|
+
|
119
|
+
def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> T_NodeData:
|
120
|
+
"""Return display data for a node."""
|
121
|
+
try:
|
122
|
+
return self._rows[index.row()].get(C_FACTOR*index.column() | role)
|
123
|
+
except Exception:
|
124
|
+
logger.error("Novel model index is inconsistent")
|
125
|
+
return None
|
126
|
+
|
127
|
+
def handle(self, index: QModelIndex) -> str | None:
|
128
|
+
"""Return item handle for the row."""
|
129
|
+
try:
|
130
|
+
return self._rows[index.row()].get(R_HANDLE) # type: ignore
|
131
|
+
except Exception:
|
132
|
+
logger.error("Novel model index is inconsistent")
|
133
|
+
return None
|
134
|
+
|
135
|
+
def key(self, index: QModelIndex) -> str | None:
|
136
|
+
"""Return item handle for the row."""
|
137
|
+
try:
|
138
|
+
return self._rows[index.row()].get(R_KEY) # type: ignore
|
139
|
+
except Exception:
|
140
|
+
logger.error("Novel model index is inconsistent")
|
141
|
+
return None
|
142
|
+
|
143
|
+
##
|
144
|
+
# Data Methods
|
145
|
+
##
|
146
|
+
|
147
|
+
def clear(self) -> None:
|
148
|
+
"""Clear the model."""
|
149
|
+
self._rows.clear()
|
150
|
+
return
|
151
|
+
|
152
|
+
def append(self, node: IndexNode) -> None:
|
153
|
+
"""Append a node to the model."""
|
154
|
+
handle = node.handle
|
155
|
+
for key, head in node.items():
|
156
|
+
if key != "T0000":
|
157
|
+
self._rows.append(self._generateEntry(handle, key, head))
|
158
|
+
return
|
159
|
+
|
160
|
+
def refresh(self, node: IndexNode) -> bool:
|
161
|
+
"""Refresh an index node."""
|
162
|
+
handle = node.handle
|
163
|
+
current = []
|
164
|
+
for i, row in enumerate(self._rows):
|
165
|
+
if row.get(R_HANDLE) == handle:
|
166
|
+
current.append(i)
|
167
|
+
|
168
|
+
if current == []:
|
169
|
+
logger.warning("No novel model entries for '%s'", handle)
|
170
|
+
return False
|
171
|
+
|
172
|
+
cols = self._columns - 1
|
173
|
+
first = current[0]
|
174
|
+
last = current[-1]
|
175
|
+
|
176
|
+
remains = []
|
177
|
+
for key, head in node.items():
|
178
|
+
if key != "T0000":
|
179
|
+
if current:
|
180
|
+
j = current.pop(0)
|
181
|
+
self._rows[j] = self._generateEntry(handle, key, head)
|
182
|
+
else:
|
183
|
+
remains.append((key, head))
|
184
|
+
|
185
|
+
self.dataChanged.emit(self.createIndex(first, 0), self.createIndex(last, cols))
|
186
|
+
|
187
|
+
if remains:
|
188
|
+
# Inserting is safe for out of bounds indices
|
189
|
+
self.beginInsertRows(QModelIndex(), last, last + len(remains) - 1)
|
190
|
+
for k, (key, head) in enumerate(remains, last + 1):
|
191
|
+
self._rows.insert(k, self._generateEntry(handle, key, head))
|
192
|
+
self.endInsertRows()
|
193
|
+
elif current:
|
194
|
+
# Deleting ranges are safe for out of bounds indices
|
195
|
+
self.beginRemoveRows(QModelIndex(), current[0], current[-1])
|
196
|
+
del self._rows[current[0]:current[-1] + 1]
|
197
|
+
self.endRemoveRows()
|
198
|
+
|
199
|
+
return True
|
200
|
+
|
201
|
+
##
|
202
|
+
# Internal Functions
|
203
|
+
##
|
204
|
+
|
205
|
+
def _generateEntry(self, handle: str, key: str, head: IndexHeading) -> dict[int, T_NodeData]:
|
206
|
+
"""Generate a cache entry."""
|
207
|
+
iLevel = nwStyles.H_LEVEL.get(head.level, 0)
|
208
|
+
data = {}
|
209
|
+
data[C_FACTOR*0 | R_TIP] = head.title
|
210
|
+
data[C_FACTOR*0 | R_TEXT] = head.title
|
211
|
+
data[C_FACTOR*0 | R_ICON] = SHARED.theme.getHeaderDecoration(iLevel)
|
212
|
+
data[C_FACTOR*1 | R_TEXT] = f"{head.mainCount:n}"
|
213
|
+
data[C_FACTOR*1 | R_ALIGN] = QtAlignRight
|
214
|
+
if self._columns == 3:
|
215
|
+
data[C_FACTOR*2 | R_ICON] = self._more
|
216
|
+
else:
|
217
|
+
if self._extraKey and (refs := head.getReferencesByKeyword(self._extraKey)):
|
218
|
+
text = ", ".join(refs)
|
219
|
+
data[C_FACTOR*2 | R_TEXT] = text
|
220
|
+
data[C_FACTOR*2 | R_TIP] = f"<b>{self._extraLabel}:</b> {text}"
|
221
|
+
data[C_FACTOR*2 | R_ACCESS] = f"{self._extraLabel}: {text}"
|
222
|
+
data[C_FACTOR*3 | R_ICON] = self._more
|
223
|
+
data[R_HANDLE] = handle
|
224
|
+
data[R_KEY] = key
|
225
|
+
return data
|
novelwriter/core/options.py
CHANGED
@@ -35,7 +35,7 @@ from novelwriter.common import checkBool, checkFloat, checkInt, checkString, jso
|
|
35
35
|
from novelwriter.constants import nwFiles
|
36
36
|
from novelwriter.error import logException
|
37
37
|
|
38
|
-
if TYPE_CHECKING:
|
38
|
+
if TYPE_CHECKING:
|
39
39
|
from novelwriter.core.project import NWProject
|
40
40
|
|
41
41
|
logger = logging.getLogger(__name__)
|
novelwriter/core/project.py
CHANGED
@@ -32,7 +32,7 @@ from pathlib import Path
|
|
32
32
|
from time import time
|
33
33
|
from typing import TYPE_CHECKING
|
34
34
|
|
35
|
-
from
|
35
|
+
from PyQt6.QtCore import QCoreApplication
|
36
36
|
|
37
37
|
from novelwriter import CONFIG, SHARED, __hexversion__, __version__
|
38
38
|
from novelwriter.common import (
|
@@ -40,7 +40,7 @@ from novelwriter.common import (
|
|
40
40
|
makeFileNameSafe, minmax
|
41
41
|
)
|
42
42
|
from novelwriter.constants import nwLabels, trConst
|
43
|
-
from novelwriter.core.index import
|
43
|
+
from novelwriter.core.index import Index
|
44
44
|
from novelwriter.core.options import OptionState
|
45
45
|
from novelwriter.core.projectdata import NWProjectData
|
46
46
|
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
|
@@ -50,8 +50,7 @@ from novelwriter.core.tree import NWTree
|
|
50
50
|
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
51
51
|
from novelwriter.error import logException
|
52
52
|
|
53
|
-
if TYPE_CHECKING:
|
54
|
-
# Requires Python 3.10
|
53
|
+
if TYPE_CHECKING:
|
55
54
|
from novelwriter.core.status import T_StatusKind, T_UpdateEntry
|
56
55
|
|
57
56
|
logger = logging.getLogger(__name__)
|
@@ -68,8 +67,8 @@ class NWProjectState(Enum):
|
|
68
67
|
class NWProject:
|
69
68
|
|
70
69
|
__slots__ = (
|
71
|
-
"
|
72
|
-
"
|
70
|
+
"_changed", "_data", "_index", "_langData", "_options", "_session",
|
71
|
+
"_state", "_storage", "_tree", "_valid", "tr",
|
73
72
|
)
|
74
73
|
|
75
74
|
def __init__(self) -> None:
|
@@ -79,7 +78,7 @@ class NWProject:
|
|
79
78
|
self._storage = NWStorage(self) # The project storage handler
|
80
79
|
self._data = NWProjectData(self) # The project settings
|
81
80
|
self._tree = NWTree(self) # The project tree
|
82
|
-
self._index =
|
81
|
+
self._index = Index(self) # The project index
|
83
82
|
self._session = NWSessionLog(self) # The session record
|
84
83
|
|
85
84
|
# Project Status
|
@@ -126,7 +125,7 @@ class NWProject:
|
|
126
125
|
return self._tree
|
127
126
|
|
128
127
|
@property
|
129
|
-
def index(self) ->
|
128
|
+
def index(self) -> Index:
|
130
129
|
return self._index
|
131
130
|
|
132
131
|
@property
|
@@ -368,7 +367,7 @@ class NWProject:
|
|
368
367
|
# Often, the index needs to be rebuilt when updating format
|
369
368
|
self._index.rebuild()
|
370
369
|
|
371
|
-
self.
|
370
|
+
self.updateCounts()
|
372
371
|
self._session.startSession()
|
373
372
|
self.setProjectChanged(False)
|
374
373
|
self._valid = True
|
@@ -398,7 +397,7 @@ class NWProject:
|
|
398
397
|
else:
|
399
398
|
self._data.incSaveCount()
|
400
399
|
|
401
|
-
self.
|
400
|
+
self.updateCounts()
|
402
401
|
self.countStatus()
|
403
402
|
|
404
403
|
xmlWriter = self._storage.getXmlWriter()
|
@@ -484,14 +483,14 @@ class NWProject:
|
|
484
483
|
|
485
484
|
def setDefaultStatusImport(self) -> None:
|
486
485
|
"""Set the default status and importance values."""
|
487
|
-
self._data.itemStatus.add(None, self.tr("New"), (
|
488
|
-
self._data.itemStatus.add(None, self.tr("Note"), (
|
489
|
-
self._data.itemStatus.add(None, self.tr("Draft"), (
|
490
|
-
self._data.itemStatus.add(None, self.tr("Finished"), (
|
491
|
-
self._data.itemImport.add(None, self.tr("New"), (
|
492
|
-
self._data.itemImport.add(None, self.tr("Minor"), (
|
493
|
-
self._data.itemImport.add(None, self.tr("Major"), (
|
494
|
-
self._data.itemImport.add(None, self.tr("Main"), (
|
486
|
+
self._data.itemStatus.add(None, self.tr("New"), (120, 120, 120), "STAR", 0)
|
487
|
+
self._data.itemStatus.add(None, self.tr("Note"), (205, 171, 143), "TRIANGLE", 0)
|
488
|
+
self._data.itemStatus.add(None, self.tr("Draft"), (143, 240, 164), "CIRCLE_T", 0)
|
489
|
+
self._data.itemStatus.add(None, self.tr("Finished"), (249, 240, 107), "STAR", 0)
|
490
|
+
self._data.itemImport.add(None, self.tr("New"), (120, 120, 120), "SQUARE", 0)
|
491
|
+
self._data.itemImport.add(None, self.tr("Minor"), (220, 138, 221), "BLOCK_2", 0)
|
492
|
+
self._data.itemImport.add(None, self.tr("Major"), (220, 138, 221), "BLOCK_3", 0)
|
493
|
+
self._data.itemImport.add(None, self.tr("Main"), (220, 138, 221), "BLOCK_4", 0)
|
495
494
|
return
|
496
495
|
|
497
496
|
def setProjectLang(self, language: str | None) -> None:
|
@@ -516,10 +515,10 @@ class NWProject:
|
|
516
515
|
# Class Methods
|
517
516
|
##
|
518
517
|
|
519
|
-
def
|
520
|
-
"""Update the total word count values."""
|
521
|
-
|
522
|
-
self._data.setCurrCounts(
|
518
|
+
def updateCounts(self) -> None:
|
519
|
+
"""Update the total word and character count values."""
|
520
|
+
wNovel, wNotes, cNovel, cNotes = self._tree.sumCounts()
|
521
|
+
self._data.setCurrCounts(wNovel=wNovel, wNotes=wNotes, cNovel=cNovel, cNotes=cNotes)
|
523
522
|
return
|
524
523
|
|
525
524
|
def countStatus(self) -> None:
|
@@ -561,13 +560,13 @@ class NWProject:
|
|
561
560
|
|
562
561
|
def _loadProjectLocalisation(self) -> bool:
|
563
562
|
"""Load the language data for the current project language."""
|
564
|
-
if self._data.language is None or CONFIG.
|
563
|
+
if self._data.language is None or CONFIG.nwLangPath is None:
|
565
564
|
self._langData = {}
|
566
565
|
return False
|
567
566
|
|
568
|
-
langFile = Path(CONFIG.
|
567
|
+
langFile = Path(CONFIG.nwLangPath) / f"project_{self._data.language}.json"
|
569
568
|
if not langFile.is_file():
|
570
|
-
langFile = Path(CONFIG.
|
569
|
+
langFile = Path(CONFIG.nwLangPath) / "project_en_GB.json"
|
571
570
|
|
572
571
|
try:
|
573
572
|
with open(langFile, mode="r", encoding="utf-8") as inFile:
|