Move the hasProject logic into the shared class

This commit is contained in:
Veronica Berglyd Olsen
2023-08-13 19:23:32 +02:00
parent fd181b18a6
commit 8154293d92
8 changed files with 71 additions and 55 deletions
+22 -8
View File
@@ -75,13 +75,20 @@ class NWProject(QObject):
self._session = NWSessionLog(self) # The session record self._session = NWSessionLog(self) # The session record
# Project Status # Project Status
self._langData = {} # Localisation data self._langData = {} # Localisation data
self._projChanged = False # The project has unsaved changes self._lockedBy = None # Data on which computer has the project open
self._lockedBy = None # Data on which computer has the project open self._changed = False # The project has unsaved changes
self._valid = False # The project was successfully loaded
# Internal Mapping # Internal Mapping
self.tr = partial(QCoreApplication.translate, "NWProject") self.tr = partial(QCoreApplication.translate, "NWProject")
logger.debug("Ready: NWProject")
return
def __del__(self): # pragma: no cover
logger.debug("Delete: NWProject")
return return
## ##
@@ -118,7 +125,11 @@ class NWProject(QObject):
@property @property
def projChanged(self) -> bool: def projChanged(self) -> bool:
return self._projChanged return self._changed
@property
def isValid(self) -> bool:
return self._valid
## ##
# Item Methods # Item Methods
@@ -212,7 +223,8 @@ class NWProject(QObject):
# Project Status # Project Status
self._langData = {} self._langData = {}
self._projChanged = False self._changed = False
self._valid = False
return return
@@ -338,6 +350,8 @@ class NWProject(QObject):
self._session.startSession() self._session.startSession()
self._storage.writeLockFile() self._storage.writeLockFile()
self.setProjectChanged(False) self.setProjectChanged(False)
self._valid = True
self.mainGui.setStatus(self.tr("Opened Project: {0}").format(self._data.name)) self.mainGui.setStatus(self.tr("Opened Project: {0}").format(self._data.name))
return True return True
@@ -503,9 +517,9 @@ class NWProject(QObject):
information to the GUI statusbar. information to the GUI statusbar.
""" """
if isinstance(status, bool): if isinstance(status, bool):
self._projChanged = status self._changed = status
self.projectStatusChanged.emit(self._projChanged) self.projectStatusChanged.emit(self._changed)
return self._projChanged return self._changed
## ##
# Getters # Getters
+3 -3
View File
@@ -563,7 +563,7 @@ class GuiProjectTree(QTreeWidget):
make sure the item is added in a place it can be added, and that make sure the item is added in a place it can be added, and that
other meta data is set correctly to ensure a valid project tree. other meta data is set correctly to ensure a valid project tree.
""" """
if not self.mainGui.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -787,7 +787,7 @@ class GuiProjectTree(QTreeWidget):
can be called on any item, and will check whether to attempt a can be called on any item, and will check whether to attempt a
permanent deletion or moving the item to Trash. permanent deletion or moving the item to Trash.
""" """
if not self.mainGui.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -823,7 +823,7 @@ class GuiProjectTree(QTreeWidget):
function only asks for confirmation once, and calls the regular function only asks for confirmation once, and calls the regular
deleteItem function for each document in the Trash folder. deleteItem function for each document in the Trash folder.
""" """
if not self.mainGui.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
+27 -30
View File
@@ -116,7 +116,6 @@ class GuiMain(QMainWindow):
SHARED.initSharedData(self, GuiTheme()) SHARED.initSharedData(self, GuiTheme())
# Core Settings # Core Settings
self.hasProject = False
self.isFocusMode = False self.isFocusMode = False
self.idleRefTime = time() self.idleRefTime = time()
self.idleTime = 0.0 self.idleTime = 0.0
@@ -371,7 +370,7 @@ class GuiMain(QMainWindow):
logger.info("Command line path: %s", cmdOpen) logger.info("Command line path: %s", cmdOpen)
self.openProject(cmdOpen) self.openProject(cmdOpen)
if not self.hasProject: if not SHARED.hasProject:
self.showProjectLoadDialog() self.showProjectLoadDialog()
# Determine whether release notes need to be shown or not # Determine whether release notes need to be shown or not
@@ -396,7 +395,7 @@ class GuiMain(QMainWindow):
def newProject(self, projData: dict | None = None) -> bool: def newProject(self, projData: dict | None = None) -> bool:
"""Create a new project via the new project wizard.""" """Create a new project via the new project wizard."""
if self.hasProject: if SHARED.hasProject:
if not self.closeProject(): if not self.closeProject():
self.makeAlert(self.tr( self.makeAlert(self.tr(
"Cannot create a new project when another project is open." "Cannot create a new project when another project is open."
@@ -435,7 +434,7 @@ class GuiMain(QMainWindow):
close application event so the user doesn't get prompted twice close application event so the user doesn't get prompted twice
to confirm. to confirm.
""" """
if not self.hasProject: if not SHARED.hasProject:
# There is no project loaded, everything OK # There is no project loaded, everything OK
return True return True
@@ -468,12 +467,11 @@ class GuiMain(QMainWindow):
self.outlineView.closeProjectTasks() self.outlineView.closeProjectTasks()
self.novelView.closeProjectTasks() self.novelView.closeProjectTasks()
SHARED.project.closeProject(self.idleTime) SHARED.closeProject(self.idleTime)
self.idleRefTime = time() self.idleRefTime = time()
self.idleTime = 0.0 self.idleTime = 0.0
self.clearGUI() self.clearGUI()
self.hasProject = False
self._changeView(nwView.PROJECT) self._changeView(nwView.PROJECT)
return saveOK return saveOK
@@ -530,7 +528,6 @@ class GuiMain(QMainWindow):
return False return False
# Project is loaded # Project is loaded
self.hasProject = True
self.idleRefTime = time() self.idleRefTime = time()
self.idleTime = 0.0 self.idleTime = 0.0
@@ -577,7 +574,7 @@ class GuiMain(QMainWindow):
def saveProject(self, autoSave: bool = False) -> bool: def saveProject(self, autoSave: bool = False) -> bool:
"""Save the current project.""" """Save the current project."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
self.projView.saveProjectTasks() self.projView.saveProjectTasks()
@@ -590,7 +587,7 @@ class GuiMain(QMainWindow):
def closeDocument(self, beforeOpen: bool = False) -> bool: def closeDocument(self, beforeOpen: bool = False) -> bool:
"""Close the document and clear the editor and title field.""" """Close the document and clear the editor and title field."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -610,7 +607,7 @@ class GuiMain(QMainWindow):
def openDocument(self, tHandle: str | None, tLine: int | None = None, def openDocument(self, tHandle: str | None, tLine: int | None = None,
changeFocus: bool = True, doScroll: bool = False) -> bool: changeFocus: bool = True, doScroll: bool = False) -> bool:
"""Open a specific document, optionally at a given line.""" """Open a specific document, optionally at a given line."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -642,7 +639,7 @@ class GuiMain(QMainWindow):
"""Opens the next document in the project tree, following the """Opens the next document in the project tree, following the
document with the given handle. Stops when reaching the end. document with the given handle. Stops when reaching the end.
""" """
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -671,7 +668,7 @@ class GuiMain(QMainWindow):
def saveDocument(self) -> bool: def saveDocument(self) -> bool:
"""Save the current documents.""" """Save the current documents."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
self.docEditor.saveText() self.docEditor.saveText()
@@ -679,7 +676,7 @@ class GuiMain(QMainWindow):
def viewDocument(self, tHandle: str | None = None, sTitle: str | None = None) -> bool: def viewDocument(self, tHandle: str | None = None, sTitle: str | None = None) -> bool:
"""Load a document for viewing in the view panel.""" """Load a document for viewing in the view panel."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -724,7 +721,7 @@ class GuiMain(QMainWindow):
"""Import the text contained in an out-of-project text file, and """Import the text contained in an out-of-project text file, and
insert the text into the currently open document. insert the text into the currently open document.
""" """
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -796,7 +793,7 @@ class GuiMain(QMainWindow):
active. It is not checked that the item is actually a document. active. It is not checked that the item is actually a document.
That should be handled by the openDocument function. That should be handled by the openDocument function.
""" """
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -825,7 +822,7 @@ class GuiMain(QMainWindow):
def editItemLabel(self, tHandle: str | None = None) -> bool: def editItemLabel(self, tHandle: str | None = None) -> bool:
"""Open the edit item dialog.""" """Open the edit item dialog."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -842,7 +839,7 @@ class GuiMain(QMainWindow):
def rebuildIndex(self, beQuiet: bool = False) -> bool: def rebuildIndex(self, beQuiet: bool = False) -> bool:
"""Rebuild the entire index.""" """Rebuild the entire index."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -947,7 +944,7 @@ class GuiMain(QMainWindow):
@pyqtSlot(int) @pyqtSlot(int)
def showProjectSettingsDialog(self, focusTab: int = GuiProjectSettings.TAB_MAIN) -> bool: def showProjectSettingsDialog(self, focusTab: int = GuiProjectSettings.TAB_MAIN) -> bool:
"""Open the project settings dialog.""" """Open the project settings dialog."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -965,7 +962,7 @@ class GuiMain(QMainWindow):
def showProjectDetailsDialog(self) -> bool: def showProjectDetailsDialog(self) -> bool:
"""Open the project details dialog.""" """Open the project details dialog."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -984,7 +981,7 @@ class GuiMain(QMainWindow):
@pyqtSlot() @pyqtSlot()
def showBuildManuscriptDialog(self) -> bool: def showBuildManuscriptDialog(self) -> bool:
"""Open the build manuscript dialog.""" """Open the build manuscript dialog."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -1004,7 +1001,7 @@ class GuiMain(QMainWindow):
def showLoremIpsumDialog(self) -> bool: def showLoremIpsumDialog(self) -> bool:
"""Open the insert lorem ipsum text dialog.""" """Open the insert lorem ipsum text dialog."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -1022,7 +1019,7 @@ class GuiMain(QMainWindow):
def showProjectWordListDialog(self) -> bool: def showProjectWordListDialog(self) -> bool:
"""Open the project word list dialog.""" """Open the project word list dialog."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -1037,7 +1034,7 @@ class GuiMain(QMainWindow):
def showWritingStatsDialog(self) -> bool: def showWritingStatsDialog(self) -> bool:
"""Open the session stats dialog.""" """Open the session stats dialog."""
if not self.hasProject: if not SHARED.hasProject:
logger.error("No project open") logger.error("No project open")
return False return False
@@ -1150,7 +1147,7 @@ class GuiMain(QMainWindow):
def closeMain(self) -> bool: def closeMain(self) -> bool:
"""Save everything, and close novelWriter.""" """Save everything, and close novelWriter."""
if self.hasProject: if SHARED.hasProject:
msgYes = self.askQuestion("%s<br>%s" % ( msgYes = self.askQuestion("%s<br>%s" % (
self.tr("Do you want to exit novelWriter?"), self.tr("Do you want to exit novelWriter?"),
self.tr("Changes are saved automatically.") self.tr("Changes are saved automatically.")
@@ -1171,7 +1168,7 @@ class GuiMain(QMainWindow):
# Ignore window size if in full screen mode # Ignore window size if in full screen mode
CONFIG.setMainWinSize(self.width(), self.height()) CONFIG.setMainWinSize(self.width(), self.height())
if self.hasProject: if SHARED.hasProject:
self.closeProject(True) self.closeProject(True)
CONFIG.saveConfig() CONFIG.saveConfig()
@@ -1475,7 +1472,7 @@ class GuiMain(QMainWindow):
@pyqtSlot() @pyqtSlot()
def _timeTick(self) -> None: def _timeTick(self) -> None:
"""Process time tick of the main timer.""" """Process time tick of the main timer."""
if not self.hasProject: if not SHARED.hasProject:
return return
currTime = time() currTime = time()
@@ -1496,7 +1493,7 @@ class GuiMain(QMainWindow):
@pyqtSlot() @pyqtSlot()
def _autoSaveProject(self) -> None: def _autoSaveProject(self) -> None:
"""Autosave of the project. This is a timer-activated slot.""" """Autosave of the project. This is a timer-activated slot."""
doSave = self.hasProject doSave = SHARED.hasProject
doSave &= SHARED.project.projChanged doSave &= SHARED.project.projChanged
doSave &= SHARED.project.storage.isOpen() doSave &= SHARED.project.storage.isOpen()
if doSave: if doSave:
@@ -1507,7 +1504,7 @@ class GuiMain(QMainWindow):
@pyqtSlot() @pyqtSlot()
def _autoSaveDocument(self) -> None: def _autoSaveDocument(self) -> None:
"""Autosave of the document. This is a timer-activated slot.""" """Autosave of the document. This is a timer-activated slot."""
if self.hasProject and self.docEditor.docChanged(): if SHARED.hasProject and self.docEditor.docChanged():
logger.debug("Autosaving document") logger.debug("Autosaving document")
self.saveDocument() self.saveDocument()
return return
@@ -1515,7 +1512,7 @@ class GuiMain(QMainWindow):
@pyqtSlot() @pyqtSlot()
def _updateStatusWordCount(self) -> None: def _updateStatusWordCount(self) -> None:
"""Update the word count on the status bar.""" """Update the word count on the status bar."""
if not self.hasProject: if not SHARED.hasProject:
self.mainStatus.setProjectStats(0, 0) self.mainStatus.setProjectStats(0, 0)
SHARED.project.updateWordCounts() SHARED.project.updateWordCounts()
@@ -1551,7 +1548,7 @@ class GuiMain(QMainWindow):
def _mainStackChanged(self, index: int) -> None: def _mainStackChanged(self, index: int) -> None:
"""Process main window tab change.""" """Process main window tab change."""
if index == self.idxOutlineView: if index == self.idxOutlineView:
if self.hasProject: if SHARED.hasProject:
self.outlineView.refreshTree() self.outlineView.refreshTree()
return return
+13 -1
View File
@@ -26,6 +26,7 @@ from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from pathlib import Path
if TYPE_CHECKING: # pragma: no cover if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain from novelwriter.guimain import GuiMain
@@ -64,6 +65,10 @@ class SharedData:
raise Exception("UserData class not properly initialised") raise Exception("UserData class not properly initialised")
return self._project return self._project
@property
def hasProject(self) -> bool:
return self.project.isValid
## ##
# Methods # Methods
## ##
@@ -79,7 +84,14 @@ class SharedData:
logger.debug("SharedData instance initialised") logger.debug("SharedData instance initialised")
return return
def openProject(self): def openProject(self, path: str | Path) -> None:
return
def saveProject(self):
return
def closeProject(self, idleTime: float) -> None:
self.project.closeProject(idleTime)
return return
## ##
-7
View File
@@ -31,9 +31,6 @@ class MockGuiMain(QObject):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._project = None
self.hasProject = True
self.mainStatus = MockStatusBar() self.mainStatus = MockStatusBar()
self.projPath = "" self.projPath = ""
@@ -44,10 +41,6 @@ class MockGuiMain(QObject):
return return
@property
def project(self):
return self._project
def postLaunchTasks(self, cmdOpen): def postLaunchTasks(self, cmdOpen):
return return
+3 -3
View File
@@ -27,7 +27,7 @@ from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QAction, QColorDialog from PyQt5.QtWidgets import QDialog, QAction, QColorDialog
from novelwriter import CONFIG from novelwriter import CONFIG, SHARED
from novelwriter.enum import nwItemType from novelwriter.enum import nwItemType
from novelwriter.dialogs.editlabel import GuiEditLabel from novelwriter.dialogs.editlabel import GuiEditLabel
from novelwriter.dialogs.projsettings import GuiProjectSettings from novelwriter.dialogs.projsettings import GuiProjectSettings
@@ -50,8 +50,8 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI):
assert getGuiItem("GuiProjectSettings") is None assert getGuiItem("GuiProjectSettings") is None
# Pretend we have a project # Pretend we have a project
nwGUI.hasProject = True SHARED.project._valid = True
nwGUI.project.data.setSpellLang("en") SHARED.project.data.setSpellLang("en")
# Get the dialog object # Get the dialog object
nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger) nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
+2 -2
View File
@@ -30,7 +30,7 @@ from tools import (
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QMessageBox, QInputDialog from PyQt5.QtWidgets import QDialog, QMessageBox, QInputDialog
from novelwriter import CONFIG from novelwriter import CONFIG, SHARED
from novelwriter.enum import nwItemType, nwView, nwWidget from novelwriter.enum import nwItemType, nwView, nwWidget
from novelwriter.constants import nwFiles from novelwriter.constants import nwFiles
from novelwriter.gui.outline import GuiOutlineView from novelwriter.gui.outline import GuiOutlineView
@@ -113,7 +113,7 @@ def testGuiMain_NewProject(monkeypatch, nwGUI, projPath):
# Close project # Close project
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
nwGUI.hasProject = True SHARED.project._valid = True
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No) mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert nwGUI.newProject(projData={"projPath": projPath}) is False assert nwGUI.newProject(projData={"projPath": projPath}) is False
+1 -1
View File
@@ -204,9 +204,9 @@ def buildTestProject(obj, projPath):
project.session.startSession() project.session.startSession()
project.setProjectChanged(True) project.setProjectChanged(True)
project.saveProject(autoSave=True) project.saveProject(autoSave=True)
project._valid = True
if nwGUI is not None: if nwGUI is not None:
nwGUI.hasProject = True
nwGUI.rebuildTrees() nwGUI.rebuildTrees()
return return