Allow the project class to create new files
This commit is contained in:
@@ -45,7 +45,7 @@ from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert
|
|||||||
from novelwriter.error import logException
|
from novelwriter.error import logException
|
||||||
from novelwriter.common import (
|
from novelwriter.common import (
|
||||||
checkString, checkBool, checkInt, isHandle, formatTimeStamp,
|
checkString, checkBool, checkInt, isHandle, formatTimeStamp,
|
||||||
makeFileNameSafe, hexToInt, simplified
|
makeFileNameSafe, hexToInt, minmax, simplified
|
||||||
)
|
)
|
||||||
from novelwriter.constants import trConst, nwFiles, nwLabels
|
from novelwriter.constants import trConst, nwFiles, nwLabels
|
||||||
|
|
||||||
@@ -154,6 +154,8 @@ class NWProject():
|
|||||||
def newFolder(self, label, pHandle):
|
def newFolder(self, label, pHandle):
|
||||||
"""Add a new folder with a given label and parent item.
|
"""Add a new folder with a given label and parent item.
|
||||||
"""
|
"""
|
||||||
|
if pHandle not in self._projTree:
|
||||||
|
return None
|
||||||
newItem = NWItem(self)
|
newItem = NWItem(self)
|
||||||
newItem.setName(label)
|
newItem.setName(label)
|
||||||
newItem.setType(nwItemType.FOLDER)
|
newItem.setType(nwItemType.FOLDER)
|
||||||
@@ -164,6 +166,8 @@ class NWProject():
|
|||||||
def newFile(self, label, pHandle):
|
def newFile(self, label, pHandle):
|
||||||
"""Add a new file with a given label and parent item.
|
"""Add a new file with a given label and parent item.
|
||||||
"""
|
"""
|
||||||
|
if pHandle not in self._projTree:
|
||||||
|
return None
|
||||||
newItem = NWItem(self)
|
newItem = NWItem(self)
|
||||||
newItem.setName(label)
|
newItem.setName(label)
|
||||||
newItem.setType(nwItemType.FILE)
|
newItem.setType(nwItemType.FILE)
|
||||||
@@ -171,6 +175,32 @@ class NWProject():
|
|||||||
self._projTree.updateItemData(newItem.itemHandle)
|
self._projTree.updateItemData(newItem.itemHandle)
|
||||||
return newItem.itemHandle
|
return newItem.itemHandle
|
||||||
|
|
||||||
|
def writeNewFile(self, tHandle, hLevel, isDocument):
|
||||||
|
"""Write content to a new document after it is created. This
|
||||||
|
will not run if the file exists and is not empty.
|
||||||
|
"""
|
||||||
|
tItem = self._projTree[tHandle]
|
||||||
|
if tItem is None:
|
||||||
|
return False
|
||||||
|
if tItem.itemType != nwItemType.FILE:
|
||||||
|
return False
|
||||||
|
|
||||||
|
newDoc = NWDoc(self, tHandle)
|
||||||
|
if newDoc.readDocument().strip():
|
||||||
|
return False
|
||||||
|
|
||||||
|
hshText = "#"*minmax(hLevel, 1, 4)
|
||||||
|
newText = f"{hshText} {tItem.itemName}\n\n"
|
||||||
|
if tItem.isNovelLike() and isDocument:
|
||||||
|
tItem.setLayout(nwItemLayout.DOCUMENT)
|
||||||
|
else:
|
||||||
|
tItem.setLayout(nwItemLayout.NOTE)
|
||||||
|
|
||||||
|
newDoc.writeDocument(newText)
|
||||||
|
self._projIndex.scanText(tHandle, newText)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def trashFolder(self):
|
def trashFolder(self):
|
||||||
"""Add the special trash root folder to the project.
|
"""Add the special trash root folder to the project.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -29,10 +29,14 @@ from lxml import etree
|
|||||||
from tools import cmpFiles, writeFile, readFile, buildTestProject, XML_IGNORE
|
from tools import cmpFiles, writeFile, readFile, buildTestProject, XML_IGNORE
|
||||||
from mock import causeOSError
|
from mock import causeOSError
|
||||||
|
|
||||||
from novelwriter.core.project import NWProject
|
|
||||||
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
|
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
|
||||||
from novelwriter.common import formatTimeStamp
|
from novelwriter.common import formatTimeStamp
|
||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
|
from novelwriter.core.tree import NWTree
|
||||||
|
from novelwriter.core.index import NWIndex
|
||||||
|
from novelwriter.core.project import NWProject
|
||||||
|
from novelwriter.core.options import OptionState
|
||||||
|
from novelwriter.core.document import NWDoc
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
@@ -280,12 +284,12 @@ def testCoreProject_NewRoot(fncDir, outDir, refDir, mockGUI, mockRnd):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI, mockRnd):
|
def testCoreProject_NewFileFolder(fncDir, outDir, refDir, mockGUI, mockRnd):
|
||||||
"""Check that new files can be added to the project.
|
"""Check that new files can be added to the project.
|
||||||
"""
|
"""
|
||||||
projFile = os.path.join(fncDir, "nwProject.nwx")
|
projFile = os.path.join(fncDir, "nwProject.nwx")
|
||||||
testFile = os.path.join(outDir, "coreProject_NewFile_nwProject.nwx")
|
testFile = os.path.join(outDir, "coreProject_NewFileFolder_nwProject.nwx")
|
||||||
compFile = os.path.join(refDir, "coreProject_NewFile_nwProject.nwx")
|
compFile = os.path.join(refDir, "coreProject_NewFileFolder_nwProject.nwx")
|
||||||
|
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
buildTestProject(theProject, fncDir)
|
buildTestProject(theProject, fncDir)
|
||||||
@@ -295,9 +299,33 @@ def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI, mockRnd):
|
|||||||
assert theProject.closeProject() is True
|
assert theProject.closeProject() is True
|
||||||
assert theProject.openProject(projFile) is True
|
assert theProject.openProject(projFile) is True
|
||||||
|
|
||||||
assert isinstance(theProject.newFile("Hello", "31489056e0916"), str)
|
# Invalid call
|
||||||
assert isinstance(theProject.newFile("Jane", "71ee45a3c0db9"), str)
|
assert theProject.newFolder("New Folder", "1234567890abc") is None
|
||||||
assert theProject.projChanged
|
assert theProject.newFile("New File", "1234567890abc") is None
|
||||||
|
|
||||||
|
# Add files properly
|
||||||
|
assert theProject.newFolder("Stuff", "0000000000015") == "0000000000028"
|
||||||
|
assert theProject.newFile("Hello", "0000000000015") == "0000000000029"
|
||||||
|
assert theProject.newFile("Jane", "0000000000012") == "000000000002a"
|
||||||
|
|
||||||
|
assert "0000000000028" in theProject.tree
|
||||||
|
assert "0000000000029" in theProject.tree
|
||||||
|
assert "000000000002a" in theProject.tree
|
||||||
|
|
||||||
|
# Write to file, failed
|
||||||
|
assert theProject.writeNewFile("blabla", 1, True) is False # Not a handle
|
||||||
|
assert theProject.writeNewFile("0000000000028", 1, True) is False # Not a file
|
||||||
|
assert theProject.writeNewFile("0000000000014", 1, True) is False # Already has content
|
||||||
|
|
||||||
|
# Write to file, success
|
||||||
|
assert theProject.writeNewFile("0000000000029", 2, True) is True
|
||||||
|
assert NWDoc(theProject, "0000000000029").readDocument() == "## Hello\n\n"
|
||||||
|
|
||||||
|
assert theProject.writeNewFile("000000000002a", 1, False) is True
|
||||||
|
assert NWDoc(theProject, "000000000002a").readDocument() == "# Jane\n\n"
|
||||||
|
|
||||||
|
# Save, close and check
|
||||||
|
assert theProject.projChanged is True
|
||||||
assert theProject.saveProject() is True
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject() is True
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
@@ -305,7 +333,7 @@ def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI, mockRnd):
|
|||||||
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
||||||
assert theProject.projChanged is False
|
assert theProject.projChanged is False
|
||||||
|
|
||||||
# END Test testCoreProject_NewFile
|
# END Test testCoreProject_NewFileFolder
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
@@ -613,6 +641,11 @@ def testCoreProject_AccessItems(nwMinimal, mockGUI):
|
|||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theProject.openProject(nwMinimal)
|
theProject.openProject(nwMinimal)
|
||||||
|
|
||||||
|
# Storage Objects
|
||||||
|
assert isinstance(theProject.index, NWIndex)
|
||||||
|
assert isinstance(theProject.tree, NWTree)
|
||||||
|
assert isinstance(theProject.options, OptionState)
|
||||||
|
|
||||||
# Move Novel ROOT to after its files
|
# Move Novel ROOT to after its files
|
||||||
oldOrder = [
|
oldOrder = [
|
||||||
"a508bb932959c", # ROOT: Novel
|
"a508bb932959c", # ROOT: Novel
|
||||||
@@ -722,7 +755,7 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
|
|||||||
# Change Importance
|
# Change Importance
|
||||||
# =================
|
# =================
|
||||||
|
|
||||||
fHandle = theProject.newFile("Jane Doe", "8b9d2e465e150")
|
fHandle = theProject.newFile("Jane Doe", "0000000000012")
|
||||||
theProject.tree[fHandle].setImport("Main")
|
theProject.tree[fHandle].setImport("Main")
|
||||||
|
|
||||||
assert theProject.tree[fHandle].itemImport == importKeys[3]
|
assert theProject.tree[fHandle].itemImport == importKeys[3]
|
||||||
@@ -894,6 +927,10 @@ def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd):
|
|||||||
assert theProject.setProjectLang("en_GB") is True
|
assert theProject.setProjectLang("en_GB") is True
|
||||||
assert theProject.projLang == "en_GB"
|
assert theProject.projLang == "en_GB"
|
||||||
|
|
||||||
|
# Language Lookup
|
||||||
|
assert theProject.localLookup(1) == "One"
|
||||||
|
assert theProject.localLookup(10) == "Ten"
|
||||||
|
|
||||||
# Automatic outline update
|
# Automatic outline update
|
||||||
theProject.projChanged = False
|
theProject.projChanged = False
|
||||||
assert theProject.setAutoOutline(True)
|
assert theProject.setAutoOutline(True)
|
||||||
@@ -1007,7 +1044,8 @@ def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
|
|||||||
|
|
||||||
# Add a file with non-existent parent
|
# Add a file with non-existent parent
|
||||||
# This file will be renoved from the project on open
|
# This file will be renoved from the project on open
|
||||||
assert theProject.newFile("Oops", "0000000000000")
|
oHandle = theProject.newFile("Oops", "b3643d0f92e32")
|
||||||
|
theProject.tree[oHandle].setParent("1234567890abc")
|
||||||
|
|
||||||
# Save and close
|
# Save and close
|
||||||
assert theProject.saveProject() is True
|
assert theProject.saveProject() is True
|
||||||
|
|||||||
Reference in New Issue
Block a user