Move the remaining project meta settings to project data class
This commit is contained in:
+19
-71
@@ -78,9 +78,6 @@ class NWProject:
|
||||
self.projChanged = False # The project has unsaved changes
|
||||
self.projAltered = False # The project has been altered this session
|
||||
self.lockedBy = None # Data on which computer has the project open
|
||||
self.saveCount = 0 # Meta data: number of saves
|
||||
self.autoCount = 0 # Meta data: number of automatic saves
|
||||
self.editTime = 0 # The accumulated edit time read from the project file
|
||||
|
||||
# Class Settings
|
||||
self.projPath = None # The full path to where the currently open project is saved
|
||||
@@ -92,10 +89,6 @@ class NWProject:
|
||||
self.projLang = None # The project language, used for builds
|
||||
self.projFiles = [] # A list of all files in the content folder on load
|
||||
|
||||
# Project Meta
|
||||
self.bookTitle = "" # The final title; should only be used for exports
|
||||
self.bookAuthors = [] # A list of book authors
|
||||
|
||||
# Project Settings
|
||||
self.autoReplace = {} # Text to auto-replace on exports
|
||||
self.titleFormat = {} # The formatting of titles for exports
|
||||
@@ -253,12 +246,12 @@ class NWProject:
|
||||
self.projOpened = 0
|
||||
self.projChanged = False
|
||||
self.projAltered = False
|
||||
self.saveCount = 0
|
||||
self.autoCount = 0
|
||||
|
||||
# Project Tree
|
||||
self._projTree.clear()
|
||||
|
||||
self._data = NWProjectData()
|
||||
|
||||
# Project Settings
|
||||
self.projPath = None
|
||||
self.projMeta = None
|
||||
@@ -268,8 +261,6 @@ class NWProject:
|
||||
self.projSpell = None
|
||||
self.projLang = None
|
||||
self.projFiles = []
|
||||
self.bookTitle = ""
|
||||
self.bookAuthors = []
|
||||
self.autoReplace = {}
|
||||
self.titleFormat = {
|
||||
"title": "%title%",
|
||||
@@ -332,16 +323,18 @@ class NWProject:
|
||||
if not self.setProjectPath(projPath, newProject=True):
|
||||
return False
|
||||
|
||||
self.data.setName(projName)
|
||||
self.setBookTitle(projTitle)
|
||||
self.setBookAuthors(projAuthors)
|
||||
self._data.setName(projName)
|
||||
self._data.setTitle(projTitle)
|
||||
self._data.setAuthors(projAuthors)
|
||||
|
||||
hNovelRoot = self.newRoot(nwItemClass.NOVEL)
|
||||
hTitlePage = self.newFile(self.tr("Title Page"), hNovelRoot)
|
||||
|
||||
titlePage = "#! %s\n\n" % (self.bookTitle if self.bookTitle else self._data.name)
|
||||
if self.bookAuthors:
|
||||
titlePage = "%s>> %s %s <<\n" % (titlePage, self.tr("By"), self.getAuthors())
|
||||
titlePage = "#! %s\n\n" % (self._data.title if self._data.title else self._data.name)
|
||||
if self._data.authors:
|
||||
titlePage = "%s>> %s %s <<\n" % (
|
||||
titlePage, self.tr("By"), self._data.getAuthors(self.tr("and"))
|
||||
)
|
||||
|
||||
aDoc = NWDoc(self, hTitlePage)
|
||||
aDoc.writeDocument(titlePage)
|
||||
@@ -557,14 +550,8 @@ class NWProject:
|
||||
# Extract Data
|
||||
# ============
|
||||
|
||||
self.bookTitle = self._data.title
|
||||
self.bookAuthors = self._data.autors
|
||||
self.saveCount = self._data.saveCount
|
||||
self.autoCount = self._data.autoCount
|
||||
self.editTime = self._data.editTime
|
||||
|
||||
logger.info("Project Name: '%s'", self._data.name)
|
||||
logger.info("Project Title: '%s'", self.bookTitle)
|
||||
logger.info("Project Title: '%s'", self._data.title)
|
||||
|
||||
xmlSettings = xmlData.get("settings", {})
|
||||
|
||||
@@ -646,9 +633,9 @@ class NWProject:
|
||||
logger.info("Saving project: %s", self.projPath)
|
||||
|
||||
if autoSave:
|
||||
self.autoCount += 1
|
||||
self._data.incAutoCount()
|
||||
else:
|
||||
self.saveCount += 1
|
||||
self._data.incSaveCount()
|
||||
|
||||
# Root element and project details
|
||||
logger.debug("Writing project meta")
|
||||
@@ -660,15 +647,15 @@ class NWProject:
|
||||
})
|
||||
|
||||
self.updateWordCounts()
|
||||
editTime = int(self.editTime + saveTime - self.projOpened)
|
||||
editTime = int(self._data.editTime + saveTime - self.projOpened)
|
||||
|
||||
# Save Project Meta
|
||||
xProject = etree.SubElement(nwXML, "project")
|
||||
self._packProjectValue(xProject, "name", self._data.name)
|
||||
self._packProjectValue(xProject, "title", self.bookTitle)
|
||||
self._packProjectValue(xProject, "author", self.bookAuthors)
|
||||
self._packProjectValue(xProject, "saveCount", str(self.saveCount))
|
||||
self._packProjectValue(xProject, "autoCount", str(self.autoCount))
|
||||
self._packProjectValue(xProject, "title", self._data.title)
|
||||
self._packProjectValue(xProject, "author", self._data.authors)
|
||||
self._packProjectValue(xProject, "saveCount", str(self._data.saveCount))
|
||||
self._packProjectValue(xProject, "autoCount", str(self._data.autoCount))
|
||||
self._packProjectValue(xProject, "editTime", str(editTime))
|
||||
|
||||
# Save Project Settings
|
||||
@@ -955,30 +942,6 @@ class NWProject:
|
||||
|
||||
return True
|
||||
|
||||
def setBookTitle(self, bookTitle):
|
||||
"""Set the book title, that is, the title to include in exports.
|
||||
"""
|
||||
self.bookTitle = simplified(bookTitle)
|
||||
self.setProjectChanged(True)
|
||||
return True
|
||||
|
||||
def setBookAuthors(self, bookAuthors):
|
||||
"""A line-separated list of authors, parsed into an array.
|
||||
"""
|
||||
if not isinstance(bookAuthors, str):
|
||||
return False
|
||||
|
||||
self.bookAuthors = []
|
||||
for bookAuthor in bookAuthors.splitlines():
|
||||
bookAuthor = simplified(bookAuthor)
|
||||
if bookAuthor == "":
|
||||
continue
|
||||
self.bookAuthors.append(bookAuthor)
|
||||
|
||||
self.setProjectChanged(True)
|
||||
|
||||
return True
|
||||
|
||||
def setProjBackup(self, doBackup):
|
||||
"""Set whether projects should be backed up or not. The user
|
||||
will be notified in case required settings are missing.
|
||||
@@ -1116,26 +1079,11 @@ class NWProject:
|
||||
# Getters
|
||||
##
|
||||
|
||||
def getAuthors(self):
|
||||
"""Return a formatted string of authors.
|
||||
"""
|
||||
nAuth = len(self.bookAuthors)
|
||||
authString = ""
|
||||
|
||||
if nAuth == 1:
|
||||
authString = self.bookAuthors[0]
|
||||
elif nAuth > 1:
|
||||
authString = "%s %s %s" % (
|
||||
", ".join(self.bookAuthors[0:-1]), self.tr("and"), self.bookAuthors[-1]
|
||||
)
|
||||
|
||||
return authString
|
||||
|
||||
def getCurrentEditTime(self):
|
||||
"""Get the total project edit time, including the time spent in
|
||||
the current session.
|
||||
"""
|
||||
return round(self.editTime + time() - self.projOpened)
|
||||
return round(self._data.editTime + time() - self.projOpened)
|
||||
|
||||
def getProjectItems(self):
|
||||
"""This function ensures that the item tree loaded is sent to
|
||||
|
||||
@@ -60,7 +60,7 @@ class NWProjectData:
|
||||
return self._title
|
||||
|
||||
@property
|
||||
def autors(self):
|
||||
def authors(self):
|
||||
return self._authors
|
||||
|
||||
@property
|
||||
@@ -75,6 +75,44 @@ class NWProjectData:
|
||||
def editTime(self):
|
||||
return self._editTime
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def addAuthor(self, value):
|
||||
self._authors.append(simplified(str(value)))
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def incSaveCount(self):
|
||||
self._saveCount += 1
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def incAutoCount(self):
|
||||
self._autoCount += 1
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
##
|
||||
# Getters
|
||||
##
|
||||
|
||||
def getAuthors(self, trAnd="and"):
|
||||
"""Return a formatted string of authors.
|
||||
"""
|
||||
nAuth = len(self._authors)
|
||||
authors = ""
|
||||
|
||||
if nAuth == 1:
|
||||
authors = self._authors[0]
|
||||
elif nAuth > 1:
|
||||
authors = "%s %s %s" % (
|
||||
", ".join(self._authors[0:-1]), trAnd, self._authors[-1]
|
||||
)
|
||||
|
||||
return authors
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
@@ -89,9 +127,17 @@ class NWProjectData:
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def addAuthor(self, value):
|
||||
self._authors.append(simplified(str(value)))
|
||||
def setAuthors(self, value):
|
||||
self._authors = []
|
||||
self._changed = True
|
||||
if isinstance(value, str):
|
||||
for author in value.splitlines():
|
||||
author = simplified(author)
|
||||
if author:
|
||||
self.addAuthor(author)
|
||||
self._changed = True
|
||||
elif isinstance(value, list):
|
||||
self._authors = value
|
||||
return
|
||||
|
||||
def setSaveCount(self, value):
|
||||
|
||||
@@ -261,8 +261,8 @@ class ToOdt(Tokenizer):
|
||||
# ===============
|
||||
|
||||
if self._headerText == "":
|
||||
theTitle = self.theProject.bookTitle
|
||||
theAuth = self.theProject.getAuthors()
|
||||
theTitle = self.theProject.data.title
|
||||
theAuth = self.theProject.data.getAuthors(self.tr("and"))
|
||||
self._headerText = f"{theTitle} / {theAuth} /"
|
||||
|
||||
# Create Roots
|
||||
|
||||
@@ -157,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)
|
||||
@@ -175,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.data.getAuthors(self.tr("and"))
|
||||
))
|
||||
authFont = self.bookAuthors.font()
|
||||
authFont.setPointSizeF(1.2*fPt)
|
||||
self.bookAuthors.setFont(authFont)
|
||||
@@ -255,7 +257,7 @@ 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)
|
||||
|
||||
@@ -115,8 +115,8 @@ class GuiProjectSettings(PagedDialog):
|
||||
doBackup = not self.tabMain.doBackup.isChecked()
|
||||
|
||||
self.theProject.data.setName(projName)
|
||||
self.theProject.setBookTitle(bookTitle)
|
||||
self.theProject.setBookAuthors(bookAuthors)
|
||||
self.theProject.data.setTitle(bookTitle)
|
||||
self.theProject.data.setAuthors(bookAuthors)
|
||||
self.theProject.setProjBackup(doBackup)
|
||||
|
||||
# Remember this as updating spell dictionary can be expensive
|
||||
@@ -219,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,
|
||||
@@ -229,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,
|
||||
|
||||
@@ -973,8 +973,8 @@ class GuiBuildNovel(QDialog):
|
||||
jsonData = {
|
||||
"meta": {
|
||||
"workingTitle": self.theProject.data.name,
|
||||
"novelTitle": self.theProject.bookTitle,
|
||||
"authors": self.theProject.bookAuthors,
|
||||
"novelTitle": self.theProject.data.title,
|
||||
"authors": self.theProject.data.authors,
|
||||
"buildTime": self.buildTime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,22 +555,22 @@ def testCoreProject_Save(monkeypatch, nwMinimal, mockGUI, refDir):
|
||||
assert os.path.isfile(backFile) is False
|
||||
|
||||
# Successful save
|
||||
saveCount = theProject.saveCount
|
||||
autoCount = theProject.autoCount
|
||||
saveCount = theProject.data.saveCount
|
||||
autoCount = theProject.data.autoCount
|
||||
assert theProject.saveProject() is True
|
||||
assert theProject.saveCount == saveCount + 1
|
||||
assert theProject.autoCount == autoCount
|
||||
assert theProject.data.saveCount == saveCount + 1
|
||||
assert theProject.data.autoCount == autoCount
|
||||
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
||||
|
||||
# Check that a second save creates a .bak file
|
||||
assert os.path.isfile(backFile) is True
|
||||
|
||||
# Successful autosave
|
||||
saveCount = theProject.saveCount
|
||||
autoCount = theProject.autoCount
|
||||
saveCount = theProject.data.saveCount
|
||||
autoCount = theProject.data.autoCount
|
||||
assert theProject.saveProject(autoSave=True) is True
|
||||
assert theProject.saveCount == saveCount
|
||||
assert theProject.autoCount == autoCount + 1
|
||||
assert theProject.data.saveCount == saveCount
|
||||
assert theProject.data.autoCount == autoCount + 1
|
||||
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
||||
|
||||
# Close test project
|
||||
@@ -902,30 +902,31 @@ def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd):
|
||||
assert theProject.data.name == "A Name"
|
||||
|
||||
# Project Title
|
||||
theProject.setBookTitle(" A Title ")
|
||||
assert theProject.bookTitle == "A Title"
|
||||
theProject.data.setTitle(" A Title ")
|
||||
assert theProject.data.title == "A Title"
|
||||
|
||||
# Project Authors
|
||||
# Check that the list is cleaned up and that it can be extracted as
|
||||
# a properly formatted string, depending on number of names
|
||||
assert not theProject.setBookAuthors([])
|
||||
assert theProject.setBookAuthors(" Jane Doe \n John Doh \n ")
|
||||
assert theProject.bookAuthors == ["Jane Doe", "John Doh"]
|
||||
theProject.data.setAuthors([])
|
||||
assert theProject.data.authors == []
|
||||
theProject.data.setAuthors(" Jane Doe \n John Doh \n ")
|
||||
assert theProject.data.authors == ["Jane Doe", "John Doh"]
|
||||
|
||||
assert theProject.setBookAuthors("")
|
||||
assert theProject.getAuthors() == ""
|
||||
theProject.data.setAuthors("")
|
||||
assert theProject.data.getAuthors() == ""
|
||||
|
||||
assert theProject.setBookAuthors("Jane Doe")
|
||||
assert theProject.getAuthors() == "Jane Doe"
|
||||
theProject.data.setAuthors("Jane Doe")
|
||||
assert theProject.data.getAuthors() == "Jane Doe"
|
||||
|
||||
assert theProject.setBookAuthors("Jane Doe\nJohn Doh")
|
||||
assert theProject.getAuthors() == "Jane Doe and John Doh"
|
||||
theProject.data.setAuthors("Jane Doe\nJohn Doh")
|
||||
assert theProject.data.getAuthors() == "Jane Doe and John Doh"
|
||||
|
||||
assert theProject.setBookAuthors("Jane Doe\nJohn Doh\nBod Owens")
|
||||
assert theProject.getAuthors() == "Jane Doe, John Doh and Bod Owens"
|
||||
theProject.data.setAuthors("Jane Doe\nJohn Doh\nBod Owens")
|
||||
assert theProject.data.getAuthors() == "Jane Doe, John Doh and Bod Owens"
|
||||
|
||||
# Edit Time
|
||||
theProject.editTime = 1234
|
||||
theProject.data.setEditTime(1234)
|
||||
theProject.projOpened = 1600000000
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("novelwriter.core.project.time", lambda: 1600005600)
|
||||
|
||||
@@ -55,7 +55,7 @@ def testDlgProjDetails_Dialog(qtbot, nwGUI, nwLipsum):
|
||||
assert projDet.tabMain.wordCountVal.text() == f"{3000:n}"
|
||||
assert projDet.tabMain.chapCountVal.text() == f"{3:n}"
|
||||
assert projDet.tabMain.sceneCountVal.text() == f"{5:n}"
|
||||
assert projDet.tabMain.revCountVal.text() == f"{nwGUI.theProject.saveCount:n}"
|
||||
assert projDet.tabMain.revCountVal.text() == f"{nwGUI.theProject.data.saveCount:n}"
|
||||
|
||||
assert projDet.tabMain.projPathVal.text() == nwLipsum
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd
|
||||
# Set some values
|
||||
theProject = nwGUI.theProject
|
||||
theProject.setSpellLang("en")
|
||||
theProject.setBookAuthors("Jane Smith\nJohn Smith")
|
||||
theProject.data.setAuthors("Jane Smith\nJohn Smith")
|
||||
theProject.setAutoReplace({"A": "B", "C": "D"})
|
||||
|
||||
# Create Dialog
|
||||
@@ -137,8 +137,8 @@ def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd
|
||||
|
||||
projSettings._doSave()
|
||||
assert theProject.data.name == "Project Name"
|
||||
assert theProject.bookTitle == "Project Title"
|
||||
assert theProject.bookAuthors == ["Jane Doe", "John Doh"]
|
||||
assert theProject.data.title == "Project Title"
|
||||
assert theProject.data.authors == ["Jane Doe", "John Doh"]
|
||||
|
||||
# Clean up
|
||||
projSettings._doClose()
|
||||
|
||||
@@ -172,9 +172,9 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
|
||||
assert nwGUI.theProject.tree.trashRoot() is None
|
||||
assert nwGUI.theProject.projPath is None
|
||||
assert nwGUI.theProject.projMeta is None
|
||||
assert nwGUI.theProject.data.name == "New Project"
|
||||
assert nwGUI.theProject.bookTitle == ""
|
||||
assert len(nwGUI.theProject.bookAuthors) == 0
|
||||
assert nwGUI.theProject.data.name == ""
|
||||
assert nwGUI.theProject.data.title == ""
|
||||
assert nwGUI.theProject.data.authors == []
|
||||
assert not nwGUI.theProject.spellCheck
|
||||
|
||||
# Check the files
|
||||
@@ -195,8 +195,8 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
|
||||
assert nwGUI.theProject.projPath == fncProj
|
||||
assert nwGUI.theProject.projMeta == os.path.join(fncProj, "meta")
|
||||
assert nwGUI.theProject.data.name == "New Project"
|
||||
assert nwGUI.theProject.bookTitle == "New Novel"
|
||||
assert len(nwGUI.theProject.bookAuthors) == 1
|
||||
assert nwGUI.theProject.data.title == "New Novel"
|
||||
assert nwGUI.theProject.data.authors == ["Jane Doe"]
|
||||
assert nwGUI.theProject.spellCheck is False
|
||||
|
||||
# Check that tree items have been created
|
||||
|
||||
+2
-2
@@ -168,8 +168,8 @@ def buildTestProject(theObject, projPath):
|
||||
theProject.clearProject()
|
||||
theProject.setProjectPath(projPath, newProject=True)
|
||||
theProject.data.setName("New Project")
|
||||
theProject.setBookTitle("New Novel")
|
||||
theProject.setBookAuthors("Jane Doe")
|
||||
theProject.data.setTitle("New Novel")
|
||||
theProject.data.setAuthors("Jane Doe")
|
||||
|
||||
# Creating a minimal project with a few root folders and a
|
||||
# single chapter folder with a single file.
|
||||
|
||||
Reference in New Issue
Block a user