novelWriter 2.6b1__py3-none-any.whl → 2.6rc1__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-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/METADATA +4 -4
- {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/RECORD +114 -98
- {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +50 -11
- 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 +2 -2
- novelwriter/assets/i18n/project_ru_RU.json +11 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +7 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +6 -0
- novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +5 -0
- novelwriter/assets/icons/typicons_light/icons.conf +7 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_size-height.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_size-width.svg +6 -0
- novelwriter/assets/icons/typicons_light/nw_toolbar.svg +5 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/text/credits_en.htm +1 -0
- novelwriter/common.py +38 -3
- novelwriter/config.py +19 -13
- novelwriter/constants.py +60 -45
- novelwriter/core/buildsettings.py +1 -1
- novelwriter/core/coretools.py +112 -126
- novelwriter/core/docbuild.py +4 -3
- novelwriter/core/document.py +1 -1
- novelwriter/core/index.py +10 -20
- novelwriter/core/item.py +40 -7
- novelwriter/core/itemmodel.py +518 -0
- novelwriter/core/options.py +1 -1
- novelwriter/core/project.py +68 -90
- novelwriter/core/projectdata.py +8 -2
- novelwriter/core/projectxml.py +1 -1
- novelwriter/core/sessions.py +1 -1
- novelwriter/core/spellcheck.py +1 -1
- novelwriter/core/status.py +24 -8
- novelwriter/core/storage.py +1 -1
- novelwriter/core/tree.py +269 -288
- novelwriter/dialogs/about.py +1 -1
- novelwriter/dialogs/docmerge.py +8 -18
- novelwriter/dialogs/docsplit.py +1 -1
- novelwriter/dialogs/editlabel.py +1 -1
- novelwriter/dialogs/preferences.py +4 -4
- novelwriter/dialogs/projectsettings.py +148 -98
- novelwriter/dialogs/quotes.py +1 -1
- novelwriter/dialogs/wordlist.py +11 -10
- novelwriter/enum.py +8 -1
- novelwriter/error.py +2 -2
- novelwriter/extensions/configlayout.py +7 -5
- novelwriter/extensions/eventfilters.py +1 -1
- novelwriter/extensions/modified.py +17 -5
- novelwriter/extensions/novelselector.py +1 -1
- novelwriter/extensions/pagedsidebar.py +4 -4
- novelwriter/extensions/progressbars.py +4 -4
- novelwriter/extensions/statusled.py +3 -3
- novelwriter/extensions/switch.py +3 -3
- novelwriter/extensions/switchbox.py +1 -1
- novelwriter/extensions/versioninfo.py +1 -1
- novelwriter/formats/shared.py +1 -1
- novelwriter/formats/todocx.py +35 -39
- novelwriter/formats/tohtml.py +15 -16
- novelwriter/formats/tokenizer.py +26 -22
- novelwriter/formats/tomarkdown.py +1 -1
- novelwriter/formats/toodt.py +54 -125
- novelwriter/formats/toqdoc.py +93 -45
- novelwriter/formats/toraw.py +1 -1
- novelwriter/gui/doceditor.py +233 -220
- novelwriter/gui/dochighlight.py +1 -1
- novelwriter/gui/docviewer.py +39 -10
- novelwriter/gui/docviewerpanel.py +15 -23
- novelwriter/gui/editordocument.py +1 -1
- novelwriter/gui/itemdetails.py +20 -27
- novelwriter/gui/mainmenu.py +14 -9
- novelwriter/gui/noveltree.py +13 -13
- novelwriter/gui/outline.py +18 -20
- novelwriter/gui/projtree.py +545 -1201
- novelwriter/gui/search.py +11 -19
- novelwriter/gui/sidebar.py +1 -1
- novelwriter/gui/statusbar.py +20 -3
- novelwriter/gui/theme.py +8 -4
- novelwriter/guimain.py +60 -48
- novelwriter/shared.py +53 -24
- novelwriter/text/counting.py +1 -1
- novelwriter/text/patterns.py +18 -6
- novelwriter/tools/dictionaries.py +1 -1
- novelwriter/tools/lipsum.py +1 -1
- novelwriter/tools/manusbuild.py +14 -12
- novelwriter/tools/manuscript.py +7 -7
- novelwriter/tools/manussettings.py +43 -53
- novelwriter/tools/noveldetails.py +1 -1
- novelwriter/tools/welcome.py +1 -1
- novelwriter/tools/writingstats.py +1 -1
- novelwriter/types.py +9 -3
- {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/top_level.txt +0 -0
novelwriter/gui/search.py
CHANGED
@@ -6,7 +6,7 @@ File History:
|
|
6
6
|
Created: 2024-03-21 [2.4b1] GuiProjectSearch
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright
|
9
|
+
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
@@ -30,15 +30,18 @@ from time import time
|
|
30
30
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
31
31
|
from PyQt5.QtGui import QCursor, QKeyEvent
|
32
32
|
from PyQt5.QtWidgets import (
|
33
|
-
QApplication, QFrame, QHBoxLayout,
|
34
|
-
|
33
|
+
QApplication, QFrame, QHBoxLayout, QLabel, QLineEdit, QToolBar,
|
34
|
+
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
|
35
35
|
)
|
36
36
|
|
37
37
|
from novelwriter import CONFIG, SHARED
|
38
38
|
from novelwriter.common import checkInt, cssCol
|
39
39
|
from novelwriter.core.coretools import DocSearch
|
40
40
|
from novelwriter.core.item import NWItem
|
41
|
-
from novelwriter.types import
|
41
|
+
from novelwriter.types import (
|
42
|
+
QtAlignMiddle, QtAlignRight, QtHeaderStretch, QtHeaderToContents,
|
43
|
+
QtUserRole
|
44
|
+
)
|
42
45
|
|
43
46
|
logger = logging.getLogger(__name__)
|
44
47
|
|
@@ -120,8 +123,8 @@ class GuiProjectSearch(QWidget):
|
|
120
123
|
|
121
124
|
treeHeader = self.searchResult.header()
|
122
125
|
treeHeader.setStretchLastSection(False)
|
123
|
-
treeHeader.setSectionResizeMode(self.C_NAME,
|
124
|
-
treeHeader.setSectionResizeMode(self.C_COUNT,
|
126
|
+
treeHeader.setSectionResizeMode(self.C_NAME, QtHeaderStretch)
|
127
|
+
treeHeader.setSectionResizeMode(self.C_COUNT, QtHeaderToContents)
|
125
128
|
|
126
129
|
# Assemble
|
127
130
|
self.headerBox = QHBoxLayout()
|
@@ -130,12 +133,8 @@ class GuiProjectSearch(QWidget):
|
|
130
133
|
self.headerBox.setContentsMargins(0, 0, 0, 0)
|
131
134
|
self.headerBox.setSpacing(0)
|
132
135
|
|
133
|
-
self.headerWidget = QWidget(self)
|
134
|
-
self.headerWidget.setLayout(self.headerBox)
|
135
|
-
self.headerWidget.setContentsMargins(0, 0, 0, 0)
|
136
|
-
|
137
136
|
self.outerBox = QVBoxLayout()
|
138
|
-
self.outerBox.
|
137
|
+
self.outerBox.addLayout(self.headerBox, 0)
|
139
138
|
self.outerBox.addWidget(self.searchText, 0)
|
140
139
|
self.outerBox.addWidget(self.searchResult, 1)
|
141
140
|
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
@@ -161,9 +160,6 @@ class GuiProjectSearch(QWidget):
|
|
161
160
|
colBase = cssCol(qPalette.base().color())
|
162
161
|
colFocus = cssCol(qPalette.highlight().color())
|
163
162
|
|
164
|
-
self.headerWidget.setStyleSheet(f"QWidget {{background: {colBase};}}")
|
165
|
-
self.headerWidget.setAutoFillBackground(True)
|
166
|
-
|
167
163
|
self.setStyleSheet(
|
168
164
|
"QToolBar {padding: 0; background: none;} "
|
169
165
|
f"QLineEdit {{border: {bPx}px solid {colBase}; padding: {mPx}px;}} "
|
@@ -331,15 +327,11 @@ class GuiProjectSearch(QWidget):
|
|
331
327
|
"""Populate the result tree."""
|
332
328
|
if results and nwItem:
|
333
329
|
tHandle = nwItem.itemHandle
|
334
|
-
docIcon = SHARED.theme.getItemIcon(
|
335
|
-
nwItem.itemType, nwItem.itemClass,
|
336
|
-
nwItem.itemLayout, nwItem.mainHeading
|
337
|
-
)
|
338
330
|
ext = "+" if capped else ""
|
339
331
|
|
340
332
|
tItem = QTreeWidgetItem()
|
341
333
|
tItem.setText(self.C_NAME, nwItem.itemName)
|
342
|
-
tItem.setIcon(self.C_NAME,
|
334
|
+
tItem.setIcon(self.C_NAME, nwItem.getMainIcon())
|
343
335
|
tItem.setData(self.C_NAME, self.D_HANDLE, tHandle)
|
344
336
|
tItem.setText(self.C_COUNT, f"({len(results):n}{ext})")
|
345
337
|
tItem.setTextAlignment(self.C_COUNT, QtAlignRight)
|
novelwriter/gui/sidebar.py
CHANGED
@@ -6,7 +6,7 @@ File History:
|
|
6
6
|
Created: 2022-05-10 [2.0rc1] GuiSideBar
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright
|
9
|
+
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
novelwriter/gui/statusbar.py
CHANGED
@@ -6,7 +6,7 @@ File History:
|
|
6
6
|
Created: 2019-04-20 [0.0.1] GuiMainStatus
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright
|
9
|
+
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
@@ -35,6 +35,7 @@ from novelwriter import CONFIG, SHARED
|
|
35
35
|
from novelwriter.common import formatTime
|
36
36
|
from novelwriter.constants import nwConst
|
37
37
|
from novelwriter.enum import nwTrinary
|
38
|
+
from novelwriter.extensions.modified import NClickableLabel
|
38
39
|
from novelwriter.extensions.statusled import StatusLED
|
39
40
|
|
40
41
|
logger = logging.getLogger(__name__)
|
@@ -92,12 +93,16 @@ class GuiMainStatus(QStatusBar):
|
|
92
93
|
|
93
94
|
# The Session Clock
|
94
95
|
# Set the minimum width so the label doesn't rescale every second
|
95
|
-
self.timeIcon =
|
96
|
-
self.
|
96
|
+
self.timeIcon = NClickableLabel(self)
|
97
|
+
self.timeIcon.mouseClicked.connect(self._onClickTimerLabel)
|
98
|
+
|
99
|
+
self.timeText = NClickableLabel("", self)
|
97
100
|
self.timeText.setToolTip(self.tr("Session Time"))
|
98
101
|
self.timeText.setMinimumWidth(SHARED.theme.getTextWidth("00:00:00:"))
|
99
102
|
self.timeIcon.setContentsMargins(0, 0, 0, 0)
|
100
103
|
self.timeText.setContentsMargins(0, 0, 0, 0)
|
104
|
+
self.timeText.setVisible(CONFIG.showSessionTime)
|
105
|
+
self.timeText.mouseClicked.connect(self._onClickTimerLabel)
|
101
106
|
self.addPermanentWidget(self.timeIcon)
|
102
107
|
self.addPermanentWidget(self.timeText)
|
103
108
|
|
@@ -224,6 +229,18 @@ class GuiMainStatus(QStatusBar):
|
|
224
229
|
self.setDocumentStatus(nwTrinary.NEGATIVE if status else nwTrinary.POSITIVE)
|
225
230
|
return
|
226
231
|
|
232
|
+
##
|
233
|
+
# Private Slots
|
234
|
+
##
|
235
|
+
|
236
|
+
@pyqtSlot()
|
237
|
+
def _onClickTimerLabel(self) -> None:
|
238
|
+
"""Process mouse click on timer label."""
|
239
|
+
state = not CONFIG.showSessionTime
|
240
|
+
self.timeText.setVisible(state)
|
241
|
+
CONFIG.showSessionTime = state
|
242
|
+
return
|
243
|
+
|
227
244
|
##
|
228
245
|
# Debug
|
229
246
|
##
|
novelwriter/gui/theme.py
CHANGED
@@ -7,7 +7,7 @@ Created: 2019-05-18 [0.1.3] GuiTheme
|
|
7
7
|
Created: 2019-11-08 [0.4] GuiIcons
|
8
8
|
|
9
9
|
This file is a part of novelWriter
|
10
|
-
Copyright
|
10
|
+
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
11
11
|
|
12
12
|
This program is free software: you can redistribute it and/or modify
|
13
13
|
it under the terms of the GNU General Public License as published by
|
@@ -151,6 +151,9 @@ class GuiTheme:
|
|
151
151
|
self.guiFont = QApplication.font()
|
152
152
|
self.guiFontB = QApplication.font()
|
153
153
|
self.guiFontB.setBold(True)
|
154
|
+
self.guiFontBU = QApplication.font()
|
155
|
+
self.guiFontBU.setBold(True)
|
156
|
+
self.guiFontBU.setUnderline(True)
|
154
157
|
self.guiFontSmall = QApplication.font()
|
155
158
|
self.guiFontSmall.setPointSizeF(0.9*self.guiFont.pointSizeF())
|
156
159
|
|
@@ -500,14 +503,15 @@ class GuiIcons:
|
|
500
503
|
|
501
504
|
# Format Icons
|
502
505
|
"fmt_bold", "fmt_bold-md", "fmt_italic", "fmt_italic-md", "fmt_mark", "fmt_strike",
|
503
|
-
"fmt_strike-md", "fmt_subscript", "fmt_superscript", "fmt_underline",
|
506
|
+
"fmt_strike-md", "fmt_subscript", "fmt_superscript", "fmt_underline", "margin_bottom",
|
507
|
+
"margin_left", "margin_right", "margin_top", "size_height", "size_width",
|
504
508
|
|
505
509
|
# General Button Icons
|
506
510
|
"add", "add_document", "backward", "bookmark", "browse", "checked", "close", "copy",
|
507
511
|
"cross", "document", "down", "edit", "export", "font", "forward", "import", "list",
|
508
512
|
"maximise", "menu", "minimise", "more", "noncheckable", "open", "panel", "quote",
|
509
|
-
"refresh", "remove", "revert", "search_replace", "search", "settings", "star", "
|
510
|
-
"up", "view",
|
513
|
+
"refresh", "remove", "revert", "search_replace", "search", "settings", "star", "toolbar",
|
514
|
+
"unchecked", "up", "view",
|
511
515
|
|
512
516
|
# Switches
|
513
517
|
"sticky-on", "sticky-off",
|
novelwriter/guimain.py
CHANGED
@@ -6,7 +6,7 @@ File History:
|
|
6
6
|
Created: 2018-09-22 [0.0.1] GuiMain
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright 2018
|
9
|
+
Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
@@ -44,7 +44,7 @@ from novelwriter.dialogs.about import GuiAbout
|
|
44
44
|
from novelwriter.dialogs.preferences import GuiPreferences
|
45
45
|
from novelwriter.dialogs.projectsettings import GuiProjectSettings
|
46
46
|
from novelwriter.dialogs.wordlist import GuiWordList
|
47
|
-
from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwFocus, nwView
|
47
|
+
from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwFocus, nwItemType, nwView
|
48
48
|
from novelwriter.gui.doceditor import GuiDocEditor
|
49
49
|
from novelwriter.gui.docviewer import GuiDocViewer
|
50
50
|
from novelwriter.gui.docviewerpanel import GuiDocViewerPanel
|
@@ -62,6 +62,7 @@ from novelwriter.tools.manuscript import GuiManuscript
|
|
62
62
|
from novelwriter.tools.noveldetails import GuiNovelDetails
|
63
63
|
from novelwriter.tools.welcome import GuiWelcome
|
64
64
|
from novelwriter.tools.writingstats import GuiWritingStats
|
65
|
+
from novelwriter.types import QtModShift
|
65
66
|
|
66
67
|
logger = logging.getLogger(__name__)
|
67
68
|
|
@@ -212,15 +213,19 @@ class GuiMain(QMainWindow):
|
|
212
213
|
SHARED.indexChangedTags.connect(self.docEditor.updateChangedTags)
|
213
214
|
SHARED.indexChangedTags.connect(self.docViewerPanel.updateChangedTags)
|
214
215
|
SHARED.indexCleared.connect(self.docViewerPanel.indexWasCleared)
|
215
|
-
SHARED.indexScannedText.connect(self.docViewerPanel.projectItemChanged)
|
216
|
-
SHARED.indexScannedText.connect(self.itemDetails.updateViewBox)
|
217
|
-
SHARED.indexScannedText.connect(self.projView.updateItemValues)
|
218
216
|
SHARED.mainClockTick.connect(self._timeTick)
|
217
|
+
SHARED.projectItemChanged.connect(self.docEditor.onProjectItemChanged)
|
218
|
+
SHARED.projectItemChanged.connect(self.docViewer.onProjectItemChanged)
|
219
|
+
SHARED.projectItemChanged.connect(self.docViewerPanel.onProjectItemChanged)
|
220
|
+
SHARED.projectItemChanged.connect(self.itemDetails.onProjectItemChanged)
|
221
|
+
SHARED.projectItemChanged.connect(self.projView.onProjectItemChanged)
|
219
222
|
SHARED.projectStatusChanged.connect(self.mainStatus.updateProjectStatus)
|
220
223
|
SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
|
224
|
+
SHARED.rootFolderChanged.connect(self.novelView.updateRootItem)
|
225
|
+
SHARED.rootFolderChanged.connect(self.outlineView.updateRootItem)
|
226
|
+
SHARED.rootFolderChanged.connect(self.projView.updateRootItem)
|
221
227
|
SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
|
222
228
|
SHARED.statusLabelsChanged.connect(self.docViewerPanel.updateStatusLabels)
|
223
|
-
SHARED.statusLabelsChanged.connect(self.projView.refreshUserLabels)
|
224
229
|
|
225
230
|
self.mainMenu.requestDocAction.connect(self._passDocumentAction)
|
226
231
|
self.mainMenu.requestDocInsert.connect(self._passDocumentInsert)
|
@@ -233,15 +238,7 @@ class GuiMain(QMainWindow):
|
|
233
238
|
|
234
239
|
self.projView.openDocumentRequest.connect(self._openDocument)
|
235
240
|
self.projView.projectSettingsRequest.connect(self.showProjectSettingsDialog)
|
236
|
-
self.projView.rootFolderChanged.connect(self.novelView.updateRootItem)
|
237
|
-
self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
|
238
|
-
self.projView.rootFolderChanged.connect(self.projView.updateRootItem)
|
239
241
|
self.projView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
240
|
-
self.projView.treeItemChanged.connect(self.docEditor.updateDocInfo)
|
241
|
-
self.projView.treeItemChanged.connect(self.docViewer.updateDocInfo)
|
242
|
-
self.projView.treeItemChanged.connect(self.docViewerPanel.projectItemChanged)
|
243
|
-
self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
|
244
|
-
self.projView.wordCountsChanged.connect(self._updateStatusWordCount)
|
245
242
|
|
246
243
|
self.novelView.openDocumentRequest.connect(self._openDocument)
|
247
244
|
self.novelView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
@@ -250,8 +247,6 @@ class GuiMain(QMainWindow):
|
|
250
247
|
self.projSearch.selectedItemChanged.connect(self.itemDetails.updateViewBox)
|
251
248
|
|
252
249
|
self.docEditor.closeEditorRequest.connect(self.closeDocEditor)
|
253
|
-
self.docEditor.docCountsChanged.connect(self.itemDetails.updateCounts)
|
254
|
-
self.docEditor.docCountsChanged.connect(self.projView.updateCounts)
|
255
250
|
self.docEditor.docTextChanged.connect(self.projSearch.textChanged)
|
256
251
|
self.docEditor.editedStatusChanged.connect(self.mainStatus.updateDocumentStatus)
|
257
252
|
self.docEditor.itemHandleChanged.connect(self.novelView.setActiveHandle)
|
@@ -259,7 +254,8 @@ class GuiMain(QMainWindow):
|
|
259
254
|
self.docEditor.loadDocumentTagRequest.connect(self._followTag)
|
260
255
|
self.docEditor.novelItemMetaChanged.connect(self.novelView.updateNovelItemMeta)
|
261
256
|
self.docEditor.novelStructureChanged.connect(self.novelView.refreshTree)
|
262
|
-
self.docEditor.
|
257
|
+
self.docEditor.openDocumentRequest.connect(self._openDocument)
|
258
|
+
self.docEditor.requestNewNoteCreation.connect(SHARED.createNewNote)
|
263
259
|
self.docEditor.requestNextDocument.connect(self.openNextDocument)
|
264
260
|
self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
|
265
261
|
self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
@@ -297,14 +293,25 @@ class GuiMain(QMainWindow):
|
|
297
293
|
self.keyReturn.setKey("Return")
|
298
294
|
self.keyReturn.activated.connect(self._keyPressReturn)
|
299
295
|
|
296
|
+
self.keyShiftReturn = QShortcut(self)
|
297
|
+
self.keyShiftReturn.setKey("Shift+Return")
|
298
|
+
self.keyShiftReturn.activated.connect(self._keyPressReturn)
|
299
|
+
|
300
300
|
self.keyEnter = QShortcut(self)
|
301
301
|
self.keyEnter.setKey("Enter")
|
302
302
|
self.keyEnter.activated.connect(self._keyPressReturn)
|
303
303
|
|
304
|
+
self.keyShiftEnter = QShortcut(self)
|
305
|
+
self.keyShiftEnter.setKey("Shift+Enter")
|
306
|
+
self.keyShiftEnter.activated.connect(self._keyPressReturn)
|
307
|
+
|
304
308
|
self.keyEscape = QShortcut(self)
|
305
309
|
self.keyEscape.setKey("Esc")
|
306
310
|
self.keyEscape.activated.connect(self._keyPressEscape)
|
307
311
|
|
312
|
+
# Internal Variables
|
313
|
+
self._lastTotalCount = 0
|
314
|
+
|
308
315
|
# Initialise Main GUI
|
309
316
|
self.initMain()
|
310
317
|
self.asProjTimer.start()
|
@@ -502,11 +509,9 @@ class GuiMain(QMainWindow):
|
|
502
509
|
|
503
510
|
def saveProject(self, autoSave: bool = False) -> bool:
|
504
511
|
"""Save the current project."""
|
505
|
-
if
|
506
|
-
|
507
|
-
|
508
|
-
self.projView.saveProjectTasks()
|
509
|
-
return SHARED.saveProject(autoSave=autoSave)
|
512
|
+
if SHARED.hasProject:
|
513
|
+
return SHARED.saveProject(autoSave=autoSave)
|
514
|
+
return False
|
510
515
|
|
511
516
|
##
|
512
517
|
# Document Actions
|
@@ -718,8 +723,11 @@ class GuiMain(QMainWindow):
|
|
718
723
|
logger.warning("No item selected")
|
719
724
|
return
|
720
725
|
|
721
|
-
if tHandle:
|
722
|
-
|
726
|
+
if tHandle and SHARED.project.tree.checkType(tHandle, nwItemType.FILE):
|
727
|
+
if QApplication.keyboardModifiers() == QtModShift:
|
728
|
+
self.viewDocument(tHandle)
|
729
|
+
else:
|
730
|
+
self.openDocument(tHandle, sTitle=sTitle, changeFocus=False, doScroll=False)
|
723
731
|
|
724
732
|
return
|
725
733
|
|
@@ -730,9 +738,8 @@ class GuiMain(QMainWindow):
|
|
730
738
|
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
731
739
|
tStart = time()
|
732
740
|
|
733
|
-
|
734
|
-
SHARED.project.
|
735
|
-
self.projView.populateTree()
|
741
|
+
SHARED.project.index.rebuild()
|
742
|
+
SHARED.project.tree.refreshAllItems()
|
736
743
|
self.novelView.refreshTree()
|
737
744
|
|
738
745
|
tEnd = time()
|
@@ -950,12 +957,8 @@ class GuiMain(QMainWindow):
|
|
950
957
|
docEditor = True
|
951
958
|
elif self.docViewer.isAncestorOf(new):
|
952
959
|
docViewer = True
|
953
|
-
|
954
960
|
self.docEditor.changeFocusState(docEditor)
|
955
961
|
self.docViewer.changeFocusState(docViewer)
|
956
|
-
|
957
|
-
logger.debug("Main focus switched to: %s", type(new).__name__)
|
958
|
-
|
959
962
|
return
|
960
963
|
|
961
964
|
@pyqtSlot(bool)
|
@@ -1044,13 +1047,8 @@ class GuiMain(QMainWindow):
|
|
1044
1047
|
self.initMain()
|
1045
1048
|
self.saveDocument()
|
1046
1049
|
|
1047
|
-
if restart:
|
1048
|
-
SHARED.info(self.tr(
|
1049
|
-
"Some changes will not be applied until novelWriter has been restarted."
|
1050
|
-
))
|
1051
|
-
|
1052
1050
|
if tree:
|
1053
|
-
|
1051
|
+
SHARED.project.tree.refreshAllItems()
|
1054
1052
|
|
1055
1053
|
if theme:
|
1056
1054
|
# We are doing this manually instead of connecting to
|
@@ -1076,8 +1074,16 @@ class GuiMain(QMainWindow):
|
|
1076
1074
|
self.projView.initSettings()
|
1077
1075
|
self.novelView.initSettings()
|
1078
1076
|
self.outlineView.initSettings()
|
1077
|
+
|
1078
|
+
# Force update of word count
|
1079
|
+
self._lastTotalCount = 0
|
1079
1080
|
self._updateStatusWordCount()
|
1080
1081
|
|
1082
|
+
if restart:
|
1083
|
+
SHARED.info(self.tr(
|
1084
|
+
"Some changes will not be applied until novelWriter has been restarted."
|
1085
|
+
))
|
1086
|
+
|
1081
1087
|
return
|
1082
1088
|
|
1083
1089
|
@pyqtSlot()
|
@@ -1213,8 +1219,10 @@ class GuiMain(QMainWindow):
|
|
1213
1219
|
self.mainStatus.setUserIdle(editIdle or userIdle)
|
1214
1220
|
SHARED.updateIdleTime(currTime, editIdle or userIdle)
|
1215
1221
|
self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime)
|
1216
|
-
if
|
1217
|
-
self.
|
1222
|
+
if int(currTime) % 5 == 0:
|
1223
|
+
self._updateStatusWordCount()
|
1224
|
+
if CONFIG.memInfo: # pragma: no cover
|
1225
|
+
self.mainStatus.memInfo()
|
1218
1226
|
return
|
1219
1227
|
|
1220
1228
|
@pyqtSlot()
|
@@ -1242,15 +1250,19 @@ class GuiMain(QMainWindow):
|
|
1242
1250
|
if not SHARED.hasProject:
|
1243
1251
|
self.mainStatus.setProjectStats(0, 0)
|
1244
1252
|
|
1245
|
-
SHARED.project.
|
1246
|
-
if
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1253
|
+
currentTotalCount = SHARED.project.currentTotalCount
|
1254
|
+
if self._lastTotalCount != currentTotalCount:
|
1255
|
+
self._lastTotalCount = currentTotalCount
|
1256
|
+
|
1257
|
+
SHARED.project.updateWordCounts()
|
1258
|
+
if CONFIG.incNotesWCount:
|
1259
|
+
iTotal = sum(SHARED.project.data.initCounts)
|
1260
|
+
cTotal = sum(SHARED.project.data.currCounts)
|
1261
|
+
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
|
1262
|
+
else:
|
1263
|
+
iNovel, _ = SHARED.project.data.initCounts
|
1264
|
+
cNovel, _ = SHARED.project.data.currCounts
|
1265
|
+
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel)
|
1254
1266
|
|
1255
1267
|
return
|
1256
1268
|
|
novelwriter/shared.py
CHANGED
@@ -7,7 +7,7 @@ Created: 2023-08-10 [2.1rc1] SharedData
|
|
7
7
|
Created: 2023-08-14 [2.1rc1] _GuiAlert
|
8
8
|
|
9
9
|
This file is a part of novelWriter
|
10
|
-
Copyright
|
10
|
+
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
11
11
|
|
12
12
|
This program is free software: you can redistribute it and/or modify
|
13
13
|
it under the terms of the GNU General Public License as published by
|
@@ -26,6 +26,7 @@ from __future__ import annotations
|
|
26
26
|
|
27
27
|
import logging
|
28
28
|
|
29
|
+
from enum import Enum
|
29
30
|
from pathlib import Path
|
30
31
|
from time import time
|
31
32
|
from typing import TYPE_CHECKING, TypeVar
|
@@ -37,9 +38,11 @@ from PyQt5.QtWidgets import QFileDialog, QFontDialog, QMessageBox, QWidget
|
|
37
38
|
from novelwriter.common import formatFileFilter
|
38
39
|
from novelwriter.constants import nwFiles
|
39
40
|
from novelwriter.core.spellcheck import NWSpellEnchant
|
41
|
+
from novelwriter.enum import nwChange, nwItemClass
|
40
42
|
|
41
43
|
if TYPE_CHECKING: # pragma: no cover
|
42
44
|
from novelwriter.core.project import NWProject
|
45
|
+
from novelwriter.core.status import T_StatusKind
|
43
46
|
from novelwriter.gui.theme import GuiTheme
|
44
47
|
from novelwriter.guimain import GuiMain
|
45
48
|
|
@@ -55,15 +58,16 @@ class SharedData(QObject):
|
|
55
58
|
"_idleTime", "_idleRefTime",
|
56
59
|
)
|
57
60
|
|
58
|
-
projectStatusChanged = pyqtSignal(bool)
|
59
|
-
projectStatusMessage = pyqtSignal(str)
|
60
|
-
spellLanguageChanged = pyqtSignal(str, str)
|
61
61
|
focusModeChanged = pyqtSignal(bool)
|
62
|
-
|
62
|
+
indexAvailable = pyqtSignal()
|
63
63
|
indexChangedTags = pyqtSignal(list, list)
|
64
64
|
indexCleared = pyqtSignal()
|
65
|
-
indexAvailable = pyqtSignal()
|
66
65
|
mainClockTick = pyqtSignal()
|
66
|
+
projectItemChanged = pyqtSignal(str, Enum)
|
67
|
+
rootFolderChanged = pyqtSignal(str, Enum)
|
68
|
+
projectStatusChanged = pyqtSignal(bool)
|
69
|
+
projectStatusMessage = pyqtSignal(str)
|
70
|
+
spellLanguageChanged = pyqtSignal(str, str)
|
67
71
|
statusLabelsChanged = pyqtSignal(str)
|
68
72
|
|
69
73
|
def __init__(self) -> None:
|
@@ -173,10 +177,12 @@ class SharedData(QObject):
|
|
173
177
|
logger.debug("Thread Pool Max Count: %d", QThreadPool.globalInstance().maxThreadCount())
|
174
178
|
return
|
175
179
|
|
176
|
-
def
|
180
|
+
def closeDocument(self, tHandle: str | None = None) -> None:
|
177
181
|
"""Close the document editor, optionally a specific document."""
|
178
182
|
if tHandle is None or tHandle == self.mainGui.docEditor.docHandle:
|
179
183
|
self.mainGui.closeDocument()
|
184
|
+
if tHandle is None or tHandle == self.mainGui.docViewer.docHandle:
|
185
|
+
self.mainGui.closeViewerPanel()
|
180
186
|
return
|
181
187
|
|
182
188
|
def saveEditor(self, tHandle: str | None = None) -> None:
|
@@ -302,30 +308,52 @@ class SharedData(QObject):
|
|
302
308
|
QDesktopServices.openUrl(QUrl(url))
|
303
309
|
return
|
304
310
|
|
311
|
+
@pyqtSlot(str, nwItemClass)
|
312
|
+
def createNewNote(self, tag: str, itemClass: nwItemClass) -> None:
|
313
|
+
"""Process new note request."""
|
314
|
+
self.project.createNewNote(tag, itemClass)
|
315
|
+
return
|
316
|
+
|
305
317
|
##
|
306
|
-
# Signal
|
318
|
+
# Signal Proxies
|
307
319
|
##
|
308
320
|
|
309
|
-
def
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
if
|
314
|
-
self.indexChangedTags.emit(
|
315
|
-
|
316
|
-
|
317
|
-
|
321
|
+
def emitIndexChangedTags(
|
322
|
+
self, project: NWProject, updated: list[str], deleted: list[str]
|
323
|
+
) -> None:
|
324
|
+
"""Emit the indexChangedTags signal."""
|
325
|
+
if self._project and self._project.data.uuid == project.data.uuid:
|
326
|
+
self.indexChangedTags.emit(updated, deleted)
|
327
|
+
return
|
328
|
+
|
329
|
+
def emitIndexCleared(self, project: NWProject) -> None:
|
330
|
+
"""Emit the indexCleared signal."""
|
331
|
+
if self._project and self._project.data.uuid == project.data.uuid:
|
318
332
|
self.indexCleared.emit()
|
319
|
-
|
333
|
+
return
|
334
|
+
|
335
|
+
def emitIndexAvailable(self, project: NWProject) -> None:
|
336
|
+
"""Emit the indexAvailable signal."""
|
337
|
+
if self._project and self._project.data.uuid == project.data.uuid:
|
320
338
|
self.indexAvailable.emit()
|
321
339
|
return
|
322
340
|
|
323
|
-
def
|
324
|
-
"""Emit
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
341
|
+
def emitStatusLabelsChanged(self, project: NWProject, kind: T_StatusKind) -> None:
|
342
|
+
"""Emit the statusLabelsChanged signal."""
|
343
|
+
if self._project and self._project.data.uuid == project.data.uuid:
|
344
|
+
self.statusLabelsChanged.emit(kind)
|
345
|
+
return
|
346
|
+
|
347
|
+
def emitProjectItemChanged(self, project: NWProject, handle: str, change: nwChange) -> None:
|
348
|
+
"""Emit the projectItemChanged signal."""
|
349
|
+
if self._project and self._project.data.uuid == project.data.uuid:
|
350
|
+
self.projectItemChanged.emit(handle, change)
|
351
|
+
return
|
352
|
+
|
353
|
+
def emitRootFolderChanged(self, project: NWProject, handle: str, change: nwChange) -> None:
|
354
|
+
"""Emit the rootFolderChanged signal."""
|
355
|
+
if self._project and self._project.data.uuid == project.data.uuid:
|
356
|
+
self.rootFolderChanged.emit(handle, change)
|
329
357
|
return
|
330
358
|
|
331
359
|
##
|
@@ -386,6 +414,7 @@ class SharedData(QObject):
|
|
386
414
|
"""Create a new project and spell checking instance."""
|
387
415
|
from novelwriter.core.project import NWProject
|
388
416
|
if isinstance(self._project, NWProject):
|
417
|
+
self._project.clear()
|
389
418
|
del self._project
|
390
419
|
del self._spelling
|
391
420
|
self._project = NWProject()
|
novelwriter/text/counting.py
CHANGED
@@ -8,7 +8,7 @@ Rewritten: 2024-02-27 [2.4b1] preProcessText, standardCounter
|
|
8
8
|
Created: 2024-02-27 [2.4b1] bodyTextCounter
|
9
9
|
|
10
10
|
This file is a part of novelWriter
|
11
|
-
Copyright
|
11
|
+
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
12
12
|
|
13
13
|
This program is free software: you can redistribute it and/or modify
|
14
14
|
it under the terms of the GNU General Public License as published by
|
novelwriter/text/patterns.py
CHANGED
@@ -7,7 +7,7 @@ Created: 2024-06-01 [2.5rc1] RegExPatterns
|
|
7
7
|
Created: 2024-11-04 [2.6b1] DialogParser
|
8
8
|
|
9
9
|
This file is a part of novelWriter
|
10
|
-
Copyright
|
10
|
+
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
11
11
|
|
12
12
|
This program is free software: you can redistribute it and/or modify
|
13
13
|
it under the terms of the GNU General Public License as published by
|
@@ -28,11 +28,13 @@ import re
|
|
28
28
|
|
29
29
|
from novelwriter import CONFIG
|
30
30
|
from novelwriter.common import compact, uniqueCompact
|
31
|
-
from novelwriter.constants import nwRegEx
|
31
|
+
from novelwriter.constants import nwRegEx, nwUnicode
|
32
32
|
|
33
33
|
|
34
34
|
class RegExPatterns:
|
35
35
|
|
36
|
+
AMBIGUOUS = (nwUnicode.U_APOS, nwUnicode.U_RSQUO)
|
37
|
+
|
36
38
|
# Static RegExes
|
37
39
|
_rxUrl = re.compile(nwRegEx.URL, re.ASCII)
|
38
40
|
_rxWords = re.compile(nwRegEx.WORDS, re.UNICODE)
|
@@ -87,16 +89,25 @@ class RegExPatterns:
|
|
87
89
|
def dialogStyle(self) -> re.Pattern | None:
|
88
90
|
"""Dialogue detection rule based on user settings."""
|
89
91
|
if CONFIG.dialogStyle > 0:
|
90
|
-
end = "|$" if CONFIG.allowOpenDial else ""
|
91
92
|
rx = []
|
92
93
|
if CONFIG.dialogStyle in (1, 3):
|
93
94
|
qO = CONFIG.fmtSQuoteOpen.strip()[:1]
|
94
95
|
qC = CONFIG.fmtSQuoteClose.strip()[:1]
|
95
|
-
|
96
|
+
if qO == qC:
|
97
|
+
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
|
98
|
+
else:
|
99
|
+
rx.append(f"(?:{qO}[^{qO}]+{qC})")
|
100
|
+
if CONFIG.allowOpenDial:
|
101
|
+
rx.append(f"(?:{qO}.+?$)")
|
96
102
|
if CONFIG.dialogStyle in (2, 3):
|
97
103
|
qO = CONFIG.fmtDQuoteOpen.strip()[:1]
|
98
104
|
qC = CONFIG.fmtDQuoteClose.strip()[:1]
|
99
|
-
|
105
|
+
if qO == qC:
|
106
|
+
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
|
107
|
+
else:
|
108
|
+
rx.append(f"(?:{qO}[^{qO}]+{qC})")
|
109
|
+
if CONFIG.allowOpenDial:
|
110
|
+
rx.append(f"(?:{qO}.+?$)")
|
100
111
|
return re.compile("|".join(rx), re.UNICODE)
|
101
112
|
return None
|
102
113
|
|
@@ -106,7 +117,8 @@ class RegExPatterns:
|
|
106
117
|
if CONFIG.altDialogOpen and CONFIG.altDialogClose:
|
107
118
|
qO = re.escape(compact(CONFIG.altDialogOpen))
|
108
119
|
qC = re.escape(compact(CONFIG.altDialogClose))
|
109
|
-
|
120
|
+
qB = r"\B" if (qO == qC or qC in self.AMBIGUOUS) else ""
|
121
|
+
return re.compile(f"{qO}.*?{qC}{qB}", re.UNICODE)
|
110
122
|
return None
|
111
123
|
|
112
124
|
|
@@ -6,7 +6,7 @@ File History:
|
|
6
6
|
Created: 2023-11-19 [2.2rc1] GuiDictionaries
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright
|
9
|
+
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
novelwriter/tools/lipsum.py
CHANGED
@@ -6,7 +6,7 @@ File History:
|
|
6
6
|
Created: 2022-04-02 [2.0rc1] GuiLipsum
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright
|
9
|
+
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|