Code and GUI text cleanup (#926)
* Move int range checkers from options class to common file * Improve error handling and reporting * Make some minor improvements to init and test suite * Fix 'trypewriter' to 'typewriter' typo * Remove menu path description in dialog help text * Improve the help text for entries in the Format menu * Reword a couple of dialog messages
This commit is contained in:
committed by
GitHub
parent
e71121f738
commit
e8bb130245
+5
-5
@@ -3253,7 +3253,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
||||||
<source>Also improves trypewriter scrolling for short documents.</source>
|
<source>Also improves typewriter scrolling for short documents.</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@@ -4610,17 +4610,17 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="788"/>
|
<location filename="../novelwriter/core/project.py" line="788"/>
|
||||||
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Preferences.</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="795"/>
|
<location filename="../novelwriter/core/project.py" line="795"/>
|
||||||
<source>Cannot backup project because no project name is set. Please set a Working Title in Project > Project Settings.</source>
|
<source>Cannot backup project because no project name is set. Please set a Working Title in Project Settings.</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="802"/>
|
<location filename="../novelwriter/core/project.py" line="802"/>
|
||||||
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Preferences.</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@@ -4630,7 +4630,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="821"/>
|
<location filename="../novelwriter/core/project.py" line="821"/>
|
||||||
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Preferences.</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
|||||||
+9
-9
@@ -3253,7 +3253,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
||||||
<source>Also improves trypewriter scrolling for short documents.</source>
|
<source>Also improves typewriter scrolling for short documents.</source>
|
||||||
<translation>Améliore également le défilement machine à écrire pour les documents courts.</translation>
|
<translation>Améliore également le défilement machine à écrire pour les documents courts.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@@ -4610,18 +4610,18 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="788"/>
|
<location filename="../novelwriter/core/project.py" line="788"/>
|
||||||
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Preferences.</source>
|
||||||
<translation>Il est impossible de sauvegarder le projet car aucun emplacement de sauvegarde n'a été défini. Veuillez en définir un dans Outils > Préférences.</translation>
|
<translation>Il est impossible de sauvegarder le projet car aucun emplacement de sauvegarde n'a été défini. Veuillez en définir un dans Préférences.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="795"/>
|
<location filename="../novelwriter/core/project.py" line="795"/>
|
||||||
<source>Cannot backup project because no project name is set. Please set a Working Title in Project > Project Settings.</source>
|
<source>Cannot backup project because no project name is set. Please set a Working Title in Project Settings.</source>
|
||||||
<translation>Il est impossible de sauvegarder le projet car il n'a pas reçu de nom. Veuillez définir un titre de travail dans Projet > Caractéristiques du projet.</translation>
|
<translation>Il est impossible de sauvegarder le projet car il n'a pas reçu de nom. Veuillez définir un titre de travail dans Caractéristiques du projet.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="802"/>
|
<location filename="../novelwriter/core/project.py" line="802"/>
|
||||||
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Preferences.</source>
|
||||||
<translation>Il est impossible de sauvegarder le projet car l'emplacement de sauvegarde défini n'existe pas. Veuillez définir un emplacement correct dans Outils > Préférences.</translation>
|
<translation>Il est impossible de sauvegarder le projet car l'emplacement de sauvegarde défini n'existe pas. Veuillez définir un emplacement correct dans Préférences.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="815"/>
|
<location filename="../novelwriter/core/project.py" line="815"/>
|
||||||
@@ -4630,8 +4630,8 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="821"/>
|
<location filename="../novelwriter/core/project.py" line="821"/>
|
||||||
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Preferences.</source>
|
||||||
<translation>La sauvegarde du projet est impossible car l'emplacement défini est situé dans le dossier à sauvegarder. Veuillez définir un autre répertoire de sauvegarde dans Outils > Préférences.</translation>
|
<translation>La sauvegarde du projet est impossible car l'emplacement défini est situé dans le dossier à sauvegarder. Veuillez définir un autre répertoire de sauvegarde dans Préférences.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="828"/>
|
<location filename="../novelwriter/core/project.py" line="828"/>
|
||||||
|
|||||||
+9
-9
@@ -3253,7 +3253,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
||||||
<source>Also improves trypewriter scrolling for short documents.</source>
|
<source>Also improves typewriter scrolling for short documents.</source>
|
||||||
<translation>Forbedrer funksjonen til skrivemaskin-rulling.</translation>
|
<translation>Forbedrer funksjonen til skrivemaskin-rulling.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@@ -4605,18 +4605,18 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="788"/>
|
<location filename="../novelwriter/core/project.py" line="788"/>
|
||||||
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Preferences.</source>
|
||||||
<translation>Kan ikke ta sikkerhetskopi av prosjektet da ingen filbane er satt. Du må først sette en filbane i Verktøy > Innstillinger.</translation>
|
<translation>Kan ikke ta sikkerhetskopi av prosjektet da ingen filbane er satt. Du må først sette en filbane i Innstillinger.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="795"/>
|
<location filename="../novelwriter/core/project.py" line="795"/>
|
||||||
<source>Cannot backup project because no project name is set. Please set a Working Title in Project > Project Settings.</source>
|
<source>Cannot backup project because no project name is set. Please set a Working Title in Project Settings.</source>
|
||||||
<translation>Kan ikke ta sikkerhetskopi av prosjektet da ingen arbeidstittel er satt. Du må først sette en arbeidstittel i Prosjekt > Prosjektinnstillinger.</translation>
|
<translation>Kan ikke ta sikkerhetskopi av prosjektet da ingen arbeidstittel er satt. Du må først sette en arbeidstittel i Prosjektinnstillinger.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="802"/>
|
<location filename="../novelwriter/core/project.py" line="802"/>
|
||||||
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Preferences.</source>
|
||||||
<translation>Kan ikke ta sikkerhetskopi av prosjektet da filbane ikke finnes. Du må sette en ny filbane i Verktøy > Innstillinger.</translation>
|
<translation>Kan ikke ta sikkerhetskopi av prosjektet da filbane ikke finnes. Du må sette en ny filbane i Innstillinger.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="815"/>
|
<location filename="../novelwriter/core/project.py" line="815"/>
|
||||||
@@ -4625,8 +4625,8 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="821"/>
|
<location filename="../novelwriter/core/project.py" line="821"/>
|
||||||
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Preferences.</source>
|
||||||
<translation>Kan ikke ta sikkerhetskopi av prosjektet da filbanen er inne i prosjektmappen. Du må sette en ny filbane i Verktøy > Innstillinger.</translation>
|
<translation>Kan ikke ta sikkerhetskopi av prosjektet da filbanen er inne i prosjektmappen. Du må sette en ny filbane i Innstillinger.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="828"/>
|
<location filename="../novelwriter/core/project.py" line="828"/>
|
||||||
|
|||||||
+8
-8
@@ -3228,7 +3228,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
||||||
<source>Also improves trypewriter scrolling for short documents.</source>
|
<source>Also improves typewriter scrolling for short documents.</source>
|
||||||
<translation>Também melhora a rolagem de máquina de escrever em documentos curtos.</translation>
|
<translation>Também melhora a rolagem de máquina de escrever em documentos curtos.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@@ -4580,18 +4580,18 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="788"/>
|
<location filename="../novelwriter/core/project.py" line="788"/>
|
||||||
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Preferences.</source>
|
||||||
<translation>Não foi possível realizar uma cópia de segurança do projeto porquê o caminho das cópias de segurança não foi definido. Por favor, defina um caminho válido para as cópias de segurança em Ferramentas > Preferências.</translation>
|
<translation>Não foi possível realizar uma cópia de segurança do projeto porquê o caminho das cópias de segurança não foi definido. Por favor, defina um caminho válido para as cópias de segurança em Preferências.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="795"/>
|
<location filename="../novelwriter/core/project.py" line="795"/>
|
||||||
<source>Cannot backup project because no project name is set. Please set a Working Title in Project > Project Settings.</source>
|
<source>Cannot backup project because no project name is set. Please set a Working Title in Project Settings.</source>
|
||||||
<translation>Não foi possível realizar a cópia de segurança do projeto porque o nome do projeto não está definido. Por favor defina o Nome do Projeto em Projeto > Configurações do Projeto.</translation>
|
<translation>Não foi possível realizar a cópia de segurança do projeto porque o nome do projeto não está definido. Por favor defina o Nome do Projeto em Configurações do Projeto.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="802"/>
|
<location filename="../novelwriter/core/project.py" line="802"/>
|
||||||
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Preferences.</source>
|
||||||
<translation>Não foi possível realizar a cópia de segurança do projeto porque o caminho das cópias de segurança não exite. Por favor, defina um cainho válido para as cópias de segurança em Ferramentas > Preferências.</translation>
|
<translation>Não foi possível realizar a cópia de segurança do projeto porque o caminho das cópias de segurança não exite. Por favor, defina um cainho válido para as cópias de segurança em Preferências.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="815"/>
|
<location filename="../novelwriter/core/project.py" line="815"/>
|
||||||
@@ -4600,7 +4600,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="821"/>
|
<location filename="../novelwriter/core/project.py" line="821"/>
|
||||||
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Preferences.</source>
|
||||||
<translation>Não foi possível realizar a cópia de segurança do projeto porque o caminho das cópias de segurança está em um caminho dentro do diretório do projeto. Por favor, escolha um caminho diferente para as cópias de segurança em Ferramentas> Preferências.</translation>
|
<translation>Não foi possível realizar a cópia de segurança do projeto porque o caminho das cópias de segurança está em um caminho dentro do diretório do projeto. Por favor, escolha um caminho diferente para as cópias de segurança em Ferramentas> Preferências.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
|||||||
+9
-9
@@ -3253,7 +3253,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
<location filename="../novelwriter/dialogs/preferences.py" line="788"/>
|
||||||
<source>Also improves trypewriter scrolling for short documents.</source>
|
<source>Also improves typewriter scrolling for short documents.</source>
|
||||||
<translation>还为短文档改进了打字机滚动。</translation>
|
<translation>还为短文档改进了打字机滚动。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@@ -4616,18 +4616,18 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="788"/>
|
<location filename="../novelwriter/core/project.py" line="788"/>
|
||||||
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because no backup path is set. Please set a valid backup location in Preferences.</source>
|
||||||
<translation>由于未设置备份路径,无法备份项目。 请在工具 > 首选项中设置一个有效的备份位置。</translation>
|
<translation>由于未设置备份路径,无法备份项目。 首选项中设置一个有效的备份位置。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="795"/>
|
<location filename="../novelwriter/core/project.py" line="795"/>
|
||||||
<source>Cannot backup project because no project name is set. Please set a Working Title in Project > Project Settings.</source>
|
<source>Cannot backup project because no project name is set. Please set a Working Title in Project Settings.</source>
|
||||||
<translation>由于未设置项目名,无法备份项目。 请在项目 > 项目设置中设置一个工作标题。</translation>
|
<translation>由于未设置项目名,无法备份项目。 项目设置中设置一个工作标题。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="802"/>
|
<location filename="../novelwriter/core/project.py" line="802"/>
|
||||||
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path does not exist. Please set a valid backup location in Preferences.</source>
|
||||||
<translation>无法备份项目,因为备份路径不存在。 请在工具 > 首选项中设置一个有效的备份位置。</translation>
|
<translation>无法备份项目,因为备份路径不存在。 首选项中设置一个有效的备份位置。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="815"/>
|
<location filename="../novelwriter/core/project.py" line="815"/>
|
||||||
@@ -4636,8 +4636,8 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="821"/>
|
<location filename="../novelwriter/core/project.py" line="821"/>
|
||||||
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Tools > Preferences.</source>
|
<source>Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Preferences.</source>
|
||||||
<translation>无法备份项目,因为备份路径在要备份的项目文件夹内。 请在工具 > 首选项中选择不同的备份路径。</translation>
|
<translation>无法备份项目,因为备份路径在要备份的项目文件夹内。 首选项中选择不同的备份路径。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../novelwriter/core/project.py" line="828"/>
|
<location filename="../novelwriter/core/project.py" line="828"/>
|
||||||
|
|||||||
@@ -215,25 +215,25 @@ def main(sysArgs=None):
|
|||||||
errorCode = 0
|
errorCode = 0
|
||||||
if sys.hexversion < 0x030600f0:
|
if sys.hexversion < 0x030600f0:
|
||||||
errorData.append(
|
errorData.append(
|
||||||
"At least Python 3.6.0 is required, found %s" % CONFIG.verPyString
|
"At least Python 3.6 is required, found %s" % CONFIG.verPyString
|
||||||
)
|
)
|
||||||
errorCode |= 4
|
errorCode |= 0x04
|
||||||
if CONFIG.verQtValue < 50300:
|
if CONFIG.verQtValue < 50300:
|
||||||
errorData.append(
|
errorData.append(
|
||||||
"At least Qt5 version 5.3 is required, found %s" % CONFIG.verQtString
|
"At least Qt5 version 5.3 is required, found %s" % CONFIG.verQtString
|
||||||
)
|
)
|
||||||
errorCode |= 8
|
errorCode |= 0x08
|
||||||
if CONFIG.verPyQtValue < 50300:
|
if CONFIG.verPyQtValue < 50300:
|
||||||
errorData.append(
|
errorData.append(
|
||||||
"At least PyQt5 version 5.3 is required, found %s" % CONFIG.verPyQtString
|
"At least PyQt5 version 5.3 is required, found %s" % CONFIG.verPyQtString
|
||||||
)
|
)
|
||||||
errorCode |= 16
|
errorCode |= 0x10
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import lxml # noqa: F401
|
import lxml # noqa: F401
|
||||||
except ImportError:
|
except ImportError:
|
||||||
errorData.append("Python module 'lxml' is missing")
|
errorData.append("Python module 'lxml' is missing")
|
||||||
errorCode |= 32
|
errorCode |= 0x20
|
||||||
|
|
||||||
if errorData:
|
if errorData:
|
||||||
errApp = QApplication([])
|
errApp = QApplication([])
|
||||||
|
|||||||
@@ -174,6 +174,26 @@ def hexToInt(value, default=0):
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def checkIntRange(value, first, last, default):
|
||||||
|
"""Check that an int is in a given range. If it isn't, return the
|
||||||
|
default value.
|
||||||
|
"""
|
||||||
|
if isinstance(value, int):
|
||||||
|
if value >= first and value <= last:
|
||||||
|
return value
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def checkIntTuple(value, valid, default):
|
||||||
|
"""Check that an int is an element of a tuple. If it isn't, return
|
||||||
|
the default value.
|
||||||
|
"""
|
||||||
|
if isinstance(value, int):
|
||||||
|
if value in valid:
|
||||||
|
return value
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================================== #
|
# =============================================================================================== #
|
||||||
# Formatting Functions
|
# Formatting Functions
|
||||||
# =============================================================================================== #
|
# =============================================================================================== #
|
||||||
|
|||||||
+12
-12
@@ -307,12 +307,12 @@ class Config:
|
|||||||
if not os.path.isdir(self.confPath):
|
if not os.path.isdir(self.confPath):
|
||||||
try:
|
try:
|
||||||
os.mkdir(self.confPath)
|
os.mkdir(self.confPath)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
logger.error("Could not create folder: %s", self.confPath)
|
logger.error("Could not create folder: %s", self.confPath)
|
||||||
logException()
|
logException()
|
||||||
self.hasError = True
|
self.hasError = True
|
||||||
self.errData.append("Could not create folder: %s" % self.confPath)
|
self.errData.append("Could not create folder: %s" % self.confPath)
|
||||||
self.errData.append(str(e))
|
self.errData.append(str(exc))
|
||||||
self.confPath = None
|
self.confPath = None
|
||||||
|
|
||||||
# Check if config file exists
|
# Check if config file exists
|
||||||
@@ -330,12 +330,12 @@ class Config:
|
|||||||
if not os.path.isdir(self.dataPath):
|
if not os.path.isdir(self.dataPath):
|
||||||
try:
|
try:
|
||||||
os.mkdir(self.dataPath)
|
os.mkdir(self.dataPath)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
logger.error("Could not create folder: %s", self.dataPath)
|
logger.error("Could not create folder: %s", self.dataPath)
|
||||||
logException()
|
logException()
|
||||||
self.hasError = True
|
self.hasError = True
|
||||||
self.errData.append("Could not create folder: %s" % self.dataPath)
|
self.errData.append("Could not create folder: %s" % self.dataPath)
|
||||||
self.errData.append(str(e))
|
self.errData.append(str(exc))
|
||||||
self.dataPath = None
|
self.dataPath = None
|
||||||
|
|
||||||
# Host and Kernel
|
# Host and Kernel
|
||||||
@@ -425,12 +425,12 @@ class Config:
|
|||||||
try:
|
try:
|
||||||
with open(cnfPath, mode="r", encoding="utf-8") as inFile:
|
with open(cnfPath, mode="r", encoding="utf-8") as inFile:
|
||||||
theConf.read_file(inFile)
|
theConf.read_file(inFile)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
logger.error("Could not load config file")
|
logger.error("Could not load config file")
|
||||||
logException()
|
logException()
|
||||||
self.hasError = True
|
self.hasError = True
|
||||||
self.errData.append("Could not load config file")
|
self.errData.append("Could not load config file")
|
||||||
self.errData.append(str(e))
|
self.errData.append(str(exc))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Main
|
# Main
|
||||||
@@ -655,12 +655,12 @@ class Config:
|
|||||||
with open(cnfPath, mode="w", encoding="utf-8") as outFile:
|
with open(cnfPath, mode="w", encoding="utf-8") as outFile:
|
||||||
theConf.write(outFile)
|
theConf.write(outFile)
|
||||||
self.confChanged = False
|
self.confChanged = False
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
logger.error("Could not save config file")
|
logger.error("Could not save config file")
|
||||||
logException()
|
logException()
|
||||||
self.hasError = True
|
self.hasError = True
|
||||||
self.errData.append("Could not save config file")
|
self.errData.append("Could not save config file")
|
||||||
self.errData.append(str(e))
|
self.errData.append(str(exc))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -688,10 +688,10 @@ class Config:
|
|||||||
"words": theEntry.get("words", 0),
|
"words": theEntry.get("words", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.hasError = True
|
self.hasError = True
|
||||||
self.errData.append("Could not load recent project cache")
|
self.errData.append("Could not load recent project cache")
|
||||||
self.errData.append(str(e))
|
self.errData.append(str(exc))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -708,10 +708,10 @@ class Config:
|
|||||||
try:
|
try:
|
||||||
with open(cacheTemp, mode="w+", encoding="utf-8") as outFile:
|
with open(cacheTemp, mode="w+", encoding="utf-8") as outFile:
|
||||||
json.dump(self.recentProj, outFile, indent=2)
|
json.dump(self.recentProj, outFile, indent=2)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.hasError = True
|
self.hasError = True
|
||||||
self.errData.append("Could not save recent project cache")
|
self.errData.append("Could not save recent project cache")
|
||||||
self.errData.append(str(e))
|
self.errData.append(str(exc))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if os.path.isfile(cacheFile):
|
if os.path.isfile(cacheFile):
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ class NWDoc():
|
|||||||
# Load the rest of the file
|
# Load the rest of the file
|
||||||
theText += inFile.read()
|
theText += inFile.read()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self._docError = str(e)
|
self._docError = str(exc)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -149,8 +149,8 @@ class NWDoc():
|
|||||||
with open(docTemp, mode="w", encoding="utf-8") as outFile:
|
with open(docTemp, mode="w", encoding="utf-8") as outFile:
|
||||||
outFile.write(docMeta)
|
outFile.write(docMeta)
|
||||||
outFile.write(docText)
|
outFile.write(docText)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self._docError = str(e)
|
self._docError = str(exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If we're here, the file was successfully saved, so we can
|
# If we're here, the file was successfully saved, so we can
|
||||||
@@ -184,8 +184,8 @@ class NWDoc():
|
|||||||
try:
|
try:
|
||||||
os.unlink(chkFile)
|
os.unlink(chkFile)
|
||||||
logger.debug("Deleted: %s", chkFile)
|
logger.debug("Deleted: %s", chkFile)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self._docError = str(e)
|
self._docError = str(exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -185,26 +185,4 @@ class OptionState():
|
|||||||
return checkBool(self._theState[group].get(name, default), default)
|
return checkBool(self._theState[group].get(name, default), default)
|
||||||
return default
|
return default
|
||||||
|
|
||||||
##
|
|
||||||
# Validators
|
|
||||||
##
|
|
||||||
|
|
||||||
def validIntRange(self, value, first, last, default):
|
|
||||||
"""Check that an int is in a given range. If it isn't, return
|
|
||||||
the default value.
|
|
||||||
"""
|
|
||||||
if isinstance(value, int):
|
|
||||||
if value >= first and value <= last:
|
|
||||||
return value
|
|
||||||
return default
|
|
||||||
|
|
||||||
def validIntTuple(self, value, valid, default):
|
|
||||||
"""Check that an int is an element of a tuple. If it isn't,
|
|
||||||
return the default value.
|
|
||||||
"""
|
|
||||||
if isinstance(value, int):
|
|
||||||
if value in valid:
|
|
||||||
return value
|
|
||||||
return default
|
|
||||||
|
|
||||||
# END Class OptionState
|
# END Class OptionState
|
||||||
|
|||||||
+42
-42
@@ -415,10 +415,10 @@ class NWProject():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
nwXML = etree.parse(fileName)
|
nwXML = etree.parse(fileName)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert(self.tr(
|
||||||
self.tr("Failed to parse project xml."), str(e)
|
"Failed to parse project xml."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
|
|
||||||
# Trying to open backup file instead
|
# Trying to open backup file instead
|
||||||
backFile = fileName[:-3]+"bak"
|
backFile = fileName[:-3]+"bak"
|
||||||
@@ -428,10 +428,10 @@ class NWProject():
|
|||||||
), nwAlert.INFO)
|
), nwAlert.INFO)
|
||||||
try:
|
try:
|
||||||
nwXML = etree.parse(backFile)
|
nwXML = etree.parse(backFile)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert(self.tr(
|
||||||
self.tr("Failed to parse project xml."), str(e)
|
"Failed to parse project xml."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
self.clearProject()
|
self.clearProject()
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
@@ -487,8 +487,8 @@ class NWProject():
|
|||||||
self.tr("File Version"),
|
self.tr("File Version"),
|
||||||
self.tr(
|
self.tr(
|
||||||
"The file format of your project is about to be updated. "
|
"The file format of your project is about to be updated. "
|
||||||
"If you proceed, this project can no longer be opened by "
|
"If you proceed, older versions of novelWriter will no "
|
||||||
"an older version of novelWriter. Continue?"
|
"longer be able to open this project. Continue?"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if not msgYes:
|
if not msgYes:
|
||||||
@@ -708,10 +708,10 @@ class NWProject():
|
|||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
xml_declaration=True
|
xml_declaration=True
|
||||||
))
|
))
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert(self.tr(
|
||||||
self.tr("Failed to save project."), str(e)
|
"Failed to save project."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If we're here, the file was successfully saved,
|
# If we're here, the file was successfully saved,
|
||||||
@@ -788,21 +788,21 @@ class NWProject():
|
|||||||
if self.mainConf.backupPath is None or self.mainConf.backupPath == "":
|
if self.mainConf.backupPath is None or self.mainConf.backupPath == "":
|
||||||
self.theParent.makeAlert(self.tr(
|
self.theParent.makeAlert(self.tr(
|
||||||
"Cannot backup project because no backup path is set. "
|
"Cannot backup project because no backup path is set. "
|
||||||
"Please set a valid backup location in Tools > Preferences."
|
"Please set a valid backup location in Preferences."
|
||||||
), nwAlert.ERROR)
|
), nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.projName is None or self.projName == "":
|
if self.projName is None or self.projName == "":
|
||||||
self.theParent.makeAlert(self.tr(
|
self.theParent.makeAlert(self.tr(
|
||||||
"Cannot backup project because no project name is set. "
|
"Cannot backup project because no project name is set. "
|
||||||
"Please set a Working Title in Project > Project Settings."
|
"Please set a Working Title in Project Settings."
|
||||||
), nwAlert.ERROR)
|
), nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not os.path.isdir(self.mainConf.backupPath):
|
if not os.path.isdir(self.mainConf.backupPath):
|
||||||
self.theParent.makeAlert(self.tr(
|
self.theParent.makeAlert(self.tr(
|
||||||
"Cannot backup project because the backup path does not exist. "
|
"Cannot backup project because the backup path does not exist. "
|
||||||
"Please set a valid backup location in Tools > Preferences."
|
"Please set a valid backup location in Preferences."
|
||||||
), nwAlert.ERROR)
|
), nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -812,17 +812,17 @@ class NWProject():
|
|||||||
try:
|
try:
|
||||||
os.mkdir(baseDir)
|
os.mkdir(baseDir)
|
||||||
logger.debug("Created folder: %s", baseDir)
|
logger.debug("Created folder: %s", baseDir)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert(self.tr(
|
||||||
self.tr("Could not create backup folder."), str(e)
|
"Could not create backup folder."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if os.path.commonpath([self.projPath, baseDir]) == self.projPath:
|
if os.path.commonpath([self.projPath, baseDir]) == self.projPath:
|
||||||
self.theParent.makeAlert(self.tr(
|
self.theParent.makeAlert(self.tr(
|
||||||
"Cannot backup project because the backup path is within the "
|
"Cannot backup project because the backup path is within the "
|
||||||
"project folder to be backed up. Please choose a different "
|
"project folder to be backed up. Please choose a different "
|
||||||
"backup path in Tools > Preferences."
|
"backup path in Preferences."
|
||||||
), nwAlert.ERROR)
|
), nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -839,10 +839,10 @@ class NWProject():
|
|||||||
"Backup archive file written to: {0}"
|
"Backup archive file written to: {0}"
|
||||||
).format(f"{os.path.join(cleanName, archName)}.zip"), nwAlert.INFO)
|
).format(f"{os.path.join(cleanName, archName)}.zip"), nwAlert.INFO)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert(self.tr(
|
||||||
self.tr("Could not write backup archive."), str(e)
|
"Could not write backup archive."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.theParent.setStatus(self.tr(
|
self.theParent.setStatus(self.tr(
|
||||||
@@ -872,10 +872,10 @@ class NWProject():
|
|||||||
try:
|
try:
|
||||||
shutil.unpack_archive(pkgSample, projPath)
|
shutil.unpack_archive(pkgSample, projPath)
|
||||||
isSuccess = True
|
isSuccess = True
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert(self.tr(
|
||||||
self.tr("Failed to create a new example project."), str(e)
|
"Failed to create a new example project."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
|
|
||||||
elif os.path.isdir(srcSample):
|
elif os.path.isdir(srcSample):
|
||||||
|
|
||||||
@@ -894,10 +894,10 @@ class NWProject():
|
|||||||
|
|
||||||
isSuccess = True
|
isSuccess = True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert(self.tr(
|
||||||
self.tr("Failed to create a new example project."), str(e)
|
"Failed to create a new example project."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.theParent.makeAlert(self.tr(
|
self.theParent.makeAlert(self.tr(
|
||||||
@@ -933,10 +933,10 @@ class NWProject():
|
|||||||
try:
|
try:
|
||||||
os.mkdir(projPath)
|
os.mkdir(projPath)
|
||||||
logger.debug("Created folder: %s", projPath)
|
logger.debug("Created folder: %s", projPath)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert(self.tr(
|
||||||
self.tr("Could not create new project folder."), str(e)
|
"Could not create new project folder."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if os.path.isdir(projPath):
|
if os.path.isdir(projPath):
|
||||||
@@ -1327,10 +1327,10 @@ class NWProject():
|
|||||||
try:
|
try:
|
||||||
os.mkdir(thePath)
|
os.mkdir(thePath)
|
||||||
logger.debug("Created folder: %s", thePath)
|
logger.debug("Created folder: %s", thePath)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert(self.tr(
|
||||||
self.tr("Could not create folder."), str(e)
|
"Could not create folder."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -776,7 +776,7 @@ class GuiPreferencesEditor(QWidget):
|
|||||||
self.mainForm.addRow(
|
self.mainForm.addRow(
|
||||||
self.tr("Scroll past end of the document"),
|
self.tr("Scroll past end of the document"),
|
||||||
self.scrollPastEnd,
|
self.scrollPastEnd,
|
||||||
self.tr("Also improves trypewriter scrolling for short documents.")
|
self.tr("Also improves typewriter scrolling for short documents.")
|
||||||
)
|
)
|
||||||
|
|
||||||
# Typewriter Scrolling
|
# Typewriter Scrolling
|
||||||
|
|||||||
@@ -183,13 +183,13 @@ def exceptionHandler(exType, exValue, exTrace):
|
|||||||
nwGUI.closeMain()
|
nwGUI.closeMain()
|
||||||
logger.info("Emergency shutdown successful")
|
logger.info("Emergency shutdown successful")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
logger.critical("Could not close the project before exiting")
|
logger.critical("Could not close the project before exiting")
|
||||||
logger.critical(str(e))
|
logger.critical(str(exc))
|
||||||
|
|
||||||
qApp.exit(1)
|
qApp.exit(1)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
logger.critical(str(e))
|
logger.critical(str(exc))
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
+16
-16
@@ -793,28 +793,28 @@ class GuiMainMenu(QMenuBar):
|
|||||||
|
|
||||||
# Format > Header 1 (Partition)
|
# Format > Header 1 (Partition)
|
||||||
self.aFmtHead1 = QAction(self.tr("Header 1 (Partition)"), self)
|
self.aFmtHead1 = QAction(self.tr("Header 1 (Partition)"), self)
|
||||||
self.aFmtHead1.setStatusTip(self.tr("Change the block format to Header 1"))
|
self.aFmtHead1.setStatusTip(self.tr("Set the text block format to Header 1 (Partition)"))
|
||||||
self.aFmtHead1.setShortcut("Ctrl+1")
|
self.aFmtHead1.setShortcut("Ctrl+1")
|
||||||
self.aFmtHead1.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H1))
|
self.aFmtHead1.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H1))
|
||||||
self.fmtMenu.addAction(self.aFmtHead1)
|
self.fmtMenu.addAction(self.aFmtHead1)
|
||||||
|
|
||||||
# Format > Header 2 (Chapter)
|
# Format > Header 2 (Chapter)
|
||||||
self.aFmtHead2 = QAction(self.tr("Header 2 (Chapter)"), self)
|
self.aFmtHead2 = QAction(self.tr("Header 2 (Chapter)"), self)
|
||||||
self.aFmtHead2.setStatusTip(self.tr("Change the block format to Header 2"))
|
self.aFmtHead2.setStatusTip(self.tr("Set the text block format to Header 2 (Chapter)"))
|
||||||
self.aFmtHead2.setShortcut("Ctrl+2")
|
self.aFmtHead2.setShortcut("Ctrl+2")
|
||||||
self.aFmtHead2.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H2))
|
self.aFmtHead2.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H2))
|
||||||
self.fmtMenu.addAction(self.aFmtHead2)
|
self.fmtMenu.addAction(self.aFmtHead2)
|
||||||
|
|
||||||
# Format > Header 3 (Scene)
|
# Format > Header 3 (Scene)
|
||||||
self.aFmtHead3 = QAction(self.tr("Header 3 (Scene)"), self)
|
self.aFmtHead3 = QAction(self.tr("Header 3 (Scene)"), self)
|
||||||
self.aFmtHead3.setStatusTip(self.tr("Change the block format to Header 3"))
|
self.aFmtHead3.setStatusTip(self.tr("Set the text block format to Header 3 (Scene)"))
|
||||||
self.aFmtHead3.setShortcut("Ctrl+3")
|
self.aFmtHead3.setShortcut("Ctrl+3")
|
||||||
self.aFmtHead3.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H3))
|
self.aFmtHead3.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H3))
|
||||||
self.fmtMenu.addAction(self.aFmtHead3)
|
self.fmtMenu.addAction(self.aFmtHead3)
|
||||||
|
|
||||||
# Format > Header 4 (Section)
|
# Format > Header 4 (Section)
|
||||||
self.aFmtHead4 = QAction(self.tr("Header 4 (Section)"), self)
|
self.aFmtHead4 = QAction(self.tr("Header 4 (Section)"), self)
|
||||||
self.aFmtHead4.setStatusTip(self.tr("Change the block format to Header 4"))
|
self.aFmtHead4.setStatusTip(self.tr("Set the text block format to Header 4 (Section)"))
|
||||||
self.aFmtHead4.setShortcut("Ctrl+4")
|
self.aFmtHead4.setShortcut("Ctrl+4")
|
||||||
self.aFmtHead4.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H4))
|
self.aFmtHead4.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H4))
|
||||||
self.fmtMenu.addAction(self.aFmtHead4)
|
self.fmtMenu.addAction(self.aFmtHead4)
|
||||||
@@ -824,13 +824,13 @@ class GuiMainMenu(QMenuBar):
|
|||||||
|
|
||||||
# Format > Novel Title
|
# Format > Novel Title
|
||||||
self.aFmtTitle = QAction(self.tr("Novel Title"), self)
|
self.aFmtTitle = QAction(self.tr("Novel Title"), self)
|
||||||
self.aFmtTitle.setStatusTip(self.tr("Change the block format to Novel Title"))
|
self.aFmtTitle.setStatusTip(self.tr("Set the text block format to Novel Title"))
|
||||||
self.aFmtTitle.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_TTL))
|
self.aFmtTitle.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_TTL))
|
||||||
self.fmtMenu.addAction(self.aFmtTitle)
|
self.fmtMenu.addAction(self.aFmtTitle)
|
||||||
|
|
||||||
# Format > Unnumbered Chapter
|
# Format > Unnumbered Chapter
|
||||||
self.aFmtUnNum = QAction(self.tr("Unnumbered Chapter"), self)
|
self.aFmtUnNum = QAction(self.tr("Unnumbered Chapter"), self)
|
||||||
self.aFmtUnNum.setStatusTip(self.tr("Change the block format to Unnumbered Chapter"))
|
self.aFmtUnNum.setStatusTip(self.tr("Set the text block format to Unnumbered Chapter"))
|
||||||
self.aFmtUnNum.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_UNN))
|
self.aFmtUnNum.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_UNN))
|
||||||
self.fmtMenu.addAction(self.aFmtUnNum)
|
self.fmtMenu.addAction(self.aFmtUnNum)
|
||||||
|
|
||||||
@@ -839,21 +839,21 @@ class GuiMainMenu(QMenuBar):
|
|||||||
|
|
||||||
# Format > Align Left
|
# Format > Align Left
|
||||||
self.aFmtAlignLeft = QAction(self.tr("Align Left"), self)
|
self.aFmtAlignLeft = QAction(self.tr("Align Left"), self)
|
||||||
self.aFmtAlignLeft.setStatusTip(self.tr("Change the block alignment to left"))
|
self.aFmtAlignLeft.setStatusTip(self.tr("Left-align the text block"))
|
||||||
self.aFmtAlignLeft.setShortcut("Ctrl+5")
|
self.aFmtAlignLeft.setShortcut("Ctrl+5")
|
||||||
self.aFmtAlignLeft.triggered.connect(lambda: self._docAction(nwDocAction.ALIGN_L))
|
self.aFmtAlignLeft.triggered.connect(lambda: self._docAction(nwDocAction.ALIGN_L))
|
||||||
self.fmtMenu.addAction(self.aFmtAlignLeft)
|
self.fmtMenu.addAction(self.aFmtAlignLeft)
|
||||||
|
|
||||||
# Format > Align Centre
|
# Format > Align Centre
|
||||||
self.aFmtAlignCentre = QAction(self.tr("Align Centre"), self)
|
self.aFmtAlignCentre = QAction(self.tr("Align Centre"), self)
|
||||||
self.aFmtAlignCentre.setStatusTip(self.tr("Change the block alignment to centre"))
|
self.aFmtAlignCentre.setStatusTip(self.tr("Centre the text block"))
|
||||||
self.aFmtAlignCentre.setShortcut("Ctrl+6")
|
self.aFmtAlignCentre.setShortcut("Ctrl+6")
|
||||||
self.aFmtAlignCentre.triggered.connect(lambda: self._docAction(nwDocAction.ALIGN_C))
|
self.aFmtAlignCentre.triggered.connect(lambda: self._docAction(nwDocAction.ALIGN_C))
|
||||||
self.fmtMenu.addAction(self.aFmtAlignCentre)
|
self.fmtMenu.addAction(self.aFmtAlignCentre)
|
||||||
|
|
||||||
# Format > Align Right
|
# Format > Align Right
|
||||||
self.aFmtAlignRight = QAction(self.tr("Align Right"), self)
|
self.aFmtAlignRight = QAction(self.tr("Align Right"), self)
|
||||||
self.aFmtAlignRight.setStatusTip(self.tr("Change the block alignment to right"))
|
self.aFmtAlignRight.setStatusTip(self.tr("Right-align the text block"))
|
||||||
self.aFmtAlignRight.setShortcut("Ctrl+7")
|
self.aFmtAlignRight.setShortcut("Ctrl+7")
|
||||||
self.aFmtAlignRight.triggered.connect(lambda: self._docAction(nwDocAction.ALIGN_R))
|
self.aFmtAlignRight.triggered.connect(lambda: self._docAction(nwDocAction.ALIGN_R))
|
||||||
self.fmtMenu.addAction(self.aFmtAlignRight)
|
self.fmtMenu.addAction(self.aFmtAlignRight)
|
||||||
@@ -863,14 +863,14 @@ class GuiMainMenu(QMenuBar):
|
|||||||
|
|
||||||
# Format > Indent Left
|
# Format > Indent Left
|
||||||
self.aFmtIndentLeft = QAction(self.tr("Indent Left"), self)
|
self.aFmtIndentLeft = QAction(self.tr("Indent Left"), self)
|
||||||
self.aFmtIndentLeft.setStatusTip(self.tr("Increase the block's left margin"))
|
self.aFmtIndentLeft.setStatusTip(self.tr("Increase the text block's left margin"))
|
||||||
self.aFmtIndentLeft.setShortcut("Ctrl+8")
|
self.aFmtIndentLeft.setShortcut("Ctrl+8")
|
||||||
self.aFmtIndentLeft.triggered.connect(lambda: self._docAction(nwDocAction.INDENT_L))
|
self.aFmtIndentLeft.triggered.connect(lambda: self._docAction(nwDocAction.INDENT_L))
|
||||||
self.fmtMenu.addAction(self.aFmtIndentLeft)
|
self.fmtMenu.addAction(self.aFmtIndentLeft)
|
||||||
|
|
||||||
# Format > Indent Right
|
# Format > Indent Right
|
||||||
self.aFmtIndentRight = QAction(self.tr("Indent Right"), self)
|
self.aFmtIndentRight = QAction(self.tr("Indent Right"), self)
|
||||||
self.aFmtIndentRight.setStatusTip(self.tr("Increase the block's right margin"))
|
self.aFmtIndentRight.setStatusTip(self.tr("Increase the text block's right margin"))
|
||||||
self.aFmtIndentRight.setShortcut("Ctrl+9")
|
self.aFmtIndentRight.setShortcut("Ctrl+9")
|
||||||
self.aFmtIndentRight.triggered.connect(lambda: self._docAction(nwDocAction.INDENT_R))
|
self.aFmtIndentRight.triggered.connect(lambda: self._docAction(nwDocAction.INDENT_R))
|
||||||
self.fmtMenu.addAction(self.aFmtIndentRight)
|
self.fmtMenu.addAction(self.aFmtIndentRight)
|
||||||
@@ -880,14 +880,14 @@ class GuiMainMenu(QMenuBar):
|
|||||||
|
|
||||||
# Format > Comment
|
# Format > Comment
|
||||||
self.aFmtComment = QAction(self.tr("Comment"), self)
|
self.aFmtComment = QAction(self.tr("Comment"), self)
|
||||||
self.aFmtComment.setStatusTip(self.tr("Change the block format to comment"))
|
self.aFmtComment.setStatusTip(self.tr("Change the text block format to comment"))
|
||||||
self.aFmtComment.setShortcut("Ctrl+/")
|
self.aFmtComment.setShortcut("Ctrl+/")
|
||||||
self.aFmtComment.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_COM))
|
self.aFmtComment.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_COM))
|
||||||
self.fmtMenu.addAction(self.aFmtComment)
|
self.fmtMenu.addAction(self.aFmtComment)
|
||||||
|
|
||||||
# Format > Remove Block Format
|
# Format > Remove Block Format
|
||||||
self.aFmtNoFormat = QAction(self.tr("Remove Block Format"), self)
|
self.aFmtNoFormat = QAction(self.tr("Remove Block Format"), self)
|
||||||
self.aFmtNoFormat.setStatusTip(self.tr("Strips block format"))
|
self.aFmtNoFormat.setStatusTip(self.tr("Strip text block format"))
|
||||||
self.aFmtNoFormat.setShortcuts(["Ctrl+0", "Ctrl+Shift+/"])
|
self.aFmtNoFormat.setShortcuts(["Ctrl+0", "Ctrl+Shift+/"])
|
||||||
self.aFmtNoFormat.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_TXT))
|
self.aFmtNoFormat.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_TXT))
|
||||||
self.fmtMenu.addAction(self.aFmtNoFormat)
|
self.fmtMenu.addAction(self.aFmtNoFormat)
|
||||||
@@ -898,7 +898,7 @@ class GuiMainMenu(QMenuBar):
|
|||||||
# Format > Replace Single Quotes
|
# Format > Replace Single Quotes
|
||||||
self.aFmtReplSng = QAction(self.tr("Replace Single Quotes"), self)
|
self.aFmtReplSng = QAction(self.tr("Replace Single Quotes"), self)
|
||||||
self.aFmtReplSng.setStatusTip(
|
self.aFmtReplSng.setStatusTip(
|
||||||
self.tr("Replace all straight single quotes in selected text")
|
self.tr("Replace all straight single quotes in the selected text")
|
||||||
)
|
)
|
||||||
self.aFmtReplSng.triggered.connect(lambda: self._docAction(nwDocAction.REPL_SNG))
|
self.aFmtReplSng.triggered.connect(lambda: self._docAction(nwDocAction.REPL_SNG))
|
||||||
self.fmtMenu.addAction(self.aFmtReplSng)
|
self.fmtMenu.addAction(self.aFmtReplSng)
|
||||||
@@ -906,7 +906,7 @@ class GuiMainMenu(QMenuBar):
|
|||||||
# Format > Replace Double Quotes
|
# Format > Replace Double Quotes
|
||||||
self.aFmtReplDbl = QAction(self.tr("Replace Double Quotes"), self)
|
self.aFmtReplDbl = QAction(self.tr("Replace Double Quotes"), self)
|
||||||
self.aFmtReplDbl.setStatusTip(
|
self.aFmtReplDbl.setStatusTip(
|
||||||
self.tr("Replace all straight double quotes in selected text")
|
self.tr("Replace all straight double quotes in the selected text")
|
||||||
)
|
)
|
||||||
self.aFmtReplDbl.triggered.connect(lambda: self._docAction(nwDocAction.REPL_DBL))
|
self.aFmtReplDbl.triggered.connect(lambda: self._docAction(nwDocAction.REPL_DBL))
|
||||||
self.fmtMenu.addAction(self.aFmtReplDbl)
|
self.fmtMenu.addAction(self.aFmtReplDbl)
|
||||||
@@ -914,7 +914,7 @@ class GuiMainMenu(QMenuBar):
|
|||||||
# Format > Remove In-Paragraph Breaks
|
# Format > Remove In-Paragraph Breaks
|
||||||
self.aFmtRmBreaks = QAction(self.tr("Remove In-Paragraph Breaks"), self)
|
self.aFmtRmBreaks = QAction(self.tr("Remove In-Paragraph Breaks"), self)
|
||||||
self.aFmtRmBreaks.setStatusTip(
|
self.aFmtRmBreaks.setStatusTip(
|
||||||
self.tr("Removes all line breaks within paragraphs in the selected text")
|
self.tr("Remove all line breaks within paragraphs in the selected text")
|
||||||
)
|
)
|
||||||
self.aFmtRmBreaks.triggered.connect(lambda: self._docAction(nwDocAction.RM_BREAKS))
|
self.aFmtRmBreaks.triggered.connect(lambda: self._docAction(nwDocAction.RM_BREAKS))
|
||||||
self.fmtMenu.addAction(self.aFmtRmBreaks)
|
self.fmtMenu.addAction(self.aFmtRmBreaks)
|
||||||
|
|||||||
+34
-33
@@ -500,10 +500,10 @@ class GuiMain(QMainWindow):
|
|||||||
),
|
),
|
||||||
self.tr(
|
self.tr(
|
||||||
"Note: If the program or the computer previously "
|
"Note: If the program or the computer previously "
|
||||||
"crashed, the lock can safely be overridden. If, "
|
"crashed, the lock can safely be overridden. However, "
|
||||||
"however, another instance of novelWriter has the "
|
"overriding it is not recommended if the project is "
|
||||||
"project open, overriding the lock may corrupt the "
|
"open in another instance of novelWriter. Doing so "
|
||||||
"project, and is not recommended."
|
"may corrupt the project."
|
||||||
),
|
),
|
||||||
lockDetails
|
lockDetails
|
||||||
),
|
),
|
||||||
@@ -730,10 +730,10 @@ class GuiMain(QMainWindow):
|
|||||||
with open(loadFile, mode="rt", encoding="utf-8") as inFile:
|
with open(loadFile, mode="rt", encoding="utf-8") as inFile:
|
||||||
theText = inFile.read()
|
theText = inFile.read()
|
||||||
self.mainConf.setLastPath(loadFile)
|
self.mainConf.setLastPath(loadFile)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.makeAlert([
|
self.makeAlert(self.tr(
|
||||||
self.tr("Could not read file. The file must be an existing text file."), str(e)
|
"Could not read file. The file must be an existing text file."
|
||||||
], nwAlert.ERROR)
|
), nwAlert.ERROR, exception=exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.docEditor.docHandle() is None:
|
if self.docEditor.docHandle() is None:
|
||||||
@@ -1116,51 +1116,52 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def makeAlert(self, theMessage, theLevel=nwAlert.INFO):
|
def makeAlert(self, message, level=nwAlert.INFO, exception=None):
|
||||||
"""Alert both the user and the logger at the same time. The
|
"""Alert both the user and the logger at the same time. The
|
||||||
message can be either a string or a list of strings.
|
message can be either a string or a list of strings.
|
||||||
"""
|
"""
|
||||||
if isinstance(theMessage, list):
|
if isinstance(message, list):
|
||||||
theMessage = list(filter(None, theMessage)) # Strip empty strings
|
message = list(filter(None, message)) # Strip empty strings
|
||||||
popMsg = "<br>".join(theMessage)
|
popMsg = "<br>".join(message)
|
||||||
logMsg = theMessage
|
logMsg = " ".join(message)
|
||||||
else:
|
else:
|
||||||
popMsg = theMessage
|
popMsg = str(message)
|
||||||
logMsg = [theMessage]
|
logMsg = str(message)
|
||||||
|
|
||||||
|
kw = {}
|
||||||
|
if exception is not None:
|
||||||
|
kw["exc_info"] = exception
|
||||||
|
popMsg = f"{popMsg}<br>{type(exception).__name__}: {str(exception)}"
|
||||||
|
|
||||||
# Write to Log
|
# Write to Log
|
||||||
if theLevel == nwAlert.INFO:
|
if level == nwAlert.INFO:
|
||||||
for msgLine in logMsg:
|
logger.info(logMsg, **kw)
|
||||||
logger.info(msgLine)
|
elif level == nwAlert.WARN:
|
||||||
elif theLevel == nwAlert.WARN:
|
logger.warning(logMsg, **kw)
|
||||||
for msgLine in logMsg:
|
elif level == nwAlert.ERROR:
|
||||||
logger.warning(msgLine)
|
logger.error(logMsg, **kw)
|
||||||
elif theLevel == nwAlert.ERROR:
|
elif level == nwAlert.BUG:
|
||||||
for msgLine in logMsg:
|
logger.error(logMsg, **kw)
|
||||||
logger.error(msgLine)
|
|
||||||
elif theLevel == nwAlert.BUG:
|
|
||||||
for msgLine in logMsg:
|
|
||||||
logger.error(msgLine)
|
|
||||||
|
|
||||||
# Popup
|
# Popup
|
||||||
msgBox = QMessageBox()
|
msgBox = QMessageBox()
|
||||||
if theLevel == nwAlert.INFO:
|
if level == nwAlert.INFO:
|
||||||
msgBox.information(self, self.tr("Information"), popMsg)
|
msgBox.information(self, self.tr("Information"), popMsg)
|
||||||
elif theLevel == nwAlert.WARN:
|
elif level == nwAlert.WARN:
|
||||||
msgBox.warning(self, self.tr("Warning"), popMsg)
|
msgBox.warning(self, self.tr("Warning"), popMsg)
|
||||||
elif theLevel == nwAlert.ERROR:
|
elif level == nwAlert.ERROR:
|
||||||
msgBox.critical(self, self.tr("Error"), popMsg)
|
msgBox.critical(self, self.tr("Error"), popMsg)
|
||||||
elif theLevel == nwAlert.BUG:
|
elif level == nwAlert.BUG:
|
||||||
popMsg += "<br>%s" % self.tr("This is a bug!")
|
popMsg += "<br>%s" % self.tr("This is a bug!")
|
||||||
msgBox.critical(self, self.tr("Internal Error"), popMsg)
|
msgBox.critical(self, self.tr("Internal Error"), popMsg)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def askQuestion(self, theTitle, theQuestion):
|
def askQuestion(self, title, question):
|
||||||
"""Ask the user a Yes/No question.
|
"""Ask the user a Yes/No question.
|
||||||
"""
|
"""
|
||||||
msgBox = QMessageBox()
|
msgBox = QMessageBox()
|
||||||
msgRes = msgBox.question(self, theTitle, theQuestion, QMessageBox.Yes | QMessageBox.No)
|
msgRes = msgBox.question(self, title, question, QMessageBox.Yes | QMessageBox.No)
|
||||||
return msgRes == QMessageBox.Yes
|
return msgRes == QMessageBox.Yes
|
||||||
|
|
||||||
def reportConfErr(self):
|
def reportConfErr(self):
|
||||||
|
|||||||
+14
-14
@@ -872,8 +872,8 @@ class GuiBuildNovel(QDialog):
|
|||||||
try:
|
try:
|
||||||
makeOdt.saveOpenDocText(savePath)
|
makeOdt.saveOpenDocText(savePath)
|
||||||
wSuccess = True
|
wSuccess = True
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
errMsg = str(e)
|
errMsg = str(exc)
|
||||||
|
|
||||||
elif theFmt == self.FMT_FODT:
|
elif theFmt == self.FMT_FODT:
|
||||||
makeOdt = ToOdt(self.theProject, isFlat=True)
|
makeOdt = ToOdt(self.theProject, isFlat=True)
|
||||||
@@ -881,8 +881,8 @@ class GuiBuildNovel(QDialog):
|
|||||||
try:
|
try:
|
||||||
makeOdt.saveFlatXML(savePath)
|
makeOdt.saveFlatXML(savePath)
|
||||||
wSuccess = True
|
wSuccess = True
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
errMsg = str(e)
|
errMsg = str(exc)
|
||||||
|
|
||||||
elif theFmt == self.FMT_HTM:
|
elif theFmt == self.FMT_HTM:
|
||||||
makeHtml = ToHtml(self.theProject)
|
makeHtml = ToHtml(self.theProject)
|
||||||
@@ -893,8 +893,8 @@ class GuiBuildNovel(QDialog):
|
|||||||
try:
|
try:
|
||||||
makeHtml.saveHTML5(savePath)
|
makeHtml.saveHTML5(savePath)
|
||||||
wSuccess = True
|
wSuccess = True
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
errMsg = str(e)
|
errMsg = str(exc)
|
||||||
|
|
||||||
elif theFmt == self.FMT_NWD:
|
elif theFmt == self.FMT_NWD:
|
||||||
makeNwd = ToMarkdown(self.theProject)
|
makeNwd = ToMarkdown(self.theProject)
|
||||||
@@ -906,8 +906,8 @@ class GuiBuildNovel(QDialog):
|
|||||||
try:
|
try:
|
||||||
makeNwd.saveRawMarkdown(savePath)
|
makeNwd.saveRawMarkdown(savePath)
|
||||||
wSuccess = True
|
wSuccess = True
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
errMsg = str(e)
|
errMsg = str(exc)
|
||||||
|
|
||||||
elif theFmt in (self.FMT_MD, self.FMT_GH):
|
elif theFmt in (self.FMT_MD, self.FMT_GH):
|
||||||
makeMd = ToMarkdown(self.theProject)
|
makeMd = ToMarkdown(self.theProject)
|
||||||
@@ -923,8 +923,8 @@ class GuiBuildNovel(QDialog):
|
|||||||
try:
|
try:
|
||||||
makeMd.saveMarkdown(savePath)
|
makeMd.saveMarkdown(savePath)
|
||||||
wSuccess = True
|
wSuccess = True
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
errMsg = str(e)
|
errMsg = str(exc)
|
||||||
|
|
||||||
elif theFmt == self.FMT_JSON_H or theFmt == self.FMT_JSON_M:
|
elif theFmt == self.FMT_JSON_H or theFmt == self.FMT_JSON_M:
|
||||||
jsonData = {
|
jsonData = {
|
||||||
@@ -968,8 +968,8 @@ class GuiBuildNovel(QDialog):
|
|||||||
with open(savePath, mode="w", encoding="utf-8") as outFile:
|
with open(savePath, mode="w", encoding="utf-8") as outFile:
|
||||||
outFile.write(json.dumps(jsonData, indent=2))
|
outFile.write(json.dumps(jsonData, indent=2))
|
||||||
wSuccess = True
|
wSuccess = True
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
errMsg = str(e)
|
errMsg = str(exc)
|
||||||
|
|
||||||
elif theFmt == self.FMT_PDF:
|
elif theFmt == self.FMT_PDF:
|
||||||
try:
|
try:
|
||||||
@@ -983,8 +983,8 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.docView.document().print(thePrinter)
|
self.docView.document().print(thePrinter)
|
||||||
wSuccess = True
|
wSuccess = True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
errMsg - str(e)
|
errMsg = str(exc)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# If the if statements above and here match, it should not
|
# If the if statements above and here match, it should not
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ from PyQt5.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter.enum import nwAlert
|
from novelwriter.enum import nwAlert
|
||||||
from novelwriter.common import formatTime, checkInt
|
from novelwriter.common import formatTime, checkInt, checkIntRange, checkIntTuple
|
||||||
from novelwriter.constants import nwConst, nwFiles
|
from novelwriter.constants import nwConst, nwFiles
|
||||||
from novelwriter.gui.custom import QSwitch
|
from novelwriter.gui.custom import QSwitch
|
||||||
|
|
||||||
@@ -114,13 +114,10 @@ class GuiWritingStats(QDialog):
|
|||||||
hHeader.setTextAlignment(self.C_IDLE, Qt.AlignRight)
|
hHeader.setTextAlignment(self.C_IDLE, Qt.AlignRight)
|
||||||
hHeader.setTextAlignment(self.C_COUNT, Qt.AlignRight)
|
hHeader.setTextAlignment(self.C_COUNT, Qt.AlignRight)
|
||||||
|
|
||||||
sortValid = (Qt.AscendingOrder, Qt.DescendingOrder)
|
sortCol = checkIntRange(self.optState.getInt("GuiWritingStats", "sortCol", 0), 0, 2, 0)
|
||||||
sortCol = self.optState.validIntRange(
|
sortOrder = checkIntTuple(
|
||||||
self.optState.getInt("GuiWritingStats", "sortCol", 0), 0, 2, 0
|
|
||||||
)
|
|
||||||
sortOrder = self.optState.validIntTuple(
|
|
||||||
self.optState.getInt("GuiWritingStats", "sortOrder", Qt.DescendingOrder),
|
self.optState.getInt("GuiWritingStats", "sortOrder", Qt.DescendingOrder),
|
||||||
sortValid, Qt.DescendingOrder
|
(Qt.AscendingOrder, Qt.DescendingOrder), Qt.DescendingOrder
|
||||||
)
|
)
|
||||||
self.listBox.sortByColumn(sortCol, sortOrder)
|
self.listBox.sortByColumn(sortCol, sortOrder)
|
||||||
self.listBox.setSortingEnabled(True)
|
self.listBox.setSortingEnabled(True)
|
||||||
@@ -406,8 +403,8 @@ class GuiWritingStats(QDialog):
|
|||||||
outFile.write(f'"{sD}",{tT:.0f},{wD},{wA},{wB},{tI}\n')
|
outFile.write(f'"{sD}",{tT:.0f},{wD},{wA},{wB},{tI}\n')
|
||||||
wSuccess = True
|
wSuccess = True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
errMsg = str(e)
|
errMsg = str(exc)
|
||||||
wSuccess = False
|
wSuccess = False
|
||||||
|
|
||||||
# Report to user
|
# Report to user
|
||||||
@@ -482,9 +479,9 @@ class GuiWritingStats(QDialog):
|
|||||||
|
|
||||||
self.logData.append((dStart, sDiff, wcNovel, wcNotes, sIdle))
|
self.logData.append((dStart, sDiff, wcNovel, wcNotes, sIdle))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.theParent.makeAlert([
|
self.theParent.makeAlert([
|
||||||
self.tr("Failed to read session log file."), str(e)
|
self.tr("Failed to read session log file."), str(exc)
|
||||||
], nwAlert.ERROR)
|
], nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,9 @@ def extractVersion():
|
|||||||
hexVers = getValue((aLine))
|
hexVers = getValue((aLine))
|
||||||
if aLine.startswith("__date__"):
|
if aLine.startswith("__date__"):
|
||||||
relDate = getValue((aLine))
|
relDate = getValue((aLine))
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
print("Could not read file: %s" % initFile)
|
print("Could not read file: %s" % initFile)
|
||||||
print(str(e))
|
print(str(exc))
|
||||||
|
|
||||||
print("novelWriter version: %s (%s) at %s" % (numVers, hexVers, relDate))
|
print("novelWriter version: %s (%s) at %s" % (numVers, hexVers, relDate))
|
||||||
|
|
||||||
@@ -127,9 +127,9 @@ def makeCheckSum(sumFile, cwd=None):
|
|||||||
with open(shaFile, mode="w") as fOut:
|
with open(shaFile, mode="w") as fOut:
|
||||||
subprocess.call(["sha256sum", sumFile], stdout=fOut, cwd=cwd)
|
subprocess.call(["sha256sum", sumFile], stdout=fOut, cwd=cwd)
|
||||||
print("SHA256 Sum: %s" % shaFile)
|
print("SHA256 Sum: %s" % shaFile)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
print("Could not generate sha256 file")
|
print("Could not generate sha256 file")
|
||||||
print(str(e))
|
print(str(exc))
|
||||||
|
|
||||||
return shaFile
|
return shaFile
|
||||||
|
|
||||||
@@ -163,9 +163,9 @@ def installPackages(hostOS):
|
|||||||
pkgCmd = stepCmd.split(" ")
|
pkgCmd = stepCmd.split(" ")
|
||||||
try:
|
try:
|
||||||
subprocess.call(pyCmd + pipCmd + pkgCmd)
|
subprocess.call(pyCmd + pipCmd + pkgCmd)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
print("Failed with error:")
|
print("Failed with error:")
|
||||||
print(str(e))
|
print(str(exc))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -243,10 +243,10 @@ def buildPdfManual():
|
|||||||
print("PDF manual build: OK")
|
print("PDF manual build: OK")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
print("PDF manual build: FAILED")
|
print("PDF manual build: FAILED")
|
||||||
print("")
|
print("")
|
||||||
print(str(e))
|
print(str(exc))
|
||||||
print("")
|
print("")
|
||||||
print("Dependencies:")
|
print("Dependencies:")
|
||||||
print(" * pip install sphinx")
|
print(" * pip install sphinx")
|
||||||
@@ -286,10 +286,10 @@ def buildQtI18n():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.call(["lrelease", "-verbose", *tsList])
|
subprocess.call(["lrelease", "-verbose", *tsList])
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
print("Qt5 Linguist tools seem to be missing")
|
print("Qt5 Linguist tools seem to be missing")
|
||||||
print("On Debian/Ubuntu, install: qttools5-dev-tools pyqt5-dev-tools")
|
print("On Debian/Ubuntu, install: qttools5-dev-tools pyqt5-dev-tools")
|
||||||
print(str(e))
|
print(str(exc))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
@@ -387,10 +387,10 @@ def buildQtI18nTS(sysArgs):
|
|||||||
|
|
||||||
# try:
|
# try:
|
||||||
# subprocess.call(["pylupdate5", "-verbose", "-noobsolete", *srcList, "-ts", *tsList])
|
# subprocess.call(["pylupdate5", "-verbose", "-noobsolete", *srcList, "-ts", *tsList])
|
||||||
# except Exception as e:
|
# except Exception as exc:
|
||||||
# print("PyQt5 Linguist tools seem to be missing")
|
# print("PyQt5 Linguist tools seem to be missing")
|
||||||
# print("On Debian/Ubuntu, install: qttools5-dev-tools pyqt5-dev-tools")
|
# print("On Debian/Ubuntu, install: qttools5-dev-tools pyqt5-dev-tools")
|
||||||
# print(str(e))
|
# print(str(exc))
|
||||||
# sys.exit(1)
|
# sys.exit(1)
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
@@ -922,9 +922,9 @@ def makeSimplePackage(embedPython):
|
|||||||
sysCmd += [libDir]
|
sysCmd += [libDir]
|
||||||
try:
|
try:
|
||||||
subprocess.call(sysCmd)
|
subprocess.call(sysCmd)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
print("Failed with error:")
|
print("Failed with error:")
|
||||||
print(str(e))
|
print(str(exc))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
for subDir in os.listdir(libDir):
|
for subDir in os.listdir(libDir):
|
||||||
@@ -1432,9 +1432,9 @@ def innoSetup():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.call(["iscc", "setup.iss"])
|
subprocess.call(["iscc", "setup.iss"])
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
print("Inno Setup failed with error:")
|
print("Inno Setup failed with error:")
|
||||||
print(str(e))
|
print(str(exc))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
+7
-7
@@ -43,15 +43,15 @@ class MockGuiMain():
|
|||||||
def releaseNotes(self):
|
def releaseNotes(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
def makeAlert(self, theMessage, theLevel):
|
def makeAlert(self, message, level=0, exception=None):
|
||||||
assert isinstance(theMessage, str) or isinstance(theMessage, list)
|
assert isinstance(message, str) or isinstance(message, list)
|
||||||
print("%s: %s" % (str(theLevel), theMessage))
|
print("%s: %s" % (str(level), message))
|
||||||
self.lastAlert = str(theMessage)
|
self.lastAlert = str(message)
|
||||||
return
|
return
|
||||||
|
|
||||||
def askQuestion(self, theTitle, theQustion):
|
def askQuestion(self, title, qustion):
|
||||||
print("Question: %s" % theQustion)
|
print("Question: %s" % qustion)
|
||||||
self.lastQuestion = (theTitle, theQustion)
|
self.lastQuestion = (title, qustion)
|
||||||
return self.askResponse
|
return self.askResponse
|
||||||
|
|
||||||
def setStatus(self, theMessage):
|
def setStatus(self, theMessage):
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ from tools import writeFile
|
|||||||
from novelwriter.guimain import GuiMain
|
from novelwriter.guimain import GuiMain
|
||||||
from novelwriter.common import (
|
from novelwriter.common import (
|
||||||
checkString, checkInt, checkFloat, checkBool, checkHandle, isHandle,
|
checkString, checkInt, checkFloat, checkBool, checkHandle, isHandle,
|
||||||
isTitleTag, isItemClass, isItemType, isItemLayout, hexToInt, formatInt,
|
isTitleTag, isItemClass, isItemType, isItemLayout, hexToInt, checkIntRange,
|
||||||
formatTimeStamp, formatTime, parseTimeStamp, splitVersionNumber,
|
checkIntTuple, formatInt, formatTimeStamp, formatTime, parseTimeStamp,
|
||||||
transferCase, fuzzyTime, numberToRoman, jsonEncode, readTextFile,
|
splitVersionNumber, transferCase, fuzzyTime, numberToRoman, jsonEncode,
|
||||||
makeFileNameSafe, sha256sum, getGuiItem, NWConfigParser
|
readTextFile, makeFileNameSafe, sha256sum, getGuiItem, NWConfigParser
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -216,6 +216,28 @@ def testBaseCommon_HexToInt():
|
|||||||
# END Test testBaseCommon_HexToInt
|
# END Test testBaseCommon_HexToInt
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.base
|
||||||
|
def testBaseCommon_CheckIntRange():
|
||||||
|
"""Test the checkIntRange function.
|
||||||
|
"""
|
||||||
|
assert checkIntRange(5, 0, 9, 3) == 5
|
||||||
|
assert checkIntRange(5, 0, 4, 3) == 3
|
||||||
|
assert checkIntRange(5, 0, 5, 3) == 5
|
||||||
|
assert checkIntRange(0, 0, 5, 3) == 0
|
||||||
|
|
||||||
|
# END Test testBaseCommon_CheckIntRange
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.base
|
||||||
|
def testBaseCommon_CheckIntTuple():
|
||||||
|
"""Test the checkIntTuple function.
|
||||||
|
"""
|
||||||
|
assert checkIntTuple(0, (0, 1, 2), 3) == 0
|
||||||
|
assert checkIntTuple(5, (0, 1, 2), 3) == 3
|
||||||
|
|
||||||
|
# END Test testBaseCommon_CheckIntTuple
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.base
|
@pytest.mark.base
|
||||||
def testBaseCommon_FormatTimeStamp():
|
def testBaseCommon_FormatTimeStamp():
|
||||||
"""Test the formatTimeStamp function.
|
"""Test the formatTimeStamp function.
|
||||||
|
|||||||
@@ -140,13 +140,4 @@ def testCoreOptions_SetGet(mockGUI):
|
|||||||
assert theOpts.getBool("GuiBuildNovel", "addNovel", None) is True
|
assert theOpts.getBool("GuiBuildNovel", "addNovel", None) is True
|
||||||
assert theOpts.getBool("GuiBuildNovel", "mockItem", None) is None
|
assert theOpts.getBool("GuiBuildNovel", "mockItem", None) is None
|
||||||
|
|
||||||
# Check integer validators
|
|
||||||
assert theOpts.validIntRange(5, 0, 9, 3) == 5
|
|
||||||
assert theOpts.validIntRange(5, 0, 4, 3) == 3
|
|
||||||
assert theOpts.validIntRange(5, 0, 5, 3) == 5
|
|
||||||
assert theOpts.validIntRange(0, 0, 5, 3) == 0
|
|
||||||
|
|
||||||
assert theOpts.validIntTuple(0, (0, 1, 2), 3) == 0
|
|
||||||
assert theOpts.validIntTuple(5, (0, 1, 2), 3) == 3
|
|
||||||
|
|
||||||
# END Test testCoreOptions_SetGet
|
# END Test testCoreOptions_SetGet
|
||||||
|
|||||||
@@ -40,17 +40,15 @@ stepDelay = 20
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("darwin"), reason="Not running on Darwin")
|
||||||
def testToolProjectWizard_Main(qtbot, monkeypatch, nwGUI, nwMinimal):
|
def testToolProjectWizard_Main(qtbot, monkeypatch, nwGUI, nwMinimal):
|
||||||
"""Test the new project wizard.
|
"""Test the new project wizard.
|
||||||
|
Disabled for macOS because the test segfaults on QWizard.show()
|
||||||
"""
|
"""
|
||||||
# Block message box
|
# Block message box
|
||||||
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
|
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
|
||||||
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
|
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
|
||||||
|
|
||||||
if sys.platform.startswith("darwin"):
|
|
||||||
# Disable for macOS because the test segfaults on QWizard.show()
|
|
||||||
return
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Test New Project Function
|
# Test New Project Function
|
||||||
##
|
##
|
||||||
|
|||||||
+4
-4
@@ -33,14 +33,14 @@ def cmpFiles(fileOne, fileTwo, ignoreLines=None, ignoreStart=None):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
foOne = open(fileOne, mode="r", encoding="utf-8")
|
foOne = open(fileOne, mode="r", encoding="utf-8")
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
print(str(e))
|
print(str(exc))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
foTwo = open(fileTwo, mode="r", encoding="utf-8")
|
foTwo = open(fileTwo, mode="r", encoding="utf-8")
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
print(str(e))
|
print(str(exc))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
txtOne = foOne.readlines()
|
txtOne = foOne.readlines()
|
||||||
|
|||||||
Reference in New Issue
Block a user