Clean up code and tests

This commit is contained in:
Veronica Berglyd Olsen
2023-08-07 20:20:04 +02:00
parent 90f9fa4451
commit 3911bc10c6
19 changed files with 131 additions and 159 deletions
+2 -2
View File
@@ -479,7 +479,7 @@ class ProjectBuilder:
except Exception as exc: except Exception as exc:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Failed to create a new example project." "Failed to create a new example project."
), nwAlert.ERROR, exception=exc) ), level=nwAlert.ERROR, exception=exc)
return False return False
else: else:
@@ -487,7 +487,7 @@ class ProjectBuilder:
"Failed to create a new example project. " "Failed to create a new example project. "
"Could not find the necessary files. " "Could not find the necessary files. "
"They seem to be missing from this installation." "They seem to be missing from this installation."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
return True return True
+28 -33
View File
@@ -173,9 +173,10 @@ class NWProject(QObject):
if self._tree.checkType(tHandle, nwItemType.FILE): if self._tree.checkType(tHandle, nwItemType.FILE):
delDoc = self._storage.getDocument(tHandle) delDoc = self._storage.getDocument(tHandle)
if not delDoc.deleteDocument(): if not delDoc.deleteDocument():
self.mainGui.makeAlert([ self.mainGui.makeAlert(
self.tr("Could not delete document file."), delDoc.getError() self.tr("Could not delete document file."),
], nwAlert.ERROR) info=delDoc.getError(), level=nwAlert.ERROR
)
return False return False
self._index.deleteHandle(tHandle) self._index.deleteHandle(tHandle)
@@ -227,7 +228,7 @@ class NWProject(QObject):
if not self._storage.openProjectInPlace(projPath): if not self._storage.openProjectInPlace(projPath):
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Could not open project with path: {0}" "Could not open project with path: {0}"
).format(projPath), nwAlert.ERROR) ).format(projPath), level=nwAlert.ERROR)
return False return False
# Project Lock # Project Lock
@@ -266,17 +267,17 @@ class NWProject(QObject):
if xmlReader.state == XMLReadState.NOT_NWX_FILE: if xmlReader.state == XMLReadState.NOT_NWX_FILE:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Project file does not appear to be a novelWriterXML file." "Project file does not appear to be a novelWriterXML file."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
elif xmlReader.state == XMLReadState.UNKNOWN_VERSION: elif xmlReader.state == XMLReadState.UNKNOWN_VERSION:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Unknown or unsupported novelWriter project file format. " "Unknown or unsupported novelWriter project file format. "
"The project cannot be opened by this version of novelWriter. " "The project cannot be opened by this version of novelWriter. "
"The file was saved with novelWriter version {0}." "The file was saved with novelWriter version {0}."
).format(appVersion), nwAlert.ERROR) ).format(appVersion), level=nwAlert.ERROR)
else: else:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Failed to parse project xml." "Failed to parse project xml."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
self.clearProject() self.clearProject()
return False return False
@@ -285,14 +286,11 @@ class NWProject(QObject):
# ==================== # ====================
if xmlReader.state == XMLReadState.WAS_LEGACY: if xmlReader.state == XMLReadState.WAS_LEGACY:
msgYes = self.mainGui.askQuestion( msgYes = self.mainGui.askQuestion(self.tr(
self.tr("File Version"), "The file format of your project is about to be updated. "
self.tr( "If you proceed, older versions of novelWriter will no "
"The file format of your project is about to be updated. " "longer be able to open this project. Continue?"
"If you proceed, older versions of novelWriter will no " ))
"longer be able to open this project. Continue?"
)
)
if not msgYes: if not msgYes:
self.clearProject() self.clearProject()
return False return False
@@ -301,16 +299,13 @@ class NWProject(QObject):
# ========================= # =========================
if xmlReader.hexVersion > hexToInt(__hexversion__): if xmlReader.hexVersion > hexToInt(__hexversion__):
msgYes = self.mainGui.askQuestion( msgYes = self.mainGui.askQuestion(self.tr(
self.tr("Version Conflict"), "This project was saved by a newer version of "
self.tr( "novelWriter, version {0}. This is version {1}. If you "
"This project was saved by a newer version of " "continue to open the project, some attributes and "
"novelWriter, version {0}. This is version {1}. If you " "settings may not be preserved, but the overall project "
"continue to open the project, some attributes and " "should be fine. Continue opening the project?"
"settings may not be preserved, but the overall project " ).format(appVersion, __version__))
"should be fine. Continue opening the project?"
).format(appVersion, __version__)
)
if not msgYes: if not msgYes:
self.clearProject() self.clearProject()
return False return False
@@ -333,7 +328,7 @@ class NWProject(QObject):
if orphans > 0: if orphans > 0:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Found {0} orphaned file(s) in the project. {1} file(s) were recovered." "Found {0} orphaned file(s) in the project. {1} file(s) were recovered."
).format(orphans, recovered), nwAlert.WARN) ).format(orphans, recovered), level=nwAlert.WARN)
self._index.loadIndex() self._index.loadIndex()
if xmlReader.state == XMLReadState.WAS_LEGACY: if xmlReader.state == XMLReadState.WAS_LEGACY:
@@ -357,7 +352,7 @@ class NWProject(QObject):
if not self._storage.isOpen(): if not self._storage.isOpen():
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"There is no project open." "There is no project open."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
saveTime = time() saveTime = time()
@@ -382,7 +377,7 @@ class NWProject(QObject):
if not xmlWriter.write(self._data, content, saveTime, editTime): if not xmlWriter.write(self._data, content, saveTime, editTime):
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Failed to save project." "Failed to save project."
), nwAlert.ERROR, exception=xmlWriter.error) ), level=nwAlert.ERROR, exception=xmlWriter.error)
return False return False
# Save other project data # Save other project data
@@ -426,14 +421,14 @@ class NWProject(QObject):
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Cannot backup project because no valid backup path is set. " "Cannot backup project because no valid backup path is set. "
"Please set a valid backup location in Preferences." "Please set a valid backup location in Preferences."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
if not self._data.name: if not self._data.name:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Cannot backup project because no project name is set. " "Cannot backup project because no project name is set. "
"Please set a Project Name in Project Settings." "Please set a Project Name in Project Settings."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
cleanName = makeFileNameSafe(self._data.name) cleanName = makeFileNameSafe(self._data.name)
@@ -443,7 +438,7 @@ class NWProject(QObject):
except Exception as exc: except Exception as exc:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Could not create backup folder." "Could not create backup folder."
), nwAlert.ERROR, exception=exc) ), level=nwAlert.ERROR, exception=exc)
return False return False
timeStamp = formatTimeStamp(time(), fileSafe=True) timeStamp = formatTimeStamp(time(), fileSafe=True)
@@ -453,11 +448,11 @@ class NWProject(QObject):
if doNotify: if doNotify:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Backup archive file written to: {0} [{1}B]" "Backup archive file written to: {0} [{1}B]"
).format(str(archName), formatInt(size)), nwAlert.INFO) ).format(str(archName), formatInt(size)))
else: else:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Could not write backup archive." "Could not write backup archive."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
self.mainGui.setStatus(self.tr( self.mainGui.setStatus(self.tr(
+4 -7
View File
@@ -225,13 +225,10 @@ class GuiProjectLoad(QDialog):
selList = self.listBox.selectedItems() selList = self.listBox.selectedItems()
if selList: if selList:
projName = selList[0].text(self.C_NAME) projName = selList[0].text(self.C_NAME)
msgYes = self.mainGui.askQuestion( msgYes = self.mainGui.askQuestion(self.tr(
self.tr("Remove Entry"), "Remove '{0}' from the recent projects list? "
self.tr( "The project files will not be deleted."
"Remove '{0}' from the recent projects list? " ).format(projName))
"The project files will not be deleted."
).format(projName)
)
if msgYes: if msgYes:
CONFIG.recentProjects.remove( CONFIG.recentProjects.remove(
selList[0].data(self.C_NAME, self.D_PATH) selList[0].data(self.C_NAME, self.D_PATH)
+8 -3
View File
@@ -1,7 +1,6 @@
""" """
novelWriter GUI Project Settings novelWriter GUI Project Settings
================================== ==================================
GUI classes for the project settings dialog
File History: File History:
Created: 2018-09-29 [0.0.1] Created: 2018-09-29 [0.0.1]
@@ -22,9 +21,12 @@ General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING
from PyQt5.QtGui import QIcon, QPixmap, QColor from PyQt5.QtGui import QIcon, QPixmap, QColor
from PyQt5.QtCore import Qt, QLocale, pyqtSlot from PyQt5.QtCore import Qt, QLocale, pyqtSlot
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
@@ -39,6 +41,9 @@ from novelwriter.extensions.switch import NSwitch
from novelwriter.extensions.pageddialog import NPagedDialog from novelwriter.extensions.pageddialog import NPagedDialog
from novelwriter.extensions.configlayout import NConfigLayout from novelwriter.extensions.configlayout import NConfigLayout
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -49,7 +54,7 @@ class GuiProjectSettings(NPagedDialog):
TAB_IMPORT = 2 TAB_IMPORT = 2
TAB_REPLACE = 3 TAB_REPLACE = 3
def __init__(self, mainGui, focusTab=TAB_MAIN): def __init__(self, mainGui: GuiMain, focusTab: int = TAB_MAIN) -> None:
super().__init__(parent=mainGui) super().__init__(parent=mainGui)
logger.debug("Create: GuiProjectSettings") logger.debug("Create: GuiProjectSettings")
@@ -441,7 +446,7 @@ class GuiProjectEditStatus(QWidget):
if selItem.data(self.COL_LABEL, self.NUM_ROLE) > 0: if selItem.data(self.COL_LABEL, self.NUM_ROLE) > 0:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Cannot delete a status item that is in use." "Cannot delete a status item that is in use."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
else: else:
self.listBox.takeTopLevelItem(iRow) self.listBox.takeTopLevelItem(iRow)
self.colDeleted.append(selItem.data(self.COL_LABEL, self.KEY_ROLE)) self.colDeleted.append(selItem.data(self.COL_LABEL, self.KEY_ROLE))
+2 -2
View File
@@ -128,13 +128,13 @@ class GuiWordList(QDialog):
if word == "": if word == "":
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Cannot add a blank word." "Cannot add a blank word."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return return
if self.listBox.findItems(word, Qt.MatchExactly): if self.listBox.findItems(word, Qt.MatchExactly):
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"The word '{0}' is already in the word list." "The word '{0}' is already in the word list."
).format(word), nwAlert.ERROR) ).format(word), level=nwAlert.ERROR)
return return
self.listBox.addItem(word) self.listBox.addItem(word)
+25 -30
View File
@@ -1,7 +1,6 @@
""" """
novelWriter GUI Document Editor novelWriter GUI Document Editor
================================= =================================
GUI classes for the main document editor
File History: File History:
Created: 2018-09-29 [0.0.1] GuiDocEditor Created: 2018-09-29 [0.0.1] GuiDocEditor
@@ -28,12 +27,14 @@ General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from __future__ import annotations
import bisect import bisect
import logging import logging
from enum import Enum from enum import Enum
from time import time from time import time
from typing import TYPE_CHECKING
from PyQt5.QtCore import ( from PyQt5.QtCore import (
Qt, QSize, QTimer, pyqtSlot, pyqtSignal, QRegExp, QRegularExpression, Qt, QSize, QTimer, pyqtSlot, pyqtSignal, QRegExp, QRegularExpression,
@@ -44,9 +45,8 @@ from PyQt5.QtGui import (
QPalette, QTextDocument, QCursor, QPixmap QPalette, QTextDocument, QCursor, QPixmap
) )
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
qApp, QTextEdit, QAction, QMenu, QShortcut, QMessageBox, QWidget, QLabel, QAction, qApp, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu,
QToolBar, QToolButton, QHBoxLayout, QGridLayout, QLineEdit, QPushButton, QPushButton, QShortcut, QTextEdit, QToolBar, QToolButton, QWidget
QFrame
) )
from novelwriter import CONFIG from novelwriter import CONFIG
@@ -57,6 +57,9 @@ from novelwriter.core.index import countWords
from novelwriter.core.spellcheck import NWSpellEnchant from novelwriter.core.spellcheck import NWSpellEnchant
from novelwriter.gui.dochighlight import GuiDocHighlighter from novelwriter.gui.dochighlight import GuiDocHighlighter
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -75,7 +78,7 @@ class GuiDocEditor(QTextEdit):
novelStructureChanged = pyqtSignal() novelStructureChanged = pyqtSignal()
novelItemMetaChanged = pyqtSignal(str) novelItemMetaChanged = pyqtSignal(str)
def __init__(self, mainGui): def __init__(self, mainGui: GuiMain):
super().__init__(parent=mainGui) super().__init__(parent=mainGui)
logger.debug("Create: GuiDocEditor") logger.debug("Create: GuiDocEditor")
@@ -357,7 +360,7 @@ class GuiDocEditor(QTextEdit):
).format( ).format(
f"{docSize/1.0e6:.2f}", f"{docSize/1.0e6:.2f}",
f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}" f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}"
), nwAlert.ERROR) ), level=nwAlert.ERROR)
self.clearEditor() self.clearEditor()
return False return False
@@ -457,7 +460,7 @@ class GuiDocEditor(QTextEdit):
).format( ).format(
f"{docSize/1.0e6:.2f}", f"{docSize/1.0e6:.2f}",
f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}" f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}"
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
qApp.setOverrideCursor(QCursor(Qt.WaitCursor)) qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
@@ -496,20 +499,19 @@ class GuiDocEditor(QTextEdit):
if not self._nwDocument.writeDocument(docText): if not self._nwDocument.writeDocument(docText):
saveOk = False saveOk = False
if self._nwDocument._currHash != self._nwDocument._prevHash: if self._nwDocument._currHash != self._nwDocument._prevHash:
msgYes = self.mainGui.askQuestion( msgYes = self.mainGui.askQuestion(self.tr(
self.tr("File Changed on Disk"), "This document has been changed outside of novelWriter "
self.tr( "while it was open. Overwrite the file on disk?"
"This document has been changed outside of novelWriter " ))
"while it was open. Overwrite the file on disk?"
)
)
if msgYes: if msgYes:
saveOk = self._nwDocument.writeDocument(docText, forceWrite=True) saveOk = self._nwDocument.writeDocument(docText, forceWrite=True)
if not saveOk: if not saveOk:
self.mainGui.makeAlert([ self.mainGui.makeAlert(
self.tr("Could not save document."), self._nwDocument.getError() self.tr("Could not save document."),
], nwAlert.ERROR) info=self._nwDocument.getError(),
level=nwAlert.ERROR
)
return False return False
@@ -726,7 +728,7 @@ class GuiDocEditor(QTextEdit):
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Spell checking requires the package PyEnchant. " "Spell checking requires the package PyEnchant. "
"It does not appear to be installed." "It does not appear to be installed."
), nwAlert.INFO) ))
theMode = False theMode = False
if self.spEnchant.spellLanguage is None: if self.spEnchant.spellLanguage is None:
@@ -868,17 +870,10 @@ class GuiDocEditor(QTextEdit):
if self._nwDocument is None: if self._nwDocument is None:
logger.error("No document open") logger.error("No document open")
return False return False
self.mainGui.makeAlert(
msgBox = QMessageBox() self.tr("The currently open file is saved in:"),
msgBox.information( info=self._nwDocument.getFileLocation()
self,
self.tr("File Location"),
"%s<br>%s" % (
self.tr("The currently open file is saved in:"),
self._nwDocument.getFileLocation()
),
) )
return return
def insertText(self, theInsert): def insertText(self, theInsert):
@@ -1116,7 +1111,7 @@ class GuiDocEditor(QTextEdit):
"The maximum size of a single novelWriter document is {0} MB." "The maximum size of a single novelWriter document is {0} MB."
).format( ).format(
f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}" f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}"
), nwAlert.ERROR) ), level=nwAlert.ERROR)
self.undo() self.undo()
return return
@@ -1675,7 +1670,7 @@ class GuiDocEditor(QTextEdit):
if not theCursor.hasSelection(): if not theCursor.hasSelection():
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Please select some text before calling replace quotes." "Please select some text before calling replace quotes."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
posS = theCursor.selectionStart() posS = theCursor.selectionStart()
+23 -31
View File
@@ -589,7 +589,7 @@ class GuiProjectTree(QTreeWidget):
if sHandle is None or pItem is None: if sHandle is None or pItem is None:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Did not find anywhere to add the file or folder!" "Did not find anywhere to add the file or folder!"
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
# Collect some information about the selected item # Collect some information about the selected item
@@ -600,7 +600,7 @@ class GuiProjectTree(QTreeWidget):
if self.theProject.tree.isTrash(sHandle): if self.theProject.tree.isTrash(sHandle):
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Cannot add new files or folders to the Trash folder." "Cannot add new files or folders to the Trash folder."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
# Set default label and determine if new item is to be added # Set default label and determine if new item is to be added
@@ -838,7 +838,7 @@ class GuiProjectTree(QTreeWidget):
if trashHandle is None: if trashHandle is None:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"There is currently no Trash folder in this project." "There is currently no Trash folder in this project."
), nwAlert.INFO) ))
return False return False
theTrash = self.getTreeFromHandle(trashHandle) theTrash = self.getTreeFromHandle(trashHandle)
@@ -849,11 +849,10 @@ class GuiProjectTree(QTreeWidget):
if nTrash == 0: if nTrash == 0:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"The Trash folder is already empty." "The Trash folder is already empty."
), nwAlert.INFO) ))
return False return False
msgYes = self.mainGui.askQuestion( msgYes = self.mainGui.askQuestion(
self.tr("Empty Trash"),
self.tr("Permanently delete {0} file(s) from Trash?").format(nTrash) self.tr("Permanently delete {0} file(s) from Trash?").format(nTrash)
) )
if not msgYes: if not msgYes:
@@ -900,7 +899,6 @@ class GuiProjectTree(QTreeWidget):
if askFirst: if askFirst:
msgYes = self.mainGui.askQuestion( msgYes = self.mainGui.askQuestion(
self.tr("Delete"),
self.tr("Move '{0}' to Trash?").format(nwItemS.itemName), self.tr("Move '{0}' to Trash?").format(nwItemS.itemName),
) )
if not msgYes: if not msgYes:
@@ -937,7 +935,7 @@ class GuiProjectTree(QTreeWidget):
if trItemS.childCount() > 0: if trItemS.childCount() > 0:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Root folders can only be deleted when they are empty." "Root folders can only be deleted when they are empty."
), nwAlert.ERROR) ), level=nwAlert.ERROR)
return False return False
logger.debug("Permanently deleting root folder '%s'", tHandle) logger.debug("Permanently deleting root folder '%s'", tHandle)
@@ -956,7 +954,6 @@ class GuiProjectTree(QTreeWidget):
else: else:
if askFirst: if askFirst:
msgYes = self.mainGui.askQuestion( msgYes = self.mainGui.askQuestion(
self.tr("Delete"),
self.tr("Permanently delete '{0}'?").format(nwItemS.itemName) self.tr("Permanently delete '{0}'?").format(nwItemS.itemName)
) )
if not msgYes: if not msgYes:
@@ -1525,13 +1522,10 @@ class GuiProjectTree(QTreeWidget):
"""Convert a folder to a note or document.""" """Convert a folder to a note or document."""
tItem = self.theProject.tree[tHandle] tItem = self.theProject.tree[tHandle]
if tItem is not None and tItem.isFolderType(): if tItem is not None and tItem.isFolderType():
msgYes = self.mainGui.askQuestion( msgYes = self.mainGui.askQuestion(self.tr(
self.tr("Convert Folder"), "Do you want to convert the folder to a {0}? "
self.tr( "This action cannot be reversed."
"Do you want to convert the folder to a {0}? " ).format(trConst(nwLabels.LAYOUT_NAME[itemLayout])))
"This action cannot be reversed."
).format(trConst(nwLabels.LAYOUT_NAME[itemLayout]))
)
if msgYes and itemLayout == nwItemLayout.DOCUMENT and tItem.documentAllowed(): if msgYes and itemLayout == nwItemLayout.DOCUMENT and tItem.documentAllowed():
tItem.setType(nwItemType.FILE) tItem.setType(nwItemType.FILE)
tItem.setLayout(nwItemLayout.DOCUMENT) tItem.setLayout(nwItemLayout.DOCUMENT)
@@ -1570,9 +1564,7 @@ class GuiProjectTree(QTreeWidget):
mrgData = dlgMerge.getData() mrgData = dlgMerge.getData()
mrgList = mrgData.get("finalItems", []) mrgList = mrgData.get("finalItems", [])
if not mrgList: if not mrgList:
self.mainGui.makeAlert([ self.mainGui.makeAlert(self.tr("No documents selected for merging."))
self.tr("No documents selected for merging.")
], nwAlert.INFO)
return False return False
# Save the open document first, in case it's part of merge # Save the open document first, in case it's part of merge
@@ -1595,9 +1587,10 @@ class GuiProjectTree(QTreeWidget):
docMerger.appendText(sHandle, True, mLabel) docMerger.appendText(sHandle, True, mLabel)
if not docMerger.writeTargetDoc(): if not docMerger.writeTargetDoc():
self.mainGui.makeAlert([ self.mainGui.makeAlert(
self.tr("Could not write document content."), docMerger.getError() self.tr("Could not write document content."),
], nwAlert.ERROR) info=docMerger.getError(), level=nwAlert.ERROR
)
return False return False
self.theProject.index.reIndexHandle(mHandle) self.theProject.index.reIndexHandle(mHandle)
@@ -1658,9 +1651,10 @@ class GuiProjectTree(QTreeWidget):
self.revealNewTreeItem(dHandle, nHandle=nHandle, wordCount=True) self.revealNewTreeItem(dHandle, nHandle=nHandle, wordCount=True)
self._alertTreeChange(dHandle, flush=False) self._alertTreeChange(dHandle, flush=False)
if not writeOk: if not writeOk:
self.mainGui.makeAlert([ self.mainGui.makeAlert(
self.tr("Could not write document content."), docSplit.getError() self.tr("Could not write document content."),
], nwAlert.ERROR) info=docSplit.getError(), level=nwAlert.ERROR
)
if splitData.get("moveToTrash", False): if splitData.get("moveToTrash", False):
self.moveItemToTrash(tHandle, askFirst=False, flush=True) self.moveItemToTrash(tHandle, askFirst=False, flush=True)
@@ -1680,13 +1674,11 @@ class GuiProjectTree(QTreeWidget):
if nItems == 0: if nItems == 0:
return False return False
elif nItems == 1: elif nItems == 1:
qTitle = self.tr("Duplicate Document") question = self.tr("Do you want to duplicate this document?")
qText = self.tr("Do you want to duplicate this document?")
else: else:
qTitle = self.tr("Duplicate from Here") question = self.tr("Do you want to duplicate this item and all child items?")
qText = self.tr("Do you want to duplicate this item and all child items?")
if not self.mainGui.askQuestion(qTitle, qText): if not self.mainGui.askQuestion(question):
return False return False
docDup = DocDuplicator(self.theProject) docDup = DocDuplicator(self.theProject)
@@ -1698,7 +1690,7 @@ class GuiProjectTree(QTreeWidget):
dupCount += 1 dupCount += 1
if dupCount != nItems: if dupCount != nItems:
self.mainGui.makeAlert(self.tr("Could not duplicate all items."), nwAlert.WARN) self.mainGui.makeAlert(self.tr("Could not duplicate all items."), level=nwAlert.WARN)
self.saveTreeOrder() self.saveTreeOrder()
@@ -1757,7 +1749,7 @@ class GuiProjectTree(QTreeWidget):
else: else:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"There is nowhere to add item with name '{0}'." "There is nowhere to add item with name '{0}'."
).format(nwItem.itemName), nwAlert.ERROR) ).format(nwItem.itemName), level=nwAlert.ERROR)
return None return None
byIndex = -1 byIndex = -1
+1 -2
View File
@@ -310,7 +310,7 @@ class GuiManuscriptBuild(QDialog):
self.buildProgress.setValue(0) self.buildProgress.setValue(0)
bPath = Path(self.buildPath.text()) bPath = Path(self.buildPath.text())
if not bPath.is_dir(): if not bPath.is_dir():
self.mainGui.makeAlert(self.tr("Output folder does not exist."), nwAlert.ERROR) self.mainGui.makeAlert(self.tr("Output folder does not exist."), level=nwAlert.ERROR)
return False return False
bExt = nwLabels.BUILD_EXT[bFormat] bExt = nwLabels.BUILD_EXT[bFormat]
@@ -318,7 +318,6 @@ class GuiManuscriptBuild(QDialog):
if buildPath.exists(): if buildPath.exists():
if not self.mainGui.askQuestion( if not self.mainGui.askQuestion(
self.tr("File Exists"),
self.tr("The file already exists. Do you want to overwrite it?") self.tr("The file already exists. Do you want to overwrite it?")
): ):
return False return False
+1 -5
View File
@@ -270,11 +270,7 @@ class GuiManuscript(QDialog):
"""Delete the currently selected build settings entry.""" """Delete the currently selected build settings entry."""
build = self._getSelectedBuild() build = self._getSelectedBuild()
if build is not None: if build is not None:
proceed = self.mainGui.askQuestion( if self.mainGui.askQuestion(self.tr("Delete build '{0}'?".format(build.name))):
self.tr("Delete Build"),
self.tr("Delete build '{0}'?".format(build.name))
)
if proceed:
self._builds.removeBuild(build.buildID) self._builds.removeBuild(build.buildID)
self._updateBuildsList() self._updateBuildsList()
return return
+1 -5
View File
@@ -248,11 +248,7 @@ class GuiBuildSettings(QDialog):
it's ok to reject them. it's ok to reject them.
""" """
if self._build.changed: if self._build.changed:
doSave = self.mainGui.askQuestion( if self.mainGui.askQuestion(self.tr("Do you want to save your changes?")):
self.tr("Build Settings"),
self.tr("Do you want to save your changes?")
)
if doSave:
self._emitBuildData() self._emitBuildData()
self._build.resetChangedState() self._build.resetChangedState()
return return
+8 -6
View File
@@ -415,13 +415,15 @@ class GuiWritingStats(QDialog):
# Report to user # Report to user
if wSuccess: if wSuccess:
self.mainGui.makeAlert([ self.mainGui.makeAlert(
self.tr("{0} file successfully written to:").format(textFmt), savePath self.tr("{0} file successfully written to:").format(textFmt),
], nwAlert.INFO) info=savePath
)
else: else:
self.mainGui.makeAlert([ self.mainGui.makeAlert(
self.tr("Failed to write {0} file.").format(textFmt), errMsg self.tr("Failed to write {0} file.").format(textFmt),
], nwAlert.ERROR) info=errMsg, level=nwAlert.ERROR
)
return wSuccess return wSuccess
+2 -4
View File
@@ -145,10 +145,8 @@ def mockGUI():
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
def nwGUI(qtbot, monkeypatch, functionFixture): def nwGUI(qtbot, monkeypatch, functionFixture):
"""Create an instance of the novelWriter GUI.""" """Create an instance of the novelWriter GUI."""
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Ok) monkeypatch.setattr(QMessageBox, "exec_", lambda *a: None)
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok) monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Ok)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
nwGUI = main(["--testmode", f"--config={_TMP_CONF}", f"--data={_TMP_CONF}"]) nwGUI = main(["--testmode", f"--config={_TMP_CONF}", f"--data={_TMP_CONF}"])
qtbot.addWidget(nwGUI) qtbot.addWidget(nwGUI)
+8 -8
View File
@@ -39,22 +39,22 @@ class MockGuiMain(QObject):
# Test Variables # Test Variables
self.askResponse = True self.askResponse = True
self.lastAlert = "" self.lastAlert = ""
self.lastQuestion = ("", "") self.lastQuestion = ""
return return
def postLaunchTasks(self, cmdOpen): def postLaunchTasks(self, cmdOpen):
return return
def makeAlert(self, message, level=0, exception=None): def makeAlert(self, text, info="", detals="", level=0, exception=None):
assert isinstance(message, str) or isinstance(message, list) assert isinstance(text, str)
print("%s: %s" % (str(level), message)) print("%s: %s" % (str(level), text))
self.lastAlert = str(message) self.lastAlert = str(text)
return return
def askQuestion(self, title, qustion): def askQuestion(self, text, info="", details="", level=3):
print("Question: %s" % qustion) print("Question: %s" % text)
self.lastQuestion = (title, qustion) self.lastQuestion = text
return self.askResponse return self.askResponse
def setStatus(self, theMessage): def setStatus(self, theMessage):
+3 -3
View File
@@ -224,7 +224,7 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.WAS_LEGACY)) mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.WAS_LEGACY))
mockGUI.askResponse = False mockGUI.askResponse = False
assert theProject.openProject(fncPath) is False assert theProject.openProject(fncPath) is False
assert "The file format of your project is about to be" in mockGUI.lastQuestion[1] assert "The file format of your project is about to be" in mockGUI.lastQuestion
mockGUI.askResponse = True mockGUI.askResponse = True
# Won't open project from newer version # Won't open project from newer version
@@ -232,7 +232,7 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: 0x99999999)) mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: 0x99999999))
mockGUI.askResponse = False mockGUI.askResponse = False
assert theProject.openProject(fncPath) is False assert theProject.openProject(fncPath) is False
assert "This project was saved by a newer version" in mockGUI.lastQuestion[1] assert "This project was saved by a newer version" in mockGUI.lastQuestion
mockGUI.askResponse = True mockGUI.askResponse = True
# Fail checking items should still pass # Fail checking items should still pass
@@ -249,7 +249,7 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
mockGUI.askResponse = True mockGUI.askResponse = True
theProject.index._indexBroken = True theProject.index._indexBroken = True
assert theProject.openProject(fncPath) is True assert theProject.openProject(fncPath) is True
assert "The file format of your project is about to be" in mockGUI.lastQuestion[1] assert "The file format of your project is about to be" in mockGUI.lastQuestion
assert theProject.index._indexBroken is False assert theProject.index._indexBroken is False
theProject.closeProject() theProject.closeProject()
+1 -1
View File
@@ -114,7 +114,7 @@ def testGuiMain_NewProject(monkeypatch, nwGUI, projPath):
# Close project # Close project
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
nwGUI.hasProject = True nwGUI.hasProject = True
mp.setattr(QMessageBox, "question", 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
# No project path # No project path
+3 -6
View File
@@ -34,12 +34,9 @@ LANG_DATA = CONFIG.listLanguages(CONFIG.LANG_NW)
@pytest.mark.skipif(not LANG_DATA, reason="No i18n Data") @pytest.mark.skipif(not LANG_DATA, reason="No i18n Data")
@pytest.mark.parametrize("language", [a for a, b in LANG_DATA]) @pytest.mark.parametrize("language", [a for a, b in LANG_DATA])
def testI18n_Localisation(qtbot, monkeypatch, language, fncPath): def testI18n_Localisation(qtbot, monkeypatch, language, fncPath):
"""test loading the gui with a specific language. """Test loading the gui with a specific language."""
""" monkeypatch.setattr(QMessageBox, "exec_", lambda *a: None)
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Ok) monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Ok)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
# Set the test langauge # Set the test langauge
CONFIG.guiLocale = language CONFIG.guiLocale = language
+5 -5
View File
@@ -642,7 +642,7 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
# The document isn't empty, so the message box should pop # The document isn't empty, so the message box should pop
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "question", lambda *a, **k: QMessageBox.No) mp.setattr(QMessageBox, "result", lambda *a, **k: QMessageBox.No)
assert not nwGUI.importDocument() assert not nwGUI.importDocument()
assert nwGUI.docEditor.getText() == "Bar" assert nwGUI.docEditor.getText() == "Bar"
@@ -655,16 +655,16 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
theMessage = "" theMessage = ""
def recordMsg(*args): def recordMsg(*args, **kwargs):
nonlocal theMessage nonlocal theMessage
theMessage = args[3] theMessage = "%s|%s" % (args[0], kwargs["info"])
return None return None
assert not theMessage assert not theMessage
monkeypatch.setattr(QMessageBox, "information", recordMsg) monkeypatch.setattr(nwGUI, "makeAlert", recordMsg)
nwGUI.mainMenu.aFileDetails.activate(QAction.Trigger) nwGUI.mainMenu.aFileDetails.activate(QAction.Trigger)
theBits = theMessage.split("<br>") theBits = theMessage.split("|")
assert len(theBits) == 2 assert len(theBits) == 2
assert theBits[0] == "The currently open file is saved in:" assert theBits[0] == "The currently open file is saved in:"
assert theBits[1] == str(projPath / "content" / "000000000000f.nwd") assert theBits[1] == str(projPath / "content" / "000000000000f.nwd")
+5 -5
View File
@@ -397,7 +397,7 @@ def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, projPath,
# User cancels action # User cancels action
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No) mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert projTree.moveItemToTrash(C.hTitlePage) is False assert projTree.moveItemToTrash(C.hTitlePage) is False
assert theProject.tree.isTrash(C.hTitlePage) is False assert theProject.tree.isTrash(C.hTitlePage) is False
@@ -444,7 +444,7 @@ def testGuiProjTree_PermanentlyDeleteItem(qtbot, caplog, monkeypatch, nwGUI, pro
# User cancels action # User cancels action
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No) mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert projTree.permDeleteItem(C.hTitlePage) is False assert projTree.permDeleteItem(C.hTitlePage) is False
assert C.hTitlePage in theProject.tree assert C.hTitlePage in theProject.tree
@@ -496,7 +496,7 @@ def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, projPath, mock
# User cancels # User cancels
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No) mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert projTree.emptyTrash() is False assert projTree.emptyTrash() is False
assert C.hTitlePage in theProject.tree assert C.hTitlePage in theProject.tree
assert C.hChapterDir in theProject.tree assert C.hChapterDir in theProject.tree
@@ -617,7 +617,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# Click no on the dialog # Click no on the dialog
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No) mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT) projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
assert nwGUI.theProject.tree[hNewFolderOne].isFolderType() assert nwGUI.theProject.tree[hNewFolderOne].isFolderType()
@@ -864,7 +864,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
# Duplicate title page, but select no # Duplicate title page, but select no
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No) mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert projTree._duplicateFromHandle(C.hTitlePage) is False assert projTree._duplicateFromHandle(C.hTitlePage) is False
assert len(nwGUI.theProject.tree) == 8 assert len(nwGUI.theProject.tree) == 8
+1 -1
View File
@@ -129,7 +129,7 @@ def testManuscriptBuild_Main(
manus.buildPath.setText(str(fncPath)) manus.buildPath.setText(str(fncPath))
manus.buildName.setText("TestBuild") manus.buildName.setText("TestBuild")
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No) mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert manus._runBuild() is False assert manus._runBuild() is False
# Finish # Finish