Add the core code for the DocSplitter tool
This commit is contained in:
@@ -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/>.
|
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.document import NWDoc
|
||||||
from novelwriter.core.index import countWords
|
from novelwriter.core.index import countWords
|
||||||
from novelwriter.core.project import NWProject
|
from novelwriter.core.project import NWProject
|
||||||
@@ -30,6 +30,7 @@ from novelwriter.core.tomd import ToMarkdown
|
|||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"DocMerger",
|
"DocMerger",
|
||||||
|
"DocSplitter",
|
||||||
"countWords",
|
"countWords",
|
||||||
"NWDoc",
|
"NWDoc",
|
||||||
"NWProject",
|
"NWProject",
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ novelWriter – Project Document Tools
|
|||||||
A collection of tools to create and manipulate documents
|
A collection of tools to create and manipulate documents
|
||||||
|
|
||||||
File History:
|
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
|
This file is a part of novelWriter
|
||||||
Copyright 2018–2022, Veronica Berglyd Olsen
|
Copyright 2018–2022, Veronica Berglyd Olsen
|
||||||
@@ -117,3 +118,90 @@ class DocMerger:
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
# END Class DocMerger
|
# 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
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class GuiDocSplit(QDialog):
|
class GuiDocSplit(QDialog):
|
||||||
|
|
||||||
|
LINE_ROLE = Qt.UserRole
|
||||||
|
LEVEL_ROLE = Qt.UserRole + 1
|
||||||
|
LABEL_ROLE = Qt.UserRole + 2
|
||||||
|
|
||||||
def __init__(self, mainGui, sHandle):
|
def __init__(self, mainGui, sHandle):
|
||||||
super().__init__(parent=mainGui)
|
super().__init__(parent=mainGui)
|
||||||
|
|
||||||
@@ -141,7 +145,9 @@ class GuiDocSplit(QDialog):
|
|||||||
headerList = []
|
headerList = []
|
||||||
for i in range(self.listBox.count()):
|
for i in range(self.listBox.count()):
|
||||||
item = self.listBox.item(i)
|
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()
|
spLevel = self.splitLevel.currentData()
|
||||||
intoFolder = self.folderSwitch.isChecked()
|
intoFolder = self.folderSwitch.isChecked()
|
||||||
@@ -157,7 +163,7 @@ class GuiDocSplit(QDialog):
|
|||||||
pOptions.setValue("GuiDocSplit", "intoFolder", intoFolder)
|
pOptions.setValue("GuiDocSplit", "intoFolder", intoFolder)
|
||||||
pOptions.setValue("GuiDocSplit", "docHierarchy", docHierarchy)
|
pOptions.setValue("GuiDocSplit", "docHierarchy", docHierarchy)
|
||||||
|
|
||||||
return self._data
|
return self._data, self._text
|
||||||
|
|
||||||
##
|
##
|
||||||
# Slots
|
# Slots
|
||||||
@@ -193,19 +199,38 @@ class GuiDocSplit(QDialog):
|
|||||||
for lineNo, aLine in enumerate(self._text):
|
for lineNo, aLine in enumerate(self._text):
|
||||||
|
|
||||||
onLine = -1
|
onLine = -1
|
||||||
if aLine.startswith(("# ", "#! ")) and spLevel >= 1:
|
hLevel = 0
|
||||||
|
if aLine.startswith("# ") and spLevel >= 1:
|
||||||
onLine = lineNo
|
onLine = lineNo
|
||||||
elif aLine.startswith(("## ", "##! ")) and spLevel >= 2:
|
hLevel = 1
|
||||||
|
hLabel = aLine[2:].strip()
|
||||||
|
elif aLine.startswith("## ") and spLevel >= 2:
|
||||||
onLine = lineNo
|
onLine = lineNo
|
||||||
|
hLevel = 2
|
||||||
|
hLabel = aLine[3:].strip()
|
||||||
elif aLine.startswith("### ") and spLevel >= 3:
|
elif aLine.startswith("### ") and spLevel >= 3:
|
||||||
onLine = lineNo
|
onLine = lineNo
|
||||||
|
hLevel = 3
|
||||||
|
hLabel = aLine[4:].strip()
|
||||||
elif aLine.startswith("#### ") and spLevel >= 4:
|
elif aLine.startswith("#### ") and spLevel >= 4:
|
||||||
onLine = lineNo
|
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 = QListWidgetItem()
|
||||||
newItem.setText(aLine.strip())
|
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)
|
self.listBox.addItem(newItem)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ from PyQt5.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter.core import DocMerger
|
from novelwriter.core import DocMerger
|
||||||
|
from novelwriter.core.doctools import DocSplitter
|
||||||
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert
|
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert
|
||||||
from novelwriter.dialogs import GuiDocMerge, GuiDocSplit, GuiEditLabel
|
from novelwriter.dialogs import GuiDocMerge, GuiDocSplit, GuiEditLabel
|
||||||
from novelwriter.constants import nwHeaders, trConst, nwLabels
|
from novelwriter.constants import nwHeaders, trConst, nwLabels
|
||||||
@@ -1475,7 +1476,18 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
|
|
||||||
if dlgSplit.result() == QDialog.Accepted:
|
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:
|
else:
|
||||||
logger.info("Action cancelled by user")
|
logger.info("Action cancelled by user")
|
||||||
|
|||||||
Reference in New Issue
Block a user