"""
novelWriter – GUI Doc Split Dialog
==================================
Custom dialog class for splitting documents.
File History:
Created: 2020-02-01 [0.4.3]
Rewritten: 2022-10-12 [2.0b1]
This file is a part of novelWriter
Copyright 2018–2022, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
import logging
import novelwriter
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QComboBox, QListWidget, QAbstractItemView,
QListWidgetItem, QDialogButtonBox, QLabel, QGridLayout
)
from novelwriter.core import NWDoc
from novelwriter.custom import QHelpLabel, QSwitch
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)
logger.debug("Initialising GuiDocSplit ...")
self.setObjectName("GuiDocSplit")
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._data = {}
self._text = []
self.setWindowTitle(self.tr("Split Document"))
self.headLabel = QLabel("{0}".format(self.tr("Document Headers")))
self.helpLabel = QHelpLabel(
self.tr("Select the maximum level to split into files."),
self.mainGui.mainTheme.helpText
)
# Values
iPx = self.mainTheme.baseIconSize
hSp = self.mainConf.pxInt(12)
vSp = self.mainConf.pxInt(8)
bSp = self.mainConf.pxInt(12)
pOptions = self.theProject.options
spLevel = pOptions.getInt("GuiDocSplit", "spLevel", 3)
intoFolder = pOptions.getBool("GuiDocSplit", "intoFolder", True)
docHierarchy = pOptions.getBool("GuiDocSplit", "docHierarchy", True)
# Header Selection
self.listBox = QListWidget()
self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop)
self.listBox.setMinimumWidth(self.mainConf.pxInt(400))
self.listBox.setMinimumHeight(self.mainConf.pxInt(180))
self.splitLevel = QComboBox(self)
self.splitLevel.addItem(self.tr("Split on Header Level 1 (Title)"), 1)
self.splitLevel.addItem(self.tr("Split up to Header Level 2 (Chapter)"), 2)
self.splitLevel.addItem(self.tr("Split up to Header Level 3 (Scene)"), 3)
self.splitLevel.addItem(self.tr("Split up to Header Level 4 (Section)"), 4)
spIndex = self.splitLevel.findData(spLevel)
if spIndex != -1:
self.splitLevel.setCurrentIndex(spIndex)
self.splitLevel.currentIndexChanged.connect(self._reloadList)
# Split Options
self.folderLabel = QLabel(self.tr("Split into a new folder"))
self.folderSwitch = QSwitch(width=2*iPx, height=iPx)
self.folderSwitch.setChecked(intoFolder)
self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"))
self.hierarchySwitch = QSwitch(width=2*iPx, height=iPx)
self.hierarchySwitch.setChecked(docHierarchy)
self.trashLabel = QLabel(self.tr("Move split document to Trash"))
self.trashSwitch = QSwitch(width=2*iPx, height=iPx)
self.optBox = QGridLayout()
self.optBox.addWidget(self.folderLabel, 0, 0)
self.optBox.addWidget(self.folderSwitch, 0, 1)
self.optBox.addWidget(self.hierarchyLabel, 1, 0)
self.optBox.addWidget(self.hierarchySwitch, 1, 1)
self.optBox.addWidget(self.trashLabel, 2, 0)
self.optBox.addWidget(self.trashSwitch, 2, 1)
self.optBox.setVerticalSpacing(vSp)
self.optBox.setHorizontalSpacing(hSp)
self.optBox.setColumnStretch(3, 1)
# Buttons
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
# Assemble
self.outerBox = QVBoxLayout()
self.outerBox.setSpacing(0)
self.outerBox.addWidget(self.headLabel)
self.outerBox.addWidget(self.helpLabel)
self.outerBox.addSpacing(vSp)
self.outerBox.addWidget(self.listBox)
self.outerBox.addWidget(self.splitLevel)
self.outerBox.addSpacing(vSp)
self.outerBox.addLayout(self.optBox)
self.outerBox.addSpacing(bSp)
self.outerBox.addWidget(self.buttonBox)
self.setLayout(self.outerBox)
# Load Content
self._loadContent(sHandle)
logger.debug("GuiDocSplit initialisation complete")
return
def getData(self):
"""Return the user's choices. Also save the users options for
the next time the dialog is used.
"""
headerList = []
for i in range(self.listBox.count()):
item = self.listBox.item(i)
if item is not None:
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()
docHierarchy = self.hierarchySwitch.isChecked()
moveToTrash = self.trashSwitch.isChecked()
self._data["spLevel"] = spLevel
self._data["headerList"] = headerList
self._data["intoFolder"] = intoFolder
self._data["docHierarchy"] = docHierarchy
self._data["moveToTrash"] = moveToTrash
pOptions = self.theProject.options
pOptions.setValue("GuiDocSplit", "spLevel", spLevel)
pOptions.setValue("GuiDocSplit", "intoFolder", intoFolder)
pOptions.setValue("GuiDocSplit", "docHierarchy", docHierarchy)
return self._data, self._text
##
# Slots
##
def _reloadList(self):
"""Reload the content of the list box.
"""
sHandle = self._data.get("sHandle", None)
self._loadContent(sHandle)
return
##
# Internal Functions
##
def _loadContent(self, sHandle):
"""Load content from a given source item.
"""
self._data = {}
self._data["sHandle"] = sHandle
self.listBox.clear()
nwItem = self.theProject.tree[sHandle]
if nwItem is None or not nwItem.isFileType():
return
spLevel = self.splitLevel.currentData()
if not self._text:
inDoc = NWDoc(self.theProject, sHandle)
self._text = (inDoc.readDocument() or "").splitlines()
for lineNo, aLine in enumerate(self._text):
onLine = -1
hLevel = 0
hLabel = aLine.strip()
if aLine.startswith("# ") and spLevel >= 1:
onLine = lineNo
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 and hLevel > 0:
newItem = QListWidgetItem()
newItem.setText(aLine.strip())
newItem.setData(self.LINE_ROLE, onLine)
newItem.setData(self.LEVEL_ROLE, hLevel)
newItem.setData(self.LABEL_ROLE, hLabel)
self.listBox.addItem(newItem)
return
# END Class GuiDocSplit