Add annotations to core tools
This commit is contained in:
@@ -23,10 +23,12 @@ General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import shutil
|
import shutil
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, Iterable
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from PyQt5.QtCore import QCoreApplication
|
from PyQt5.QtCore import QCoreApplication
|
||||||
@@ -35,8 +37,12 @@ from novelwriter import CONFIG
|
|||||||
from novelwriter.enum import nwAlert
|
from novelwriter.enum import nwAlert
|
||||||
from novelwriter.common import minmax, simplified
|
from novelwriter.common import minmax, simplified
|
||||||
from novelwriter.constants import nwItemClass
|
from novelwriter.constants import nwItemClass
|
||||||
|
from novelwriter.core.item import NWItem
|
||||||
from novelwriter.core.project import NWProject
|
from novelwriter.core.project import NWProject
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from novelwriter.guimain import GuiMain
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -46,26 +52,22 @@ class DocMerger:
|
|||||||
GuiDocMerge dialog.
|
GuiDocMerge dialog.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, theProject):
|
def __init__(self, project: NWProject) -> None:
|
||||||
|
self._project = project
|
||||||
self.theProject = theProject
|
|
||||||
|
|
||||||
self._error = ""
|
self._error = ""
|
||||||
self._targetDoc = None
|
self._targetDoc = None
|
||||||
self._targetText = []
|
self._targetText = []
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Methods
|
# Methods
|
||||||
##
|
##
|
||||||
|
|
||||||
def getError(self):
|
def getError(self) -> str:
|
||||||
"""Return any collected errors.
|
"""Return any collected errors."""
|
||||||
"""
|
|
||||||
return self._error
|
return self._error
|
||||||
|
|
||||||
def setTargetDoc(self, tHandle):
|
def setTargetDoc(self, tHandle: str) -> None:
|
||||||
"""Set the target document for the merging. Calling this
|
"""Set the target document for the merging. Calling this
|
||||||
function resets the class.
|
function resets the class.
|
||||||
"""
|
"""
|
||||||
@@ -73,33 +75,33 @@ class DocMerger:
|
|||||||
self._targetText = []
|
self._targetText = []
|
||||||
return
|
return
|
||||||
|
|
||||||
def newTargetDoc(self, srcHandle, docLabel):
|
def newTargetDoc(self, srcHandle: str, docLabel: str) -> str | None:
|
||||||
"""Create a barnd new target document based on a source handle
|
"""Create a barnd new target document based on a source handle
|
||||||
and a new doc label. Calling this function resets the class.
|
and a new doc label. Calling this function resets the class.
|
||||||
"""
|
"""
|
||||||
srcItem = self.theProject.tree[srcHandle]
|
srcItem = self._project.tree[srcHandle]
|
||||||
if srcItem is None:
|
if srcItem is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
newHandle = self.theProject.newFile(docLabel, srcItem.itemParent)
|
newHandle = self._project.newFile(docLabel, srcItem.itemParent)
|
||||||
newItem = self.theProject.tree[newHandle]
|
newItem = self._project.tree[newHandle]
|
||||||
newItem.setLayout(srcItem.itemLayout)
|
if isinstance(newItem, NWItem):
|
||||||
newItem.setStatus(srcItem.itemStatus)
|
newItem.setLayout(srcItem.itemLayout)
|
||||||
newItem.setImport(srcItem.itemImport)
|
newItem.setStatus(srcItem.itemStatus)
|
||||||
|
newItem.setImport(srcItem.itemImport)
|
||||||
|
|
||||||
self._targetDoc = newHandle
|
self._targetDoc = newHandle
|
||||||
self._targetText = []
|
self._targetText = []
|
||||||
|
|
||||||
return newHandle
|
return newHandle
|
||||||
|
|
||||||
def appendText(self, srcHandle, addComment, cmtPrefix):
|
def appendText(self, srcHandle: str, addComment: bool, cmtPrefix: str) -> bool:
|
||||||
"""Append text from an existing document to the text buffer.
|
"""Append text from an existing document to the text buffer."""
|
||||||
"""
|
srcItem = self._project.tree[srcHandle]
|
||||||
srcItem = self.theProject.tree[srcHandle]
|
|
||||||
if srcItem is None:
|
if srcItem is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
inDoc = self.theProject.storage.getDocument(srcHandle)
|
inDoc = self._project.storage.getDocument(srcHandle)
|
||||||
docText = (inDoc.readDocument() or "").rstrip("\n")
|
docText = (inDoc.readDocument() or "").rstrip("\n")
|
||||||
|
|
||||||
if addComment:
|
if addComment:
|
||||||
@@ -112,14 +114,14 @@ class DocMerger:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def writeTargetDoc(self):
|
def writeTargetDoc(self) -> bool:
|
||||||
"""Write the accumulated text into the designated target
|
"""Write the accumulated text into the designated target
|
||||||
document, appending any existing text.
|
document, appending any existing text.
|
||||||
"""
|
"""
|
||||||
if self._targetDoc is None:
|
if self._targetDoc is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
outDoc = self.theProject.storage.getDocument(self._targetDoc)
|
outDoc = self._project.storage.getDocument(self._targetDoc)
|
||||||
docText = (outDoc.readDocument() or "").rstrip("\n")
|
docText = (outDoc.readDocument() or "").rstrip("\n")
|
||||||
if docText:
|
if docText:
|
||||||
self._targetText.insert(0, docText)
|
self._targetText.insert(0, docText)
|
||||||
@@ -139,9 +141,9 @@ class DocSplitter:
|
|||||||
GuiDocSplit dialog.
|
GuiDocSplit dialog.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, theProject, sHandle):
|
def __init__(self, project: NWProject, sHandle: str) -> None:
|
||||||
|
|
||||||
self.theProject = theProject
|
self._project = project
|
||||||
|
|
||||||
self._error = ""
|
self._error = ""
|
||||||
self._parHandle = None
|
self._parHandle = None
|
||||||
@@ -151,7 +153,7 @@ class DocSplitter:
|
|||||||
self._inFolder = False
|
self._inFolder = False
|
||||||
self._rawData = []
|
self._rawData = []
|
||||||
|
|
||||||
srcItem = self.theProject.tree[sHandle]
|
srcItem = self._project.tree[sHandle]
|
||||||
if srcItem is not None and srcItem.isFileType():
|
if srcItem is not None and srcItem.isFileType():
|
||||||
self._srcHandle = sHandle
|
self._srcHandle = sHandle
|
||||||
self._srcItem = srcItem
|
self._srcItem = srcItem
|
||||||
@@ -162,12 +164,11 @@ class DocSplitter:
|
|||||||
# Methods
|
# Methods
|
||||||
##
|
##
|
||||||
|
|
||||||
def getError(self):
|
def getError(self) -> str:
|
||||||
"""Return any collected errors.
|
"""Return any collected errors."""
|
||||||
"""
|
|
||||||
return self._error
|
return self._error
|
||||||
|
|
||||||
def setParentItem(self, pHandle):
|
def setParentItem(self, pHandle: str) -> None:
|
||||||
"""Set the item that will be the top level parent item for the
|
"""Set the item that will be the top level parent item for the
|
||||||
new documents.
|
new documents.
|
||||||
"""
|
"""
|
||||||
@@ -175,25 +176,27 @@ class DocSplitter:
|
|||||||
self._inFolder = False
|
self._inFolder = False
|
||||||
return
|
return
|
||||||
|
|
||||||
def newParentFolder(self, pHandle, folderLabel):
|
def newParentFolder(self, pHandle: str, folderLabel: str) -> str | None:
|
||||||
"""Create a new folder that will be the top level parent item
|
"""Create a new folder that will be the top level parent item
|
||||||
for the new documents.
|
for the new documents.
|
||||||
"""
|
"""
|
||||||
if self._srcItem is None:
|
if self._srcItem is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
newHandle = self.theProject.newFolder(folderLabel, pHandle)
|
newHandle = self._project.newFolder(folderLabel, pHandle)
|
||||||
newItem = self.theProject.tree[newHandle]
|
newItem = self._project.tree[newHandle]
|
||||||
newItem.setStatus(self._srcItem.itemStatus)
|
if isinstance(newItem, NWItem):
|
||||||
newItem.setImport(self._srcItem.itemImport)
|
newItem.setStatus(self._srcItem.itemStatus)
|
||||||
|
newItem.setImport(self._srcItem.itemImport)
|
||||||
|
|
||||||
self._parHandle = newHandle
|
self._parHandle = newHandle
|
||||||
self._inFolder = True
|
self._inFolder = True
|
||||||
|
|
||||||
return newHandle
|
return newHandle
|
||||||
|
|
||||||
def splitDocument(self, splitData, splitText):
|
def splitDocument(self, splitData: list, splitText: list[str]) -> None:
|
||||||
"""Loop through the split data record and perform the split job.
|
"""Loop through the split data record and perform the split job
|
||||||
|
on a list of text lines.
|
||||||
"""
|
"""
|
||||||
self._rawData = []
|
self._rawData = []
|
||||||
buffer = splitText.copy()
|
buffer = splitText.copy()
|
||||||
@@ -201,10 +204,9 @@ class DocSplitter:
|
|||||||
chunk = buffer[lineNo:]
|
chunk = buffer[lineNo:]
|
||||||
buffer = buffer[:lineNo]
|
buffer = buffer[:lineNo]
|
||||||
self._rawData.insert(0, (chunk, hLevel, hLabel))
|
self._rawData.insert(0, (chunk, hLevel, hLabel))
|
||||||
|
return
|
||||||
|
|
||||||
return True
|
def writeDocuments(self, docHierarchy: bool) -> Iterable[tuple[bool, str | None, str | None]]:
|
||||||
|
|
||||||
def writeDocuments(self, docHierarchy):
|
|
||||||
"""An iterator that will write each document in the buffer, and
|
"""An iterator that will write each document in the buffer, and
|
||||||
return its new handle, parent handle, and sibling handle.
|
return its new handle, parent handle, and sibling handle.
|
||||||
"""
|
"""
|
||||||
@@ -237,14 +239,15 @@ class DocSplitter:
|
|||||||
elif hLevel > pLevel:
|
elif hLevel > pLevel:
|
||||||
nHandle = pHandle
|
nHandle = pHandle
|
||||||
|
|
||||||
dHandle = self.theProject.newFile(docLabel, pHandle)
|
dHandle = self._project.newFile(docLabel, pHandle)
|
||||||
hHandle[hLevel] = dHandle
|
hHandle[hLevel] = dHandle
|
||||||
|
|
||||||
newItem = self.theProject.tree[dHandle]
|
newItem = self._project.tree[dHandle]
|
||||||
newItem.setStatus(self._srcItem.itemStatus)
|
if isinstance(newItem, NWItem):
|
||||||
newItem.setImport(self._srcItem.itemImport)
|
newItem.setStatus(self._srcItem.itemStatus)
|
||||||
|
newItem.setImport(self._srcItem.itemImport)
|
||||||
|
|
||||||
outDoc = self.theProject.storage.getDocument(dHandle)
|
outDoc = self._project.storage.getDocument(dHandle)
|
||||||
status = outDoc.writeDocument("\n".join(docText))
|
status = outDoc.writeDocument("\n".join(docText))
|
||||||
if not status:
|
if not status:
|
||||||
self._error = outDoc.getError()
|
self._error = outDoc.getError()
|
||||||
@@ -265,7 +268,7 @@ class ProjectBuilder:
|
|||||||
parameter provided by the New Projecty Wizard.
|
parameter provided by the New Projecty Wizard.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, mainGui):
|
def __init__(self, mainGui: GuiMain) -> None:
|
||||||
self.mainGui = mainGui
|
self.mainGui = mainGui
|
||||||
self.tr = partial(QCoreApplication.translate, "NWProject")
|
self.tr = partial(QCoreApplication.translate, "NWProject")
|
||||||
return
|
return
|
||||||
@@ -274,7 +277,7 @@ class ProjectBuilder:
|
|||||||
# Methods
|
# Methods
|
||||||
##
|
##
|
||||||
|
|
||||||
def buildProject(self, data):
|
def buildProject(self, data: dict) -> bool:
|
||||||
"""Build a project from a data dictionary of specifications
|
"""Build a project from a data dictionary of specifications
|
||||||
provided by the wizard.
|
provided by the wizard.
|
||||||
"""
|
"""
|
||||||
@@ -416,7 +419,7 @@ class ProjectBuilder:
|
|||||||
# Internal Functions
|
# Internal Functions
|
||||||
##
|
##
|
||||||
|
|
||||||
def _extractSampleProject(self, data):
|
def _extractSampleProject(self, data: dict) -> bool:
|
||||||
"""Make a copy of the sample project by extracting the
|
"""Make a copy of the sample project by extracting the
|
||||||
sample.zip file to the new path.
|
sample.zip file to the new path.
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user