Add the core code for the DocSplitter tool

This commit is contained in:
Veronica Berglyd Olsen
2022-10-12 23:39:56 +02:00
parent baafd5f83c
commit 31a5761ba0
4 changed files with 135 additions and 9 deletions
+2 -1
View File
@@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from novelwriter.core.doctools import DocMerger
from novelwriter.core.doctools import DocMerger, DocSplitter
from novelwriter.core.document import NWDoc
from novelwriter.core.index import countWords
from novelwriter.core.project import NWProject
@@ -30,6 +30,7 @@ from novelwriter.core.tomd import ToMarkdown
__all__ = [
"DocMerger",
"DocSplitter",
"countWords",
"NWDoc",
"NWProject",
+89 -1
View File
@@ -4,7 +4,8 @@ novelWriter Project Document Tools
A collection of tools to create and manipulate documents
File History:
Created: 2022-10-02 [2.0b1]
Created: 2022-10-02 [2.0b1] DocMerger
Created: 2022-10-11 [2.0b1] DocSplitter
This file is a part of novelWriter
Copyright 20182022, Veronica Berglyd Olsen
@@ -117,3 +118,90 @@ class DocMerger:
return status
# END Class DocMerger
class DocSplitter:
def __init__(self, theProject, sHandle):
self.theProject = theProject
self._error = ""
self._parHandle = None
self._srcHandle = None
self._srcItem = None
self._rawData = []
srcItem = self.theProject.tree[sHandle]
if srcItem is not None and srcItem.isFileType():
self._srcHandle = sHandle
self._srcItem = srcItem
return
##
# Methods
##
def getError(self):
"""Return any collected errors.
"""
return self._error
def setParentItem(self, pHandle):
"""Set the item that will be the top level parent item for the
new documents.
"""
self._parHandle = pHandle
return
def newParentFolder(self, pHandle, folderLabel):
"""Create a new folder that will be the top level parent item
for the new documents.
"""
if self._srcItem is None:
return None
newHandle = self.theProject.newFolder(folderLabel, pHandle)
newItem = self.theProject.tree[self._parHandle]
newItem.setStatus(self._srcItem.itemStatus)
newItem.setImport(self._srcItem.itemImport)
self._parHandle = newHandle
return newHandle
def splitDocument(self, splitData, splitText):
"""Loop through the split data record and perform the split job.
"""
self._rawData = []
buffer = splitText.copy()
for lineNo, hLevel, hLabel in reversed(splitData):
chunk = buffer[lineNo:]
buffer = buffer[:lineNo]
self._rawData.insert(0, (chunk, hLevel, hLabel))
return True
def writeDocuments(self):
"""An iterator that will write each document in the buffer, and
return its new handle, parent handle, and sibling handle.
"""
nearHandle = self._parHandle
for docText, hLevel, docLabel in self._rawData:
newHandle = self.theProject.newFile(docLabel, self._parHandle)
outDoc = NWDoc(self.theProject, newHandle)
status = outDoc.writeDocument("\n".join(docText))
if not status:
self._error = outDoc.getError()
yield newHandle, self._parHandle, nearHandle
nearHandle = newHandle
return
# END Class DocSplitter
+31 -6
View File
@@ -41,6 +41,10 @@ logger = logging.getLogger(__name__)
class GuiDocSplit(QDialog):
LINE_ROLE = Qt.UserRole
LEVEL_ROLE = Qt.UserRole + 1
LABEL_ROLE = Qt.UserRole + 2
def __init__(self, mainGui, sHandle):
super().__init__(parent=mainGui)
@@ -141,7 +145,9 @@ class GuiDocSplit(QDialog):
headerList = []
for i in range(self.listBox.count()):
item = self.listBox.item(i)
headerList.append((item.text(), item.data(Qt.UserRole)))
headerList.append(
(item.data(self.LINE_ROLE), item.data(self.LEVEL_ROLE), item.data(self.LABEL_ROLE))
)
spLevel = self.splitLevel.currentData()
intoFolder = self.folderSwitch.isChecked()
@@ -157,7 +163,7 @@ class GuiDocSplit(QDialog):
pOptions.setValue("GuiDocSplit", "intoFolder", intoFolder)
pOptions.setValue("GuiDocSplit", "docHierarchy", docHierarchy)
return self._data
return self._data, self._text
##
# Slots
@@ -193,19 +199,38 @@ class GuiDocSplit(QDialog):
for lineNo, aLine in enumerate(self._text):
onLine = -1
if aLine.startswith(("# ", "#! ")) and spLevel >= 1:
hLevel = 0
if aLine.startswith("# ") and spLevel >= 1:
onLine = lineNo
elif aLine.startswith(("## ", "##! ")) and spLevel >= 2:
hLevel = 1
hLabel = aLine[2:].strip()
elif aLine.startswith("## ") and spLevel >= 2:
onLine = lineNo
hLevel = 2
hLabel = aLine[3:].strip()
elif aLine.startswith("### ") and spLevel >= 3:
onLine = lineNo
hLevel = 3
hLabel = aLine[4:].strip()
elif aLine.startswith("#### ") and spLevel >= 4:
onLine = lineNo
hLevel = 4
hLabel = aLine[5:].strip()
elif aLine.startswith("#! ") and spLevel >= 1:
onLine = lineNo
hLevel = 1
hLabel = aLine[3:].strip()
elif aLine.startswith("##! ") and spLevel >= 2:
onLine = lineNo
hLevel = 2
hLabel = aLine[4:].strip()
if onLine >= 0:
if onLine >= 0 and hLevel > 0:
newItem = QListWidgetItem()
newItem.setText(aLine.strip())
newItem.setData(Qt.UserRole, onLine)
newItem.setData(self.LINE_ROLE, onLine)
newItem.setData(self.LEVEL_ROLE, hLevel)
newItem.setData(self.LABEL_ROLE, hLabel)
self.listBox.addItem(newItem)
return True
+13 -1
View File
@@ -40,6 +40,7 @@ from PyQt5.QtWidgets import (
)
from novelwriter.core import DocMerger
from novelwriter.core.doctools import DocSplitter
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert
from novelwriter.dialogs import GuiDocMerge, GuiDocSplit, GuiEditLabel
from novelwriter.constants import nwHeaders, trConst, nwLabels
@@ -1475,7 +1476,18 @@ class GuiProjectTree(QTreeWidget):
if dlgSplit.result() == QDialog.Accepted:
print(dlgSplit.getData())
splitData, splitText = dlgSplit.getData()
print(splitData)
headerList = splitData.get("headerList", [])
docSplit = DocSplitter(self.theProject, tHandle)
docSplit.setParentItem(tItem.itemParent)
docSplit.splitDocument(headerList, splitText)
for dHandle, _, nHandle in docSplit.writeDocuments():
self.mainGui.projView.revealNewTreeItem(dHandle, nHandle)
self._alertTreeChange(dHandle, flush=False)
else:
logger.info("Action cancelled by user")