Merge branch 'main' into i18n-de_DE-created
This commit is contained in:
@@ -23,7 +23,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
@@ -44,7 +43,7 @@ logger = logging.getLogger(__name__)
|
||||
class GuiAbout(QDialog):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QDialog.__init__(self, mainGui)
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
logger.debug("Initialising GuiAbout ...")
|
||||
self.setObjectName("GuiAbout")
|
||||
@@ -234,7 +233,7 @@ class GuiAbout(QDialog):
|
||||
def _fillNotesPage(self):
|
||||
"""Load the content for the Release Notes page.
|
||||
"""
|
||||
docPath = os.path.join(self.mainConf.assetPath, "text", "release_notes.htm")
|
||||
docPath = self.mainConf.assetPath("text") / "release_notes.htm"
|
||||
docText = readTextFile(docPath)
|
||||
if docText:
|
||||
self.pageNotes.setHtml(docText)
|
||||
@@ -245,7 +244,7 @@ class GuiAbout(QDialog):
|
||||
def _fillLicensePage(self):
|
||||
"""Load the content for the Licence page.
|
||||
"""
|
||||
docPath = os.path.join(self.mainConf.assetPath, "text", "gplv3_en.htm")
|
||||
docPath = self.mainConf.assetPath("text") / "gplv3_en.htm"
|
||||
docText = readTextFile(docPath)
|
||||
if docText:
|
||||
self.pageLicense.setHtml(docText)
|
||||
|
||||
+88
-110
@@ -1,10 +1,11 @@
|
||||
"""
|
||||
novelWriter – GUI Doc Merge Tool
|
||||
================================
|
||||
GUI class for merging multiple documents to one document
|
||||
novelWriter – GUI Doc Merge Dialog
|
||||
==================================
|
||||
Custom dialog class for merging documents.
|
||||
|
||||
File History:
|
||||
Created: 2020-01-23 [0.4.3]
|
||||
Created: 2020-01-23 [0.4.3]
|
||||
Rewritten: 2022-10-06 [2.0b1]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2022, Veronica Berglyd Olsen
|
||||
@@ -26,169 +27,146 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtCore import Qt, QSize
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QLabel, QListWidget, QAbstractItemView,
|
||||
QListWidgetItem, QDialogButtonBox
|
||||
QAbstractItemView, QDialog, QDialogButtonBox, QGridLayout, QLabel,
|
||||
QListWidget, QListWidgetItem, QVBoxLayout,
|
||||
)
|
||||
|
||||
from novelwriter.core import NWDoc
|
||||
from novelwriter.enum import nwAlert, nwItemType
|
||||
from novelwriter.gui.custom import QHelpLabel
|
||||
from novelwriter.custom import QHelpLabel, QSwitch
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiDocMerge(QDialog):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QDialog.__init__(self, mainGui)
|
||||
def __init__(self, mainGui, sHandle, itemList):
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
logger.debug("Initialising GuiDocMerge ...")
|
||||
self.setObjectName("GuiDocMerge")
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.sourceItem = None
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self._data = {}
|
||||
|
||||
self.setWindowTitle(self.tr("Merge Documents"))
|
||||
|
||||
self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Documents to Merge")))
|
||||
self.helpLabel = QHelpLabel(
|
||||
self.tr("Drag and drop items to change the order."), self.mainGui.mainTheme.helpText
|
||||
)
|
||||
self.helpLabel = QHelpLabel(self.tr(
|
||||
"Drag and drop items to change the order, or uncheck to exclude."
|
||||
), self.mainTheme.helpText)
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
hSp = self.mainConf.pxInt(12)
|
||||
vSp = self.mainConf.pxInt(8)
|
||||
bSp = self.mainConf.pxInt(12)
|
||||
|
||||
self.listBox = QListWidget()
|
||||
self.listBox.setDragDropMode(QAbstractItemView.InternalMove)
|
||||
self.listBox.setIconSize(QSize(iPx, iPx))
|
||||
self.listBox.setMinimumWidth(self.mainConf.pxInt(400))
|
||||
self.listBox.setMinimumHeight(self.mainConf.pxInt(180))
|
||||
self.listBox.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.listBox.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
self.listBox.setDragDropMode(QAbstractItemView.InternalMove)
|
||||
|
||||
# Merge Options
|
||||
self.trashLabel = QLabel(self.tr("Move merged items to Trash"))
|
||||
self.trashSwitch = QSwitch(width=2*iPx, height=iPx)
|
||||
|
||||
self.optBox = QGridLayout()
|
||||
self.optBox.addWidget(self.trashLabel, 0, 0)
|
||||
self.optBox.addWidget(self.trashSwitch, 0, 1)
|
||||
self.optBox.setHorizontalSpacing(hSp)
|
||||
self.optBox.setColumnStretch(2, 1)
|
||||
|
||||
# Buttons
|
||||
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
self.buttonBox.accepted.connect(self._doMerge)
|
||||
self.buttonBox.rejected.connect(self._doClose)
|
||||
self.buttonBox.accepted.connect(self.accept)
|
||||
self.buttonBox.rejected.connect(self.reject)
|
||||
|
||||
self.resetButton = self.buttonBox.addButton(QDialogButtonBox.Reset)
|
||||
self.resetButton.clicked.connect(self._resetList)
|
||||
|
||||
# Assemble
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.outerBox.setSpacing(0)
|
||||
self.outerBox.addWidget(self.headLabel)
|
||||
self.outerBox.addWidget(self.helpLabel)
|
||||
self.outerBox.addSpacing(self.mainConf.pxInt(8))
|
||||
self.outerBox.addSpacing(vSp)
|
||||
self.outerBox.addWidget(self.listBox)
|
||||
self.outerBox.addSpacing(self.mainConf.pxInt(12))
|
||||
self.outerBox.addSpacing(vSp)
|
||||
self.outerBox.addLayout(self.optBox)
|
||||
self.outerBox.addSpacing(bSp)
|
||||
self.outerBox.addWidget(self.buttonBox)
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
self.rejected.connect(self._doClose)
|
||||
|
||||
self._populateList()
|
||||
# Load Content
|
||||
self._loadContent(sHandle, itemList)
|
||||
|
||||
logger.debug("GuiDocMerge initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Buttons
|
||||
##
|
||||
|
||||
def _doMerge(self):
|
||||
"""Perform the merge of the files in the selected folder, and
|
||||
create a new file in the same parent folder. The old files are
|
||||
not removed in the merge process, and must be deleted manually.
|
||||
def getData(self):
|
||||
"""Return the user's choices.
|
||||
"""
|
||||
logger.verbose("GuiDocMerge merge button clicked")
|
||||
|
||||
finalOrder = []
|
||||
finalItems = []
|
||||
for i in range(self.listBox.count()):
|
||||
finalOrder.append(self.listBox.item(i).data(Qt.UserRole))
|
||||
item = self.listBox.item(i)
|
||||
if item is not None and item.checkState() == Qt.Checked:
|
||||
finalItems.append(item.data(Qt.UserRole))
|
||||
|
||||
if len(finalOrder) == 0:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"No source documents found. Nothing to do."
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
self._data["moveToTrash"] = self.trashSwitch.isChecked()
|
||||
self._data["finalItems"] = finalItems
|
||||
|
||||
theText = ""
|
||||
for tHandle in finalOrder:
|
||||
inDoc = NWDoc(self.theProject, tHandle)
|
||||
docText = inDoc.readDocument()
|
||||
docErr = inDoc.getError()
|
||||
if docText is None and docErr:
|
||||
self.mainGui.makeAlert([
|
||||
self.tr("Failed to open document file."), docErr
|
||||
], nwAlert.ERROR)
|
||||
if docText:
|
||||
theText += docText.rstrip("\n")+"\n\n"
|
||||
return self._data
|
||||
|
||||
if self.sourceItem is None:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"No source folder selected. Nothing to do."
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
##
|
||||
# Slots
|
||||
##
|
||||
|
||||
srcItem = self.theProject.tree[self.sourceItem]
|
||||
if srcItem is None:
|
||||
self.mainGui.makeAlert(self.tr("Internal error."), nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
nHandle = self.theProject.newFile(srcItem.itemName, srcItem.itemParent)
|
||||
newItem = self.theProject.tree[nHandle]
|
||||
newItem.setStatus(srcItem.itemStatus)
|
||||
newItem.setImport(srcItem.itemImport)
|
||||
|
||||
outDoc = NWDoc(self.theProject, nHandle)
|
||||
if not outDoc.writeDocument(theText):
|
||||
self.mainGui.makeAlert([
|
||||
self.tr("Could not save document."), outDoc.getError()
|
||||
], nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
self.mainGui.projView.revealNewTreeItem(nHandle)
|
||||
self.mainGui.openDocument(nHandle, doScroll=True)
|
||||
|
||||
self._doClose()
|
||||
|
||||
return True
|
||||
|
||||
def _doClose(self):
|
||||
"""Close the dialog window without doing anything.
|
||||
def _resetList(self):
|
||||
"""Reset the content of the list box to its original state.
|
||||
"""
|
||||
self.close()
|
||||
logger.debug("Resetting list box content")
|
||||
sHandle = self._data.get("sHandle", None)
|
||||
itemList = self._data.get("origItems", [])
|
||||
self._loadContent(sHandle, itemList)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _populateList(self):
|
||||
"""Get the item selected in the tree, check that it is a folder,
|
||||
and try to find all files associated with it. The valid files
|
||||
are then added to the list view in order. The list itself can be
|
||||
reordered by the user.
|
||||
def _loadContent(self, sHandle, itemList):
|
||||
"""Load content from a given list of items.
|
||||
"""
|
||||
tHandle = self.mainGui.projView.getSelectedHandle()
|
||||
self.sourceItem = tHandle
|
||||
if tHandle is None:
|
||||
return False
|
||||
self._data = {}
|
||||
self._data["sHandle"] = sHandle
|
||||
self._data["origItems"] = itemList
|
||||
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
if nwItem is None:
|
||||
return False
|
||||
|
||||
if nwItem.itemType is not nwItemType.FOLDER:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Element selected in the project tree must be a folder."
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
for sHandle in self.mainGui.projView.getTreeFromHandle(tHandle):
|
||||
newItem = QListWidgetItem()
|
||||
nwItem = self.theProject.tree[sHandle]
|
||||
if nwItem.itemType is not nwItemType.FILE:
|
||||
self.listBox.clear()
|
||||
for tHandle in itemList:
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
if nwItem is None or not nwItem.isFileType():
|
||||
continue
|
||||
|
||||
itemIcon = self.mainTheme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, nwItem.mainHeading
|
||||
)
|
||||
|
||||
newItem = QListWidgetItem()
|
||||
newItem.setIcon(itemIcon)
|
||||
newItem.setText(nwItem.itemName)
|
||||
newItem.setData(Qt.UserRole, sHandle)
|
||||
newItem.setData(Qt.UserRole, tHandle)
|
||||
newItem.setCheckState(Qt.Checked)
|
||||
|
||||
self.listBox.addItem(newItem)
|
||||
|
||||
return True
|
||||
return
|
||||
|
||||
# END Class GuiDocMerge
|
||||
|
||||
+131
-160
@@ -1,10 +1,11 @@
|
||||
"""
|
||||
novelWriter – GUI Doc Split Tool
|
||||
================================
|
||||
GUI class for splitting a single document into multiple documents
|
||||
novelWriter – GUI Doc Split Dialog
|
||||
==================================
|
||||
Custom dialog class for splitting documents.
|
||||
|
||||
File History:
|
||||
Created: 2020-02-01 [0.4.3]
|
||||
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
|
||||
@@ -29,32 +30,34 @@ import novelwriter
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QComboBox, QListWidget, QAbstractItemView,
|
||||
QListWidgetItem, QDialogButtonBox, QLabel
|
||||
QListWidgetItem, QDialogButtonBox, QLabel, QGridLayout
|
||||
)
|
||||
|
||||
from novelwriter.core import NWDoc
|
||||
from novelwriter.enum import nwAlert, nwItemType
|
||||
from novelwriter.gui.custom import QHelpLabel
|
||||
from novelwriter.custom import QHelpLabel, QSwitch
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiDocSplit(QDialog):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QDialog.__init__(self, mainGui)
|
||||
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.sourceItem = None
|
||||
self.sourceText = []
|
||||
self._data = {}
|
||||
self._text = []
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.setWindowTitle(self.tr("Split Document"))
|
||||
|
||||
self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Document Headers")))
|
||||
@@ -63,6 +66,18 @@ class GuiDocSplit(QDialog):
|
||||
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))
|
||||
@@ -73,206 +88,162 @@ class GuiDocSplit(QDialog):
|
||||
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(
|
||||
self.theProject.options.getInt("GuiDocSplit", "spLevel", 3)
|
||||
)
|
||||
spIndex = self.splitLevel.findData(spLevel)
|
||||
if spIndex != -1:
|
||||
self.splitLevel.setCurrentIndex(spIndex)
|
||||
self.splitLevel.currentIndexChanged.connect(self._populateList)
|
||||
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._doSplit)
|
||||
self.buttonBox.rejected.connect(self._doClose)
|
||||
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(self.mainConf.pxInt(8))
|
||||
self.outerBox.addSpacing(vSp)
|
||||
self.outerBox.addWidget(self.listBox)
|
||||
self.outerBox.addWidget(self.splitLevel)
|
||||
self.outerBox.addSpacing(self.mainConf.pxInt(12))
|
||||
self.outerBox.addSpacing(vSp)
|
||||
self.outerBox.addLayout(self.optBox)
|
||||
self.outerBox.addSpacing(bSp)
|
||||
self.outerBox.addWidget(self.buttonBox)
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
self.rejected.connect(self._doClose)
|
||||
|
||||
self._populateList()
|
||||
# Load Content
|
||||
self._loadContent(sHandle)
|
||||
|
||||
logger.debug("GuiDocSplit initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Buttons
|
||||
##
|
||||
|
||||
def _doSplit(self):
|
||||
"""Perform the split of the file, create a new folder in the
|
||||
same parent folder, and multiple files depending on split level
|
||||
settings. The old file is not removed in the split process, and
|
||||
must be deleted manually.
|
||||
def getData(self):
|
||||
"""Return the user's choices. Also save the users options for
|
||||
the next time the dialog is used.
|
||||
"""
|
||||
logger.verbose("GuiDocSplit split button clicked")
|
||||
|
||||
if self.sourceItem is None:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"No source document selected. Nothing to do."
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
srcItem = self.theProject.tree[self.sourceItem]
|
||||
if srcItem is None:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Could not parse source document."
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
inDoc = NWDoc(self.theProject, self.sourceItem)
|
||||
theText = inDoc.readDocument()
|
||||
|
||||
docErr = inDoc.getError()
|
||||
if theText is None and docErr:
|
||||
self.mainGui.makeAlert([
|
||||
self.tr("Failed to open document file."), docErr
|
||||
], nwAlert.ERROR)
|
||||
|
||||
if theText is None:
|
||||
theText = ""
|
||||
|
||||
nLines = len(self.sourceText)
|
||||
logger.debug("Splitting document %s with %d lines", self.sourceItem, nLines)
|
||||
|
||||
finalOrder = []
|
||||
headerList = []
|
||||
for i in range(self.listBox.count()):
|
||||
listItem = self.listBox.item(i)
|
||||
wTitle = listItem.text()
|
||||
lineNo = listItem.data(Qt.UserRole)
|
||||
finalOrder.append([wTitle, lineNo, nLines])
|
||||
if i > 0:
|
||||
finalOrder[i-1][2] = lineNo
|
||||
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),
|
||||
))
|
||||
|
||||
nFiles = len(finalOrder)
|
||||
if nFiles == 0:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"No headers found. Nothing to do."
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
spLevel = self.splitLevel.currentData()
|
||||
intoFolder = self.folderSwitch.isChecked()
|
||||
docHierarchy = self.hierarchySwitch.isChecked()
|
||||
moveToTrash = self.trashSwitch.isChecked()
|
||||
|
||||
msgYes = self.mainGui.askQuestion(
|
||||
self.tr("Split Document"),
|
||||
"{0}<br><br>{1}".format(
|
||||
self.tr(
|
||||
"The document will be split into {0} file(s) in a new folder. "
|
||||
"The original document will remain intact."
|
||||
).format(nFiles),
|
||||
self.tr(
|
||||
"Continue with the splitting process?"
|
||||
)
|
||||
)
|
||||
)
|
||||
if not msgYes:
|
||||
return False
|
||||
self._data["spLevel"] = spLevel
|
||||
self._data["headerList"] = headerList
|
||||
self._data["intoFolder"] = intoFolder
|
||||
self._data["docHierarchy"] = docHierarchy
|
||||
self._data["moveToTrash"] = moveToTrash
|
||||
|
||||
# Create the folder
|
||||
fHandle = self.theProject.newFolder(srcItem.itemName, srcItem.itemParent)
|
||||
self.mainGui.projView.revealNewTreeItem(fHandle)
|
||||
logger.verbose("Creating folder '%s'", fHandle)
|
||||
pOptions = self.theProject.options
|
||||
pOptions.setValue("GuiDocSplit", "spLevel", spLevel)
|
||||
pOptions.setValue("GuiDocSplit", "intoFolder", intoFolder)
|
||||
pOptions.setValue("GuiDocSplit", "docHierarchy", docHierarchy)
|
||||
|
||||
# Loop through, and create the files
|
||||
for wTitle, iStart, iEnd in finalOrder:
|
||||
return self._data, self._text
|
||||
|
||||
wTitle = wTitle.lstrip("#").strip()
|
||||
nHandle = self.theProject.newFile(wTitle, fHandle)
|
||||
newItem = self.theProject.tree[nHandle]
|
||||
newItem.setStatus(srcItem.itemStatus)
|
||||
newItem.setImport(srcItem.itemImport)
|
||||
logger.verbose(
|
||||
"Creating new document '%s' with text from line %d to %d",
|
||||
nHandle, iStart+1, iEnd
|
||||
)
|
||||
##
|
||||
# Slots
|
||||
##
|
||||
|
||||
theText = "\n".join(self.sourceText[iStart:iEnd])
|
||||
theText = theText.rstrip("\n") + "\n\n"
|
||||
|
||||
outDoc = NWDoc(self.theProject, nHandle)
|
||||
if not outDoc.writeDocument(theText):
|
||||
self.mainGui.makeAlert([
|
||||
self.tr("Could not save document."), outDoc.getError()
|
||||
], nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
self.mainGui.projView.revealNewTreeItem(nHandle)
|
||||
|
||||
self._doClose()
|
||||
|
||||
return True
|
||||
|
||||
def _doClose(self):
|
||||
"""Close the dialog window without doing anything.
|
||||
def _reloadList(self):
|
||||
"""Reload the content of the list box.
|
||||
"""
|
||||
self.theProject.options.saveSettings()
|
||||
self.close()
|
||||
sHandle = self._data.get("sHandle", None)
|
||||
self._loadContent(sHandle)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _populateList(self):
|
||||
"""Get the item selected in the tree, check that it is a folder,
|
||||
and try to find all files associated with it. The valid files
|
||||
are then added to the list view in order. The list itself can be
|
||||
reordered by the user.
|
||||
def _loadContent(self, sHandle):
|
||||
"""Load content from a given source item.
|
||||
"""
|
||||
self._data = {}
|
||||
self._data["sHandle"] = sHandle
|
||||
|
||||
self.listBox.clear()
|
||||
if self.sourceItem is None:
|
||||
self.sourceItem = self.mainGui.projView.getSelectedHandle()
|
||||
|
||||
if self.sourceItem is None:
|
||||
return False
|
||||
|
||||
nwItem = self.theProject.tree[self.sourceItem]
|
||||
if nwItem is None:
|
||||
return False
|
||||
|
||||
if nwItem.itemType is not nwItemType.FILE:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Element selected in the project tree must be a file."
|
||||
), nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
inDoc = NWDoc(self.theProject, self.sourceItem)
|
||||
theText = inDoc.readDocument()
|
||||
if theText is None:
|
||||
theText = ""
|
||||
return False
|
||||
nwItem = self.theProject.tree[sHandle]
|
||||
if nwItem is None or not nwItem.isFileType():
|
||||
return
|
||||
|
||||
spLevel = self.splitLevel.currentData()
|
||||
self.theProject.options.setValue("GuiDocSplit", "spLevel", spLevel)
|
||||
logger.debug(
|
||||
"Scanning document '%s' for headings level <= %d",
|
||||
self.sourceItem, spLevel
|
||||
)
|
||||
if not self._text:
|
||||
inDoc = self.theProject.storage.getDocument(sHandle)
|
||||
self._text = (inDoc.readDocument() or "").splitlines()
|
||||
|
||||
self.sourceText = theText.splitlines()
|
||||
for lineNo, aLine in enumerate(self.sourceText):
|
||||
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:
|
||||
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
|
||||
return
|
||||
|
||||
# END Class GuiDocSplit
|
||||
|
||||
@@ -36,7 +36,7 @@ logger = logging.getLogger(__name__)
|
||||
class GuiEditLabel(QDialog):
|
||||
|
||||
def __init__(self, parent, text=""):
|
||||
QDialog.__init__(self, parent=parent)
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.setObjectName("GuiEditLabel")
|
||||
self.setWindowTitle(self.tr("Item Label"))
|
||||
|
||||
+100
-125
@@ -23,7 +23,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
@@ -34,8 +33,7 @@ from PyQt5.QtWidgets import (
|
||||
QLineEdit, QFileDialog, QFontDialog, QDoubleSpinBox
|
||||
)
|
||||
|
||||
from novelwriter.enum import nwAlert
|
||||
from novelwriter.gui.custom import QSwitch, QConfigLayout, PagedDialog
|
||||
from novelwriter.custom import QSwitch, QConfigLayout, PagedDialog
|
||||
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -44,7 +42,7 @@ logger = logging.getLogger(__name__)
|
||||
class GuiPreferences(PagedDialog):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
PagedDialog.__init__(self, mainGui)
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
logger.debug("Initialising GuiPreferences ...")
|
||||
self.setObjectName("GuiPreferences")
|
||||
@@ -55,13 +53,13 @@ class GuiPreferences(PagedDialog):
|
||||
|
||||
self.setWindowTitle(self.tr("Preferences"))
|
||||
|
||||
self.tabGeneral = GuiPreferencesGeneral(self.mainGui)
|
||||
self.tabProjects = GuiPreferencesProjects(self.mainGui)
|
||||
self.tabDocs = GuiPreferencesDocuments(self.mainGui)
|
||||
self.tabEditor = GuiPreferencesEditor(self.mainGui)
|
||||
self.tabSyntax = GuiPreferencesSyntax(self.mainGui)
|
||||
self.tabAuto = GuiPreferencesAutomation(self.mainGui)
|
||||
self.tabQuote = GuiPreferencesQuotes(self.mainGui)
|
||||
self.tabGeneral = GuiPreferencesGeneral(self)
|
||||
self.tabProjects = GuiPreferencesProjects(self)
|
||||
self.tabDocs = GuiPreferencesDocuments(self)
|
||||
self.tabEditor = GuiPreferencesEditor(self)
|
||||
self.tabSyntax = GuiPreferencesSyntax(self)
|
||||
self.tabAuto = GuiPreferencesAutomation(self)
|
||||
self.tabQuote = GuiPreferencesQuotes(self)
|
||||
|
||||
self.addTab(self.tabGeneral, self.tr("General"))
|
||||
self.addTab(self.tabProjects, self.tr("Projects"))
|
||||
@@ -76,12 +74,38 @@ class GuiPreferences(PagedDialog):
|
||||
self.buttonBox.rejected.connect(self._doClose)
|
||||
self.addControls(self.buttonBox)
|
||||
|
||||
self.resize(*self.mainConf.getPreferencesSize())
|
||||
self.resize(*self.mainConf.preferencesWinSize)
|
||||
|
||||
# Settings
|
||||
self._updateTheme = False
|
||||
self._updateSyntax = False
|
||||
self._needsRestart = False
|
||||
self._refreshTree = False
|
||||
|
||||
logger.debug("GuiPreferences initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def updateTheme(self):
|
||||
return self._updateTheme
|
||||
|
||||
@property
|
||||
def updateSyntax(self):
|
||||
return self._updateSyntax
|
||||
|
||||
@property
|
||||
def needsRestart(self):
|
||||
return self._needsRestart
|
||||
|
||||
@property
|
||||
def refreshTree(self):
|
||||
return self._refreshTree
|
||||
|
||||
##
|
||||
# Slots
|
||||
##
|
||||
@@ -92,8 +116,7 @@ class GuiPreferences(PagedDialog):
|
||||
"""
|
||||
logger.debug("Saving new preferences")
|
||||
|
||||
needsRestart, refreshTree = self.tabGeneral.saveValues()
|
||||
|
||||
self.tabGeneral.saveValues()
|
||||
self.tabProjects.saveValues()
|
||||
self.tabDocs.saveValues()
|
||||
self.tabEditor.saveValues()
|
||||
@@ -101,15 +124,8 @@ class GuiPreferences(PagedDialog):
|
||||
self.tabAuto.saveValues()
|
||||
self.tabQuote.saveValues()
|
||||
|
||||
if needsRestart:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Some changes will not be applied until novelWriter has been restarted."
|
||||
), nwAlert.INFO)
|
||||
|
||||
if refreshTree:
|
||||
self.mainGui.projView.populateTree()
|
||||
|
||||
self._saveWindowSize()
|
||||
self.mainConf.saveConfig()
|
||||
self.accept()
|
||||
|
||||
return
|
||||
@@ -128,9 +144,7 @@ class GuiPreferences(PagedDialog):
|
||||
def _saveWindowSize(self):
|
||||
"""Save the dialog window size.
|
||||
"""
|
||||
winWidth = self.mainConf.rpxInt(self.width())
|
||||
winHeight = self.mainConf.rpxInt(self.height())
|
||||
self.mainConf.setPreferencesSize(winWidth, winHeight)
|
||||
self.mainConf.setPreferencesWinSize(self.width(), self.height())
|
||||
return
|
||||
|
||||
# END Class GuiPreferences
|
||||
@@ -138,12 +152,13 @@ class GuiPreferences(PagedDialog):
|
||||
|
||||
class GuiPreferencesGeneral(QWidget):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.prefsGui = prefsGui
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = QConfigLayout()
|
||||
@@ -156,19 +171,19 @@ class GuiPreferencesGeneral(QWidget):
|
||||
minWidth = self.mainConf.pxInt(200)
|
||||
|
||||
# Select Locale
|
||||
self.guiLang = QComboBox()
|
||||
self.guiLang.setMinimumWidth(minWidth)
|
||||
self.guiLocale = QComboBox()
|
||||
self.guiLocale.setMinimumWidth(minWidth)
|
||||
theLangs = self.mainConf.listLanguages(self.mainConf.LANG_NW)
|
||||
for lang, langName in theLangs:
|
||||
self.guiLang.addItem(langName, lang)
|
||||
langIdx = self.guiLang.findData(self.mainConf.guiLang)
|
||||
self.guiLocale.addItem(langName, lang)
|
||||
langIdx = self.guiLocale.findData(self.mainConf.guiLocale)
|
||||
if langIdx != -1:
|
||||
self.guiLang.setCurrentIndex(langIdx)
|
||||
self.guiLocale.setCurrentIndex(langIdx)
|
||||
|
||||
self.mainForm.addRow(
|
||||
self.tr("Main GUI language"),
|
||||
self.guiLang,
|
||||
self.tr("Requires restart.")
|
||||
self.guiLocale,
|
||||
self.tr("Requires restart to take effect.")
|
||||
)
|
||||
|
||||
# Select Theme
|
||||
@@ -184,23 +199,7 @@ class GuiPreferencesGeneral(QWidget):
|
||||
self.mainForm.addRow(
|
||||
self.tr("Main GUI theme"),
|
||||
self.guiTheme,
|
||||
self.tr("Requires restart.")
|
||||
)
|
||||
|
||||
# Select Icon Theme
|
||||
self.guiIcons = QComboBox()
|
||||
self.guiIcons.setMinimumWidth(minWidth)
|
||||
self.iconCache = self.mainTheme.iconCache.listThemes()
|
||||
for iconDir, iconName in self.iconCache:
|
||||
self.guiIcons.addItem(iconName, iconDir)
|
||||
iconIdx = self.guiIcons.findData(self.mainConf.guiIcons)
|
||||
if iconIdx != -1:
|
||||
self.guiIcons.setCurrentIndex(iconIdx)
|
||||
|
||||
self.mainForm.addRow(
|
||||
self.tr("Main icon theme"),
|
||||
self.guiIcons,
|
||||
self.tr("Requires restart.")
|
||||
self.tr("General colour theme and icons.")
|
||||
)
|
||||
|
||||
# Editor Theme
|
||||
@@ -230,7 +229,7 @@ class GuiPreferencesGeneral(QWidget):
|
||||
self.mainForm.addRow(
|
||||
self.tr("Font family"),
|
||||
self.guiFont,
|
||||
self.tr("Requires restart."),
|
||||
self.tr("Requires restart to take effect."),
|
||||
theButton=self.fontButton
|
||||
)
|
||||
|
||||
@@ -243,7 +242,7 @@ class GuiPreferencesGeneral(QWidget):
|
||||
self.mainForm.addRow(
|
||||
self.tr("Font size"),
|
||||
self.guiFontSize,
|
||||
self.tr("Requires restart."),
|
||||
self.tr("Requires restart to take effect."),
|
||||
theUnit=self.tr("pt")
|
||||
)
|
||||
|
||||
@@ -288,29 +287,23 @@ class GuiPreferencesGeneral(QWidget):
|
||||
def saveValues(self):
|
||||
"""Save the values set for this tab.
|
||||
"""
|
||||
guiLang = self.guiLang.currentData()
|
||||
guiLocale = self.guiLocale.currentData()
|
||||
guiTheme = self.guiTheme.currentData()
|
||||
guiIcons = self.guiIcons.currentData()
|
||||
guiSyntax = self.guiSyntax.currentData()
|
||||
guiFont = self.guiFont.text()
|
||||
guiFontSize = self.guiFontSize.value()
|
||||
emphLabels = self.emphLabels.isChecked()
|
||||
|
||||
# Check if restart is needed
|
||||
needsRestart = False
|
||||
needsRestart |= self.mainConf.guiLang != guiLang
|
||||
needsRestart |= self.mainConf.guiTheme != guiTheme
|
||||
needsRestart |= self.mainConf.guiIcons != guiIcons
|
||||
needsRestart |= self.mainConf.guiFont != guiFont
|
||||
needsRestart |= self.mainConf.guiFontSize != guiFontSize
|
||||
# Update Flags
|
||||
self.prefsGui._updateTheme |= self.mainConf.guiTheme != guiTheme
|
||||
self.prefsGui._updateSyntax |= self.mainConf.guiSyntax != guiSyntax
|
||||
self.prefsGui._needsRestart |= self.mainConf.guiLocale != guiLocale
|
||||
self.prefsGui._needsRestart |= self.mainConf.guiFont != guiFont
|
||||
self.prefsGui._needsRestart |= self.mainConf.guiFontSize != guiFontSize
|
||||
self.prefsGui._refreshTree |= self.mainConf.emphLabels != emphLabels
|
||||
|
||||
# Check if refreshing project tree is needed
|
||||
refreshTree = False
|
||||
refreshTree |= self.mainConf.emphLabels != emphLabels
|
||||
|
||||
self.mainConf.guiLang = guiLang
|
||||
self.mainConf.guiLocale = guiLocale
|
||||
self.mainConf.guiTheme = guiTheme
|
||||
self.mainConf.guiIcons = guiIcons
|
||||
self.mainConf.guiSyntax = guiSyntax
|
||||
self.mainConf.guiFont = guiFont
|
||||
self.mainConf.guiFontSize = guiFontSize
|
||||
@@ -319,9 +312,7 @@ class GuiPreferencesGeneral(QWidget):
|
||||
self.mainConf.hideVScroll = self.hideVScroll.isChecked()
|
||||
self.mainConf.hideHScroll = self.hideHScroll.isChecked()
|
||||
|
||||
self.mainConf.confChanged = True
|
||||
|
||||
return needsRestart, refreshTree
|
||||
return
|
||||
|
||||
##
|
||||
# Slots
|
||||
@@ -344,12 +335,12 @@ class GuiPreferencesGeneral(QWidget):
|
||||
|
||||
class GuiPreferencesProjects(QWidget):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = QConfigLayout()
|
||||
@@ -391,7 +382,7 @@ class GuiPreferencesProjects(QWidget):
|
||||
self.mainForm.addGroupLabel(self.tr("Project Backup"))
|
||||
|
||||
# Backup Path
|
||||
self.backupPath = self.mainConf.backupPath
|
||||
self.backupPath = self.mainConf.backupPath()
|
||||
self.backupGetPath = QPushButton(self.tr("Browse"))
|
||||
self.backupGetPath.clicked.connect(self._backupFolder)
|
||||
self.backupPathRow = self.mainForm.addRow(
|
||||
@@ -458,7 +449,7 @@ class GuiPreferencesProjects(QWidget):
|
||||
self.mainConf.autoSaveProj = self.autoSaveProj.value()
|
||||
|
||||
# Project Backup
|
||||
self.mainConf.backupPath = self.backupPath
|
||||
self.mainConf.setBackupPath(self.backupPath)
|
||||
self.mainConf.backupOnClose = self.backupOnClose.isChecked()
|
||||
self.mainConf.askBeforeBackup = self.askBeforeBackup.isChecked()
|
||||
|
||||
@@ -466,8 +457,6 @@ class GuiPreferencesProjects(QWidget):
|
||||
self.mainConf.stopWhenIdle = self.stopWhenIdle.isChecked()
|
||||
self.mainConf.userIdleTime = round(self.userIdleTime.value() * 60)
|
||||
|
||||
self.mainConf.confChanged = True
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
@@ -477,12 +466,9 @@ class GuiPreferencesProjects(QWidget):
|
||||
def _backupFolder(self):
|
||||
"""Open a dialog to select the backup folder.
|
||||
"""
|
||||
currDir = self.backupPath
|
||||
if not os.path.isdir(currDir):
|
||||
currDir = ""
|
||||
|
||||
currDir = self.backupPath or ""
|
||||
newDir = QFileDialog.getExistingDirectory(
|
||||
self, self.tr("Backup Directory"), currDir, options=QFileDialog.ShowDirsOnly
|
||||
self, self.tr("Backup Directory"), str(currDir), options=QFileDialog.ShowDirsOnly
|
||||
)
|
||||
if newDir:
|
||||
self.backupPath = newDir
|
||||
@@ -505,12 +491,12 @@ class GuiPreferencesProjects(QWidget):
|
||||
|
||||
class GuiPreferencesDocuments(QWidget):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = QConfigLayout()
|
||||
@@ -640,8 +626,6 @@ class GuiPreferencesDocuments(QWidget):
|
||||
self.mainConf.textMargin = self.textMargin.value()
|
||||
self.mainConf.tabWidth = self.tabWidth.value()
|
||||
|
||||
self.mainConf.confChanged = True
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
@@ -666,12 +650,12 @@ class GuiPreferencesDocuments(QWidget):
|
||||
|
||||
class GuiPreferencesEditor(QWidget):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = QConfigLayout()
|
||||
@@ -831,8 +815,6 @@ class GuiPreferencesEditor(QWidget):
|
||||
self.mainConf.autoScroll = self.autoScroll.isChecked()
|
||||
self.mainConf.autoScrollPos = self.autoScrollPos.value()
|
||||
|
||||
self.mainConf.confChanged = True
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiPreferencesEditor
|
||||
@@ -840,12 +822,12 @@ class GuiPreferencesEditor(QWidget):
|
||||
|
||||
class GuiPreferencesSyntax(QWidget):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = QConfigLayout()
|
||||
@@ -922,8 +904,6 @@ class GuiPreferencesSyntax(QWidget):
|
||||
# Text Errors
|
||||
self.mainConf.showMultiSpaces = self.showMultiSpaces.isChecked()
|
||||
|
||||
self.mainConf.confChanged = True
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
@@ -943,12 +923,12 @@ class GuiPreferencesSyntax(QWidget):
|
||||
|
||||
class GuiPreferencesAutomation(QWidget):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = QConfigLayout()
|
||||
@@ -1076,8 +1056,6 @@ class GuiPreferencesAutomation(QWidget):
|
||||
self.mainConf.fmtPadAfter = self.fmtPadAfter.text().strip()
|
||||
self.mainConf.fmtPadThin = self.fmtPadThin.isChecked()
|
||||
|
||||
self.mainConf.confChanged = True
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
@@ -1100,12 +1078,12 @@ class GuiPreferencesAutomation(QWidget):
|
||||
|
||||
class GuiPreferencesQuotes(QWidget):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = QConfigLayout()
|
||||
@@ -1126,7 +1104,7 @@ class GuiPreferencesQuotes(QWidget):
|
||||
self.quoteSym["SO"].setReadOnly(True)
|
||||
self.quoteSym["SO"].setFixedWidth(qWidth)
|
||||
self.quoteSym["SO"].setAlignment(Qt.AlignCenter)
|
||||
self.quoteSym["SO"].setText(self.mainConf.fmtSingleQuotes[0])
|
||||
self.quoteSym["SO"].setText(self.mainConf.fmtSQuoteOpen)
|
||||
self.btnSingleStyleO = QPushButton("...")
|
||||
self.btnSingleStyleO.setMaximumWidth(bWidth)
|
||||
self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO"))
|
||||
@@ -1142,7 +1120,7 @@ class GuiPreferencesQuotes(QWidget):
|
||||
self.quoteSym["SC"].setReadOnly(True)
|
||||
self.quoteSym["SC"].setFixedWidth(qWidth)
|
||||
self.quoteSym["SC"].setAlignment(Qt.AlignCenter)
|
||||
self.quoteSym["SC"].setText(self.mainConf.fmtSingleQuotes[1])
|
||||
self.quoteSym["SC"].setText(self.mainConf.fmtSQuoteClose)
|
||||
self.btnSingleStyleC = QPushButton("...")
|
||||
self.btnSingleStyleC.setMaximumWidth(bWidth)
|
||||
self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC"))
|
||||
@@ -1159,7 +1137,7 @@ class GuiPreferencesQuotes(QWidget):
|
||||
self.quoteSym["DO"].setReadOnly(True)
|
||||
self.quoteSym["DO"].setFixedWidth(qWidth)
|
||||
self.quoteSym["DO"].setAlignment(Qt.AlignCenter)
|
||||
self.quoteSym["DO"].setText(self.mainConf.fmtDoubleQuotes[0])
|
||||
self.quoteSym["DO"].setText(self.mainConf.fmtDQuoteOpen)
|
||||
self.btnDoubleStyleO = QPushButton("...")
|
||||
self.btnDoubleStyleO.setMaximumWidth(bWidth)
|
||||
self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO"))
|
||||
@@ -1175,7 +1153,7 @@ class GuiPreferencesQuotes(QWidget):
|
||||
self.quoteSym["DC"].setReadOnly(True)
|
||||
self.quoteSym["DC"].setFixedWidth(qWidth)
|
||||
self.quoteSym["DC"].setAlignment(Qt.AlignCenter)
|
||||
self.quoteSym["DC"].setText(self.mainConf.fmtDoubleQuotes[1])
|
||||
self.quoteSym["DC"].setText(self.mainConf.fmtDQuoteClose)
|
||||
self.btnDoubleStyleC = QPushButton("...")
|
||||
self.btnDoubleStyleC.setMaximumWidth(bWidth)
|
||||
self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC"))
|
||||
@@ -1192,13 +1170,10 @@ class GuiPreferencesQuotes(QWidget):
|
||||
"""Save the values set for this tab.
|
||||
"""
|
||||
# Quotation Style
|
||||
self.mainConf.fmtSingleQuotes[0] = self.quoteSym["SO"].text()
|
||||
self.mainConf.fmtSingleQuotes[1] = self.quoteSym["SC"].text()
|
||||
self.mainConf.fmtDoubleQuotes[0] = self.quoteSym["DO"].text()
|
||||
self.mainConf.fmtDoubleQuotes[1] = self.quoteSym["DC"].text()
|
||||
|
||||
self.mainConf.confChanged = True
|
||||
|
||||
self.mainConf.fmtSQuoteOpen = self.quoteSym["SO"].text()
|
||||
self.mainConf.fmtSQuoteClose = self.quoteSym["SC"].text()
|
||||
self.mainConf.fmtDQuoteOpen = self.quoteSym["DO"].text()
|
||||
self.mainConf.fmtDQuoteClose = self.quoteSym["DC"].text()
|
||||
return
|
||||
|
||||
##
|
||||
|
||||
@@ -27,16 +27,18 @@ import math
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from PyQt5.QtCore import Qt, QSize
|
||||
from PyQt5.QtCore import Qt, QSize, pyqtSlot
|
||||
from PyQt5.QtGui import QFont
|
||||
from PyQt5.QtWidgets import (
|
||||
QWidget, QDialogButtonBox, QVBoxLayout, QTreeWidget, QTreeWidgetItem,
|
||||
QLabel, QSpinBox, QGridLayout, QHBoxLayout, QLineEdit, QAbstractItemView
|
||||
QAbstractItemView, QComboBox, QDialogButtonBox, QGridLayout, QHBoxLayout,
|
||||
QLabel, QLineEdit, QSpinBox, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
|
||||
QWidget
|
||||
)
|
||||
|
||||
from novelwriter.enum import nwItemClass
|
||||
from novelwriter.common import numberToRoman
|
||||
from novelwriter.constants import nwUnicode
|
||||
from novelwriter.gui.custom import PagedDialog, QSwitch
|
||||
from novelwriter.custom import PagedDialog, QSwitch
|
||||
from novelwriter.constants import nwLabels, nwUnicode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -44,7 +46,7 @@ logger = logging.getLogger(__name__)
|
||||
class GuiProjectDetails(PagedDialog):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
PagedDialog.__init__(self, mainGui)
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
logger.debug("Initialising GuiProjectDetails ...")
|
||||
self.setObjectName("GuiProjectDetails")
|
||||
@@ -140,7 +142,7 @@ class GuiProjectDetails(PagedDialog):
|
||||
class GuiProjectDetailsMain(QWidget):
|
||||
|
||||
def __init__(self, mainGui, theProject):
|
||||
QWidget.__init__(self, mainGui)
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theProject = theProject
|
||||
@@ -155,7 +157,7 @@ class GuiProjectDetailsMain(QWidget):
|
||||
# Header
|
||||
# ======
|
||||
|
||||
self.bookTitle = QLabel(self.theProject.bookTitle)
|
||||
self.bookTitle = QLabel(self.theProject.data.title)
|
||||
bookFont = self.bookTitle.font()
|
||||
bookFont.setPointSizeF(2.2*fPt)
|
||||
bookFont.setWeight(QFont.Bold)
|
||||
@@ -164,7 +166,7 @@ class GuiProjectDetailsMain(QWidget):
|
||||
self.bookTitle.setWordWrap(True)
|
||||
|
||||
self.projName = QLabel(
|
||||
self.tr("Working Title: {0}").format(self.theProject.projName)
|
||||
self.tr("Working Title: {0}").format(self.theProject.data.name)
|
||||
)
|
||||
workFont = self.projName.font()
|
||||
workFont.setPointSizeF(0.8*fPt)
|
||||
@@ -173,7 +175,9 @@ class GuiProjectDetailsMain(QWidget):
|
||||
self.projName.setAlignment(Qt.AlignHCenter)
|
||||
self.projName.setWordWrap(True)
|
||||
|
||||
self.bookAuthors = QLabel(self.tr("By {0}").format(self.theProject.getAuthors()))
|
||||
self.bookAuthors = QLabel(self.tr("By {0}").format(
|
||||
self.theProject.getFormattedAuthors()
|
||||
))
|
||||
authFont = self.bookAuthors.font()
|
||||
authFont.setPointSizeF(1.2*fPt)
|
||||
self.bookAuthors.setFont(authFont)
|
||||
@@ -253,10 +257,10 @@ class GuiProjectDetailsMain(QWidget):
|
||||
self.wordCountVal.setText(f"{nwCount:n}")
|
||||
self.chapCountVal.setText(f"{hCounts[2]:n}")
|
||||
self.sceneCountVal.setText(f"{hCounts[3]:n}")
|
||||
self.revCountVal.setText(f"{self.theProject.saveCount:n}")
|
||||
self.revCountVal.setText(f"{self.theProject.data.saveCount:n}")
|
||||
self.editTimeVal.setText(f"{edTime//3600:02d}:{edTime%3600//60:02d}")
|
||||
|
||||
self.projPathVal.setText(self.theProject.projPath)
|
||||
self.projPathVal.setText(str(self.theProject.storage.storagePath))
|
||||
|
||||
return
|
||||
|
||||
@@ -272,7 +276,7 @@ class GuiProjectDetailsContents(QWidget):
|
||||
C_PROG = 4
|
||||
|
||||
def __init__(self, mainGui, theProject):
|
||||
QWidget.__init__(self, mainGui)
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.theProject = theProject
|
||||
@@ -281,12 +285,26 @@ class GuiProjectDetailsContents(QWidget):
|
||||
|
||||
# Internal
|
||||
self._theToC = []
|
||||
self._currentRoot = None
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
hPx = self.mainConf.pxInt(12)
|
||||
vPx = self.mainConf.pxInt(4)
|
||||
pOptions = self.theProject.options
|
||||
|
||||
# Header
|
||||
# ======
|
||||
|
||||
self.tocLabel = QLabel("<b>%s</b>" % self.tr("Table of Contents"))
|
||||
|
||||
self.novelValue = QComboBox(self)
|
||||
self.novelValue.setMinimumWidth(self.mainConf.pxInt(200))
|
||||
self.novelValue.currentIndexChanged.connect(self._novelValueChanged)
|
||||
|
||||
self.headBox = QHBoxLayout()
|
||||
self.headBox.addWidget(self.tocLabel)
|
||||
self.headBox.addWidget(self.novelValue)
|
||||
|
||||
# Contents Tree
|
||||
# =============
|
||||
|
||||
@@ -389,7 +407,7 @@ class GuiProjectDetailsContents(QWidget):
|
||||
# ========
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.outerBox.addWidget(QLabel("<b>%s</b>" % self.tr("Table of Contents")))
|
||||
self.outerBox.addLayout(self.headBox)
|
||||
self.outerBox.addWidget(self.tocTree)
|
||||
self.outerBox.addLayout(self.optionsBox)
|
||||
|
||||
@@ -412,19 +430,35 @@ class GuiProjectDetailsContents(QWidget):
|
||||
def updateValues(self):
|
||||
"""Populate the tree.
|
||||
"""
|
||||
self._prepareData()
|
||||
self._currentRoot = None
|
||||
self._populateNovelList()
|
||||
|
||||
rootHandle = self.novelValue.currentData()
|
||||
self._prepareData(rootHandle)
|
||||
self._populateTree()
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _prepareData(self):
|
||||
"""Extract the data for the tree.
|
||||
def _populateNovelList(self):
|
||||
"""Fill the novel combo box with a list of all novel folders.
|
||||
"""
|
||||
self._theToC = []
|
||||
self._theToC = self.theProject.index.getTableOfContents(2)
|
||||
self.novelValue.clear()
|
||||
|
||||
tIcon = self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
|
||||
for tHandle, nwItem in self.theProject.tree.iterRoots(nwItemClass.NOVEL):
|
||||
self.novelValue.addItem(tIcon, nwItem.itemName, tHandle)
|
||||
|
||||
return
|
||||
|
||||
def _prepareData(self, rootHandle):
|
||||
"""Extract the information from the project index.
|
||||
"""
|
||||
logger.debug("Populating ToC from handle '%s'", rootHandle)
|
||||
self._theToC = self.theProject.index.getTableOfContents(rootHandle, 2)
|
||||
self._theToC.append(("", 0, self.tr("END"), 0))
|
||||
return
|
||||
|
||||
@@ -432,6 +466,18 @@ class GuiProjectDetailsContents(QWidget):
|
||||
# Slots
|
||||
##
|
||||
|
||||
@pyqtSlot()
|
||||
def _novelValueChanged(self):
|
||||
"""Refresh the tree with another root item.
|
||||
"""
|
||||
rootHandle = self.novelValue.currentData()
|
||||
if rootHandle != self._currentRoot:
|
||||
self._prepareData(rootHandle)
|
||||
self._populateTree()
|
||||
self._currentRoot = rootHandle
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _populateTree(self):
|
||||
"""Set the content of the chapter/page tree.
|
||||
"""
|
||||
@@ -466,10 +512,11 @@ class GuiProjectDetailsContents(QWidget):
|
||||
progPage = f"{cPage:n}"
|
||||
progText = f"{pgProg:.1f}{nwUnicode.U_THSP}%"
|
||||
|
||||
hDec = self.mainTheme.getHeaderDecoration(tLevel)
|
||||
if tTitle.strip() == "":
|
||||
tTitle = self.tr("Untitled")
|
||||
|
||||
newItem.setIcon(self.C_TITLE, self.mainTheme.getIcon("doc_h%d" % tLevel))
|
||||
newItem.setData(self.C_TITLE, Qt.DecorationRole, hDec)
|
||||
newItem.setText(self.C_TITLE, tTitle)
|
||||
newItem.setText(self.C_WORDS, f"{wCount:n}")
|
||||
newItem.setText(self.C_PAGES, f"{pCount:n}")
|
||||
|
||||
@@ -23,10 +23,10 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
from PyQt5.QtGui import QKeySequence
|
||||
@@ -54,7 +54,7 @@ class GuiProjectLoad(QDialog):
|
||||
C_TIME = 2
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QDialog.__init__(self, mainGui)
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
logger.debug("Initialising GuiProjectLoad ...")
|
||||
self.setObjectName("GuiProjectLoad")
|
||||
@@ -77,7 +77,6 @@ class GuiProjectLoad(QDialog):
|
||||
self.setWindowTitle(self.tr("Open Project"))
|
||||
self.setMinimumWidth(self.mainConf.pxInt(650))
|
||||
self.setMinimumHeight(self.mainConf.pxInt(400))
|
||||
self.setModal(True)
|
||||
|
||||
self.nwIcon = QLabel()
|
||||
self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
|
||||
@@ -158,7 +157,6 @@ class GuiProjectLoad(QDialog):
|
||||
def _doOpenRecent(self):
|
||||
"""Close the dialog window with a recent project selected.
|
||||
"""
|
||||
logger.verbose("GuiProjectLoad open button clicked")
|
||||
self._saveSettings()
|
||||
|
||||
self.openPath = None
|
||||
@@ -183,7 +181,6 @@ class GuiProjectLoad(QDialog):
|
||||
def _doBrowse(self):
|
||||
"""Browse for a folder path.
|
||||
"""
|
||||
logger.verbose("GuiProjectLoad browse button clicked")
|
||||
extFilter = [
|
||||
self.tr("novelWriter Project File ({0})").format(nwFiles.PROJ_FILE),
|
||||
self.tr("All files ({0})").format("*"),
|
||||
@@ -192,8 +189,8 @@ class GuiProjectLoad(QDialog):
|
||||
self, self.tr("Open Project"), "", filter=";;".join(extFilter)
|
||||
)
|
||||
if projFile:
|
||||
thePath = os.path.abspath(os.path.dirname(projFile))
|
||||
self.selPath.setText(thePath)
|
||||
thePath = Path(projFile).absolute()
|
||||
self.selPath.setText(str(thePath))
|
||||
self.openPath = thePath
|
||||
self.openState = self.OPEN_STATE
|
||||
self.accept()
|
||||
@@ -203,7 +200,6 @@ class GuiProjectLoad(QDialog):
|
||||
def _doCancel(self):
|
||||
"""Close the dialog window without doing anything.
|
||||
"""
|
||||
logger.verbose("GuiProjectLoad close button clicked")
|
||||
self.openPath = None
|
||||
self.openState = self.NONE_STATE
|
||||
self.close()
|
||||
@@ -212,7 +208,6 @@ class GuiProjectLoad(QDialog):
|
||||
def _doNewProject(self):
|
||||
"""Create a new project.
|
||||
"""
|
||||
logger.verbose("GuiProjectLoad new project button clicked")
|
||||
self._saveSettings()
|
||||
self.openPath = None
|
||||
self.openState = self.NEW_STATE
|
||||
@@ -233,7 +228,7 @@ class GuiProjectLoad(QDialog):
|
||||
).format(projName)
|
||||
)
|
||||
if msgYes:
|
||||
self.mainConf.removeFromRecentCache(
|
||||
self.mainConf.recentProjects.remove(
|
||||
selList[0].data(self.C_NAME, Qt.UserRole)
|
||||
)
|
||||
self._populateList()
|
||||
@@ -262,29 +257,23 @@ class GuiProjectLoad(QDialog):
|
||||
colWidths[self.C_NAME] = self.listBox.columnWidth(self.C_NAME)
|
||||
colWidths[self.C_COUNT] = self.listBox.columnWidth(self.C_COUNT)
|
||||
colWidths[self.C_TIME] = self.listBox.columnWidth(self.C_TIME)
|
||||
self.mainConf.setProjColWidths(colWidths)
|
||||
self.mainConf.setProjLoadColWidths(colWidths)
|
||||
return
|
||||
|
||||
def _populateList(self):
|
||||
"""Populate the list box with recent project data.
|
||||
"""
|
||||
dataList = []
|
||||
for projPath in self.mainConf.recentProj:
|
||||
theEntry = self.mainConf.recentProj[projPath]
|
||||
theTitle = theEntry.get("title", "")
|
||||
theTime = theEntry.get("time", 0)
|
||||
theWords = theEntry.get("words", 0)
|
||||
dataList.append([theTitle, theTime, theWords, projPath])
|
||||
|
||||
self.listBox.clear()
|
||||
sortList = sorted(dataList, key=lambda x: x[1], reverse=True)
|
||||
for theTitle, theTime, theWords, projPath in sortList:
|
||||
dataList = self.mainConf.recentProjects.listEntries()
|
||||
sortList = sorted(dataList, key=lambda x: x[3], reverse=True)
|
||||
nwxIcon = self.mainGui.mainTheme.getIcon("proj_nwx")
|
||||
for path, title, words, time in sortList:
|
||||
newItem = QTreeWidgetItem([""]*4)
|
||||
newItem.setIcon(self.C_NAME, self.mainGui.mainTheme.getIcon("proj_nwx"))
|
||||
newItem.setText(self.C_NAME, theTitle)
|
||||
newItem.setData(self.C_NAME, Qt.UserRole, projPath)
|
||||
newItem.setText(self.C_COUNT, formatInt(theWords))
|
||||
newItem.setText(self.C_TIME, datetime.fromtimestamp(theTime).strftime("%x %X"))
|
||||
newItem.setIcon(self.C_NAME, nwxIcon)
|
||||
newItem.setText(self.C_NAME, title)
|
||||
newItem.setData(self.C_NAME, Qt.UserRole, path)
|
||||
newItem.setText(self.C_COUNT, formatInt(words))
|
||||
newItem.setText(self.C_TIME, datetime.fromtimestamp(time).strftime("%x %X"))
|
||||
newItem.setTextAlignment(self.C_NAME, Qt.AlignLeft | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_TIME, Qt.AlignRight | Qt.AlignVCenter)
|
||||
@@ -294,7 +283,7 @@ class GuiProjectLoad(QDialog):
|
||||
if self.listBox.topLevelItemCount() > 0:
|
||||
self.listBox.topLevelItem(0).setSelected(True)
|
||||
|
||||
projColWidth = self.mainConf.getProjColWidths()
|
||||
projColWidth = self.mainConf.projLoadColWidths
|
||||
if len(projColWidth) == 3:
|
||||
self.listBox.setColumnWidth(self.C_NAME, projColWidth[self.C_NAME])
|
||||
self.listBox.setColumnWidth(self.C_COUNT, projColWidth[self.C_COUNT])
|
||||
|
||||
@@ -36,15 +36,20 @@ from PyQt5.QtWidgets import (
|
||||
|
||||
from novelwriter.enum import nwAlert
|
||||
from novelwriter.common import simplified
|
||||
from novelwriter.gui.custom import QSwitch, PagedDialog, QConfigLayout
|
||||
from novelwriter.custom import QSwitch, PagedDialog, QConfigLayout
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiProjectSettings(PagedDialog):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
PagedDialog.__init__(self, mainGui)
|
||||
TAB_MAIN = 0
|
||||
TAB_STATUS = 1
|
||||
TAB_IMPORT = 2
|
||||
TAB_REPLACE = 3
|
||||
|
||||
def __init__(self, mainGui, focusTab=TAB_MAIN):
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
logger.debug("Initialising GuiProjectSettings ...")
|
||||
self.setObjectName("GuiProjectSettings")
|
||||
@@ -67,10 +72,10 @@ class GuiProjectSettings(PagedDialog):
|
||||
self.mainConf.pxInt(pOptions.getInt("GuiProjectSettings", "winHeight", wH))
|
||||
)
|
||||
|
||||
self.tabMain = GuiProjectEditMain(self.mainGui, self.theProject)
|
||||
self.tabStatus = GuiProjectEditStatus(self.mainGui, self.theProject, True)
|
||||
self.tabImport = GuiProjectEditStatus(self.mainGui, self.theProject, False)
|
||||
self.tabReplace = GuiProjectEditReplace(self.mainGui, self.theProject)
|
||||
self.tabMain = GuiProjectEditMain(self)
|
||||
self.tabStatus = GuiProjectEditStatus(self, True)
|
||||
self.tabImport = GuiProjectEditStatus(self, False)
|
||||
self.tabReplace = GuiProjectEditReplace(self)
|
||||
|
||||
self.addTab(self.tabMain, self.tr("Settings"))
|
||||
self.addTab(self.tabStatus, self.tr("Status"))
|
||||
@@ -83,12 +88,19 @@ class GuiProjectSettings(PagedDialog):
|
||||
self.addControls(self.buttonBox)
|
||||
|
||||
# Flags
|
||||
self.spellChanged = False
|
||||
self._spellChanged = False
|
||||
|
||||
# Focus Tab
|
||||
self._focusTab(focusTab)
|
||||
|
||||
logger.debug("GuiProjectSettings initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
@property
|
||||
def spellChanged(self):
|
||||
return self._spellChanged
|
||||
|
||||
##
|
||||
# Slots
|
||||
##
|
||||
@@ -96,21 +108,19 @@ class GuiProjectSettings(PagedDialog):
|
||||
def _doSave(self):
|
||||
"""Save settings and close dialog.
|
||||
"""
|
||||
logger.verbose("GuiProjectSettings save button clicked")
|
||||
|
||||
projName = self.tabMain.editName.text()
|
||||
bookTitle = self.tabMain.editTitle.text()
|
||||
bookAuthors = self.tabMain.editAuthors.toPlainText()
|
||||
spellLang = self.tabMain.spellLang.currentData()
|
||||
doBackup = not self.tabMain.doBackup.isChecked()
|
||||
|
||||
self.theProject.setProjectName(projName)
|
||||
self.theProject.setBookTitle(bookTitle)
|
||||
self.theProject.setBookAuthors(bookAuthors)
|
||||
self.theProject.setProjBackup(doBackup)
|
||||
self.theProject.data.setName(projName)
|
||||
self.theProject.data.setTitle(bookTitle)
|
||||
self.theProject.data.setAuthors(bookAuthors)
|
||||
self.theProject.data.setDoBackup(doBackup)
|
||||
|
||||
# Remember this as updating spell dictionary can be expensive
|
||||
self.spellChanged = self.theProject.setSpellLang(spellLang)
|
||||
self._spellChanged = self.theProject.data.setSpellLang(spellLang)
|
||||
|
||||
if self.tabStatus.colChanged:
|
||||
newList, delList = self.tabStatus.getNewList()
|
||||
@@ -125,7 +135,7 @@ class GuiProjectSettings(PagedDialog):
|
||||
|
||||
if self.tabReplace.arChanged:
|
||||
newList = self.tabReplace.getNewList()
|
||||
self.theProject.setAutoReplace(newList)
|
||||
self.theProject.data.setAutoReplace(newList)
|
||||
|
||||
self._saveGuiSettings()
|
||||
self.accept()
|
||||
@@ -143,6 +153,19 @@ class GuiProjectSettings(PagedDialog):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _focusTab(self, tab):
|
||||
"""Change which is the focused tab.
|
||||
"""
|
||||
if tab == self.TAB_MAIN:
|
||||
self.setCurrentWidget(self.tabMain)
|
||||
elif tab == self.TAB_STATUS:
|
||||
self.setCurrentWidget(self.tabStatus)
|
||||
elif tab == self.TAB_IMPORT:
|
||||
self.setCurrentWidget(self.tabImport)
|
||||
elif tab == self.TAB_REPLACE:
|
||||
self.setCurrentWidget(self.tabReplace)
|
||||
return
|
||||
|
||||
def _saveGuiSettings(self):
|
||||
"""Save GUI settings.
|
||||
"""
|
||||
@@ -166,12 +189,12 @@ class GuiProjectSettings(PagedDialog):
|
||||
|
||||
class GuiProjectEditMain(QWidget):
|
||||
|
||||
def __init__(self, mainGui, theProject):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, projGui):
|
||||
super().__init__(parent=projGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.theProject = theProject
|
||||
self.mainGui = projGui.mainGui
|
||||
self.theProject = projGui.theProject
|
||||
|
||||
# The Form
|
||||
self.mainForm = QConfigLayout()
|
||||
@@ -186,7 +209,7 @@ class GuiProjectEditMain(QWidget):
|
||||
self.editName = QLineEdit()
|
||||
self.editName.setMaxLength(200)
|
||||
self.editName.setMaximumWidth(xW)
|
||||
self.editName.setText(self.theProject.projName)
|
||||
self.editName.setText(self.theProject.data.name)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Project name"),
|
||||
self.editName,
|
||||
@@ -196,7 +219,7 @@ class GuiProjectEditMain(QWidget):
|
||||
self.editTitle = QLineEdit()
|
||||
self.editTitle.setMaxLength(200)
|
||||
self.editTitle.setMaximumWidth(xW)
|
||||
self.editTitle.setText(self.theProject.bookTitle)
|
||||
self.editTitle.setText(self.theProject.data.title)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Novel title"),
|
||||
self.editTitle,
|
||||
@@ -206,7 +229,7 @@ class GuiProjectEditMain(QWidget):
|
||||
self.editAuthors = QPlainTextEdit()
|
||||
self.editAuthors.setMaximumHeight(xH)
|
||||
self.editAuthors.setMaximumWidth(xW)
|
||||
self.editAuthors.setPlainText("\n".join(self.theProject.bookAuthors))
|
||||
self.editAuthors.setPlainText("\n".join(self.theProject.data.authors))
|
||||
self.mainForm.addRow(
|
||||
self.tr("Author(s)"),
|
||||
self.editAuthors,
|
||||
@@ -229,13 +252,13 @@ class GuiProjectEditMain(QWidget):
|
||||
)
|
||||
|
||||
spellIdx = 0
|
||||
if self.theProject.projSpell is not None:
|
||||
spellIdx = self.spellLang.findData(self.theProject.projSpell)
|
||||
if self.theProject.data.spellLang is not None:
|
||||
spellIdx = self.spellLang.findData(self.theProject.data.spellLang)
|
||||
if spellIdx != -1:
|
||||
self.spellLang.setCurrentIndex(spellIdx)
|
||||
|
||||
self.doBackup = QSwitch(self)
|
||||
self.doBackup.setChecked(not self.theProject.doBackup)
|
||||
self.doBackup.setChecked(not self.theProject.data.doBackup)
|
||||
self.mainForm.addRow(
|
||||
self.tr("No backup on close"),
|
||||
self.doBackup,
|
||||
@@ -256,20 +279,20 @@ class GuiProjectEditStatus(QWidget):
|
||||
COL_ROLE = Qt.UserRole + 1
|
||||
NUM_ROLE = Qt.UserRole + 2
|
||||
|
||||
def __init__(self, mainGui, theProject, isStatus):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, projGui, isStatus):
|
||||
super().__init__(parent=projGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.theProject = theProject
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = projGui.mainGui
|
||||
self.theProject = projGui.theProject
|
||||
self.mainTheme = projGui.mainGui.mainTheme
|
||||
|
||||
if isStatus:
|
||||
self.theStatus = self.theProject.statusItems
|
||||
self.theStatus = self.theProject.data.itemStatus
|
||||
pageLabel = self.tr("Novel File Status Levels")
|
||||
colSetting = "statusColW"
|
||||
else:
|
||||
self.theStatus = self.theProject.importItems
|
||||
self.theStatus = self.theProject.data.itemImport
|
||||
pageLabel = self.tr("Note File Importance Levels")
|
||||
colSetting = "importColW"
|
||||
|
||||
@@ -367,11 +390,12 @@ class GuiProjectEditStatus(QWidget):
|
||||
newList = []
|
||||
for n in range(self.listBox.topLevelItemCount()):
|
||||
item = self.listBox.topLevelItem(n)
|
||||
newList.append({
|
||||
"key": item.data(self.COL_LABEL, self.KEY_ROLE),
|
||||
"name": item.text(self.COL_LABEL),
|
||||
"cols": item.data(self.COL_LABEL, self.COL_ROLE),
|
||||
})
|
||||
if item is not None:
|
||||
newList.append({
|
||||
"key": item.data(self.COL_LABEL, self.KEY_ROLE),
|
||||
"name": item.text(self.COL_LABEL),
|
||||
"cols": item.data(self.COL_LABEL, self.COL_ROLE),
|
||||
})
|
||||
return newList, self.colDeleted
|
||||
|
||||
return [], []
|
||||
@@ -470,7 +494,8 @@ class GuiProjectEditStatus(QWidget):
|
||||
self.listBox.insertTopLevelItem(nIndex, cItem)
|
||||
self.listBox.clearSelection()
|
||||
|
||||
cItem.setSelected(True)
|
||||
if cItem is not None:
|
||||
cItem.setSelected(True)
|
||||
self.colChanged = True
|
||||
|
||||
return
|
||||
@@ -527,13 +552,13 @@ class GuiProjectEditReplace(QWidget):
|
||||
COL_KEY = 0
|
||||
COL_REPL = 1
|
||||
|
||||
def __init__(self, mainGui, theProject):
|
||||
QWidget.__init__(self, mainGui)
|
||||
def __init__(self, projGui):
|
||||
super().__init__(parent=projGui)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = theProject
|
||||
self.mainGui = projGui.mainGui
|
||||
self.mainTheme = projGui.mainGui.mainTheme
|
||||
self.theProject = projGui.theProject
|
||||
self.arChanged = False
|
||||
|
||||
wCol0 = self.mainConf.pxInt(
|
||||
@@ -553,7 +578,7 @@ class GuiProjectEditReplace(QWidget):
|
||||
self.listBox.setColumnWidth(self.COL_KEY, wCol0)
|
||||
self.listBox.setIndentation(0)
|
||||
|
||||
for aKey, aVal in self.theProject.autoReplace.items():
|
||||
for aKey, aVal in self.theProject.data.autoReplace.items():
|
||||
newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
|
||||
self.listBox.addTopLevelItem(newItem)
|
||||
|
||||
@@ -619,10 +644,11 @@ class GuiProjectEditReplace(QWidget):
|
||||
newList = {}
|
||||
for n in range(self.listBox.topLevelItemCount()):
|
||||
tItem = self.listBox.topLevelItem(n)
|
||||
aKey = self._stripNotAllowed(tItem.text(0))
|
||||
aVal = tItem.text(1)
|
||||
if len(aKey) > 0:
|
||||
newList[aKey] = aVal
|
||||
if tItem is not None:
|
||||
aKey = self._stripNotAllowed(tItem.text(0))
|
||||
aVal = tItem.text(1)
|
||||
if len(aKey) > 0:
|
||||
newList[aKey] = aVal
|
||||
|
||||
return newList
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class GuiQuoteSelect(QDialog):
|
||||
selectedQuote = ""
|
||||
|
||||
def __init__(self, parent=None, currentQuote='"'):
|
||||
QDialog.__init__(self, parent=parent)
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.mainConf = novelwriter.CONFIG
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ logger = logging.getLogger(__name__)
|
||||
class GuiUpdates(QDialog):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QDialog.__init__(self, mainGui)
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
logger.debug("Initialising GuiUpdates ...")
|
||||
self.setObjectName("GuiUpdates")
|
||||
@@ -135,7 +135,7 @@ class GuiUpdates(QDialog):
|
||||
logException()
|
||||
|
||||
relVersion = rawData.get("tag_name", "Unknown")
|
||||
relDate = rawData.get("created_at", None)
|
||||
relDate = rawData.get("created_at", "")
|
||||
|
||||
try:
|
||||
relDate = datetime.strptime(relDate[:10], "%Y-%m-%d").strftime("%x")
|
||||
|
||||
@@ -23,10 +23,11 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QListWidget,
|
||||
@@ -43,7 +44,7 @@ logger = logging.getLogger(__name__)
|
||||
class GuiWordList(QDialog):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
QDialog.__init__(self, mainGui)
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
logger.debug("Initialising GuiWordList ...")
|
||||
self.setObjectName("GuiWordList")
|
||||
@@ -150,13 +151,19 @@ class GuiWordList(QDialog):
|
||||
"""
|
||||
self._saveGuiSettings()
|
||||
|
||||
dctFile = os.path.join(self.theProject.projMeta, nwFiles.PROJ_DICT)
|
||||
tmpFile = dctFile + "~"
|
||||
dctFile = self.theProject.storage.getMetaFile(nwFiles.PROJ_DICT)
|
||||
if not isinstance(dctFile, Path):
|
||||
return False
|
||||
|
||||
tmpFile = dctFile.with_suffix(".tmp")
|
||||
try:
|
||||
with open(tmpFile, mode="w", encoding="utf-8") as outFile:
|
||||
for i in range(self.listBox.count()):
|
||||
outFile.write(self.listBox.item(i).text() + "\n")
|
||||
item = self.listBox.item(i)
|
||||
if item is not None:
|
||||
outFile.write(item.text() + "\n")
|
||||
|
||||
tmpFile.replace(dctFile)
|
||||
|
||||
except Exception:
|
||||
logger.error("Could not save new word list")
|
||||
@@ -164,9 +171,6 @@ class GuiWordList(QDialog):
|
||||
self.reject()
|
||||
return False
|
||||
|
||||
if os.path.isfile(dctFile):
|
||||
os.unlink(dctFile)
|
||||
os.rename(tmpFile, dctFile)
|
||||
self.accept()
|
||||
|
||||
return True
|
||||
@@ -185,10 +189,12 @@ class GuiWordList(QDialog):
|
||||
def _loadWordList(self):
|
||||
"""Load the project's word list, if it exists.
|
||||
"""
|
||||
self.listBox.clear()
|
||||
wordList = self.theProject.storage.getMetaFile(nwFiles.PROJ_DICT)
|
||||
if not isinstance(wordList, Path):
|
||||
return False
|
||||
|
||||
wordList = os.path.join(self.theProject.projMeta, nwFiles.PROJ_DICT)
|
||||
if not os.path.isfile(wordList):
|
||||
self.listBox.clear()
|
||||
if not wordList.exists():
|
||||
logger.debug("No project dictionary file found")
|
||||
return False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user