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