Update the new project code and add title page
This commit is contained in:
+173
-186
@@ -171,179 +171,6 @@ class NWProject():
|
|||||||
# Project Methods
|
# Project Methods
|
||||||
##
|
##
|
||||||
|
|
||||||
def newProject(self, projData={}):
|
|
||||||
"""Create a new project by populating the project tree with a
|
|
||||||
few starter items.
|
|
||||||
"""
|
|
||||||
popMinimal = True
|
|
||||||
popCustom = False
|
|
||||||
popSample = False
|
|
||||||
if "popMinimal" in projData:
|
|
||||||
popMinimal = projData["popMinimal"]
|
|
||||||
if "popCustom" in projData:
|
|
||||||
popCustom = projData["popCustom"]
|
|
||||||
if "popSample" in projData:
|
|
||||||
popSample = projData["popSample"]
|
|
||||||
|
|
||||||
# Check if we're extracting the sample project.
|
|
||||||
# This is handled differently as it isn't actually a new project.
|
|
||||||
if popSample:
|
|
||||||
return self.extractSampleProject(projData)
|
|
||||||
|
|
||||||
# Set the project path
|
|
||||||
if "projPath" in projData:
|
|
||||||
self.setProjectPath(projData["projPath"], newProject=True)
|
|
||||||
else:
|
|
||||||
logger.error("No project path set for the new project")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Project Title and Authors
|
|
||||||
if "projName" in projData:
|
|
||||||
self.setProjectName(projData["projName"])
|
|
||||||
else:
|
|
||||||
self.setProjectName("New Project")
|
|
||||||
if "projTitle" in projData:
|
|
||||||
self.setBookTitle(projData["projTitle"])
|
|
||||||
if "projAuthors" in projData:
|
|
||||||
self.setBookAuthors(projData["projAuthors"])
|
|
||||||
|
|
||||||
if popMinimal:
|
|
||||||
# Creating a minimal project with a few root folders, a
|
|
||||||
# single chapter folder with a single file.
|
|
||||||
hNovel = self.newRoot("Novel", nwItemClass.NOVEL)
|
|
||||||
hChars = self.newRoot("Characters", nwItemClass.CHARACTER)
|
|
||||||
hWorld = self.newRoot("Plot", nwItemClass.PLOT)
|
|
||||||
hWorld = self.newRoot("World", nwItemClass.WORLD)
|
|
||||||
hChapF = self.newFolder("New Chapter", nwItemClass.NOVEL, hNovel)
|
|
||||||
hScene = self.newFile("New Scene", nwItemClass.NOVEL, hChapF)
|
|
||||||
|
|
||||||
elif popCustom:
|
|
||||||
# Create a project structure based on selected root folders
|
|
||||||
# and a number of chapters and scenes selected in the
|
|
||||||
# wizard's custom page.
|
|
||||||
|
|
||||||
# Create Root Folders
|
|
||||||
hNovel = self.newRoot("Novel", nwItemClass.NOVEL)
|
|
||||||
if "addRoots" in projData:
|
|
||||||
for newRoot in projData["addRoots"]:
|
|
||||||
if newRoot in nwItemClass:
|
|
||||||
self.newRoot(nwLabels.CLASS_NAME[newRoot], newRoot)
|
|
||||||
|
|
||||||
# Create Chapters and Scenes
|
|
||||||
numChapters = 0
|
|
||||||
numScenes = 0
|
|
||||||
chFolders = False
|
|
||||||
if "numChapters" in projData:
|
|
||||||
numChapters = projData["numChapters"]
|
|
||||||
if "numScenes" in projData:
|
|
||||||
numScenes = projData["numScenes"]
|
|
||||||
if "chFolders" in projData:
|
|
||||||
chFolders = projData["chFolders"]
|
|
||||||
|
|
||||||
# Create Chapters
|
|
||||||
if numChapters > 0:
|
|
||||||
for ch in range(numChapters):
|
|
||||||
chTitle = "Chapter %d" % (ch+1)
|
|
||||||
hParDir = hNovel
|
|
||||||
if chFolders:
|
|
||||||
hParDir = self.newFolder(chTitle, nwItemClass.NOVEL, hNovel)
|
|
||||||
hChapD = self.newFile(chTitle, nwItemClass.NOVEL, hParDir)
|
|
||||||
chItem = self.projTree[hChapD]
|
|
||||||
if hChapD is None:
|
|
||||||
logger.error("Something went wrong when creating chapter file.")
|
|
||||||
continue
|
|
||||||
chItem.setLayout(nwItemLayout.CHAPTER)
|
|
||||||
|
|
||||||
# Create Chapter > Scenes
|
|
||||||
if numScenes > 0:
|
|
||||||
for sc in range(numScenes):
|
|
||||||
scTitle = "Scene %d.%d" % (ch+1, sc+1)
|
|
||||||
hScene = self.newFile(scTitle, nwItemClass.NOVEL, hParDir)
|
|
||||||
|
|
||||||
# Create Scenes (No Chapters)
|
|
||||||
elif numScenes > 0:
|
|
||||||
for sc in range(numScenes):
|
|
||||||
scTitle = "Scene %d" % (sc+1)
|
|
||||||
hScene = self.newFile(scTitle, nwItemClass.NOVEL, hNovel)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Fallback just in case.
|
|
||||||
self.newRoot("Novel", nwItemClass.NOVEL)
|
|
||||||
|
|
||||||
# Finalise
|
|
||||||
self.projOpened = time()
|
|
||||||
self.setProjectChanged(True)
|
|
||||||
self.saveProject(autoSave=True)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def extractSampleProject(self, projData):
|
|
||||||
"""Make a copy of the sample project.
|
|
||||||
First, try to copy the content of the sample folder to the new
|
|
||||||
project path, or if the folder doesn't exist, look for the zip
|
|
||||||
file in the assets folder.
|
|
||||||
"""
|
|
||||||
if "projName" in projData:
|
|
||||||
projName = projData["projName"]
|
|
||||||
else:
|
|
||||||
projName = "Sample Project"
|
|
||||||
|
|
||||||
if "projPath" in projData:
|
|
||||||
projPath = projData["projPath"]
|
|
||||||
else:
|
|
||||||
logger.error("No project path set for the example project")
|
|
||||||
return False
|
|
||||||
|
|
||||||
srcSample = path.abspath(path.join(self.mainConf.appRoot, "sample"))
|
|
||||||
pkgSample = path.join(self.mainConf.assetPath, "sample.zip")
|
|
||||||
|
|
||||||
isSuccess = False
|
|
||||||
if path.isfile(pkgSample):
|
|
||||||
|
|
||||||
self.setProjectPath(projPath, newProject=True)
|
|
||||||
try:
|
|
||||||
unpack_archive(pkgSample, projPath)
|
|
||||||
isSuccess = True
|
|
||||||
except Exception as e:
|
|
||||||
self.makeAlert(
|
|
||||||
["Failed to create a new example project.", str(e)], nwAlert.ERROR
|
|
||||||
)
|
|
||||||
|
|
||||||
elif path.isdir(srcSample):
|
|
||||||
|
|
||||||
self.setProjectPath(projPath, newProject=True)
|
|
||||||
try:
|
|
||||||
srcProj = path.join(srcSample, nwFiles.PROJ_FILE)
|
|
||||||
dstProj = path.join(projPath, nwFiles.PROJ_FILE)
|
|
||||||
copyfile(srcProj, dstProj)
|
|
||||||
|
|
||||||
srcContent = path.join(srcSample, "content")
|
|
||||||
dstContent = path.join(projPath, "content")
|
|
||||||
for srcFile in listdir(srcContent):
|
|
||||||
srcDoc = path.join(srcContent, srcFile)
|
|
||||||
dstDoc = path.join(dstContent, srcFile)
|
|
||||||
copyfile(srcDoc, dstDoc)
|
|
||||||
|
|
||||||
isSuccess = True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.makeAlert(
|
|
||||||
["Failed to create a new example project.", str(e)], nwAlert.ERROR
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.makeAlert((
|
|
||||||
"Failed to create a new example project. "
|
|
||||||
"Could not find the necessary files."
|
|
||||||
), nwAlert.ERROR)
|
|
||||||
|
|
||||||
if isSuccess:
|
|
||||||
self.clearProject()
|
|
||||||
self.theParent.openProject(projPath)
|
|
||||||
self.theParent.rebuildIndex()
|
|
||||||
|
|
||||||
return isSuccess
|
|
||||||
|
|
||||||
def clearProject(self):
|
def clearProject(self):
|
||||||
"""Clear the data for the current project, and set them to
|
"""Clear the data for the current project, and set them to
|
||||||
default values.
|
default values.
|
||||||
@@ -379,15 +206,15 @@ class NWProject():
|
|||||||
self.spellCheck = False
|
self.spellCheck = False
|
||||||
self.autoOutline = True
|
self.autoOutline = True
|
||||||
self.statusItems = NWStatus()
|
self.statusItems = NWStatus()
|
||||||
self.statusItems.addEntry("New", (100,100,100))
|
self.statusItems.addEntry("New", (100, 100, 100))
|
||||||
self.statusItems.addEntry("Note", (200, 50, 0))
|
self.statusItems.addEntry("Note", (200, 50, 0))
|
||||||
self.statusItems.addEntry("Draft", (200,150, 0))
|
self.statusItems.addEntry("Draft", (200, 150, 0))
|
||||||
self.statusItems.addEntry("Finished",( 50,200, 0))
|
self.statusItems.addEntry("Finished",( 50, 200, 0))
|
||||||
self.importItems = NWStatus()
|
self.importItems = NWStatus()
|
||||||
self.importItems.addEntry("New", (100,100,100))
|
self.importItems.addEntry("New", (100, 100, 100))
|
||||||
self.importItems.addEntry("Minor", (200, 50, 0))
|
self.importItems.addEntry("Minor", (200, 50, 0))
|
||||||
self.importItems.addEntry("Major", (200,150, 0))
|
self.importItems.addEntry("Major", (200, 150, 0))
|
||||||
self.importItems.addEntry("Main", ( 50,200, 0))
|
self.importItems.addEntry("Main", ( 50, 200, 0))
|
||||||
self.lastEdited = None
|
self.lastEdited = None
|
||||||
self.lastViewed = None
|
self.lastViewed = None
|
||||||
self.lastWCount = 0
|
self.lastWCount = 0
|
||||||
@@ -397,6 +224,104 @@ class NWProject():
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def newProject(self, projData={}):
|
||||||
|
"""Create a new project by populating the project tree with a
|
||||||
|
few starter items.
|
||||||
|
"""
|
||||||
|
popMinimal = projData.get("popMinimal", True)
|
||||||
|
popCustom = projData.get("popCustom", False)
|
||||||
|
popSample = projData.get("popSample", False)
|
||||||
|
|
||||||
|
# Check if we're extracting the sample project. This is handled
|
||||||
|
# differently as it isn't actually a new project, so we forward
|
||||||
|
# this to another function and return here.
|
||||||
|
if popSample:
|
||||||
|
return self.extractSampleProject(projData)
|
||||||
|
|
||||||
|
# Project Settings
|
||||||
|
projPath = projData.get("projPath", None)
|
||||||
|
projName = projData.get("projName", "New Project")
|
||||||
|
projTitle = projData.get("projTitle", "")
|
||||||
|
projAuthors = projData.get("projAuthors", "")
|
||||||
|
|
||||||
|
if projPath is None:
|
||||||
|
logger.error("No project path set for the new project")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not self.setProjectPath(projPath, newProject=True):
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.setProjectName(projName)
|
||||||
|
self.setBookTitle(projTitle)
|
||||||
|
self.setBookAuthors(projAuthors)
|
||||||
|
|
||||||
|
if popMinimal:
|
||||||
|
# Creating a minimal project with a few root folders and a
|
||||||
|
# single chapter folder with a single file.
|
||||||
|
nHandle = self.newRoot("Novel", nwItemClass.NOVEL)
|
||||||
|
xHandle = self.newRoot("Plot", nwItemClass.PLOT)
|
||||||
|
xHandle = self.newRoot("Characters", nwItemClass.CHARACTER)
|
||||||
|
xHandle = self.newRoot("World", nwItemClass.WORLD)
|
||||||
|
tHandle = self.newFile("Title Page", nwItemClass.NOVEL, nHandle)
|
||||||
|
cHandle = self.newFolder("New Chapter", nwItemClass.NOVEL, nHandle)
|
||||||
|
fHandle = self.newFile("New Chapter", nwItemClass.NOVEL, cHandle)
|
||||||
|
XHandle = self.newFile("New Scene", nwItemClass.NOVEL, cHandle)
|
||||||
|
self.projTree.setFileItemLayout(tHandle, nwItemLayout.TITLE)
|
||||||
|
self.projTree.setFileItemLayout(fHandle, nwItemLayout.CHAPTER)
|
||||||
|
|
||||||
|
elif popCustom:
|
||||||
|
# Create a project structure based on selected root folders
|
||||||
|
# and a number of chapters and scenes selected in the
|
||||||
|
# wizard's custom page.
|
||||||
|
|
||||||
|
# Create root folders
|
||||||
|
nHandle = self.newRoot("Novel", nwItemClass.NOVEL)
|
||||||
|
for newRoot in projData.get("addRoots", []):
|
||||||
|
if newRoot in nwItemClass:
|
||||||
|
self.newRoot(nwLabels.CLASS_NAME[newRoot], newRoot)
|
||||||
|
|
||||||
|
# Create a title page
|
||||||
|
tHandle = self.newFile("Title Page", nwItemClass.NOVEL, nHandle)
|
||||||
|
self.projTree.setFileItemLayout(tHandle, nwItemLayout.TITLE)
|
||||||
|
|
||||||
|
# Create chapters and scenes
|
||||||
|
numChapters = projData.get("numChapters", 0)
|
||||||
|
numScenes = projData.get("numScenes", 0)
|
||||||
|
chFolders = projData.get("chFolders", False)
|
||||||
|
|
||||||
|
# Create chapters
|
||||||
|
if numChapters > 0:
|
||||||
|
for ch in range(numChapters):
|
||||||
|
chTitle = "Chapter %d" % (ch+1)
|
||||||
|
pHandle = nHandle
|
||||||
|
if chFolders:
|
||||||
|
pHandle = self.newFolder(chTitle, nwItemClass.NOVEL, nHandle)
|
||||||
|
cHandle = self.newFile(chTitle, nwItemClass.NOVEL, pHandle)
|
||||||
|
self.projTree.setFileItemLayout(cHandle, nwItemLayout.CHAPTER)
|
||||||
|
|
||||||
|
# Create chapter scenes
|
||||||
|
if numScenes > 0:
|
||||||
|
for sc in range(numScenes):
|
||||||
|
scTitle = "Scene %d.%d" % (ch+1, sc+1)
|
||||||
|
sHandle = self.newFile(scTitle, nwItemClass.NOVEL, pHandle)
|
||||||
|
|
||||||
|
# Create scenes (no chapters)
|
||||||
|
elif numScenes > 0:
|
||||||
|
for sc in range(numScenes):
|
||||||
|
scTitle = "Scene %d" % (sc+1)
|
||||||
|
sHandle = self.newFile(scTitle, nwItemClass.NOVEL, nHandle)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Fallback just in case. We shouldn't reach here.
|
||||||
|
self.newRoot("Novel", nwItemClass.NOVEL)
|
||||||
|
|
||||||
|
# Finalise
|
||||||
|
self.projOpened = time()
|
||||||
|
self.setProjectChanged(True)
|
||||||
|
self.saveProject(autoSave=True)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def openProject(self, fileName, overrideLock=False):
|
def openProject(self, fileName, overrideLock=False):
|
||||||
"""Open the project file provided, or if doesn't exist, assume
|
"""Open the project file provided, or if doesn't exist, assume
|
||||||
it is a folder, and look for the file within it. If successful,
|
it is a folder, and look for the file within it. If successful,
|
||||||
@@ -716,9 +641,9 @@ class NWProject():
|
|||||||
if len(aKey) > 0:
|
if len(aKey) > 0:
|
||||||
self._packProjectValue(xTitleFmt, aKey, aValue)
|
self._packProjectValue(xTitleFmt, aKey, aValue)
|
||||||
|
|
||||||
xStatus = etree.SubElement(xSettings,"status")
|
xStatus = etree.SubElement(xSettings, "status")
|
||||||
self.statusItems.packEntries(xStatus)
|
self.statusItems.packEntries(xStatus)
|
||||||
xStatus = etree.SubElement(xSettings,"importance")
|
xStatus = etree.SubElement(xSettings, "importance")
|
||||||
self.importItems.packEntries(xStatus)
|
self.importItems.packEntries(xStatus)
|
||||||
|
|
||||||
# Save Tree Content
|
# Save Tree Content
|
||||||
@@ -733,8 +658,8 @@ class NWProject():
|
|||||||
with open(tempFile, mode="wb") as outFile:
|
with open(tempFile, mode="wb") as outFile:
|
||||||
outFile.write(etree.tostring(
|
outFile.write(etree.tostring(
|
||||||
nwXML,
|
nwXML,
|
||||||
pretty_print = True,
|
pretty_print = True,
|
||||||
encoding = "utf-8",
|
encoding = "utf-8",
|
||||||
xml_declaration = True
|
xml_declaration = True
|
||||||
))
|
))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -794,7 +719,7 @@ class NWProject():
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
##
|
##
|
||||||
# Backup Project
|
# Zip/Unzip Project
|
||||||
##
|
##
|
||||||
|
|
||||||
def zipIt(self, doNotify):
|
def zipIt(self, doNotify):
|
||||||
@@ -870,6 +795,68 @@ class NWProject():
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def extractSampleProject(self, projData):
|
||||||
|
"""Make a copy of the sample project.
|
||||||
|
First, try to copy the content of the sample folder to the new
|
||||||
|
project path, or if the folder doesn't exist, look for the zip
|
||||||
|
file in the assets folder.
|
||||||
|
"""
|
||||||
|
projName = projData.get("projName", "Sample Project")
|
||||||
|
projPath = projData.get("projPath", None)
|
||||||
|
if projPath is None:
|
||||||
|
logger.error("No project path set for the example project")
|
||||||
|
return False
|
||||||
|
|
||||||
|
srcSample = path.abspath(path.join(self.mainConf.appRoot, "sample"))
|
||||||
|
pkgSample = path.join(self.mainConf.assetPath, "sample.zip")
|
||||||
|
|
||||||
|
isSuccess = False
|
||||||
|
if path.isfile(pkgSample):
|
||||||
|
|
||||||
|
self.setProjectPath(projPath, newProject=True)
|
||||||
|
try:
|
||||||
|
unpack_archive(pkgSample, projPath)
|
||||||
|
isSuccess = True
|
||||||
|
except Exception as e:
|
||||||
|
self.makeAlert(
|
||||||
|
["Failed to create a new example project.", str(e)], nwAlert.ERROR
|
||||||
|
)
|
||||||
|
|
||||||
|
elif path.isdir(srcSample):
|
||||||
|
|
||||||
|
self.setProjectPath(projPath, newProject=True)
|
||||||
|
try:
|
||||||
|
srcProj = path.join(srcSample, nwFiles.PROJ_FILE)
|
||||||
|
dstProj = path.join(projPath, nwFiles.PROJ_FILE)
|
||||||
|
copyfile(srcProj, dstProj)
|
||||||
|
|
||||||
|
srcContent = path.join(srcSample, "content")
|
||||||
|
dstContent = path.join(projPath, "content")
|
||||||
|
for srcFile in listdir(srcContent):
|
||||||
|
srcDoc = path.join(srcContent, srcFile)
|
||||||
|
dstDoc = path.join(dstContent, srcFile)
|
||||||
|
copyfile(srcDoc, dstDoc)
|
||||||
|
|
||||||
|
isSuccess = True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.makeAlert(
|
||||||
|
["Failed to create a new example project.", str(e)], nwAlert.ERROR
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.makeAlert((
|
||||||
|
"Failed to create a new example project. "
|
||||||
|
"Could not find the necessary files."
|
||||||
|
), nwAlert.ERROR)
|
||||||
|
|
||||||
|
if isSuccess:
|
||||||
|
self.clearProject()
|
||||||
|
self.theParent.openProject(projPath)
|
||||||
|
self.theParent.rebuildIndex()
|
||||||
|
|
||||||
|
return isSuccess
|
||||||
|
|
||||||
##
|
##
|
||||||
# Setters
|
# Setters
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -314,6 +314,22 @@ class NWTree():
|
|||||||
self._handleSeed = theSeed
|
self._handleSeed = theSeed
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def setFileItemLayout(self, tHandle, itemLayout):
|
||||||
|
"""Set the nwItemLayout for a specific file.
|
||||||
|
"""
|
||||||
|
tItem = self.__getitem__(tHandle)
|
||||||
|
if tItem is None:
|
||||||
|
return False
|
||||||
|
if tItem.itemType != nwItemType.FILE:
|
||||||
|
logger.error("Item '%s' is not a file" % tHandle)
|
||||||
|
return False
|
||||||
|
if not isinstance(itemLayout, nwItemLayout):
|
||||||
|
return False
|
||||||
|
|
||||||
|
tItem.setLayout(itemLayout)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
##
|
##
|
||||||
# Getters
|
# Getters
|
||||||
##
|
##
|
||||||
|
|||||||
+1
-1
@@ -192,7 +192,7 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
nHandle = pHandle
|
nHandle = pHandle
|
||||||
pHandle = pItem.parHandle
|
pHandle = pItem.parHandle
|
||||||
|
|
||||||
# If we again has no home, give up
|
# If we again have no home, give up
|
||||||
if pHandle is None:
|
if pHandle is None:
|
||||||
self.makeAlert(
|
self.makeAlert(
|
||||||
"Did not find anywhere to add the file or folder!", nwAlert.ERROR
|
"Did not find anywhere to add the file or folder!", nwAlert.ERROR
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ class ProjWizardCustomPage(QWizardPage):
|
|||||||
|
|
||||||
self.addPlot.setChecked(True)
|
self.addPlot.setChecked(True)
|
||||||
self.addChar.setChecked(True)
|
self.addChar.setChecked(True)
|
||||||
|
self.addWorld.setChecked(True)
|
||||||
|
|
||||||
self.rootForm.addWidget(self.lblPlot, 0, 0)
|
self.rootForm.addWidget(self.lblPlot, 0, 0)
|
||||||
self.rootForm.addWidget(self.lblChar, 1, 0)
|
self.rootForm.addWidget(self.lblChar, 1, 0)
|
||||||
|
|||||||
+1
-4
@@ -281,10 +281,7 @@ class GuiMain(QMainWindow):
|
|||||||
if projData is None:
|
if projData is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
projPath = None
|
projPath = projData.get("projPath", None)
|
||||||
if "projPath" in projData:
|
|
||||||
projPath = projData["projPath"]
|
|
||||||
|
|
||||||
if projPath is None or projData is None:
|
if projPath is None or projData is None:
|
||||||
logger.error("No projData or projPath set")
|
logger.error("No projData or projPath set")
|
||||||
return False
|
return False
|
||||||
|
|||||||
Reference in New Issue
Block a user