Complete the create new project code path
This commit is contained in:
+101
-107
@@ -30,6 +30,7 @@ import shutil
|
||||
import logging
|
||||
|
||||
from typing import Iterable
|
||||
from pathlib import Path
|
||||
from functools import partial
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
@@ -39,6 +40,7 @@ from novelwriter.common import minmax, simplified
|
||||
from novelwriter.constants import nwItemClass
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.storage import NWStorageCreate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -310,9 +312,15 @@ class ProjectBuilder:
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._path = None
|
||||
self.tr = partial(QCoreApplication.translate, "NWProject")
|
||||
return
|
||||
|
||||
@property
|
||||
def projPath(self) -> Path | None:
|
||||
"""The path of the newly created project."""
|
||||
return self._path
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -325,40 +333,56 @@ class ProjectBuilder:
|
||||
logger.error("Invalid call to newProject function")
|
||||
return False
|
||||
|
||||
popMinimal = data.get("popMinimal", True)
|
||||
popCustom = data.get("popCustom", False)
|
||||
popSample = data.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(data)
|
||||
|
||||
projPath = data.get("projPath", None)
|
||||
if projPath is None:
|
||||
logger.error("No project path set for the new project")
|
||||
path = data.get("path", None)
|
||||
if path is None:
|
||||
SHARED.error("A project path is required.")
|
||||
return False
|
||||
|
||||
if data.get("sample", False):
|
||||
self._path = path
|
||||
return self._extractSampleProject(path)
|
||||
elif data.get("template"):
|
||||
pass
|
||||
else:
|
||||
self._buildAndPopulate(path, data)
|
||||
|
||||
return True
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _buildAndPopulate(self, path: Path, data: dict) -> bool:
|
||||
"""Build a project from a data dictionary of specifications
|
||||
provided by the wizard.
|
||||
"""
|
||||
project = NWProject()
|
||||
if not project.storage.createNewProject(projPath):
|
||||
status = project.storage.createNewProject(path)
|
||||
if status == NWStorageCreate.NOT_EMPTY:
|
||||
SHARED.error(self.tr(
|
||||
"A project already exists in that location. "
|
||||
"Please choose another folder."
|
||||
))
|
||||
return False
|
||||
elif status == NWStorageCreate.OS_ERROR:
|
||||
SHARED.error(self.tr(
|
||||
"An error occured while trying to create the project."
|
||||
), exc=project.storage.exc)
|
||||
return False
|
||||
|
||||
self._path = project.storage.storagePath
|
||||
|
||||
lblNewProject = self.tr("New Project")
|
||||
lblNewChapter = self.tr("New Chapter")
|
||||
lblNewScene = self.tr("New Scene")
|
||||
lblTitlePage = self.tr("Title Page")
|
||||
lblByAuthors = self.tr("By")
|
||||
|
||||
# Settings
|
||||
projName = data.get("projName", lblNewProject)
|
||||
projTitle = data.get("projTitle", lblNewProject)
|
||||
projAuthor = data.get("projAuthor", "")
|
||||
projLang = data.get("projLang", "en_GB")
|
||||
projName = data.get("name", lblNewProject)
|
||||
projAuthor = data.get("author", "")
|
||||
projLang = data.get("language", "en_GB")
|
||||
|
||||
project.data.setUuid(None)
|
||||
project.data.setName(projName)
|
||||
project.data.setTitle(projTitle)
|
||||
project.data.setAuthor(projAuthor)
|
||||
project.data.setLanguage(projLang)
|
||||
project.setDefaultStatusImport()
|
||||
@@ -376,110 +400,80 @@ class ProjectBuilder:
|
||||
aDoc = project.storage.getDocument(hTitlePage)
|
||||
aDoc.writeDocument(titlePage)
|
||||
|
||||
if popMinimal:
|
||||
# Creating a minimal project with a few root folders and a
|
||||
# single chapter with a single scene.
|
||||
hChapter = project.newFile(lblNewChapter, hNovelRoot)
|
||||
aDoc = project.storage.getDocument(hChapter)
|
||||
aDoc.writeDocument(f"## {lblNewChapter}\n\n")
|
||||
# Create a project structure based on selected root folders
|
||||
# and a number of chapters and scenes selected in the
|
||||
# wizard's custom page.
|
||||
|
||||
if hChapter:
|
||||
hScene = project.newFile(lblNewScene, hChapter)
|
||||
aDoc = project.storage.getDocument(hScene)
|
||||
aDoc.writeDocument(f"### {lblNewScene}\n\n")
|
||||
# Create chapters and scenes
|
||||
numChapters = data.get("chapters", 0)
|
||||
numScenes = data.get("scenes", 0)
|
||||
|
||||
project.newRoot(nwItemClass.PLOT)
|
||||
project.newRoot(nwItemClass.CHARACTER)
|
||||
project.newRoot(nwItemClass.WORLD)
|
||||
project.newRoot(nwItemClass.ARCHIVE)
|
||||
chSynop = self.tr("Summary of the chapter.")
|
||||
scSynop = self.tr("Summary of the scene.")
|
||||
bfNote = self.tr("A short description.")
|
||||
|
||||
project.saveProject()
|
||||
project.closeProject()
|
||||
# Create chapters
|
||||
if numChapters > 0:
|
||||
for ch in range(numChapters):
|
||||
chTitle = self.tr("Chapter {0}").format(f"{ch+1:d}")
|
||||
cHandle = project.newFile(chTitle, hNovelRoot)
|
||||
aDoc = project.storage.getDocument(cHandle)
|
||||
aDoc.writeDocument(f"## {chTitle}\n\n%Synopsis: {chSynop}\n\n")
|
||||
|
||||
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 chapter scenes
|
||||
if numScenes > 0 and cHandle:
|
||||
for sc in range(numScenes):
|
||||
scTitle = self.tr("Scene {0}").format(f"{ch+1:d}.{sc+1:d}")
|
||||
sHandle = project.newFile(scTitle, cHandle)
|
||||
aDoc = project.storage.getDocument(sHandle)
|
||||
aDoc.writeDocument(f"### {scTitle}\n\n%Synopsis: {scSynop}\n\n")
|
||||
|
||||
# Create chapters and scenes
|
||||
numChapters = data.get("numChapters", 0)
|
||||
numScenes = data.get("numScenes", 0)
|
||||
# Create scenes (no chapters)
|
||||
elif numScenes > 0:
|
||||
for sc in range(numScenes):
|
||||
scTitle = self.tr("Scene {0}").format(f"{sc+1:d}")
|
||||
sHandle = project.newFile(scTitle, hNovelRoot)
|
||||
aDoc = project.storage.getDocument(sHandle)
|
||||
aDoc.writeDocument(f"### {scTitle}\n\n%Synopsis: {scSynop}\n\n")
|
||||
|
||||
chSynop = self.tr("Summary of the chapter.")
|
||||
scSynop = self.tr("Summary of the scene.")
|
||||
bfNote = self.tr("A short description.")
|
||||
# Create notes folders
|
||||
noteTitles = {
|
||||
nwItemClass.PLOT: self.tr("Main Plot"),
|
||||
nwItemClass.CHARACTER: self.tr("Protagonist"),
|
||||
nwItemClass.WORLD: self.tr("Main Location"),
|
||||
}
|
||||
|
||||
# Create chapters
|
||||
if numChapters > 0:
|
||||
for ch in range(numChapters):
|
||||
chTitle = self.tr("Chapter {0}").format(f"{ch+1:d}")
|
||||
cHandle = project.newFile(chTitle, hNovelRoot)
|
||||
aDoc = project.storage.getDocument(cHandle)
|
||||
aDoc.writeDocument(f"## {chTitle}\n\n% Synopsis: {chSynop}\n\n")
|
||||
addNotes = data.get("notes", False)
|
||||
for newRoot in data.get("roots", []):
|
||||
if newRoot in nwItemClass:
|
||||
rHandle = project.newRoot(newRoot)
|
||||
if addNotes:
|
||||
aHandle = project.newFile(noteTitles[newRoot], rHandle)
|
||||
ntTag = simplified(noteTitles[newRoot]).replace(" ", "")
|
||||
aDoc = project.storage.getDocument(aHandle)
|
||||
aDoc.writeDocument(
|
||||
f"# {noteTitles[newRoot]}\n\n"
|
||||
f"@tag: {ntTag}\n\n"
|
||||
f"%Short: {bfNote}\n\n"
|
||||
)
|
||||
|
||||
# Create chapter scenes
|
||||
if numScenes > 0 and cHandle:
|
||||
for sc in range(numScenes):
|
||||
scTitle = self.tr("Scene {0}").format(f"{ch+1:d}.{sc+1:d}")
|
||||
sHandle = project.newFile(scTitle, cHandle)
|
||||
aDoc = project.storage.getDocument(sHandle)
|
||||
aDoc.writeDocument(f"### {scTitle}\n\n% Synopsis: {scSynop}\n\n")
|
||||
# Also add the archive and trash folders
|
||||
project.newRoot(nwItemClass.ARCHIVE)
|
||||
project.trashFolder()
|
||||
|
||||
# Create scenes (no chapters)
|
||||
elif numScenes > 0:
|
||||
for sc in range(numScenes):
|
||||
scTitle = self.tr("Scene {0}").format(f"{sc+1:d}")
|
||||
sHandle = project.newFile(scTitle, hNovelRoot)
|
||||
aDoc = project.storage.getDocument(sHandle)
|
||||
aDoc.writeDocument(f"### {scTitle}\n\n% Synopsis: {scSynop}\n\n")
|
||||
|
||||
# Create notes folders
|
||||
noteTitles = {
|
||||
nwItemClass.PLOT: self.tr("Main Plot"),
|
||||
nwItemClass.CHARACTER: self.tr("Protagonist"),
|
||||
nwItemClass.WORLD: self.tr("Main Location"),
|
||||
}
|
||||
|
||||
addNotes = data.get("addNotes", False)
|
||||
for newRoot in data.get("addRoots", []):
|
||||
if newRoot in nwItemClass:
|
||||
rHandle = project.newRoot(newRoot)
|
||||
if addNotes:
|
||||
aHandle = project.newFile(noteTitles[newRoot], rHandle)
|
||||
ntTag = simplified(noteTitles[newRoot]).replace(" ", "")
|
||||
aDoc = project.storage.getDocument(aHandle)
|
||||
aDoc.writeDocument(
|
||||
f"# {noteTitles[newRoot]}\n\n"
|
||||
f"@tag: {ntTag}\n\n"
|
||||
f"% Short: {bfNote}\n\n"
|
||||
)
|
||||
|
||||
# Also add the archive and trash folders
|
||||
project.newRoot(nwItemClass.ARCHIVE)
|
||||
project.trashFolder()
|
||||
|
||||
project.saveProject()
|
||||
project.closeProject()
|
||||
project.saveProject()
|
||||
project.closeProject()
|
||||
|
||||
return True
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _extractSampleProject(self, data: dict) -> bool:
|
||||
def _extractSampleProject(self, path: Path) -> bool:
|
||||
"""Make a copy of the sample project by extracting the
|
||||
sample.zip file to the new path.
|
||||
"""
|
||||
projPath = data.get("projPath", None)
|
||||
if projPath is None:
|
||||
logger.error("No project path set for the example project")
|
||||
return False
|
||||
|
||||
pkgSample = CONFIG.assetPath("sample.zip")
|
||||
if pkgSample.is_file():
|
||||
try:
|
||||
shutil.unpack_archive(pkgSample, projPath)
|
||||
shutil.unpack_archive(pkgSample, path)
|
||||
except Exception as exc:
|
||||
SHARED.error(self.tr(
|
||||
"Failed to create a new example project."
|
||||
|
||||
@@ -57,6 +57,15 @@ class NWStorageOpen(Enum):
|
||||
# END Enum NWStorageOpen
|
||||
|
||||
|
||||
class NWStorageCreate(Enum):
|
||||
|
||||
NOT_EMPTY = 0
|
||||
OS_ERROR = 1
|
||||
READY = 2
|
||||
|
||||
# END Enum NWStorageCreate
|
||||
|
||||
|
||||
class NWStorage:
|
||||
"""Core: Project Storage Class
|
||||
|
||||
@@ -133,12 +142,12 @@ class NWStorage:
|
||||
"""Check if the storage location is open."""
|
||||
return self._ready and self._runtimePath is not None
|
||||
|
||||
def createNewProject(self, path: str | Path) -> bool:
|
||||
def createNewProject(self, path: str | Path) -> NWStorageCreate:
|
||||
"""Create a new project at the given location."""
|
||||
inPath = Path(path).resolve()
|
||||
if inPath.is_dir() and len(list(inPath.iterdir())) > 0:
|
||||
logger.error("Folder is not empty: %s", inPath)
|
||||
return False
|
||||
return NWStorageCreate.NOT_EMPTY
|
||||
|
||||
self._storagePath = inPath
|
||||
self._runtimePath = inPath
|
||||
@@ -156,11 +165,11 @@ class NWStorage:
|
||||
self._exception = exc
|
||||
logger.error("Failed to create project folders", exc_info=exc)
|
||||
self.clear()
|
||||
return False
|
||||
return NWStorageCreate.OS_ERROR
|
||||
|
||||
self._ready = True
|
||||
|
||||
return True
|
||||
return NWStorageCreate.READY
|
||||
|
||||
def initProjectStorage(self, path: str | Path, clearLock: bool = False) -> NWStorageOpen:
|
||||
"""Initialise a novelWriter project location."""
|
||||
|
||||
@@ -132,14 +132,10 @@ class GuiMainMenu(QMenuBar):
|
||||
# Project
|
||||
self.projMenu = self.addMenu(self.tr("&Project"))
|
||||
|
||||
# Project > New Project
|
||||
self.aNewProject = self.projMenu.addAction(self.tr("New Project"))
|
||||
self.aNewProject.triggered.connect(lambda: self.mainGui.newProject(None))
|
||||
|
||||
# Project > Open Project
|
||||
self.aOpenProject = self.projMenu.addAction(self.tr("Open Project"))
|
||||
# Project > Create or Open Project
|
||||
self.aOpenProject = self.projMenu.addAction(self.tr("Create or Open Project"))
|
||||
self.aOpenProject.setShortcut("Ctrl+Shift+O")
|
||||
self.aOpenProject.triggered.connect(lambda: self.mainGui.showProjectLoadDialog())
|
||||
self.aOpenProject.triggered.connect(self.mainGui.showWelcomeDialog)
|
||||
|
||||
# Project > Save Project
|
||||
self.aSaveProject = self.projMenu.addAction(self.tr("Save Project"))
|
||||
|
||||
+20
-10
@@ -51,7 +51,7 @@ from novelwriter.gui.itemdetails import GuiItemDetails
|
||||
from novelwriter.gui.docviewerpanel import GuiDocViewerPanel
|
||||
from novelwriter.dialogs.about import GuiAbout
|
||||
from novelwriter.dialogs.updates import GuiUpdates
|
||||
# from novelwriter.dialogs.projload import GuiProjectLoad
|
||||
from novelwriter.dialogs.projload import GuiProjectLoad
|
||||
from novelwriter.dialogs.wordlist import GuiWordList
|
||||
from novelwriter.dialogs.preferences import GuiPreferences
|
||||
from novelwriter.dialogs.projdetails import GuiProjectDetails
|
||||
@@ -360,7 +360,7 @@ class GuiMain(QMainWindow):
|
||||
self.openProject(cmdOpen)
|
||||
|
||||
if not SHARED.hasProject:
|
||||
self.showProjectLoadDialog()
|
||||
self.showWelcomeDialog()
|
||||
|
||||
# Determine whether release notes need to be shown or not
|
||||
if hexToInt(CONFIG.lastNotes) < hexToInt(__hexversion__):
|
||||
@@ -844,18 +844,22 @@ class GuiMain(QMainWindow):
|
||||
browse button for projects not yet cached. Selecting to create a
|
||||
new project is forwarded to the new project wizard.
|
||||
"""
|
||||
# dlgProj = GuiProjectLoad(self)
|
||||
# dlgProj.exec_()
|
||||
dlgProj = GuiProjectLoad(self)
|
||||
dlgProj.exec_()
|
||||
|
||||
# if dlgProj.result() == QDialog.Accepted:
|
||||
# if dlgProj.openState == GuiProjectLoad.OPEN_STATE:
|
||||
# self.openProject(dlgProj.openPath)
|
||||
# elif dlgProj.openState == GuiProjectLoad.NEW_STATE:
|
||||
# self.newProject()
|
||||
if dlgProj.result() == QDialog.Accepted:
|
||||
if dlgProj.openState == GuiProjectLoad.OPEN_STATE:
|
||||
self.openProject(dlgProj.openPath)
|
||||
elif dlgProj.openState == GuiProjectLoad.NEW_STATE:
|
||||
self.newProject()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def showWelcomeDialog(self) -> None:
|
||||
"""Open the welcome dialog."""
|
||||
dialog = GuiWelcome(self)
|
||||
dialog.openProjectRequest.connect(self._openProject)
|
||||
dialog.exec_()
|
||||
|
||||
return
|
||||
|
||||
def showNewProjectDialog(self) -> dict | None:
|
||||
@@ -1208,6 +1212,12 @@ class GuiMain(QMainWindow):
|
||||
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
||||
return
|
||||
|
||||
@pyqtSlot(Path)
|
||||
def _openProject(self, path: Path) -> None:
|
||||
"""Handle an open project request."""
|
||||
self.openProject(path)
|
||||
return
|
||||
|
||||
@pyqtSlot(str, nwDocMode, str, bool)
|
||||
def _openDocument(self, tHandle: str, mode: nwDocMode, sTitle: str, setFocus: bool) -> None:
|
||||
"""Handle an open document request."""
|
||||
|
||||
@@ -38,8 +38,10 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED, __version__, __date__
|
||||
from novelwriter.enum import nwItemClass
|
||||
from novelwriter.common import makeFileNameSafe
|
||||
from novelwriter.constants import nwUnicode
|
||||
from novelwriter.core.coretools import ProjectBuilder
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
@@ -50,6 +52,8 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class GuiWelcome(QDialog):
|
||||
|
||||
openProjectRequest = pyqtSignal(Path)
|
||||
|
||||
def __init__(self, mainGui: GuiMain) -> None:
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
@@ -84,6 +88,7 @@ class GuiWelcome(QDialog):
|
||||
self.tabOpen = _OpenProjectPage(self)
|
||||
self.tabNew = _NewProjectPage(self)
|
||||
self.tabNew.cancelNewProject.connect(self._showOpenProjectPage)
|
||||
self.tabNew.openProjectRequest.connect(self._setProjectPath)
|
||||
|
||||
self.mainStack = QStackedWidget()
|
||||
self.mainStack.addWidget(self.tabOpen)
|
||||
@@ -167,6 +172,15 @@ class GuiWelcome(QDialog):
|
||||
self.mainStack.setCurrentWidget(self.tabOpen)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
@pyqtSlot(Path)
|
||||
def _setProjectPath(self, path: Path | None = None) -> None:
|
||||
"""Set the path variable for the project to open."""
|
||||
if isinstance(path, Path):
|
||||
self.openProjectRequest.emit(path)
|
||||
self.close()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
@@ -207,6 +221,7 @@ class _OpenProjectPage(QWidget):
|
||||
class _NewProjectPage(QWidget):
|
||||
|
||||
cancelNewProject = pyqtSignal()
|
||||
openProjectRequest = pyqtSignal(Path)
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
@@ -225,13 +240,14 @@ class _NewProjectPage(QWidget):
|
||||
# Controls
|
||||
# ========
|
||||
|
||||
self.createButton = QPushButton(self.tr("Create Project"), self)
|
||||
self.createButton.setIcon(SHARED.theme.getIcon("star"))
|
||||
|
||||
self.cancelButton = QPushButton(self.tr("Go Back"), self)
|
||||
self.cancelButton.setIcon(SHARED.theme.getIcon("backward"))
|
||||
self.cancelButton.clicked.connect(lambda: self.cancelNewProject.emit())
|
||||
|
||||
self.createButton = QPushButton(self.tr("Create Project"), self)
|
||||
self.createButton.setIcon(SHARED.theme.getIcon("star"))
|
||||
self.createButton.clicked.connect(self._createNewProject)
|
||||
|
||||
self.buttonBox = QHBoxLayout()
|
||||
self.buttonBox.addStretch(1)
|
||||
self.buttonBox.addWidget(self.cancelButton, 0)
|
||||
@@ -258,6 +274,22 @@ class _NewProjectPage(QWidget):
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
@pyqtSlot()
|
||||
def _createNewProject(self) -> None:
|
||||
"""Create a new project from the data in the form."""
|
||||
data = self.projectForm.getProjectData()
|
||||
if not data.get("name"):
|
||||
SHARED.error(self.tr("A project name is required."))
|
||||
return
|
||||
builder = ProjectBuilder()
|
||||
if builder.buildProject(data) and (path := builder.projPath):
|
||||
self.openProjectRequest.emit(path)
|
||||
return
|
||||
|
||||
# END Class _NewProjectPage
|
||||
|
||||
|
||||
@@ -422,6 +454,29 @@ class _NewProjectForm(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def getProjectData(self) -> dict:
|
||||
"""Collect form data and return it as a dictionary."""
|
||||
roots = []
|
||||
if self.addPlot.isChecked():
|
||||
roots.append(nwItemClass.PLOT)
|
||||
if self.addChar.isChecked():
|
||||
roots.append(nwItemClass.CHARACTER)
|
||||
if self.addWorld.isChecked():
|
||||
roots.append(nwItemClass.WORLD)
|
||||
return {
|
||||
"name": self.projName.text().strip(),
|
||||
"author": self.projAuthor.text().strip(),
|
||||
"language": self.projLang.currentData(),
|
||||
"path": self.projPath.text(),
|
||||
"blank": self._fillMode == self.FILL_BLANK,
|
||||
"sample": self._fillMode == self.FILL_SAMPLE,
|
||||
"template": self._copyPath if self._fillMode == self.FILL_COPY else None,
|
||||
"chapters": self.numChapters.value(),
|
||||
"scenes": self.numScenes.value(),
|
||||
"roots": roots,
|
||||
"notes": self.addNotes.isChecked(),
|
||||
}
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
@@ -472,9 +527,10 @@ class _NewProjectForm(QWidget):
|
||||
@pyqtSlot()
|
||||
def _setFillCopy(self) -> None:
|
||||
"""Set fill mode to copy project."""
|
||||
self._fillMode = self.FILL_COPY
|
||||
self._copyPath = SHARED.getProjectPath(self, allowZip=True)
|
||||
self._updateFillInfo()
|
||||
if copyPath := SHARED.getProjectPath(self, allowZip=True):
|
||||
self._fillMode = self.FILL_COPY
|
||||
self._copyPath = copyPath
|
||||
self._updateFillInfo()
|
||||
return
|
||||
|
||||
##
|
||||
|
||||
@@ -32,7 +32,7 @@ from mocked import causeOSError
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.storage import NWStorage, NWStorageOpen, _LegacyStorage
|
||||
from novelwriter.core.storage import NWStorage, NWStorageOpen, NWStorageCreate, _LegacyStorage
|
||||
from novelwriter.core.document import NWDocument
|
||||
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter
|
||||
|
||||
@@ -67,16 +67,16 @@ def testCoreStorage_CreateNewProject(mockGUI, fncPath):
|
||||
|
||||
# Cannot prepare a non-empty folder
|
||||
(fncPath / "foobar.txt").touch()
|
||||
assert storage.createNewProject(fncPath) is False
|
||||
assert storage.createNewProject(fncPath) == NWStorageCreate.NOT_EMPTY
|
||||
|
||||
# Try creating in a non-existent subfolder instead
|
||||
assert storage.createNewProject(fncPath / "project1") is True
|
||||
assert storage.createNewProject(fncPath / "project1") == NWStorageCreate.READY
|
||||
assert (fncPath / "project1").is_dir()
|
||||
assert (fncPath / "project1" / "meta").is_dir()
|
||||
assert (fncPath / "project1" / "content").is_dir()
|
||||
|
||||
# However, the parent folder must exist
|
||||
assert storage.createNewProject(fncPath / "foobar" / "project1") is False
|
||||
assert storage.createNewProject(fncPath / "foobar" / "project1") == NWStorageCreate.OS_ERROR
|
||||
assert isinstance(storage.exc, FileNotFoundError)
|
||||
|
||||
project.closeProject()
|
||||
|
||||
Reference in New Issue
Block a user