novelWriter 2.6.3__py3-none-any.whl → 2.7b1__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 +84 -74
- novelwriter/assets/i18n/project_en_GB.json +1 -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 +108 -0
- novelwriter/assets/icons/remix_outline.icons +108 -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/text/credits_en.htm +6 -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/solarized_dark.conf +24 -8
- novelwriter/assets/themes/solarized_light.conf +22 -6
- novelwriter/common.py +33 -26
- novelwriter/config.py +118 -127
- novelwriter/constants.py +50 -36
- novelwriter/core/buildsettings.py +23 -16
- novelwriter/core/coretools.py +11 -7
- novelwriter/core/docbuild.py +19 -13
- novelwriter/core/document.py +2 -2
- novelwriter/core/index.py +142 -432
- novelwriter/core/indexdata.py +403 -0
- novelwriter/core/item.py +35 -28
- novelwriter/core/itemmodel.py +27 -26
- novelwriter/core/novelmodel.py +223 -0
- novelwriter/core/options.py +1 -1
- novelwriter/core/project.py +10 -11
- novelwriter/core/projectdata.py +5 -5
- novelwriter/core/projectxml.py +1 -1
- novelwriter/core/sessions.py +3 -2
- novelwriter/core/spellcheck.py +4 -3
- novelwriter/core/status.py +12 -15
- novelwriter/core/storage.py +1 -1
- novelwriter/core/tree.py +46 -8
- novelwriter/dialogs/about.py +19 -22
- novelwriter/dialogs/docmerge.py +21 -23
- novelwriter/dialogs/docsplit.py +20 -23
- novelwriter/dialogs/editlabel.py +9 -13
- novelwriter/dialogs/preferences.py +111 -48
- novelwriter/dialogs/projectsettings.py +48 -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 +18 -18
- 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 +19 -30
- novelwriter/extensions/switchbox.py +7 -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 +36 -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 +216 -265
- 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 +239 -405
- novelwriter/gui/outline.py +133 -72
- novelwriter/gui/projtree.py +138 -132
- novelwriter/gui/search.py +33 -31
- novelwriter/gui/sidebar.py +13 -18
- novelwriter/gui/statusbar.py +13 -15
- novelwriter/gui/theme.py +533 -430
- novelwriter/guimain.py +27 -29
- novelwriter/shared.py +32 -23
- novelwriter/text/comments.py +70 -0
- novelwriter/text/patterns.py +4 -4
- novelwriter/tools/dictionaries.py +20 -29
- novelwriter/tools/lipsum.py +16 -17
- novelwriter/tools/manusbuild.py +39 -42
- novelwriter/tools/manuscript.py +101 -114
- novelwriter/tools/manussettings.py +78 -83
- novelwriter/tools/noveldetails.py +51 -64
- novelwriter/tools/welcome.py +56 -75
- novelwriter/tools/writingstats.py +44 -57
- novelwriter/types.py +5 -7
- {novelWriter-2.6.3.dist-info → novelwriter-2.7b1.dist-info}/METADATA +6 -6
- novelwriter-2.7b1.dist-info/RECORD +159 -0
- {novelWriter-2.6.3.dist-info → novelwriter-2.7b1.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.7b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.6.3.dist-info → novelwriter-2.7b1.dist-info/licenses}/LICENSE.md +0 -0
- {novelWriter-2.6.3.dist-info → novelwriter-2.7b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,223 @@
|
|
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_HANDLE = 0xff01
|
50
|
+
R_KEY = 0xff02
|
51
|
+
|
52
|
+
T_NodeData = str | QIcon | QPixmap | Qt.AlignmentFlag | None
|
53
|
+
|
54
|
+
|
55
|
+
class NovelModel(QAbstractTableModel):
|
56
|
+
|
57
|
+
__slots__ = ("_columns", "_extraKey", "_extraLabel", "_more", "_rows")
|
58
|
+
|
59
|
+
def __init__(self) -> None:
|
60
|
+
super().__init__()
|
61
|
+
self._rows: list[dict[int, T_NodeData]] = []
|
62
|
+
self._more = SHARED.theme.getIcon("more_arrow")
|
63
|
+
self._columns = 3
|
64
|
+
self._extraKey = ""
|
65
|
+
self._extraLabel = ""
|
66
|
+
return
|
67
|
+
|
68
|
+
def __del__(self) -> None: # pragma: no cover
|
69
|
+
logger.debug("Delete: NovelModel")
|
70
|
+
return
|
71
|
+
|
72
|
+
##
|
73
|
+
# Properties
|
74
|
+
##
|
75
|
+
|
76
|
+
@property
|
77
|
+
def columns(self) -> int:
|
78
|
+
"""Return the number of columns."""
|
79
|
+
return self._columns
|
80
|
+
|
81
|
+
##
|
82
|
+
# Setters
|
83
|
+
##
|
84
|
+
|
85
|
+
def setExtraColumn(self, extra: nwNovelExtra) -> None:
|
86
|
+
"""Set extra data column settings."""
|
87
|
+
match extra:
|
88
|
+
case nwNovelExtra.HIDDEN:
|
89
|
+
self._columns = 3
|
90
|
+
self._extraKey = ""
|
91
|
+
self._extraLabel = ""
|
92
|
+
case nwNovelExtra.POV:
|
93
|
+
self._columns = 4
|
94
|
+
self._extraKey = nwKeyWords.POV_KEY
|
95
|
+
self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
|
96
|
+
case nwNovelExtra.FOCUS:
|
97
|
+
self._columns = 4
|
98
|
+
self._extraKey = nwKeyWords.FOCUS_KEY
|
99
|
+
self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])
|
100
|
+
case nwNovelExtra.PLOT:
|
101
|
+
self._columns = 4
|
102
|
+
self._extraKey = nwKeyWords.PLOT_KEY
|
103
|
+
self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY])
|
104
|
+
return
|
105
|
+
|
106
|
+
##
|
107
|
+
# Model Interface
|
108
|
+
##
|
109
|
+
|
110
|
+
def rowCount(self, index: QModelIndex) -> int:
|
111
|
+
"""Return the number of rows."""
|
112
|
+
return len(self._rows)
|
113
|
+
|
114
|
+
def columnCount(self, index: QModelIndex) -> int:
|
115
|
+
"""Return the number of columns."""
|
116
|
+
return self._columns
|
117
|
+
|
118
|
+
def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> T_NodeData:
|
119
|
+
"""Return display data for a node."""
|
120
|
+
try:
|
121
|
+
return self._rows[index.row()].get(C_FACTOR*index.column() | role)
|
122
|
+
except Exception:
|
123
|
+
logger.error("Novel model index is inconsistent")
|
124
|
+
return None
|
125
|
+
|
126
|
+
def handle(self, index: QModelIndex) -> str | None:
|
127
|
+
"""Return item handle for the row."""
|
128
|
+
try:
|
129
|
+
return self._rows[index.row()].get(R_HANDLE) # type: ignore
|
130
|
+
except Exception:
|
131
|
+
logger.error("Novel model index is inconsistent")
|
132
|
+
return None
|
133
|
+
|
134
|
+
def key(self, index: QModelIndex) -> str | None:
|
135
|
+
"""Return item handle for the row."""
|
136
|
+
try:
|
137
|
+
return self._rows[index.row()].get(R_KEY) # type: ignore
|
138
|
+
except Exception:
|
139
|
+
logger.error("Novel model index is inconsistent")
|
140
|
+
return None
|
141
|
+
|
142
|
+
##
|
143
|
+
# Data Methods
|
144
|
+
##
|
145
|
+
|
146
|
+
def clear(self) -> None:
|
147
|
+
"""Clear the model."""
|
148
|
+
self._rows.clear()
|
149
|
+
return
|
150
|
+
|
151
|
+
def append(self, node: IndexNode) -> None:
|
152
|
+
"""Append a node to the model."""
|
153
|
+
handle = node.handle
|
154
|
+
for key, head in node.items():
|
155
|
+
if key != "T0000":
|
156
|
+
self._rows.append(self._generateEntry(handle, key, head))
|
157
|
+
return
|
158
|
+
|
159
|
+
def refresh(self, node: IndexNode) -> bool:
|
160
|
+
"""Refresh an index node."""
|
161
|
+
handle = node.handle
|
162
|
+
current = []
|
163
|
+
for i, row in enumerate(self._rows):
|
164
|
+
if row.get(R_HANDLE) == handle:
|
165
|
+
current.append(i)
|
166
|
+
|
167
|
+
if current == []:
|
168
|
+
logger.warning("No novel model entries for '%s'", handle)
|
169
|
+
return False
|
170
|
+
|
171
|
+
cols = self._columns - 1
|
172
|
+
first = current[0]
|
173
|
+
last = current[-1]
|
174
|
+
|
175
|
+
remains = []
|
176
|
+
for key, head in node.items():
|
177
|
+
if key != "T0000":
|
178
|
+
if current:
|
179
|
+
j = current.pop(0)
|
180
|
+
self._rows[j] = self._generateEntry(handle, key, head)
|
181
|
+
else:
|
182
|
+
remains.append((key, head))
|
183
|
+
|
184
|
+
self.dataChanged.emit(self.createIndex(first, 0), self.createIndex(last, cols))
|
185
|
+
|
186
|
+
if remains:
|
187
|
+
# Inserting is safe for out of bounds indices
|
188
|
+
self.beginInsertRows(QModelIndex(), last, last + len(remains) - 1)
|
189
|
+
for k, (key, head) in enumerate(remains, last + 1):
|
190
|
+
self._rows.insert(k, self._generateEntry(handle, key, head))
|
191
|
+
self.endInsertRows()
|
192
|
+
elif current:
|
193
|
+
# Deleting ranges are safe for out of bounds indices
|
194
|
+
self.beginRemoveRows(QModelIndex(), current[0], current[-1])
|
195
|
+
del self._rows[current[0]:current[-1] + 1]
|
196
|
+
self.endRemoveRows()
|
197
|
+
|
198
|
+
return True
|
199
|
+
|
200
|
+
##
|
201
|
+
# Internal Functions
|
202
|
+
##
|
203
|
+
|
204
|
+
def _generateEntry(self, handle: str, key: str, head: IndexHeading) -> dict[int, T_NodeData]:
|
205
|
+
"""Generate a cache entry."""
|
206
|
+
iLevel = nwStyles.H_LEVEL.get(head.level, 0)
|
207
|
+
data = {}
|
208
|
+
data[C_FACTOR*0 | R_TIP] = head.title
|
209
|
+
data[C_FACTOR*0 | R_TEXT] = head.title
|
210
|
+
data[C_FACTOR*0 | R_ICON] = SHARED.theme.getHeaderDecoration(iLevel)
|
211
|
+
data[C_FACTOR*1 | R_TEXT] = f"{head.mainCount:n}"
|
212
|
+
data[C_FACTOR*1 | R_ALIGN] = QtAlignRight
|
213
|
+
if self._columns == 3:
|
214
|
+
data[C_FACTOR*2 | R_ICON] = self._more
|
215
|
+
else:
|
216
|
+
if self._extraKey and (refs := head.getReferencesByKeyword(self._extraKey)):
|
217
|
+
text = ", ".join(refs)
|
218
|
+
data[C_FACTOR*2 | R_TEXT] = text
|
219
|
+
data[C_FACTOR*2 | R_TIP] = f"<b>{self._extraLabel}:</b> {text}"
|
220
|
+
data[C_FACTOR*3 | R_ICON] = self._more
|
221
|
+
data[R_HANDLE] = handle
|
222
|
+
data[R_KEY] = key
|
223
|
+
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
|
@@ -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:
|
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__)
|
@@ -69,10 +69,10 @@ class NWProjectData:
|
|
69
69
|
self._initCounts = [0, 0]
|
70
70
|
self._currCounts = [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] = {
|
novelwriter/core/projectxml.py
CHANGED
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__)
|
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
|
@@ -388,7 +427,7 @@ class NWTree:
|
|
388
427
|
|
389
428
|
def checkType(self, tHandle: str, itemType: nwItemType) -> bool:
|
390
429
|
"""Check if item exists and is of the specified item type."""
|
391
|
-
if tItem := self
|
430
|
+
if tItem := self[tHandle]:
|
392
431
|
return tItem.itemType == itemType
|
393
432
|
return False
|
394
433
|
|
@@ -406,8 +445,7 @@ class NWTree:
|
|
406
445
|
node = parent
|
407
446
|
else:
|
408
447
|
return path
|
409
|
-
|
410
|
-
logger.error("Max project tree depth reached")
|
448
|
+
logger.error("Max project tree depth reached")
|
411
449
|
return path
|
412
450
|
|
413
451
|
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
|
)
|