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