novelWriter 2.6.2__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/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_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 +75 -56
- 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 +15 -18
- novelwriter/gui/mainmenu.py +147 -146
- novelwriter/gui/noveltree.py +239 -405
- novelwriter/gui/outline.py +137 -76
- 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 +113 -126
- 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.2.dist-info → novelwriter-2.7b1.dist-info}/METADATA +6 -6
- novelwriter-2.7b1.dist-info/RECORD +159 -0
- {novelWriter-2.6.2.dist-info → novelwriter-2.7b1.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.7b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.6.2.dist-info → novelwriter-2.7b1.dist-info/licenses}/LICENSE.md +0 -0
- {novelWriter-2.6.2.dist-info → novelwriter-2.7b1.dist-info}/top_level.txt +0 -0
novelwriter/guimain.py
CHANGED
@@ -30,11 +30,11 @@ from datetime import datetime
|
|
30
30
|
from pathlib import Path
|
31
31
|
from time import time
|
32
32
|
|
33
|
-
from
|
34
|
-
from
|
35
|
-
from
|
33
|
+
from PyQt6.QtCore import Qt, QTimer, pyqtSlot
|
34
|
+
from PyQt6.QtGui import QCloseEvent, QCursor, QIcon, QShortcut
|
35
|
+
from PyQt6.QtWidgets import (
|
36
36
|
QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox,
|
37
|
-
|
37
|
+
QSplitter, QStackedWidget, QVBoxLayout, QWidget
|
38
38
|
)
|
39
39
|
|
40
40
|
from novelwriter import CONFIG, SHARED, __hexversion__, __version__
|
@@ -56,7 +56,6 @@ from novelwriter.gui.projtree import GuiProjectView
|
|
56
56
|
from novelwriter.gui.search import GuiProjectSearch
|
57
57
|
from novelwriter.gui.sidebar import GuiSideBar
|
58
58
|
from novelwriter.gui.statusbar import GuiMainStatus
|
59
|
-
from novelwriter.gui.theme import GuiTheme
|
60
59
|
from novelwriter.tools.dictionaries import GuiDictionaries
|
61
60
|
from novelwriter.tools.manuscript import GuiManuscript
|
62
61
|
from novelwriter.tools.noveldetails import GuiNovelDetails
|
@@ -92,8 +91,8 @@ class GuiMain(QMainWindow):
|
|
92
91
|
logger.info("OS: %s", CONFIG.osType)
|
93
92
|
logger.info("Kernel: %s", CONFIG.kernelVer)
|
94
93
|
logger.info("Host: %s", CONFIG.hostName)
|
95
|
-
logger.info("
|
96
|
-
logger.info("
|
94
|
+
logger.info("Qt: %s (0x%06x)", CONFIG.verQtString, CONFIG.verQtValue)
|
95
|
+
logger.info("PyQt: %s (0x%06x)", CONFIG.verPyQtString, CONFIG.verPyQtValue)
|
97
96
|
logger.info("Python: %s (0x%08x)", CONFIG.verPyString, sys.hexversion)
|
98
97
|
logger.info("GUI Language: %s", CONFIG.guiLocale)
|
99
98
|
|
@@ -101,7 +100,7 @@ class GuiMain(QMainWindow):
|
|
101
100
|
# ============
|
102
101
|
|
103
102
|
# Initialise UserData Instance
|
104
|
-
SHARED.initSharedData(self
|
103
|
+
SHARED.initSharedData(self)
|
105
104
|
|
106
105
|
# Prepare Main Window
|
107
106
|
self.resize(*CONFIG.mainWinSize)
|
@@ -115,10 +114,6 @@ class GuiMain(QMainWindow):
|
|
115
114
|
# Build the GUI
|
116
115
|
# =============
|
117
116
|
|
118
|
-
# Sizes
|
119
|
-
mPx = CONFIG.pxInt(4)
|
120
|
-
hWd = CONFIG.pxInt(4)
|
121
|
-
|
122
117
|
# Main GUI Elements
|
123
118
|
self.mainStatus = GuiMainStatus(self)
|
124
119
|
self.projView = GuiProjectView(self)
|
@@ -143,7 +138,7 @@ class GuiMain(QMainWindow):
|
|
143
138
|
self.treePane = QWidget(self)
|
144
139
|
self.treeBox = QVBoxLayout()
|
145
140
|
self.treeBox.setContentsMargins(0, 0, 0, 0)
|
146
|
-
self.treeBox.setSpacing(
|
141
|
+
self.treeBox.setSpacing(4)
|
147
142
|
self.treeBox.addWidget(self.projStack)
|
148
143
|
self.treeBox.addWidget(self.itemDetails)
|
149
144
|
self.treePane.setLayout(self.treeBox)
|
@@ -152,7 +147,7 @@ class GuiMain(QMainWindow):
|
|
152
147
|
self.splitView = QSplitter(Qt.Orientation.Vertical, self)
|
153
148
|
self.splitView.addWidget(self.docViewer)
|
154
149
|
self.splitView.addWidget(self.docViewerPanel)
|
155
|
-
self.splitView.setHandleWidth(
|
150
|
+
self.splitView.setHandleWidth(4)
|
156
151
|
self.splitView.setOpaqueResize(False)
|
157
152
|
self.splitView.setSizes(CONFIG.viewPanePos)
|
158
153
|
self.splitView.setCollapsible(0, False)
|
@@ -163,7 +158,7 @@ class GuiMain(QMainWindow):
|
|
163
158
|
self.splitDocs.addWidget(self.docEditor)
|
164
159
|
self.splitDocs.addWidget(self.splitView)
|
165
160
|
self.splitDocs.setOpaqueResize(False)
|
166
|
-
self.splitDocs.setHandleWidth(
|
161
|
+
self.splitDocs.setHandleWidth(4)
|
167
162
|
self.splitDocs.setCollapsible(0, False)
|
168
163
|
self.splitDocs.setCollapsible(1, False)
|
169
164
|
|
@@ -173,7 +168,7 @@ class GuiMain(QMainWindow):
|
|
173
168
|
self.splitMain.addWidget(self.treePane)
|
174
169
|
self.splitMain.addWidget(self.splitDocs)
|
175
170
|
self.splitMain.setOpaqueResize(False)
|
176
|
-
self.splitMain.setHandleWidth(
|
171
|
+
self.splitMain.setHandleWidth(4)
|
177
172
|
self.splitMain.setSizes(CONFIG.mainPanePos)
|
178
173
|
self.splitMain.setCollapsible(0, False)
|
179
174
|
self.splitMain.setCollapsible(0, False)
|
@@ -252,8 +247,6 @@ class GuiMain(QMainWindow):
|
|
252
247
|
self.docEditor.itemHandleChanged.connect(self.novelView.setActiveHandle)
|
253
248
|
self.docEditor.itemHandleChanged.connect(self.projView.setActiveHandle)
|
254
249
|
self.docEditor.loadDocumentTagRequest.connect(self._followTag)
|
255
|
-
self.docEditor.novelItemMetaChanged.connect(self.novelView.updateNovelItemMeta)
|
256
|
-
self.docEditor.novelStructureChanged.connect(self.novelView.refreshTree)
|
257
250
|
self.docEditor.openDocumentRequest.connect(self._openDocument)
|
258
251
|
self.docEditor.requestNewNoteCreation.connect(SHARED.createNewNote)
|
259
252
|
self.docEditor.requestNextDocument.connect(self.openNextDocument)
|
@@ -377,7 +370,7 @@ class GuiMain(QMainWindow):
|
|
377
370
|
return True
|
378
371
|
|
379
372
|
if not isYes:
|
380
|
-
msgYes = SHARED.question("
|
373
|
+
msgYes = SHARED.question("{0}<br>{1}".format(
|
381
374
|
self.tr("Close the current project?"),
|
382
375
|
self.tr("Changes are saved automatically.")
|
383
376
|
))
|
@@ -537,7 +530,7 @@ class GuiMain(QMainWindow):
|
|
537
530
|
) -> bool:
|
538
531
|
"""Open a specific document, optionally at a given line."""
|
539
532
|
if not (SHARED.hasProject and tHandle):
|
540
|
-
logger.error("Nothing to open
|
533
|
+
logger.error("Nothing to open")
|
541
534
|
return False
|
542
535
|
|
543
536
|
if sTitle and tLine is None:
|
@@ -740,7 +733,6 @@ class GuiMain(QMainWindow):
|
|
740
733
|
|
741
734
|
SHARED.project.index.rebuild()
|
742
735
|
SHARED.project.tree.refreshAllItems()
|
743
|
-
self.novelView.refreshTree()
|
744
736
|
|
745
737
|
tEnd = time()
|
746
738
|
self.mainStatus.setStatusMessage(
|
@@ -852,7 +844,7 @@ class GuiMain(QMainWindow):
|
|
852
844
|
|
853
845
|
def closeMain(self) -> bool:
|
854
846
|
"""Save everything, and close novelWriter."""
|
855
|
-
if SHARED.hasProject and CONFIG.askBeforeExit and not SHARED.question("
|
847
|
+
if SHARED.hasProject and CONFIG.askBeforeExit and not SHARED.question("{0}<br>{1}".format(
|
856
848
|
self.tr("Do you want to exit novelWriter?"),
|
857
849
|
self.tr("Changes are saved automatically.")
|
858
850
|
)):
|
@@ -861,10 +853,10 @@ class GuiMain(QMainWindow):
|
|
861
853
|
logger.info("Exiting novelWriter")
|
862
854
|
|
863
855
|
if not SHARED.focusMode:
|
864
|
-
CONFIG.
|
865
|
-
CONFIG.
|
856
|
+
CONFIG.mainPanePos = self.splitMain.sizes()
|
857
|
+
CONFIG.outlinePanePos = self.outlineView.splitSizes()
|
866
858
|
if self.docViewerPanel.isVisible():
|
867
|
-
CONFIG.
|
859
|
+
CONFIG.viewPanePos = self.splitView.sizes()
|
868
860
|
|
869
861
|
CONFIG.showViewerPanel = self.docViewerPanel.isVisible()
|
870
862
|
wFull = Qt.WindowState.WindowFullScreen
|
@@ -1017,7 +1009,7 @@ class GuiMain(QMainWindow):
|
|
1017
1009
|
fN = self.novelView.treeHasFocus()
|
1018
1010
|
|
1019
1011
|
self._changeView(nwView.EDITOR)
|
1020
|
-
if (vM and (vP and fP or vN and not fN)) or (not vM and vN):
|
1012
|
+
if (vM and ((vP and fP) or (vN and not fN))) or (not vM and vN):
|
1021
1013
|
self._changeView(nwView.NOVEL)
|
1022
1014
|
self.novelView.setTreeFocus()
|
1023
1015
|
else:
|
@@ -1051,9 +1043,8 @@ class GuiMain(QMainWindow):
|
|
1051
1043
|
SHARED.project.tree.refreshAllItems()
|
1052
1044
|
|
1053
1045
|
if theme:
|
1054
|
-
# We are doing this manually instead of connecting to
|
1055
|
-
# paletteChanged since the processing order matters
|
1056
1046
|
SHARED.theme.loadTheme()
|
1047
|
+
self.setPalette(QApplication.palette())
|
1057
1048
|
self.docEditor.updateTheme()
|
1058
1049
|
self.docViewer.updateTheme()
|
1059
1050
|
self.docViewerPanel.updateTheme()
|
@@ -1064,10 +1055,11 @@ class GuiMain(QMainWindow):
|
|
1064
1055
|
self.outlineView.updateTheme()
|
1065
1056
|
self.itemDetails.updateTheme()
|
1066
1057
|
self.mainStatus.updateTheme()
|
1058
|
+
SHARED.project.tree.refreshAllItems()
|
1067
1059
|
|
1068
1060
|
if syntax:
|
1069
1061
|
SHARED.theme.loadSyntax()
|
1070
|
-
self.docEditor.
|
1062
|
+
self.docEditor.updateSyntaxColors()
|
1071
1063
|
|
1072
1064
|
self.docEditor.initEditor()
|
1073
1065
|
self.docViewer.initViewer()
|
@@ -1179,6 +1171,12 @@ class GuiMain(QMainWindow):
|
|
1179
1171
|
)
|
1180
1172
|
elif view == nwView.OUTLINE:
|
1181
1173
|
self.mainStack.setCurrentWidget(self.outlineView)
|
1174
|
+
|
1175
|
+
# Set active status
|
1176
|
+
isMain = self.mainStack.currentWidget() == self.splitMain
|
1177
|
+
isNovel = self.projStack.currentWidget() == self.novelView
|
1178
|
+
self.novelView.setActive(isMain and isNovel)
|
1179
|
+
|
1182
1180
|
return
|
1183
1181
|
|
1184
1182
|
@pyqtSlot(nwDocAction)
|
novelwriter/shared.py
CHANGED
@@ -31,16 +31,16 @@ from pathlib import Path
|
|
31
31
|
from time import time
|
32
32
|
from typing import TYPE_CHECKING, TypeVar
|
33
33
|
|
34
|
-
from
|
35
|
-
from
|
36
|
-
from
|
34
|
+
from PyQt6.QtCore import QObject, QRunnable, QThreadPool, QTimer, QUrl, pyqtSignal, pyqtSlot
|
35
|
+
from PyQt6.QtGui import QDesktopServices, QFont
|
36
|
+
from PyQt6.QtWidgets import QFileDialog, QFontDialog, QMessageBox, QWidget
|
37
37
|
|
38
38
|
from novelwriter.common import formatFileFilter
|
39
39
|
from novelwriter.constants import nwFiles
|
40
40
|
from novelwriter.core.spellcheck import NWSpellEnchant
|
41
41
|
from novelwriter.enum import nwChange, nwItemClass
|
42
42
|
|
43
|
-
if TYPE_CHECKING:
|
43
|
+
if TYPE_CHECKING:
|
44
44
|
from novelwriter.core.project import NWProject
|
45
45
|
from novelwriter.core.status import T_StatusKind
|
46
46
|
from novelwriter.gui.theme import GuiTheme
|
@@ -54,8 +54,8 @@ NWWidget = TypeVar("NWWidget", bound=QWidget)
|
|
54
54
|
class SharedData(QObject):
|
55
55
|
|
56
56
|
__slots__ = (
|
57
|
-
"_gui", "
|
58
|
-
"
|
57
|
+
"_gui", "_idleRefTime", "_idleTime", "_lastAlert", "_lockedBy",
|
58
|
+
"_project", "_spelling", "_theme",
|
59
59
|
)
|
60
60
|
|
61
61
|
focusModeChanged = pyqtSignal(bool)
|
@@ -63,10 +63,11 @@ class SharedData(QObject):
|
|
63
63
|
indexChangedTags = pyqtSignal(list, list)
|
64
64
|
indexCleared = pyqtSignal()
|
65
65
|
mainClockTick = pyqtSignal()
|
66
|
+
novelStructureChanged = pyqtSignal(str)
|
66
67
|
projectItemChanged = pyqtSignal(str, Enum)
|
67
|
-
rootFolderChanged = pyqtSignal(str, Enum)
|
68
68
|
projectStatusChanged = pyqtSignal(bool)
|
69
69
|
projectStatusMessage = pyqtSignal(str)
|
70
|
+
rootFolderChanged = pyqtSignal(str, Enum)
|
70
71
|
spellLanguageChanged = pyqtSignal(str, str)
|
71
72
|
statusLabelsChanged = pyqtSignal(str)
|
72
73
|
|
@@ -100,28 +101,28 @@ class SharedData(QObject):
|
|
100
101
|
def mainGui(self) -> GuiMain:
|
101
102
|
"""Return the Main GUI instance."""
|
102
103
|
if self._gui is None:
|
103
|
-
raise
|
104
|
+
raise RuntimeError("SharedData class not fully initialised")
|
104
105
|
return self._gui
|
105
106
|
|
106
107
|
@property
|
107
108
|
def theme(self) -> GuiTheme:
|
108
109
|
"""Return the GUI Theme instance."""
|
109
110
|
if self._theme is None:
|
110
|
-
raise
|
111
|
+
raise RuntimeError("SharedData class not fully initialised")
|
111
112
|
return self._theme
|
112
113
|
|
113
114
|
@property
|
114
115
|
def project(self) -> NWProject:
|
115
116
|
"""Return the active NWProject instance."""
|
116
117
|
if self._project is None:
|
117
|
-
raise
|
118
|
+
raise RuntimeError("SharedData class not fully initialised")
|
118
119
|
return self._project
|
119
120
|
|
120
121
|
@property
|
121
122
|
def spelling(self) -> NWSpellEnchant:
|
122
123
|
"""Return the active NWProject instance."""
|
123
124
|
if self._spelling is None:
|
124
|
-
raise
|
125
|
+
raise RuntimeError("SharedData class not fully initialised")
|
125
126
|
return self._spelling
|
126
127
|
|
127
128
|
@property
|
@@ -164,17 +165,24 @@ class SharedData(QObject):
|
|
164
165
|
# Methods
|
165
166
|
##
|
166
167
|
|
167
|
-
def
|
168
|
+
def initTheme(self, theme: GuiTheme) -> None:
|
169
|
+
"""Initialise the GUI theme. This must be called before the GUI
|
170
|
+
is created.
|
171
|
+
"""
|
172
|
+
self._theme = theme
|
173
|
+
return
|
174
|
+
|
175
|
+
def initSharedData(self, gui: GuiMain) -> None:
|
168
176
|
"""Initialise the SharedData instance. This must be called as
|
169
177
|
soon as the Main GUI is created to ensure the SHARED singleton
|
170
178
|
has the properties needed for operation.
|
171
179
|
"""
|
172
180
|
self._clock.start()
|
173
181
|
self._gui = gui
|
174
|
-
self._theme = theme
|
175
182
|
self._resetProject()
|
176
183
|
logger.debug("Ready: SharedData")
|
177
|
-
|
184
|
+
if pool := QThreadPool.globalInstance():
|
185
|
+
logger.debug("Thread Pool Max Count: %d", pool.maxThreadCount())
|
178
186
|
return
|
179
187
|
|
180
188
|
def closeDocument(self, tHandle: str | None = None) -> None:
|
@@ -266,7 +274,8 @@ class SharedData(QObject):
|
|
266
274
|
|
267
275
|
def runInThreadPool(self, runnable: QRunnable, priority: int = 0) -> None:
|
268
276
|
"""Queue a runnable in the application thread pool."""
|
269
|
-
QThreadPool.globalInstance()
|
277
|
+
if pool := QThreadPool.globalInstance():
|
278
|
+
pool.start(runnable, priority=priority)
|
270
279
|
return
|
271
280
|
|
272
281
|
def getProjectPath(
|
@@ -278,13 +287,13 @@ class SharedData(QObject):
|
|
278
287
|
label = (self.tr("novelWriter Project File or Zip File")
|
279
288
|
if allowZip else self.tr("novelWriter Project File"))
|
280
289
|
ext = f"{nwFiles.PROJ_FILE} *.zip" if allowZip else nwFiles.PROJ_FILE
|
281
|
-
|
290
|
+
fFilter = formatFileFilter([(label, ext), "*"])
|
282
291
|
selected, _ = QFileDialog.getOpenFileName(
|
283
|
-
parent, self.tr("Open Project"), str(path or ""), filter=
|
292
|
+
parent, self.tr("Open Project"), str(path or ""), filter=fFilter
|
284
293
|
)
|
285
294
|
return Path(selected) if selected else None
|
286
295
|
|
287
|
-
def getFont(self, current: QFont, native: bool) -> tuple[QFont, bool]:
|
296
|
+
def getFont(self, current: QFont, native: bool) -> tuple[QFont, bool | None]:
|
288
297
|
"""Open the font dialog and select a font."""
|
289
298
|
kwargs = {}
|
290
299
|
if not native:
|
@@ -471,7 +480,7 @@ class _GuiAlert(QMessageBox):
|
|
471
480
|
def setException(self, exception: Exception) -> None:
|
472
481
|
"""Add exception details."""
|
473
482
|
info = self.informativeText()
|
474
|
-
text = f"<b>{type(exception).__name__}</b>: {
|
483
|
+
text = f"<b>{type(exception).__name__}</b>: {exception!s}"
|
475
484
|
self.setInformativeText(f"{info}<br>{text}" if info else text)
|
476
485
|
return
|
477
486
|
|
@@ -485,15 +494,15 @@ class _GuiAlert(QMessageBox):
|
|
485
494
|
self.setStandardButtons(QMessageBox.StandardButton.Ok)
|
486
495
|
pSz = 2*self._theme.baseIconHeight
|
487
496
|
if level == self.INFO:
|
488
|
-
self.setIconPixmap(self._theme.getPixmap("alert_info", (pSz, pSz)))
|
497
|
+
self.setIconPixmap(self._theme.getPixmap("alert_info", (pSz, pSz), "blue"))
|
489
498
|
self.setWindowTitle(self.tr("Information"))
|
490
499
|
elif level == self.WARN:
|
491
|
-
self.setIconPixmap(self._theme.getPixmap("alert_warn", (pSz, pSz)))
|
500
|
+
self.setIconPixmap(self._theme.getPixmap("alert_warn", (pSz, pSz), "orange"))
|
492
501
|
self.setWindowTitle(self.tr("Warning"))
|
493
502
|
elif level == self.ERROR:
|
494
|
-
self.setIconPixmap(self._theme.getPixmap("alert_error", (pSz, pSz)))
|
503
|
+
self.setIconPixmap(self._theme.getPixmap("alert_error", (pSz, pSz), "red"))
|
495
504
|
self.setWindowTitle(self.tr("Error"))
|
496
505
|
elif level == self.ASK:
|
497
|
-
self.setIconPixmap(self._theme.getPixmap("alert_question", (pSz, pSz)))
|
506
|
+
self.setIconPixmap(self._theme.getPixmap("alert_question", (pSz, pSz), "blue"))
|
498
507
|
self.setWindowTitle(self.tr("Question"))
|
499
508
|
return
|
@@ -0,0 +1,70 @@
|
|
1
|
+
"""
|
2
|
+
novelWriter – Text Comments
|
3
|
+
===========================
|
4
|
+
|
5
|
+
File History:
|
6
|
+
Created: 2023-11-23 [2.2b1]
|
7
|
+
Moved: 2025-02-09 [2.7b1]
|
8
|
+
|
9
|
+
This file is a part of novelWriter
|
10
|
+
Copyright (C) 2025 Veronica Berglyd Olsen and novelWriter contributors
|
11
|
+
|
12
|
+
This program is free software: you can redistribute it and/or modify
|
13
|
+
it under the terms of the GNU General Public License as published by
|
14
|
+
the Free Software Foundation, either version 3 of the License, or
|
15
|
+
(at your option) any later version.
|
16
|
+
|
17
|
+
This program is distributed in the hope that it will be useful, but
|
18
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
20
|
+
General Public License for more details.
|
21
|
+
|
22
|
+
You should have received a copy of the GNU General Public License
|
23
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
24
|
+
"""
|
25
|
+
from __future__ import annotations
|
26
|
+
|
27
|
+
from novelwriter.enum import nwComment
|
28
|
+
|
29
|
+
MODIFIERS = {
|
30
|
+
"synopsis": nwComment.SYNOPSIS,
|
31
|
+
"short": nwComment.SHORT,
|
32
|
+
"note": nwComment.NOTE,
|
33
|
+
"footnote": nwComment.FOOTNOTE,
|
34
|
+
"story": nwComment.STORY,
|
35
|
+
}
|
36
|
+
KEY_REQ = {
|
37
|
+
"synopsis": 0, # Key not allowed
|
38
|
+
"short": 0, # Key not allowed
|
39
|
+
"note": 1, # Key optional
|
40
|
+
"footnote": 2, # Key required
|
41
|
+
"story": 2, # Key required
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
def _checkModKey(modifier: str, key: str) -> bool:
|
46
|
+
"""Check if a modifier and key set are ok."""
|
47
|
+
if modifier in MODIFIERS:
|
48
|
+
if key == "":
|
49
|
+
return KEY_REQ[modifier] < 2
|
50
|
+
elif key.replace("_", "").isalnum():
|
51
|
+
return KEY_REQ[modifier] > 0
|
52
|
+
return False
|
53
|
+
|
54
|
+
|
55
|
+
def processComment(text: str) -> tuple[nwComment, str, str, int, int]:
|
56
|
+
"""Extract comment style, key and text. Should only be called on
|
57
|
+
text starting with a %.
|
58
|
+
"""
|
59
|
+
if text[:2] == "%~":
|
60
|
+
return nwComment.IGNORE, "", text[2:].lstrip(), 0, 0
|
61
|
+
|
62
|
+
check = text[1:].strip()
|
63
|
+
start, _, content = check.partition(":")
|
64
|
+
modifier, _, key = start.rstrip().partition(".")
|
65
|
+
if content and (clean := modifier.lower()) and _checkModKey(clean, key):
|
66
|
+
col = text.find(":") + 1
|
67
|
+
dot = text.find(".", 0, col) + 1
|
68
|
+
return MODIFIERS[clean], key, content.lstrip(), dot, col
|
69
|
+
|
70
|
+
return nwComment.PLAIN, "", check, 0, 0
|
novelwriter/text/patterns.py
CHANGED
@@ -93,7 +93,7 @@ class RegExPatterns:
|
|
93
93
|
if CONFIG.dialogStyle in (1, 3):
|
94
94
|
qO = CONFIG.fmtSQuoteOpen.strip()[:1]
|
95
95
|
qC = CONFIG.fmtSQuoteClose.strip()[:1]
|
96
|
-
if qO == qC:
|
96
|
+
if qO == qC or qC in self.AMBIGUOUS:
|
97
97
|
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
|
98
98
|
else:
|
99
99
|
rx.append(f"(?:{qO}[^{qO}]+{qC})")
|
@@ -102,7 +102,7 @@ class RegExPatterns:
|
|
102
102
|
if CONFIG.dialogStyle in (2, 3):
|
103
103
|
qO = CONFIG.fmtDQuoteOpen.strip()[:1]
|
104
104
|
qC = CONFIG.fmtDQuoteClose.strip()[:1]
|
105
|
-
if qO == qC:
|
105
|
+
if qO == qC or qC in self.AMBIGUOUS:
|
106
106
|
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
|
107
107
|
else:
|
108
108
|
rx.append(f"(?:{qO}[^{qO}]+{qC})")
|
@@ -128,8 +128,8 @@ REGEX_PATTERNS = RegExPatterns()
|
|
128
128
|
class DialogParser:
|
129
129
|
|
130
130
|
__slots__ = (
|
131
|
-
"
|
132
|
-
"_narrator", "
|
131
|
+
"_alternate", "_breakD", "_breakQ", "_dialog", "_enabled", "_mode",
|
132
|
+
"_narrator", "_quotes",
|
133
133
|
)
|
134
134
|
|
135
135
|
def __init__(self) -> None:
|
@@ -28,18 +28,18 @@ import logging
|
|
28
28
|
from pathlib import Path
|
29
29
|
from zipfile import ZipFile
|
30
30
|
|
31
|
-
from
|
32
|
-
from
|
33
|
-
from
|
31
|
+
from PyQt6.QtCore import pyqtSlot
|
32
|
+
from PyQt6.QtGui import QCloseEvent, QTextCursor
|
33
|
+
from PyQt6.QtWidgets import (
|
34
34
|
QApplication, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout, QLabel,
|
35
35
|
QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget
|
36
36
|
)
|
37
37
|
|
38
38
|
from novelwriter import CONFIG, SHARED
|
39
|
-
from novelwriter.common import
|
39
|
+
from novelwriter.common import formatFileFilter, formatInt, getFileSize, openExternalPath
|
40
40
|
from novelwriter.error import formatException
|
41
41
|
from novelwriter.extensions.modified import NIconToolButton, NNonBlockingDialog
|
42
|
-
from novelwriter.types import QtDialogClose
|
42
|
+
from novelwriter.types import QtDialogClose, QtHexArgb
|
43
43
|
|
44
44
|
logger = logging.getLogger(__name__)
|
45
45
|
|
@@ -57,12 +57,9 @@ class GuiDictionaries(NNonBlockingDialog):
|
|
57
57
|
self._currDicts = set()
|
58
58
|
|
59
59
|
iSz = SHARED.theme.baseIconSize
|
60
|
-
iPx = CONFIG.pxInt(4)
|
61
|
-
mPx = CONFIG.pxInt(8)
|
62
|
-
sPx = CONFIG.pxInt(16)
|
63
60
|
|
64
|
-
self.setMinimumWidth(
|
65
|
-
self.setMinimumHeight(
|
61
|
+
self.setMinimumWidth(500)
|
62
|
+
self.setMinimumHeight(300)
|
66
63
|
|
67
64
|
# Hunspell Dictionaries
|
68
65
|
loUrl = "https://extensions.libreoffice.org"
|
@@ -78,13 +75,13 @@ class GuiDictionaries(NNonBlockingDialog):
|
|
78
75
|
self.huBrowse = NIconToolButton(self, iSz, "browse")
|
79
76
|
self.huBrowse.clicked.connect(self._doBrowseHunspell)
|
80
77
|
self.huImport = QPushButton(self.tr("Add Dictionary"), self)
|
81
|
-
self.huImport.setIcon(SHARED.theme.getIcon("add"))
|
78
|
+
self.huImport.setIcon(SHARED.theme.getIcon("add", "green"))
|
82
79
|
self.huImport.clicked.connect(self._doImportHunspell)
|
83
80
|
|
84
81
|
self.huPathBox = QHBoxLayout()
|
85
82
|
self.huPathBox.addWidget(self.huInput)
|
86
83
|
self.huPathBox.addWidget(self.huBrowse)
|
87
|
-
self.huPathBox.setSpacing(
|
84
|
+
self.huPathBox.setSpacing(4)
|
88
85
|
self.huAddBox = QHBoxLayout()
|
89
86
|
self.huAddBox.addStretch(1)
|
90
87
|
self.huAddBox.addWidget(self.huImport)
|
@@ -99,12 +96,11 @@ class GuiDictionaries(NNonBlockingDialog):
|
|
99
96
|
self.inBox = QHBoxLayout()
|
100
97
|
self.inBox.addWidget(self.inPath)
|
101
98
|
self.inBox.addWidget(self.inBrowse)
|
102
|
-
self.inBox.setSpacing(
|
99
|
+
self.inBox.setSpacing(4)
|
103
100
|
|
104
101
|
# Info Box
|
105
102
|
self.infoBox = QPlainTextEdit(self)
|
106
103
|
self.infoBox.setReadOnly(True)
|
107
|
-
self.infoBox.setFixedHeight(4*SHARED.theme.fontPixelSize)
|
108
104
|
self.infoBox.setFrameStyle(QFrame.Shape.NoFrame)
|
109
105
|
|
110
106
|
# Buttons
|
@@ -112,21 +108,16 @@ class GuiDictionaries(NNonBlockingDialog):
|
|
112
108
|
self.buttonBox.rejected.connect(self.reject)
|
113
109
|
|
114
110
|
# Assemble
|
115
|
-
self.innerBox = QVBoxLayout()
|
116
|
-
self.innerBox.addWidget(self.huInfo)
|
117
|
-
self.innerBox.addLayout(self.huPathBox)
|
118
|
-
self.innerBox.addLayout(self.huAddBox)
|
119
|
-
self.innerBox.addSpacing(mPx)
|
120
|
-
self.innerBox.addWidget(self.inInfo)
|
121
|
-
self.innerBox.addLayout(self.inBox)
|
122
|
-
self.innerBox.addWidget(self.infoBox)
|
123
|
-
self.innerBox.setSpacing(iPx)
|
124
|
-
|
125
111
|
self.outerBox = QVBoxLayout()
|
126
|
-
self.outerBox.
|
127
|
-
self.outerBox.
|
112
|
+
self.outerBox.addWidget(self.huInfo, 0)
|
113
|
+
self.outerBox.addLayout(self.huPathBox, 0)
|
114
|
+
self.outerBox.addLayout(self.huAddBox, 0)
|
115
|
+
self.outerBox.addSpacing(8)
|
116
|
+
self.outerBox.addWidget(self.inInfo, 0)
|
117
|
+
self.outerBox.addLayout(self.inBox, 0)
|
118
|
+
self.outerBox.addWidget(self.infoBox, 1)
|
119
|
+
self.outerBox.addSpacing(8)
|
128
120
|
self.outerBox.addWidget(self.buttonBox, 0)
|
129
|
-
self.outerBox.setSpacing(sPx)
|
130
121
|
|
131
122
|
self.setLayout(self.outerBox)
|
132
123
|
|
@@ -251,8 +242,8 @@ class GuiDictionaries(NNonBlockingDialog):
|
|
251
242
|
cursor.movePosition(QTextCursor.MoveOperation.End)
|
252
243
|
if cursor.position() > 0:
|
253
244
|
cursor.insertText("\n")
|
254
|
-
textCol =
|
255
|
-
cursor.insertHtml(f"<font style='color: {textCol}'>{text}</font>")
|
245
|
+
textCol = SHARED.theme.errorText if err else self.palette().text().color()
|
246
|
+
cursor.insertHtml(f"<font style='color: {textCol.name(QtHexArgb)}'>{text}</font>")
|
256
247
|
cursor.movePosition(QTextCursor.MoveOperation.End)
|
257
248
|
cursor.deleteChar()
|
258
249
|
self.infoBox.setTextCursor(cursor)
|
novelwriter/tools/lipsum.py
CHANGED
@@ -26,8 +26,8 @@ from __future__ import annotations
|
|
26
26
|
import logging
|
27
27
|
import random
|
28
28
|
|
29
|
-
from
|
30
|
-
from
|
29
|
+
from PyQt6.QtCore import pyqtSlot
|
30
|
+
from PyQt6.QtWidgets import (
|
31
31
|
QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel, QSpinBox, QVBoxLayout,
|
32
32
|
QWidget
|
33
33
|
)
|
@@ -52,18 +52,15 @@ class GuiLipsum(NDialog):
|
|
52
52
|
|
53
53
|
self._lipsumText = ""
|
54
54
|
|
55
|
-
vSp = CONFIG.pxInt(4)
|
56
|
-
nPx = CONFIG.pxInt(64)
|
57
|
-
|
58
55
|
self.innerBox = QHBoxLayout()
|
59
|
-
self.innerBox.setSpacing(
|
56
|
+
self.innerBox.setSpacing(16)
|
60
57
|
|
61
58
|
# Icon
|
62
59
|
self.docIcon = QLabel(self)
|
63
|
-
self.docIcon.setPixmap(SHARED.theme.getPixmap("
|
60
|
+
self.docIcon.setPixmap(SHARED.theme.getPixmap("text", (64, 64), "blue"))
|
64
61
|
|
65
62
|
self.leftBox = QVBoxLayout()
|
66
|
-
self.leftBox.setSpacing(
|
63
|
+
self.leftBox.setSpacing(4)
|
67
64
|
self.leftBox.addWidget(self.docIcon)
|
68
65
|
self.leftBox.addStretch(1)
|
69
66
|
self.innerBox.addLayout(self.leftBox)
|
@@ -87,7 +84,7 @@ class GuiLipsum(NDialog):
|
|
87
84
|
self.formBox.addWidget(self.paraCount, 1, 1, 1, 1, QtAlignRight)
|
88
85
|
self.formBox.addWidget(self.randLabel, 2, 0, 1, 1, QtAlignLeft)
|
89
86
|
self.formBox.addWidget(self.randSwitch, 2, 1, 1, 1, QtAlignRight)
|
90
|
-
self.formBox.setVerticalSpacing(
|
87
|
+
self.formBox.setVerticalSpacing(4)
|
91
88
|
self.formBox.setRowStretch(3, 1)
|
92
89
|
self.innerBox.addLayout(self.formBox)
|
93
90
|
|
@@ -96,17 +93,19 @@ class GuiLipsum(NDialog):
|
|
96
93
|
self.buttonBox.rejected.connect(self.reject)
|
97
94
|
|
98
95
|
self.btnClose = self.buttonBox.addButton(QtDialogClose)
|
99
|
-
self.btnClose
|
96
|
+
if self.btnClose:
|
97
|
+
self.btnClose.setAutoDefault(False)
|
100
98
|
|
101
99
|
self.btnInsert = self.buttonBox.addButton(self.tr("Insert"), QtRoleAction)
|
102
|
-
self.btnInsert
|
103
|
-
|
100
|
+
if self.btnInsert:
|
101
|
+
self.btnInsert.clicked.connect(self._doInsert)
|
102
|
+
self.btnInsert.setAutoDefault(False)
|
104
103
|
|
105
104
|
# Assemble
|
106
105
|
self.outerBox = QVBoxLayout()
|
107
106
|
self.outerBox.addLayout(self.innerBox)
|
108
107
|
self.outerBox.addWidget(self.buttonBox)
|
109
|
-
self.outerBox.setSpacing(
|
108
|
+
self.outerBox.setSpacing(16)
|
110
109
|
self.setLayout(self.outerBox)
|
111
110
|
|
112
111
|
logger.debug("Ready: GuiLipsum")
|
@@ -125,10 +124,10 @@ class GuiLipsum(NDialog):
|
|
125
124
|
@classmethod
|
126
125
|
def getLipsum(cls, parent: QWidget) -> str:
|
127
126
|
"""Pop the dialog and return the lipsum text."""
|
128
|
-
|
129
|
-
|
130
|
-
text =
|
131
|
-
|
127
|
+
dialog = cls(parent)
|
128
|
+
dialog.exec()
|
129
|
+
text = dialog.lipsumText
|
130
|
+
dialog.softDelete()
|
132
131
|
return text
|
133
132
|
|
134
133
|
##
|