Rewrap self.tr and fix a few bugs

This commit is contained in:
Veronica K. B. Olsen
2021-02-15 16:47:57 +01:00
parent dba8865d75
commit df19ced50c
28 changed files with 682 additions and 516 deletions
+3 -2
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from nw.constants.constants import ( from nw.constants.constants import (
nwConst, nwLists, nwRegEx, nwFiles, nwKeyWords, nwLabels, nwQuotes, trConst, nwConst, nwLists, nwRegEx, nwFiles, nwKeyWords, nwLabels,
nwUnicode, nwHtmlUnicode nwQuotes, nwUnicode, nwHtmlUnicode
) )
from nw.constants.enum import ( from nw.constants.enum import (
nwAlert, nwDocAction, nwItemClass, nwItemLayout, nwItemType, nwOutline, nwAlert, nwDocAction, nwItemClass, nwItemLayout, nwItemType, nwOutline,
@@ -9,6 +9,7 @@ from nw.constants.enum import (
) )
__all__ = [ __all__ = [
"trConst",
"nwConst", "nwConst",
"nwLists", "nwLists",
"nwRegEx", "nwRegEx",
+66 -60
View File
@@ -24,12 +24,18 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from PyQt5.QtCore import QT_TRANSLATE_NOOP from PyQt5.QtCore import QCoreApplication
from PyQt5.QtCore import QT_TRANSLATE_NOOP as QT_TRN
from nw.constants.enum import ( from nw.constants.enum import (
nwItemClass, nwItemLayout, nwItemType, nwOutline nwItemClass, nwItemLayout, nwItemType, nwOutline
) )
def trConst(tString):
"""Wrapper function for locally translating constants.
"""
return QCoreApplication.translate("Constant", tString)
class nwConst(): class nwConst():
# Date and Time Formats # Date and Time Formats
@@ -121,17 +127,17 @@ class nwKeyWords:
class nwLabels(): class nwLabels():
CLASS_NAME = { CLASS_NAME = {
nwItemClass.NO_CLASS : QT_TRANSLATE_NOOP("Constant", "None"), nwItemClass.NO_CLASS : QT_TRN("Constant", "None"),
nwItemClass.NOVEL : QT_TRANSLATE_NOOP("Constant", "Novel"), nwItemClass.NOVEL : QT_TRN("Constant", "Novel"),
nwItemClass.PLOT : QT_TRANSLATE_NOOP("Constant", "Plot"), nwItemClass.PLOT : QT_TRN("Constant", "Plot"),
nwItemClass.CHARACTER : QT_TRANSLATE_NOOP("Constant", "Characters"), nwItemClass.CHARACTER : QT_TRN("Constant", "Characters"),
nwItemClass.WORLD : QT_TRANSLATE_NOOP("Constant", "Locations"), nwItemClass.WORLD : QT_TRN("Constant", "Locations"),
nwItemClass.TIMELINE : QT_TRANSLATE_NOOP("Constant", "Timeline"), nwItemClass.TIMELINE : QT_TRN("Constant", "Timeline"),
nwItemClass.OBJECT : QT_TRANSLATE_NOOP("Constant", "Objects"), nwItemClass.OBJECT : QT_TRN("Constant", "Objects"),
nwItemClass.ENTITY : QT_TRANSLATE_NOOP("Constant", "Entity"), nwItemClass.ENTITY : QT_TRN("Constant", "Entity"),
nwItemClass.CUSTOM : QT_TRANSLATE_NOOP("Constant", "Custom"), nwItemClass.CUSTOM : QT_TRN("Constant", "Custom"),
nwItemClass.ARCHIVE : QT_TRANSLATE_NOOP("Constant", "Outtakes"), nwItemClass.ARCHIVE : QT_TRN("Constant", "Outtakes"),
nwItemClass.TRASH : QT_TRANSLATE_NOOP("Constant", "Trash"), nwItemClass.TRASH : QT_TRN("Constant", "Trash"),
} }
CLASS_FLAG = { CLASS_FLAG = {
nwItemClass.NO_CLASS : "0", nwItemClass.NO_CLASS : "0",
@@ -160,15 +166,15 @@ class nwLabels():
nwItemClass.TRASH : "cls_trash", nwItemClass.TRASH : "cls_trash",
} }
LAYOUT_NAME = { LAYOUT_NAME = {
nwItemLayout.NO_LAYOUT : QT_TRANSLATE_NOOP("Constant", "None"), nwItemLayout.NO_LAYOUT : QT_TRN("Constant", "None"),
nwItemLayout.TITLE : QT_TRANSLATE_NOOP("Constant", "Title Page"), nwItemLayout.TITLE : QT_TRN("Constant", "Title Page"),
nwItemLayout.BOOK : QT_TRANSLATE_NOOP("Constant", "Book"), nwItemLayout.BOOK : QT_TRN("Constant", "Book"),
nwItemLayout.PAGE : QT_TRANSLATE_NOOP("Constant", "Plain Page"), nwItemLayout.PAGE : QT_TRN("Constant", "Plain Page"),
nwItemLayout.PARTITION : QT_TRANSLATE_NOOP("Constant", "Partition"), nwItemLayout.PARTITION : QT_TRN("Constant", "Partition"),
nwItemLayout.UNNUMBERED : QT_TRANSLATE_NOOP("Constant", "Unnumbered"), nwItemLayout.UNNUMBERED : QT_TRN("Constant", "Unnumbered"),
nwItemLayout.CHAPTER : QT_TRANSLATE_NOOP("Constant", "Chapter"), nwItemLayout.CHAPTER : QT_TRN("Constant", "Chapter"),
nwItemLayout.SCENE : QT_TRANSLATE_NOOP("Constant", "Scene"), nwItemLayout.SCENE : QT_TRN("Constant", "Scene"),
nwItemLayout.NOTE : QT_TRANSLATE_NOOP("Constant", "Note"), nwItemLayout.NOTE : QT_TRN("Constant", "Note"),
} }
LAYOUT_FLAG = { LAYOUT_FLAG = {
nwItemLayout.NO_LAYOUT : "Xo", nwItemLayout.NO_LAYOUT : "Xo",
@@ -182,27 +188,27 @@ class nwLabels():
nwItemLayout.NOTE : "Nt", nwItemLayout.NOTE : "Nt",
} }
KEY_NAME = { KEY_NAME = {
nwKeyWords.TAG_KEY : QT_TRANSLATE_NOOP("Constant", "Tag"), nwKeyWords.TAG_KEY : QT_TRN("Constant", "Tag"),
nwKeyWords.POV_KEY : QT_TRANSLATE_NOOP("Constant", "Point of View"), nwKeyWords.POV_KEY : QT_TRN("Constant", "Point of View"),
nwKeyWords.FOCUS_KEY : QT_TRANSLATE_NOOP("Constant", "Focus"), nwKeyWords.FOCUS_KEY : QT_TRN("Constant", "Focus"),
nwKeyWords.CHAR_KEY : QT_TRANSLATE_NOOP("Constant", "Characters"), nwKeyWords.CHAR_KEY : QT_TRN("Constant", "Characters"),
nwKeyWords.PLOT_KEY : QT_TRANSLATE_NOOP("Constant", "Plot"), nwKeyWords.PLOT_KEY : QT_TRN("Constant", "Plot"),
nwKeyWords.TIME_KEY : QT_TRANSLATE_NOOP("Constant", "Timeline"), nwKeyWords.TIME_KEY : QT_TRN("Constant", "Timeline"),
nwKeyWords.WORLD_KEY : QT_TRANSLATE_NOOP("Constant", "Locations"), nwKeyWords.WORLD_KEY : QT_TRN("Constant", "Locations"),
nwKeyWords.OBJECT_KEY : QT_TRANSLATE_NOOP("Constant", "Objects"), nwKeyWords.OBJECT_KEY : QT_TRN("Constant", "Objects"),
nwKeyWords.ENTITY_KEY : QT_TRANSLATE_NOOP("Constant", "Entities"), nwKeyWords.ENTITY_KEY : QT_TRN("Constant", "Entities"),
nwKeyWords.CUSTOM_KEY : QT_TRANSLATE_NOOP("Constant", "Custom"), nwKeyWords.CUSTOM_KEY : QT_TRN("Constant", "Custom"),
} }
OUTLINE_COLS = { OUTLINE_COLS = {
nwOutline.TITLE : QT_TRANSLATE_NOOP("Constant", "Title"), nwOutline.TITLE : QT_TRN("Constant", "Title"),
nwOutline.LEVEL : QT_TRANSLATE_NOOP("Constant", "Level"), nwOutline.LEVEL : QT_TRN("Constant", "Level"),
nwOutline.LABEL : QT_TRANSLATE_NOOP("Constant", "Document"), nwOutline.LABEL : QT_TRN("Constant", "Document"),
nwOutline.LINE : QT_TRANSLATE_NOOP("Constant", "Line"), nwOutline.LINE : QT_TRN("Constant", "Line"),
nwOutline.CCOUNT : QT_TRANSLATE_NOOP("Constant", "Chars"), nwOutline.CCOUNT : QT_TRN("Constant", "Chars"),
nwOutline.WCOUNT : QT_TRANSLATE_NOOP("Constant", "Words"), nwOutline.WCOUNT : QT_TRN("Constant", "Words"),
nwOutline.PCOUNT : QT_TRANSLATE_NOOP("Constant", "Pars"), nwOutline.PCOUNT : QT_TRN("Constant", "Pars"),
nwOutline.POV : QT_TRANSLATE_NOOP("Constant", "POV"), nwOutline.POV : QT_TRN("Constant", "POV"),
nwOutline.FOCUS : QT_TRANSLATE_NOOP("Constant", "Focus"), nwOutline.FOCUS : QT_TRN("Constant", "Focus"),
nwOutline.CHAR : KEY_NAME[nwKeyWords.CHAR_KEY], nwOutline.CHAR : KEY_NAME[nwKeyWords.CHAR_KEY],
nwOutline.PLOT : KEY_NAME[nwKeyWords.PLOT_KEY], nwOutline.PLOT : KEY_NAME[nwKeyWords.PLOT_KEY],
nwOutline.TIME : KEY_NAME[nwKeyWords.TIME_KEY], nwOutline.TIME : KEY_NAME[nwKeyWords.TIME_KEY],
@@ -210,7 +216,7 @@ class nwLabels():
nwOutline.OBJECT : KEY_NAME[nwKeyWords.OBJECT_KEY], nwOutline.OBJECT : KEY_NAME[nwKeyWords.OBJECT_KEY],
nwOutline.ENTITY : KEY_NAME[nwKeyWords.ENTITY_KEY], nwOutline.ENTITY : KEY_NAME[nwKeyWords.ENTITY_KEY],
nwOutline.CUSTOM : KEY_NAME[nwKeyWords.CUSTOM_KEY], nwOutline.CUSTOM : KEY_NAME[nwKeyWords.CUSTOM_KEY],
nwOutline.SYNOP : QT_TRANSLATE_NOOP("Constant", "Synopsis"), nwOutline.SYNOP : QT_TRN("Constant", "Synopsis"),
} }
# END Class nwLabels # END Class nwLabels
@@ -220,28 +226,28 @@ class nwQuotes():
Source: https://en.wikipedia.org/wiki/Quotation_mark Source: https://en.wikipedia.org/wiki/Quotation_mark
""" """
SYMBOLS = { SYMBOLS = {
"\u0027" : QT_TRANSLATE_NOOP("Constant", "Straight single quotation mark"), "\u0027" : QT_TRN("Constant", "Straight single quotation mark"),
"\u0022" : QT_TRANSLATE_NOOP("Constant", "Straight double quotation mark"), "\u0022" : QT_TRN("Constant", "Straight double quotation mark"),
"\u2018" : QT_TRANSLATE_NOOP("Constant", "Left single quotation mark"), "\u2018" : QT_TRN("Constant", "Left single quotation mark"),
"\u2019" : QT_TRANSLATE_NOOP("Constant", "Right single quotation mark"), "\u2019" : QT_TRN("Constant", "Right single quotation mark"),
"\u201a" : QT_TRANSLATE_NOOP("Constant", "Single low-9 quotation mark"), "\u201a" : QT_TRN("Constant", "Single low-9 quotation mark"),
"\u201b" : QT_TRANSLATE_NOOP("Constant", "Single high-reversed-9 quotation mark"), "\u201b" : QT_TRN("Constant", "Single high-reversed-9 quotation mark"),
"\u201c" : QT_TRANSLATE_NOOP("Constant", "Left double quotation mark"), "\u201c" : QT_TRN("Constant", "Left double quotation mark"),
"\u201d" : QT_TRANSLATE_NOOP("Constant", "Right double quotation mark"), "\u201d" : QT_TRN("Constant", "Right double quotation mark"),
"\u201e" : QT_TRANSLATE_NOOP("Constant", "Double low-9 quotation mark"), "\u201e" : QT_TRN("Constant", "Double low-9 quotation mark"),
"\u201f" : QT_TRANSLATE_NOOP("Constant", "Double high-reversed-9 quotation mark"), "\u201f" : QT_TRN("Constant", "Double high-reversed-9 quotation mark"),
"\u2e42" : QT_TRANSLATE_NOOP("Constant", "Double low-reversed-9 quotation mark"), "\u2e42" : QT_TRN("Constant", "Double low-reversed-9 quotation mark"),
"\u2039" : QT_TRANSLATE_NOOP("Constant", "Single left-pointing angle quotation mark"), "\u2039" : QT_TRN("Constant", "Single left-pointing angle quotation mark"),
"\u203a" : QT_TRANSLATE_NOOP("Constant", "Single right-pointing angle quotation mark"), "\u203a" : QT_TRN("Constant", "Single right-pointing angle quotation mark"),
"\u00ab" : QT_TRANSLATE_NOOP("Constant", "Left-pointing double angle quotation mark"), "\u00ab" : QT_TRN("Constant", "Left-pointing double angle quotation mark"),
"\u00bb" : QT_TRANSLATE_NOOP("Constant", "Right-pointing double angle quotation mark"), "\u00bb" : QT_TRN("Constant", "Right-pointing double angle quotation mark"),
"\u300c" : QT_TRANSLATE_NOOP("Constant", "Left corner bracket"), "\u300c" : QT_TRN("Constant", "Left corner bracket"),
"\u300d" : QT_TRANSLATE_NOOP("Constant", "Right corner bracket"), "\u300d" : QT_TRN("Constant", "Right corner bracket"),
"\u300e" : QT_TRANSLATE_NOOP("Constant", "Left white corner bracket"), "\u300e" : QT_TRN("Constant", "Left white corner bracket"),
"\u300f" : QT_TRANSLATE_NOOP("Constant", "Right white corner bracket"), "\u300f" : QT_TRN("Constant", "Right white corner bracket"),
} }
# END Class nwQuotes # END Class nwQuotes
+12 -6
View File
@@ -24,10 +24,11 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from functools import partial
import logging import logging
import os import os
from functools import partial
from PyQt5.QtCore import QCoreApplication from PyQt5.QtCore import QCoreApplication
from nw.constants import nwAlert from nw.constants import nwAlert
@@ -51,7 +52,7 @@ class NWDoc():
# Internal Mapping # Internal Mapping
self.makeAlert = self.theParent.makeAlert self.makeAlert = self.theParent.makeAlert
self.tr = partial(QCoreApplication.translate, self.__class__.__name__) self.tr = partial(QCoreApplication.translate, "NWDoc")
return return
@@ -131,7 +132,9 @@ class NWDoc():
self.theParent.setStatus( self.theParent.setStatus(
self.tr("{0}: {1}").format( self.tr("{0}: {1}").format(
self.tr("Opened Document"), self.tr("Opened Document"),
self._theItem.itemName)) self._theItem.itemName
)
)
return theText return theText
@@ -178,7 +181,9 @@ class NWDoc():
self.theParent.setStatus( self.theParent.setStatus(
self.tr("{0}: {1}").format( self.tr("{0}: {1}").format(
self.tr("Saved Document"), self.tr("Saved Document"),
self._theItem.itemName)) self._theItem.itemName
)
)
return True return True
@@ -201,8 +206,9 @@ class NWDoc():
os.unlink(chkFile) os.unlink(chkFile)
logger.debug("Deleted: %s" % chkFile) logger.debug("Deleted: %s" % chkFile)
except Exception as e: except Exception as e:
self.makeAlert([self.tr("Could not delete document file."), str(e)], self.makeAlert(
nwAlert.ERROR) [self.tr("Could not delete document file."), str(e)], nwAlert.ERROR
)
return False return False
return True return True
+4 -3
View File
@@ -24,13 +24,13 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from functools import partial
import nw import nw
import logging import logging
import json import json
import os import os
from time import time from time import time
from functools import partial
from PyQt5.QtCore import QCoreApplication from PyQt5.QtCore import QCoreApplication
@@ -68,10 +68,11 @@ class NWIndex():
self._timeNotes = 0 self._timeNotes = 0
self._timeIndex = 0 self._timeIndex = 0
self.tr = partial(QCoreApplication.translate, self.__class__.__name__)
self.clearIndex() self.clearIndex()
# Internal Mappings
self.tr = partial(QCoreApplication.translate, "NWIndex")
return return
## ##
+130 -96
View File
@@ -24,9 +24,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from functools import partial
from PyQt5.QtCore import QCoreApplication
import nw import nw
import logging import logging
import os import os
@@ -34,6 +31,9 @@ import shutil
from lxml import etree from lxml import etree
from time import time from time import time
from functools import partial
from PyQt5.QtCore import QCoreApplication
from nw.core.tree import NWTree from nw.core.tree import NWTree
from nw.core.item import NWItem from nw.core.item import NWItem
@@ -45,7 +45,7 @@ from nw.common import (
makeFileNameSafe, hexToInt makeFileNameSafe, hexToInt
) )
from nw.constants import ( from nw.constants import (
nwFiles, nwItemType, nwItemClass, nwItemLayout, nwLabels, nwAlert trConst, nwFiles, nwItemType, nwItemClass, nwItemLayout, nwLabels, nwAlert
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -102,7 +102,7 @@ class NWProject():
# Internal Mapping # Internal Mapping
self.makeAlert = self.theParent.makeAlert self.makeAlert = self.theParent.makeAlert
self.tr = partial(QCoreApplication.translate, self.__class__.__name__) self.tr = partial(QCoreApplication.translate, "NWProject")
# Set Defaults # Set Defaults
self.clearProject() self.clearProject()
@@ -302,8 +302,8 @@ class NWProject():
nHandle = self.newRoot(self.tr("Novel"), nwItemClass.NOVEL) nHandle = self.newRoot(self.tr("Novel"), nwItemClass.NOVEL)
for newRoot in projData.get("addRoots", []): for newRoot in projData.get("addRoots", []):
if newRoot in nwItemClass: if newRoot in nwItemClass:
self.newRoot(QCoreApplication.translate( self.newRoot(trConst(nwLabels.CLASS_NAME[newRoot]), newRoot
"Constant", nwLabels.CLASS_NAME[newRoot]), newRoot) )
# Create a title page # Create a title page
tHandle = self.newFile(self.tr("Title Page"), nwItemClass.NOVEL, nHandle) tHandle = self.newFile(self.tr("Title Page"), nwItemClass.NOVEL, nHandle)
@@ -424,13 +424,15 @@ class NWProject():
# Trying to open backup file instead # Trying to open backup file instead
backFile = fileName[:-3]+"bak" backFile = fileName[:-3]+"bak"
if os.path.isfile(backFile): if os.path.isfile(backFile):
self.makeAlert(self.tr("Attempting to open backup project file instead."), self.makeAlert(
nwAlert.INFO) self.tr("Attempting to open backup project file instead."), nwAlert.INFO
)
try: try:
nwXML = etree.parse(backFile) nwXML = etree.parse(backFile)
except Exception as e: except Exception as e:
self.makeAlert([self.tr("Failed to parse project xml."), str(e)], self.makeAlert(
nwAlert.ERROR) [self.tr("Failed to parse project xml."), str(e)], nwAlert.ERROR
)
self.clearProject() self.clearProject()
return False return False
else: else:
@@ -477,23 +479,31 @@ class NWProject():
# read the file. Introduced in version 0.10. # read the file. Introduced in version 0.10.
if fileVersion == "1.0": if fileVersion == "1.0":
msgYes = self.theParent.askQuestion(self.tr("Old Project Version"), ( msgYes = self.theParent.askQuestion(
self.tr("Old Project Version"),
"%s<br><br>%s" % ( "%s<br><br>%s" % (
self.tr("The project file and data is created by a novelWriter version " self.tr(
"lower than 0.7. Do you want to upgrade the project to the " "The project file and data is created by a novelWriter version "
"most recent format?"), "lower than 0.7. Do you want to upgrade the project to the "
self.tr("Note that after the upgrade, you " "most recent format?"
"cannot open the project with an older version of novelWriter " ),
"any more, so make sure you have a recent backup.")))) self.tr(
"Note that after the upgrade, you cannot open the project with "
"an older version of novelWriter any more, so make sure you "
"have a recent backup.")
)
)
if not msgYes: if not msgYes:
self.clearProject() self.clearProject()
return False return False
elif fileVersion != "1.1" and fileVersion != "1.2": elif fileVersion != "1.1" and fileVersion != "1.2":
self.makeAlert(( self.makeAlert((
self.tr("Unknown or unsupported novelWriter project file format. " self.tr(
"The project cannot be opened by this version of novelWriter. " "Unknown or unsupported novelWriter project file format. "
"The file was saved with novelWriter version {0}.").format(appVersion) "The project cannot be opened by this version of novelWriter. "
"The file was saved with novelWriter version {0}."
).format(appVersion)
), nwAlert.ERROR) ), nwAlert.ERROR)
self.clearProject() self.clearProject()
return False return False
@@ -502,15 +512,18 @@ class NWProject():
# ========================= # =========================
if hexToInt(hexVersion) > hexToInt(nw.__hexversion__): if hexToInt(hexVersion) > hexToInt(nw.__hexversion__):
msgYes = self.theParent.askQuestion(self.tr("Version Conflict"), ( msgYes = self.theParent.askQuestion(
self.tr("This project was saved by a newer version of novelWriter, version " self.tr("Version Conflict"),
"{new_version}. This is version {version}. If you continue to open the " self.tr(
"project, some attributes and settings may not be preserved, but the " "This project was saved by a newer version of novelWriter, version "
"overall project should be fine. Continue opening the project?") "{new_version}. This is version {version}. If you continue to open the "
).format( "project, some attributes and settings may not be preserved, but the "
new_version = appVersion, "overall project should be fine. Continue opening the project?"
version = nw.__version__ ).format(
)) new_version = appVersion,
version = nw.__version__
)
)
if not msgYes: if not msgYes:
self.clearProject() self.clearProject()
return False return False
@@ -610,8 +623,8 @@ class NWProject():
self.mainConf.saveRecentCache() self.mainConf.saveRecentCache()
self.theParent.setStatus(self.tr("{0}: {1}").format( self.theParent.setStatus(self.tr("{0}: {1}").format(
self.tr("Opened Project"), self.tr("Opened Project"), self.projName)
self.projName)) )
self._scanProjectFolder() self._scanProjectFolder()
@@ -731,8 +744,8 @@ class NWProject():
self._writeLockFile() self._writeLockFile()
self.theParent.setStatus(self.tr("{0}: {1}").format( self.theParent.setStatus(self.tr("{0}: {1}").format(
self.tr("Saved Project"), self.tr("Saved Project"), self.projName)
self.projName)) )
self.setProjectChanged(False) self.setProjectChanged(False)
return True return True
@@ -787,24 +800,30 @@ class NWProject():
self.theParent.setStatus(self.tr("Backing up project ...")) self.theParent.setStatus(self.tr("Backing up project ..."))
if self.mainConf.backupPath is None or self.mainConf.backupPath == "": if self.mainConf.backupPath is None or self.mainConf.backupPath == "":
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("Cannot backup project because no backup path is set. " self.tr(
"Please set a valid backup location in Tools > Preferences.") "Cannot backup project because no backup path is set. "
), nwAlert.ERROR) "Please set a valid backup location in Tools > Preferences."
), 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.theParent.makeAlert(
self.tr("Cannot backup project because no project name is set. " self.tr(
"Please set a Working Title in Project > Project Settings.") "Cannot backup project because no project name is set. "
), nwAlert.ERROR) "Please set a Working Title in Project > Project Settings."
), 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.theParent.makeAlert(
self.tr("Cannot backup project because the backup path does not exist. " self.tr(
"Please set a valid backup location in Tools > Preferences.") "Cannot backup project because the backup path does not exist. "
), nwAlert.ERROR) "Please set a valid backup location in Tools > Preferences."
), nwAlert.ERROR
)
return False return False
cleanName = makeFileNameSafe(self.projName) cleanName = makeFileNameSafe(self.projName)
@@ -821,11 +840,13 @@ class NWProject():
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.theParent.makeAlert(
self.tr("Cannot backup project because the backup path is within the " self.tr(
"project folder to be backed up. Please choose a different " "Cannot backup project because the backup path is within the "
"backup path in Tools > Preferences.") "project folder to be backed up. Please choose a different "
), nwAlert.ERROR) "backup path in Tools > Preferences."
), nwAlert.ERROR
)
return False return False
archName = self.tr("Backup from {0}").format(formatTimeStamp(time(), fileSafe=True)) archName = self.tr("Backup from {0}").format(formatTimeStamp(time(), fileSafe=True))
@@ -838,9 +859,11 @@ class NWProject():
logger.info("Backup written to: %s" % archName) logger.info("Backup written to: %s" % archName)
if doNotify: if doNotify:
self.theParent.makeAlert( self.theParent.makeAlert(
self.tr("Backup archive file written to: {0}").format( self.tr(
f"{os.path.join(cleanName, archName)}.zip"), "Backup archive file written to: {0}"
nwAlert.INFO ).format(
f"{os.path.join(cleanName, archName)}.zip"
), nwAlert.INFO
) )
except Exception as e: except Exception as e:
@@ -865,9 +888,8 @@ class NWProject():
logger.error("No project path set for the example project") logger.error("No project path set for the example project")
return False return False
srcSample = os.path.abspath(os.path.join(self.mainConf.appRoot, srcSample = os.path.abspath(os.path.join(self.mainConf.appRoot, "sample"))
self.tr("sample"))) pkgSample = os.path.join(self.mainConf.assetPath, "sample.zip")
pkgSample = os.path.join(self.mainConf.assetPath, "%s.zip" % self.tr("sample"))
isSuccess = False isSuccess = False
if os.path.isfile(pkgSample): if os.path.isfile(pkgSample):
@@ -889,8 +911,8 @@ class NWProject():
dstProj = os.path.join(projPath, nwFiles.PROJ_FILE) dstProj = os.path.join(projPath, nwFiles.PROJ_FILE)
shutil.copyfile(srcProj, dstProj) shutil.copyfile(srcProj, dstProj)
srcContent = os.path.join(srcSample, self.tr("content")) srcContent = os.path.join(srcSample, "content")
dstContent = os.path.join(projPath, self.tr("content")) dstContent = os.path.join(projPath, "content")
for srcFile in os.listdir(srcContent): for srcFile in os.listdir(srcContent):
srcDoc = os.path.join(srcContent, srcFile) srcDoc = os.path.join(srcContent, srcFile)
dstDoc = os.path.join(dstContent, srcFile) dstDoc = os.path.join(dstContent, srcFile)
@@ -904,10 +926,12 @@ class NWProject():
) )
else: else:
self.makeAlert(( self.makeAlert(
self.tr("Failed to create a new example project. Could not find the " self.tr(
"necessary files. They seem to be missing from this installation.") "Failed to create a new example project. Could not find the "
), nwAlert.ERROR) "necessary files. They seem to be missing from this installation."
), nwAlert.ERROR
)
if isSuccess: if isSuccess:
self.clearProject() self.clearProject()
@@ -944,10 +968,12 @@ class NWProject():
if os.path.isdir(projPath): if os.path.isdir(projPath):
if os.listdir(self.projPath): if os.listdir(self.projPath):
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("New project folder is not empty. " self.tr(
"Each project requires a dedicated project folder.") "New project folder is not empty. "
), nwAlert.ERROR) "Each project requires a dedicated project folder."
), nwAlert.ERROR
)
return False return False
self.ensureFolderStructure() self.ensureFolderStructure()
@@ -994,17 +1020,21 @@ class NWProject():
self.doBackup = doBackup self.doBackup = doBackup
if doBackup: if doBackup:
if not os.path.isdir(self.mainConf.backupPath): if not os.path.isdir(self.mainConf.backupPath):
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("You must set a valid backup path in preferences to use " self.tr(
"the automatic project backup feature.") "You must set a valid backup path in preferences to use "
), nwAlert.WARN) "the automatic project backup feature."
), nwAlert.WARN
)
return False return False
if self.projName == "": if self.projName == "":
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("You must set a valid project name in project settings to " self.tr(
"use the automatic project backup feature.") "You must set a valid project name in project settings to "
), nwAlert.WARN) "use the automatic project backup feature."
), nwAlert.WARN
)
return False return False
return True return True
@@ -1354,6 +1384,7 @@ class NWProject():
aDoc = NWDoc(self, self.theParent) aDoc = NWDoc(self, self.theParent)
nOrph = 0 nOrph = 0
noWhere = False noWhere = False
oPrefix = self.tr("Recovered")
for oHandle in orphanFiles: for oHandle in orphanFiles:
# Look for meta data # Look for meta data
@@ -1365,9 +1396,9 @@ class NWProject():
oName, oParent, oClass, oLayout = aDoc.getMeta() oName, oParent, oClass, oLayout = aDoc.getMeta()
if oName: if oName:
oName = self.tr("{0}: {1}").format( oName = self.tr("[{0}] {1}").format(
self.tr("Recovered"), oPrefix, oName.strip("[%s]" % oPrefix).strip()
oName.lstrip(self.tr("{0}: ").format(self.tr("Recovered")))) )
else: else:
nOrph += 1 nOrph += 1
oName = self.tr("Recovered File {0}").format(nOrph) oName = self.tr("Recovered File {0}").format(nOrph)
@@ -1397,10 +1428,12 @@ class NWProject():
self.projTree.append(oHandle, oParent, orphItem) self.projTree.append(oHandle, oParent, orphItem)
if noWhere: if noWhere:
self.makeAlert(( self.makeAlert(
self.tr("One or more orphaned files could not be added back into the " self.tr(
"project. Make sure at least a Novel root folder exists.") "One or more orphaned files could not be added back into the "
), nwAlert.WARN) "project. Make sure at least a Novel root folder exists."
), nwAlert.WARN
)
return True return True
@@ -1418,13 +1451,9 @@ class NWProject():
if not isFile: if not isFile:
# It's a new file, so add a header # It's a new file, so add a header
if self.lastWCount > 0: if self.lastWCount > 0:
outFile.write("# %s\n" % self.tr("Offset {0}").format(self.lastWCount)) outFile.write("# Offset %d\n" % self.lastWCount)
outFile.write("# %-17s %-19s %8s %8s %8s\n" % ( outFile.write("# %-17s %-19s %8s %8s %8s\n" % (
self.tr("Start Time"), "Start Time", "End Time", "Novel", "Notes", "Idle"
self.tr("End Time"),
self.tr("Novel"),
self.tr("Notes"),
self.tr("Idle"),
)) ))
outFile.write("%-19s %-19s %8d %8d %8d\n" % ( outFile.write("%-19s %-19s %8d %8d %8d\n" % (
@@ -1471,10 +1500,12 @@ class NWProject():
newPath = os.path.join(self.projContent, tHandle+".nwd") newPath = os.path.join(self.projContent, tHandle+".nwd")
try: try:
os.rename(theFile, newPath) os.rename(theFile, newPath)
logger.info(self.tr("{0}: {1}").format(self.tr("Moved file"), theFile)) logger.info("Moved file: %s" % theFile)
logger.info(self.tr("{0}: {1}").format(self.tr("New location"), newPath)) logger.info("New location: %s" % newPath)
except Exception: except Exception:
errList.append(self.tr("{0}: {1}").format(self.tr("Could not move"), theFile)) errList.append(
self.tr("{0}: {1}").format(self.tr("Could not move"), theFile)
)
logger.error("Could not move: %s" % theFile) logger.error("Could not move: %s" % theFile)
nw.logException() nw.logException()
@@ -1483,8 +1514,9 @@ class NWProject():
os.unlink(theFile) os.unlink(theFile)
logger.info("Deleted file: %s" % theFile) logger.info("Deleted file: %s" % theFile)
except Exception: except Exception:
errList.append(self.tr("{0}: {1}").format( errList.append(
self.tr("Could not delete"), theFile)) self.tr("{0}: {1}").format(self.tr("Could not delete"), theFile)
)
logger.error("Could not delete: %s" % theFile) logger.error("Could not delete: %s" % theFile)
nw.logException() nw.logException()
@@ -1499,7 +1531,9 @@ class NWProject():
os.rmdir(theData) os.rmdir(theData)
logger.info("Removed folder: %s" % theFolder) logger.info("Removed folder: %s" % theFolder)
except Exception: except Exception:
errList.append(self.tr("{0}: {1}").format(self.tr("Failed to remove"), theFolder)) errList.append(
self.tr("{0}: {1}").format(self.tr("Failed to remove"), theFolder)
)
logger.error("Failed to remove: %s" % theFolder) logger.error("Failed to remove: %s" % theFolder)
nw.logException() nw.logException()
@@ -1509,7 +1543,7 @@ class NWProject():
"""Move an item that doesn't belong in the project folder to """Move an item that doesn't belong in the project folder to
a junk folder. a junk folder.
""" """
theJunk = os.path.join(self.projPath, self.tr("junk")) theJunk = os.path.join(self.projPath, "junk")
if not self._checkFolder(theJunk): if not self._checkFolder(theJunk):
return self.tr("{0}: {1}").format(self.tr("Could not make folder"), theJunk) return self.tr("{0}: {1}").format(self.tr("Could not make folder"), theJunk)
@@ -1522,7 +1556,7 @@ class NWProject():
except Exception: except Exception:
logger.error("Could not move item %s to junk." % theSrc) logger.error("Could not move item %s to junk." % theSrc)
nw.logException() nw.logException()
return self.tr("Could not move item {0} to junk.").format(theSrc) return self.tr("Could not move item {0} to {1}.").format(theSrc, theJunk)
return "" return ""
+5 -5
View File
@@ -407,13 +407,11 @@ class ToHtml(Tokenizer):
""" """
if self.genMode == self.M_PREVIEW: if self.genMode == self.M_PREVIEW:
return "<p class='comment'><span class='synopsis'>%s:</span> %s</p>\n" % ( return "<p class='comment'><span class='synopsis'>%s:</span> %s</p>\n" % (
self.tr("Synopsis"), self._trSynopsis, tText
tText
) )
else: else:
return "<p class='synopsis'><strong>%s:</strong> %s</p>\n" % ( return "<p class='synopsis'><strong>%s:</strong> %s</p>\n" % (
self.tr("Synopsis"), self._trSynopsis, tText
tText
) )
def _formatComments(self, tText): def _formatComments(self, tText):
@@ -422,7 +420,9 @@ class ToHtml(Tokenizer):
if self.genMode == self.M_PREVIEW: if self.genMode == self.M_PREVIEW:
return "<p class='comment'>%s</p>\n" % tText return "<p class='comment'>%s</p>\n" % tText
else: else:
return "<p class='comment'><strong>%s:</strong> %s</p>\n" % (self.tr("Comment"), tText) return "<p class='comment'><strong>%s:</strong> %s</p>\n" % (
self._trComment, tText
)
def _formatKeywords(self, tText): def _formatKeywords(self, tText):
"""Apply HTML formatting to keywords. """Apply HTML formatting to keywords.
+10 -3
View File
@@ -24,11 +24,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from functools import partial
import logging import logging
import re import re
from operator import itemgetter from operator import itemgetter
from functools import partial
from PyQt5.QtCore import QCoreApplication, QRegularExpression from PyQt5.QtCore import QCoreApplication, QRegularExpression
from nw.core.document import NWDoc from nw.core.document import NWDoc
@@ -142,7 +143,13 @@ class Tokenizer():
# Error Handling # Error Handling
self.errData = [] self.errData = []
self.tr = partial(QCoreApplication.translate, self.__class__.__name__) # Internal Mappings
self.tr = partial(QCoreApplication.translate, "Tokenizer")
# Localisation
self._trSynopsis = self.tr("Synopsis")
self._trComment = self.tr("Comment")
self._trNotes = self.tr("Notes")
return return
@@ -252,7 +259,7 @@ class Tokenizer():
if theItem.itemType != nwItemType.ROOT: if theItem.itemType != nwItemType.ROOT:
return False return False
theTitle = self.tr("{0}: {1}").format(self.tr("Notes"), theItem.itemName) theTitle = self.tr("{0}: {1}").format(self._trNotes, theItem.itemName)
self.theTokens = [] self.theTokens = []
self.theTokens.append(( self.theTokens.append((
self.T_TITLE, 0, theTitle, None, self.A_PBB | self.A_CENTRE self.T_TITLE, 0, theTitle, None, self.A_PBB | self.A_CENTRE
+4 -3
View File
@@ -24,14 +24,14 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from functools import partial
import nw import nw
import logging import logging
import os import os
from time import time
from lxml import etree from lxml import etree
from hashlib import sha256 from hashlib import sha256
from time import time from functools import partial
from PyQt5.QtCore import QCoreApplication from PyQt5.QtCore import QCoreApplication
@@ -82,7 +82,8 @@ class NWTree():
self._handleSeed = None # Used for generating handles for testing self._handleSeed = None # Used for generating handles for testing
self.tr = partial(QCoreApplication.translate, self.__class__.__name__) # Internal Mappings
self.tr = partial(QCoreApplication.translate, "NWTree")
return return
+70 -51
View File
@@ -62,7 +62,7 @@ class GuiAbout(QDialog):
nPx = self.mainConf.pxInt(96) nPx = self.mainConf.pxInt(96)
self.nwIcon = QLabel() self.nwIcon = QLabel()
self.nwIcon.setPixmap(self.theParent.theTheme.getPixmap("novelwriter", (nPx, nPx))) self.nwIcon.setPixmap(self.theParent.theTheme.getPixmap("novelwriter", (nPx, nPx)))
self.lblName = QLabel("<b>%s</b>" % self.tr("novelWriter")) self.lblName = QLabel("<b>novelWriter</b>")
self.lblVers = QLabel("v%s" % nw.__version__) self.lblVers = QLabel("v%s" % nw.__version__)
self.lblDate = QLabel(datetime.strptime(nw.__date__, "%Y-%m-%d").strftime("%x")) self.lblDate = QLabel(datetime.strptime(nw.__date__, "%Y-%m-%d").strftime("%x"))
@@ -136,24 +136,31 @@ class GuiAbout(QDialog):
aboutMsg = "".join([ aboutMsg = "".join([
"<h2>%s</h2>" % self.tr("About novelWriter"), "<h2>%s</h2>" % self.tr("About novelWriter"),
"<p>{copyright:s}.</p>", "<p>{copyright:s}.</p>",
"<p>%s</p>" % (self.tr("{0}: {1}").format( "<p>%s</p>" % self.tr("{0}: {1}").format(
self.tr("Website"), self.tr("Website"), "<a href=\"{website:s}\">{domain:s}</a>"
"<a href=\"{website:s}\">{domain:s}</a>" ),
)), "<p>%s</p>" % self.tr(
"<p>%s</p>" % self.tr("novelWriter is a markdown-like text editor designed for " "novelWriter is a markdown-like text editor designed for organising and "
"organising and writing novels. It is written in Python 3 with " "writing novels. It is written in Python 3 with a Qt5 GUI, using PyQt5."
"a Qt5 GUI, using PyQt5."), ),
"<p>%s</p>" % self.tr("novelWriter is free software: you can redistribute it and/or " "<p>%s</p>" % self.tr(
"modify it under the terms of the GNU General Public License as " "novelWriter is free software: you can redistribute it and/or modify it "
"published by the Free Software Foundation, either version 3 of " "under the terms of the GNU General Public License as published by the "
"the License, or (at your option) any later version."), "Free Software Foundation, either version 3 of the License, or (at your "
"<p>%s</p>" % self.tr("novelWriter is distributed in the hope that it will be " "option) any later version."
"useful, but WITHOUT ANY WARRANTY; without even the implied " ),
"warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR " "<p>%s</p>" % self.tr(
"PURPOSE."), "novelWriter is distributed in the hope that it will be useful, but "
"<p>%s</p>" % (self.tr("See the License tab for the full license text, or visit the " "WITHOUT ANY WARRANTY; without even the implied warranty of "
"GNU website at {0} for more details.").format( "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
"<a href=\"https://www.gnu.org/licenses/gpl-3.0.html\">GPL v3.0</a>")), ),
"<p>%s</p>" % (
self.tr(
"See the License tab for the full license text, or visit the "
"GNU website at {0} for more details.").format(
"<a href=\"https://www.gnu.org/licenses/gpl-3.0.html\">GPL v3.0</a>"
)
),
"<h3>%s</h3>" % self.tr("Credits"), "<h3>%s</h3>" % self.tr("Credits"),
"<p>{credits:s}</p>", "<p>{credits:s}</p>",
]).format( ]).format(
@@ -167,49 +174,61 @@ class GuiAbout(QDialog):
theIcons = self.theParent.theTheme.theIcons theIcons = self.theParent.theTheme.theIcons
if theTheme.themeName: if theTheme.themeName:
aboutMsg += "".join([ aboutMsg += "".join([
("<h4>%s</h4>" % self.tr("{0}: {1}").format(self.tr("Theme"), theTheme.themeName)), "<h4>%s</h4>" % self.tr("{0}: {1}").format(
self.tr("Theme"), theTheme.themeName
),
"<p>", "<p>",
("%s<br/>" % self.tr("<b>{0}:</b> {1}").format( "%s<br/>" % self.tr("<b>{0}:</b> {1}").format(
self.tr("Author"), theTheme.themeAuthor)), self.tr("Author"), theTheme.themeAuthor
("%s<br/>" % self.tr("<b>{0}:</b> {1}").format( ),
self.tr("Credit"), theTheme.themeCredit)), "%s<br/>" % self.tr("<b>{0}:</b> {1}").format(
(self.tr("<b>{0}:</b> {1}").format( self.tr("Credit"), theTheme.themeCredit
self.tr("License"), ),
"<a href=\"{0}\">{1}</a>".format( self.tr("<b>{0}:</b> {1}").format(
theTheme.themeLicenseUrl, theTheme.themeLicense) self.tr("License"), "<a href='{0}'>{1}</a>".format(
)), theTheme.themeLicenseUrl, theTheme.themeLicense
)
),
"</p>" "</p>"
]) ])
if theIcons.themeName: if theIcons.themeName:
aboutMsg += "".join([ aboutMsg += "".join([
("<h4>%s</h4>" % self.tr("{0}: {1}").format(self.tr("Icons"), theIcons.themeName)), "<h4>%s</h4>" % self.tr("{0}: {1}").format(
self.tr("Icons"), theIcons.themeName
),
"<p>", "<p>",
("%s<br/>" % self.tr("<b>{0}:</b> {1}").format( "%s<br/>" % self.tr("<b>{0}:</b> {1}").format(
self.tr("Author"), theIcons.themeAuthor)), self.tr("Author"), theIcons.themeAuthor
("%s<br/>" % self.tr("<b>{0}:</b> {1}").format( ),
self.tr("Credit"), theIcons.themeCredit)), "%s<br/>" % self.tr("<b>{0}:</b> {1}").format(
(self.tr("<b>{0}:</b> {1}").format( self.tr("Credit"), theIcons.themeCredit
self.tr("License"), ),
"<a href=\"{0}\">{1}</a>".format( self.tr("<b>{0}:</b> {1}").format(
theIcons.themeLicenseUrl, theIcons.themeLicense) self.tr("License"), "<a href='{0}'>{1}</a>".format(
)), theIcons.themeLicenseUrl, theIcons.themeLicense
)
),
"</p>" "</p>"
]) ])
if theTheme.syntaxName: if theTheme.syntaxName:
aboutMsg += "".join([ aboutMsg += "".join([
("<h4>%s</h4>" % self.tr("{0}: {1}").format( "<h4>%s</h4>" % self.tr("{0}: {1}").format(
self.tr("Syntax"), self.tr("Syntax"), theTheme.syntaxName
theTheme.syntaxName)), ),
"<p>", "<p>",
("%s<br/>" % self.tr("<b>{0}:</b> {1}").format( "%s<br/>" % self.tr("<b>{0}:</b> {1}").format(
self.tr("Author"), theTheme.syntaxAuthor)), self.tr("Author"), theTheme.syntaxAuthor
("%s<br/>" % self.tr("<b>{0}</b> {1}").format( ),
self.tr("Credit"), theTheme.syntaxCredit)), "%s<br/>" % self.tr("<b>{0}</b> {1}").format(
(self.tr("<b>{0}:</b> {1}").format( self.tr("Credit"), theTheme.syntaxCredit
self.tr("License"), ),
"<a href=\"{0}\">{1}</a>".format( self.tr("<b>{0}:</b> {1}").format(
theTheme.syntaxLicenseUrl, theTheme.syntaxLicense) self.tr("License"), "<a href='{0}'>{1}</a>".format(
)), theTheme.syntaxLicenseUrl, theTheme.syntaxLicense
)
),
"</p>" "</p>"
]) ])
+56 -40
View File
@@ -105,7 +105,7 @@ class GuiBuildNovel(QDialog):
self.titleForm = QGridLayout(self) self.titleForm = QGridLayout(self)
self.titleGroup.setLayout(self.titleForm) self.titleGroup.setLayout(self.titleForm)
fmtHelp = "<br>".join( fmtHelp = "<br>".join([
"<b>%s</b>" % self.tr("{0}:").format("Formatting Codes"), "<b>%s</b>" % self.tr("{0}:").format("Formatting Codes"),
self.tr("{0} for the title as set in the document").format(r"%title%"), self.tr("{0} for the title as set in the document").format(r"%title%"),
self.tr("{0} for chapter number (1, 2, 3)").format(r"%ch%"), self.tr("{0} for chapter number (1, 2, 3)").format(r"%ch%"),
@@ -114,14 +114,13 @@ class GuiBuildNovel(QDialog):
self.tr("{0} for chapter number in lower case Roman").format(r"%chi%"), self.tr("{0} for chapter number in lower case Roman").format(r"%chi%"),
self.tr("{0} for scene number within chapter").format(r"%sc%"), self.tr("{0} for scene number within chapter").format(r"%sc%"),
self.tr("{0} for scene number within novel").format(r"%sca%"), self.tr("{0} for scene number within novel").format(r"%sca%"),
) ])
fmtScHelp = ( fmtScHelp = "<br><br>%s" % self.tr(
"<br><br>%s" % "Leave blank to skip this heading, or set to a static text, like "
self.tr("Leave blank to skip this heading, or set to a static text, like " "for instance '{0}', to make a separator. The separator will "
"for instance '{0}', to make a separator. The separator will " "be centred automatically and only appear between sections of "
"be centred automatically and only appear between sections of " "the same type."
"the same type.").format("* * *") ).format("* * *")
)
xFmt = self.mainConf.pxInt(100) xFmt = self.mainConf.pxInt(100)
self.fmtTitle = QLineEdit() self.fmtTitle = QLineEdit()
@@ -332,10 +331,10 @@ class GuiBuildNovel(QDialog):
self.fileGroup.setLayout(self.fileForm) self.fileGroup.setLayout(self.fileForm)
self.novelFiles = QSwitch(width=wS, height=hS) self.novelFiles = QSwitch(width=wS, height=hS)
self.novelFiles.setToolTip( self.novelFiles.setToolTip(self.tr(
self.tr("Include files with layouts 'Book', 'Page', 'Partition', " "Include files with layouts 'Book', 'Page', 'Partition', "
"'Chapter', 'Unnumbered', and 'Scene'.") "'Chapter', 'Unnumbered', and 'Scene'."
) ))
self.novelFiles.setChecked( self.novelFiles.setChecked(
self.optState.getBool("GuiBuildNovel", "addNovel", True) self.optState.getBool("GuiBuildNovel", "addNovel", True)
) )
@@ -347,10 +346,10 @@ class GuiBuildNovel(QDialog):
) )
self.ignoreFlag = QSwitch(width=wS, height=hS) self.ignoreFlag = QSwitch(width=wS, height=hS)
self.ignoreFlag.setToolTip( self.ignoreFlag.setToolTip(self.tr(
self.tr("Ignore the 'Include when building project' setting and include " "Ignore the 'Include when building project' setting and include "
"all files in the output.") "all files in the output."
) ))
self.ignoreFlag.setChecked( self.ignoreFlag.setChecked(
self.optState.getBool("GuiBuildNovel", "ignoreFlag", False) self.optState.getBool("GuiBuildNovel", "ignoreFlag", False)
) )
@@ -430,42 +429,51 @@ class GuiBuildNovel(QDialog):
self.btnSave = QPushButton("Save As") self.btnSave = QPushButton("Save As")
self.btnSave.setMenu(self.saveMenu) self.btnSave.setMenu(self.saveMenu)
self.saveODT = QAction(self.tr("{0} ({1})").format(self.tr("Open Document"), ".odt"), self) self.saveODT = QAction(
self.tr("{0} ({1})").format(self.tr("Open Document"), ".odt"), self
)
self.saveODT.triggered.connect(lambda: self._saveDocument(self.FMT_ODT)) self.saveODT.triggered.connect(lambda: self._saveDocument(self.FMT_ODT))
self.saveMenu.addAction(self.saveODT) self.saveMenu.addAction(self.saveODT)
self.saveFODT = QAction( self.saveFODT = QAction(
self.tr("{0} ({1})").format(self.tr("Flat Open Document"), ".fodt"), self) self.tr("{0} ({1})").format(self.tr("Flat Open Document"), ".fodt"), self
)
self.saveFODT.triggered.connect(lambda: self._saveDocument(self.FMT_FODT)) self.saveFODT.triggered.connect(lambda: self._saveDocument(self.FMT_FODT))
self.saveMenu.addAction(self.saveFODT) self.saveMenu.addAction(self.saveFODT)
self.saveHTM = QAction(self.tr("{0} ({1})").format( self.saveHTM = QAction(
self.tr("novelWriter HTML"), ".htm"), self) self.tr("{0} ({1})").format(self.tr("novelWriter HTML"), ".htm"), self
)
self.saveHTM.triggered.connect(lambda: self._saveDocument(self.FMT_HTM)) self.saveHTM.triggered.connect(lambda: self._saveDocument(self.FMT_HTM))
self.saveMenu.addAction(self.saveHTM) self.saveMenu.addAction(self.saveHTM)
self.saveNWD = QAction(self.tr("{0} ({1})").format( self.saveNWD = QAction(
self.tr("novelWriter Markdown"), ".nwd"), self) self.tr("{0} ({1})").format(self.tr("novelWriter Markdown"), ".nwd"), self
)
self.saveNWD.triggered.connect(lambda: self._saveDocument(self.FMT_NWD)) self.saveNWD.triggered.connect(lambda: self._saveDocument(self.FMT_NWD))
self.saveMenu.addAction(self.saveNWD) self.saveMenu.addAction(self.saveNWD)
self.saveMD = QAction( self.saveMD = QAction(
self.tr("{0} ({1})").format(self.tr("Standard Markdown"), ".md"), self) self.tr("{0} ({1})").format(self.tr("Standard Markdown"), ".md"), self
)
self.saveMD.triggered.connect(lambda: self._saveDocument(self.FMT_MD)) self.saveMD.triggered.connect(lambda: self._saveDocument(self.FMT_MD))
self.saveMenu.addAction(self.saveMD) self.saveMenu.addAction(self.saveMD)
self.saveGH = QAction( self.saveGH = QAction(
self.tr("{0} ({1})").format(self.tr("GitHub Markdown"), ".md"), self) self.tr("{0} ({1})").format(self.tr("GitHub Markdown"), ".md"), self
)
self.saveGH.triggered.connect(lambda: self._saveDocument(self.FMT_GH)) self.saveGH.triggered.connect(lambda: self._saveDocument(self.FMT_GH))
self.saveMenu.addAction(self.saveGH) self.saveMenu.addAction(self.saveGH)
self.saveJsonH = QAction(self.tr("{0} ({1})").format( self.saveJsonH = QAction(
self.tr("JSON + novelWriter HTML"), ".json"), self) self.tr("{0} ({1})").format(self.tr("JSON + novelWriter HTML"), ".json"), self
)
self.saveJsonH.triggered.connect(lambda: self._saveDocument(self.FMT_JSON_H)) self.saveJsonH.triggered.connect(lambda: self._saveDocument(self.FMT_JSON_H))
self.saveMenu.addAction(self.saveJsonH) self.saveMenu.addAction(self.saveJsonH)
self.saveJsonM = QAction(self.tr("{0} ({1})").format( self.saveJsonM = QAction(
self.tr("JSON + novelWriters Markdown"), ".json"), self) self.tr("{0} ({1})").format(self.tr("JSON + novelWriters Markdown"), ".json"), self
)
self.saveJsonM.triggered.connect(lambda: self._saveDocument(self.FMT_JSON_M)) self.saveJsonM.triggered.connect(lambda: self._saveDocument(self.FMT_JSON_M))
self.saveMenu.addAction(self.saveJsonM) self.saveMenu.addAction(self.saveJsonM)
@@ -745,7 +753,8 @@ class GuiBuildNovel(QDialog):
if bldObj.errData: if bldObj.errData:
self.theParent.makeAlert("%s:<br>-&nbsp;%s" % ( self.theParent.makeAlert("%s:<br>-&nbsp;%s" % (
self.tr("There were problems when building the project"), self.tr("There were problems when building the project"),
"<br>-&nbsp;".join(bldObj.errData)), nwAlert.ERROR) "<br>-&nbsp;".join(bldObj.errData)), nwAlert.ERROR
)
return return
@@ -997,14 +1006,14 @@ class GuiBuildNovel(QDialog):
if wSuccess: if wSuccess:
self.theParent.makeAlert( self.theParent.makeAlert(
"%s<br> %s" % ( "%s<br> %s" % (
self.tr("{0} file successfully written to:").format(textFmt), self.tr("{0} file successfully written to:").format(textFmt), savePath
savePath ),
), nwAlert.INFO nwAlert.INFO
) )
else: else:
self.theParent.makeAlert( self.theParent.makeAlert(
self.tr("Failed to write {0} file. {1}").format( self.tr("Failed to write {0} file. {1}").format(textFmt, errMsg),
textFmt, errMsg), nwAlert.ERROR nwAlert.ERROR
) )
return wSuccess return wSuccess
@@ -1200,9 +1209,11 @@ class GuiBuildNovelDocView(QTextBrowser):
self.qDocument = self.document() self.qDocument = self.document()
self.qDocument.setDocumentMargin(self.mainConf.getTextMargin()) self.qDocument.setDocumentMargin(self.mainConf.getTextMargin())
self.setPlaceholderText( self.setPlaceholderText(
self.tr("This area will show the content of the document to be " self.tr(
"exported or printed. Press the \"Build Preview\" button " "This area will show the content of the document to be "
"to generate content.") "exported or printed. Press the \"Build Preview\" button "
"to generate content."
)
) )
theFont = QFont() theFont = QFont()
@@ -1234,7 +1245,8 @@ class GuiBuildNovelDocView(QTextBrowser):
fPx = int(1.1*self.theTheme.fontPixelSize) fPx = int(1.1*self.theTheme.fontPixelSize)
self.theTitle = QLabel(self.tr("<b>{0}:</b> {1}".format( self.theTitle = QLabel(self.tr("<b>{0}:</b> {1}".format(
self.tr("Build Time"), self.tr("Unknown"))), self) self.tr("Build Time"), self.tr("Unknown"))), self
)
self.theTitle.setIndent(0) self.theTitle.setIndent(0)
self.theTitle.setAutoFillBackground(True) self.theTitle.setAutoFillBackground(True)
self.theTitle.setAlignment(Qt.AlignCenter) self.theTitle.setAlignment(Qt.AlignCenter)
@@ -1349,8 +1361,12 @@ class GuiBuildNovelDocView(QTextBrowser):
) )
else: else:
strBuildTime = self.tr("Unknown") strBuildTime = self.tr("Unknown")
self.theTitle.setText(self.tr("<b>{0}:</b> {1}").format( self.theTitle.setText(self.tr("<b>{0}:</b> {1}").format(
self.tr("Build Time"), strBuildTime)) self.tr("Build Time"), strBuildTime)
)
return
def _updateDocMargins(self): def _updateDocMargins(self):
"""Automatically adjust the header to fill the top of the """Automatically adjust the header to fill the top of the
+49 -40
View File
@@ -36,7 +36,7 @@ import logging
from time import time from time import time
from PyQt5.QtCore import ( from PyQt5.QtCore import (
QCoreApplication, Qt, QSize, QTimer, pyqtSlot, pyqtSignal, QRegExp, QRegularExpression, Qt, QSize, QTimer, pyqtSlot, pyqtSignal, QRegExp, QRegularExpression,
QPointF, QObject, QRunnable, QPropertyAnimation QPointF, QObject, QRunnable, QPropertyAnimation
) )
from PyQt5.QtGui import ( from PyQt5.QtGui import (
@@ -53,8 +53,8 @@ from nw.core import NWDoc, NWSpellSimple, countWords
from nw.gui.dochighlight import GuiDocHighlighter from nw.gui.dochighlight import GuiDocHighlighter
from nw.common import transferCase from nw.common import transferCase
from nw.constants import ( from nw.constants import (
nwConst, nwAlert, nwUnicode, nwDocAction, nwDocInsert, nwItemClass, trConst, nwConst, nwAlert, nwUnicode, nwDocAction, nwDocInsert,
nwKeyWords, nwLabels nwItemClass, nwKeyWords, nwLabels
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -293,15 +293,17 @@ class GuiDocEditor(QTextEdit):
docSize = len(theDoc) docSize = len(theDoc)
if docSize > nwConst.MAX_DOCSIZE: if docSize > nwConst.MAX_DOCSIZE:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("The document you are trying to open is too big. " self.tr(
"The document size is {doc_size}. " "The document you are trying to open is too big. "
"The maximum size allowed is {max_size}."). "The document size is {doc_size}. "
format( "The maximum size allowed is {max_size}."
).format(
doc_size=self.tr("{0}\u202fMB").format(f"{docSize/1.0e6:.2f}"), doc_size=self.tr("{0}\u202fMB").format(f"{docSize/1.0e6:.2f}"),
max_size=self.tr("{0}\u202fMB").format(f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}") max_size=self.tr("{0}\u202fMB").format(f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}")
) ),
), nwAlert.ERROR) nwAlert.ERROR
)
self.clearEditor() self.clearEditor()
return False return False
@@ -384,15 +386,17 @@ class GuiDocEditor(QTextEdit):
""" """
docSize = len(theText) docSize = len(theText)
if docSize > nwConst.MAX_DOCSIZE: if docSize > nwConst.MAX_DOCSIZE:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("The text you are trying to add is too big. " self.tr(
"The text size is {text_size}. " "The text you are trying to add is too big. "
"The maximum size allowed is {max_size}."). "The text size is {text_size}. "
format( "The maximum size allowed is {max_size}."
).format(
text_size=self.tr("{0}\u202fMB").format(f"{docSize/1.0e6:.2f}"), text_size=self.tr("{0}\u202fMB").format(f"{docSize/1.0e6:.2f}"),
max_size=self.tr("{0}\u202fMB").format(f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}") max_size=self.tr("{0}\u202fMB").format(f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}")
) ),
), nwAlert.ERROR) nwAlert.ERROR
)
return False return False
qApp.setOverrideCursor(QCursor(Qt.WaitCursor)) qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
@@ -747,15 +751,14 @@ class GuiDocEditor(QTextEdit):
return False return False
msgBox = QMessageBox() msgBox = QMessageBox()
msgBox.information(self, self.tr("File Location"), "".join([ msgBox.information(
(self.tr("{0}<br>").format(self.tr("File details for the currently open file"))), self,
(self.tr("{0}<br>").format( self.tr("File Location"),
self.tr("{0}: {1}").format(self.tr("Handle"), "{handle:s}"))), "%s<br>%s" % (
(self.tr("{0}: {1}").format(self.tr("Location"), "{fileLoc:s}")) self.tr("The currently open file is saved in:"),
]).format( self.nwDocument.getFileLocation()
handle = self.theHandle, ),
fileLoc = str(self.nwDocument.getFileLocation()) )
))
return return
@@ -938,11 +941,15 @@ class GuiDocEditor(QTextEdit):
self.lastFind = None self.lastFind = None
if self.qDocument.characterCount() > nwConst.MAX_DOCSIZE: if self.qDocument.characterCount() > nwConst.MAX_DOCSIZE:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("The document has grown too big and you cannot add more text to it. " self.tr(
"The maximum size of a single novelWriter document is {max_size}."). "The document has grown too big and you cannot add more text to it. "
format(max_size=self.tr("{0}\u202fMB").format(f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}")) "The maximum size of a single novelWriter document is {max_size}."
), nwAlert.ERROR) ).format(
max_size=self.tr("{0}\u202fMB").format(f"{nwConst.MAX_DOCSIZE/1.0e6:.2f}")
),
nwAlert.ERROR
)
self.undo() self.undo()
return return
@@ -1860,8 +1867,7 @@ class GuiDocEditSearch(QFrame):
self.searchOpt.addAction(self.toggleWord) self.searchOpt.addAction(self.toggleWord)
self.toggleRegEx = QAction(self.tr("RegEx Mode"), self) self.toggleRegEx = QAction(self.tr("RegEx Mode"), self)
self.toggleRegEx.setToolTip(self.tr("Use regular expressions (requires Qt {0})").format( self.toggleRegEx.setToolTip(self.tr("Search using regular expressions"))
"5.3"))
self.toggleRegEx.setIcon(self.theTheme.getIcon("search_regex")) self.toggleRegEx.setIcon(self.theTheme.getIcon("search_regex"))
self.toggleRegEx.setCheckable(True) self.toggleRegEx.setCheckable(True)
self.toggleRegEx.setChecked(self.isRegEx) self.toggleRegEx.setChecked(self.isRegEx)
@@ -2541,10 +2547,8 @@ class GuiDocEditFooter(QWidget):
theIcon = self.theParent.importIcons[iStatus] theIcon = self.theParent.importIcons[iStatus]
sIcon = theIcon.pixmap(self.sPx, self.sPx) sIcon = theIcon.pixmap(self.sPx, self.sPx)
sClass = QCoreApplication.translate( sClass = trConst(nwLabels.CLASS_NAME[self.theItem.itemClass])
"Constant", nwLabels.CLASS_NAME[self.theItem.itemClass]) sLayout = trConst(nwLabels.LAYOUT_NAME[self.theItem.itemLayout])
sLayout = QCoreApplication.translate(
"Constant", nwLabels.LAYOUT_NAME[self.theItem.itemLayout])
sText = f"{self.theItem.itemStatus} / {sClass} / {sLayout}" sText = f"{self.theItem.itemStatus} / {sClass} / {sLayout}"
self.statusIcon.setPixmap(sIcon) self.statusIcon.setPixmap(sIcon)
@@ -2565,7 +2569,9 @@ class GuiDocEditFooter(QWidget):
self.linesText.setText( self.linesText.setText(
self.tr("{0}: {1} ({2}\u202f%%)".format( self.tr("{0}: {1} ({2}\u202f%%)".format(
self.tr("Line"), f"{iLine:n}", f"{iDist:.0f}"))) self.tr("Line"), f"{iLine:n}", f"{iDist:.0f}")
)
)
return return
@@ -2581,11 +2587,14 @@ class GuiDocEditFooter(QWidget):
self.wordsText.setText( self.wordsText.setText(
self.tr("{0}: {1} ({2})".format( self.tr("{0}: {1} ({2})".format(
self.tr("Words"), f"{wCount:n}", f"{wDiff:+n}"))) self.tr("Words"), f"{wCount:n}", f"{wDiff:+n}")
)
)
byteSize = self.docEditor.qDocument.characterCount() byteSize = self.docEditor.qDocument.characterCount()
self.wordsText.setToolTip( self.wordsText.setToolTip(
(self.tr("Document size is {0} bytes").format(f"{byteSize:n}"))) self.tr("Document size is {0} bytes").format(f"{byteSize:n}")
)
return return
+12 -12
View File
@@ -104,9 +104,9 @@ class GuiDocMerge(QDialog):
finalOrder.append(self.listBox.item(i).data(Qt.UserRole)) finalOrder.append(self.listBox.item(i).data(Qt.UserRole))
if len(finalOrder) == 0: if len(finalOrder) == 0:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("No source documents found. Nothing to do.") self.tr("No source documents found. Nothing to do."), nwAlert.ERROR
), nwAlert.ERROR) )
return return
theDoc = NWDoc(self.theProject, self.theParent) theDoc = NWDoc(self.theProject, self.theParent)
@@ -116,16 +116,16 @@ class GuiDocMerge(QDialog):
theText += "\n\n" theText += "\n\n"
if self.sourceItem is None: if self.sourceItem is None:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("No source document selected. Nothing to do.") self.tr("No source document selected. Nothing to do."), nwAlert.ERROR
), nwAlert.ERROR) )
return return
srcItem = self.theProject.projTree[self.sourceItem] srcItem = self.theProject.projTree[self.sourceItem]
if srcItem is None: if srcItem is None:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("Could not parse source document.") self.tr("Could not parse source document."), nwAlert.ERROR
), nwAlert.ERROR) )
return return
nHandle = self.theProject.newFile(srcItem.itemName, srcItem.itemClass, srcItem.itemParent) nHandle = self.theProject.newFile(srcItem.itemName, srcItem.itemClass, srcItem.itemParent)
@@ -166,9 +166,9 @@ class GuiDocMerge(QDialog):
if nwItem is None: if nwItem is None:
return return
if nwItem.itemType is not nwItemType.FOLDER: if nwItem.itemType is not nwItemType.FOLDER:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("Element selected in the project tree must be a folder.") self.tr("Element selected in the project tree must be a folder."), nwAlert.ERROR
), nwAlert.ERROR) )
return return
for sHandle in self.theParent.treeView.getTreeFromHandle(tHandle): for sHandle in self.theParent.treeView.getTreeFromHandle(tHandle):
+30 -22
View File
@@ -118,16 +118,16 @@ class GuiDocSplit(QDialog):
logger.verbose("GuiDocSplit split button clicked") logger.verbose("GuiDocSplit split button clicked")
if self.sourceItem is None: if self.sourceItem is None:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("No source document selected. Nothing to do.") self.tr("No source document selected. Nothing to do."), nwAlert.ERROR
), nwAlert.ERROR) )
return return
srcItem = self.theProject.projTree[self.sourceItem] srcItem = self.theProject.projTree[self.sourceItem]
if srcItem is None: if srcItem is None:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("Could not parse source document.") self.tr("Could not parse source document."), nwAlert.ERROR
), nwAlert.ERROR) )
return return
theDoc = NWDoc(self.theProject, self.theParent) theDoc = NWDoc(self.theProject, self.theParent)
@@ -150,26 +150,34 @@ class GuiDocSplit(QDialog):
nFiles = len(finalOrder) nFiles = len(finalOrder)
if nFiles == 0: if nFiles == 0:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("No headers found. Nothing to do.") self.tr("No headers found. Nothing to do."), nwAlert.ERROR
), nwAlert.ERROR) )
return return
# Check that another folder can be created # Check that another folder can be created
parTree = self.theProject.projTree.getItemPath(srcItem.itemParent) parTree = self.theProject.projTree.getItemPath(srcItem.itemParent)
if len(parTree) >= nwConst.MAX_DEPTH - 1: if len(parTree) >= nwConst.MAX_DEPTH - 1:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("Cannot add new folder for the document split. " self.tr(
"Maximum folder depth has been reached. " "Cannot add new folder for the document split. "
"Please move the file to another level in the project tree.") "Maximum folder depth has been reached. "
), nwAlert.ERROR) "Please move the file to another level in the project tree."
), nwAlert.ERROR
)
return return
msgYes = self.theParent.askQuestion(self.tr("Split Document"), "%s<br><br>%s" % ( msgYes = self.theParent.askQuestion(
self.tr("The document will be split into {0} file(s) in a new folder. " self.tr("Split Document"),
"The original document will remain intact.", n=nFiles).format(nFiles), "%s<br><br>%s" % (
self.tr("Continue with the splitting process?") self.tr(
)) "The document will be split into {0} file(s) in a new folder. "
"The original document will remain intact.").format(nFiles),
self.tr(
"Continue with the splitting process?"
)
)
)
if not msgYes: if not msgYes:
return return
@@ -245,9 +253,9 @@ class GuiDocSplit(QDialog):
if nwItem is None: if nwItem is None:
return return
if nwItem.itemType is not nwItemType.FILE: if nwItem.itemType is not nwItemType.FILE:
self.theParent.makeAlert(( self.theParent.makeAlert(
self.tr("Element selected in the project tree must be a file.") self.tr("Element selected in the project tree must be a file."), nwAlert.ERROR
), nwAlert.ERROR) )
return return
self.listBox.clear() self.listBox.clear()
+10 -6
View File
@@ -244,10 +244,13 @@ class GuiDocViewer(QTextBrowser):
tHandle, _, sTitle = self.theParent.theIndex.getTagSource(theTag) tHandle, _, sTitle = self.theParent.theIndex.getTagSource(theTag)
if tHandle is None: if tHandle is None:
self.theParent.makeAlert( self.theParent.makeAlert(
self.tr("Could not find the reference for tag '{0}'. It either doesn't " self.tr(
"exist, or the index is out of date. The index can be updated " "Could not find the reference for tag '{0}'. It either doesn't "
"from the Tools menu, or by pressing {1}."). "exist, or the index is out of date. The index can be updated "
format(theTag, "F9"), nwAlert.ERROR) "from the Tools menu, or by pressing {1}."
).format(theTag, "F9"),
nwAlert.ERROR
)
return False return False
else: else:
# Let the parent handle the opening as it also ensures that # Let the parent handle the opening as it also ensures that
@@ -956,8 +959,9 @@ class GuiDocViewFooter(QWidget):
self.stickyRefs.setFixedSize(QSize(fPx, fPx)) self.stickyRefs.setFixedSize(QSize(fPx, fPx))
self.stickyRefs.toggled.connect(self._doToggleSticky) self.stickyRefs.toggled.connect(self._doToggleSticky)
self.stickyRefs.setToolTip( self.stickyRefs.setToolTip(
self.tr("Activate to freeze the content of the references panel when " self.tr(
"changing document") "Activate to freeze the content of the references panel when changing document"
)
) )
# Show Comments # Show Comments
+7 -9
View File
@@ -27,12 +27,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import nw import nw
import logging import logging
from PyQt5.QtCore import QCoreApplication, Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QPixmap from PyQt5.QtGui import QFont, QPixmap
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel
from nw.constants import ( from nw.constants import (
nwLabels, nwItemClass, nwItemType, nwItemLayout trConst, nwLabels, nwItemClass, nwItemType, nwItemLayout
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -118,7 +118,7 @@ class GuiItemDetails(QWidget):
self.layoutData.setAlignment(Qt.AlignLeft) self.layoutData.setAlignment(Qt.AlignLeft)
# Character Count # Character Count
self.cCountName = QLabel(self.tr(" Characters")) self.cCountName = QLabel(" "+self.tr("Characters"))
self.cCountName.setFont(self.fntLabel) self.cCountName.setFont(self.fntLabel)
self.cCountName.setAlignment(Qt.AlignRight) self.cCountName.setAlignment(Qt.AlignRight)
@@ -127,7 +127,7 @@ class GuiItemDetails(QWidget):
self.cCountData.setAlignment(Qt.AlignRight) self.cCountData.setAlignment(Qt.AlignRight)
# Word Count # Word Count
self.wCountName = QLabel(self.tr(" Words")) self.wCountName = QLabel(" "+self.tr("Words"))
self.wCountName.setFont(self.fntLabel) self.wCountName.setFont(self.fntLabel)
self.wCountName.setAlignment(Qt.AlignRight) self.wCountName.setAlignment(Qt.AlignRight)
@@ -136,7 +136,7 @@ class GuiItemDetails(QWidget):
self.wCountData.setAlignment(Qt.AlignRight) self.wCountData.setAlignment(Qt.AlignRight)
# Paragraph Count # Paragraph Count
self.pCountName = QLabel(self.tr(" Paragraphs")) self.pCountName = QLabel(" "+self.tr("Paragraphs"))
self.pCountName.setFont(self.fntLabel) self.pCountName.setFont(self.fntLabel)
self.pCountName.setAlignment(Qt.AlignRight) self.pCountName.setAlignment(Qt.AlignRight)
@@ -268,10 +268,8 @@ class GuiItemDetails(QWidget):
self.labelData.setText(theLabel) self.labelData.setText(theLabel)
self.statusData.setText(nwItem.itemStatus) self.statusData.setText(nwItem.itemStatus)
self.classData.setText(QCoreApplication.translate( self.classData.setText(trConst(nwLabels.CLASS_NAME[nwItem.itemClass]))
"Constant", nwLabels.CLASS_NAME[nwItem.itemClass])) self.layoutData.setText(trConst(nwLabels.LAYOUT_NAME[nwItem.itemLayout]))
self.layoutData.setText(QCoreApplication.translate(
"Constant", nwLabels.LAYOUT_NAME[nwItem.itemLayout]))
if nwItem.itemType == nwItemType.FILE: if nwItem.itemType == nwItemType.FILE:
self.cCountData.setText(f"{nwItem.charCount:n}") self.cCountData.setText(f"{nwItem.charCount:n}")
+15 -12
View File
@@ -27,14 +27,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import nw import nw
import logging import logging
from PyQt5.QtCore import QCoreApplication, pyqtSlot from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QGridLayout, QLineEdit, QComboBox, QLabel, QDialog, QVBoxLayout, QGridLayout, QLineEdit, QComboBox, QLabel,
QDialogButtonBox QDialogButtonBox
) )
from nw.gui.custom import QSwitch from nw.gui.custom import QSwitch
from nw.constants import nwLabels, nwItemLayout, nwItemType, nwLists from nw.constants import trConst, nwLabels, nwItemLayout, nwItemType, nwLists
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -103,8 +103,7 @@ class GuiItemEditor(QDialog):
for itemLayout in nwItemLayout: for itemLayout in nwItemLayout:
if itemLayout in validLayouts: if itemLayout in validLayouts:
self.editLayout.addItem(QCoreApplication.translate( self.editLayout.addItem(trConst(nwLabels.LAYOUT_NAME[itemLayout]), itemLayout)
"Constant", nwLabels.LAYOUT_NAME[itemLayout]), itemLayout)
# Export Switch # Export Switch
self.textExport = QLabel(self.tr("Include when building project")) self.textExport = QLabel(self.tr("Include when building project"))
@@ -139,17 +138,21 @@ class GuiItemEditor(QDialog):
# Assemble # Assemble
## ##
nameLabel = QLabel(self.tr("Label"))
statusLabel = QLabel(self.tr("Status"))
layoutLabel = QLabel(self.tr("Layout"))
self.mainForm = QGridLayout() self.mainForm = QGridLayout()
self.mainForm.setVerticalSpacing(vSp) self.mainForm.setVerticalSpacing(vSp)
self.mainForm.setHorizontalSpacing(mSp) self.mainForm.setHorizontalSpacing(mSp)
self.mainForm.addWidget(QLabel(self.tr("Label")), 0, 0, 1, 1) self.mainForm.addWidget(nameLabel, 0, 0, 1, 1)
self.mainForm.addWidget(self.editName, 0, 1, 1, 2) self.mainForm.addWidget(self.editName, 0, 1, 1, 2)
self.mainForm.addWidget(QLabel(self.tr("Status")), 1, 0, 1, 1) self.mainForm.addWidget(statusLabel, 1, 0, 1, 1)
self.mainForm.addWidget(self.editStatus, 1, 1, 1, 2) self.mainForm.addWidget(self.editStatus, 1, 1, 1, 2)
self.mainForm.addWidget(QLabel(self.tr("Layout")), 2, 0, 1, 1) self.mainForm.addWidget(layoutLabel, 2, 0, 1, 1)
self.mainForm.addWidget(self.editLayout, 2, 1, 1, 2) self.mainForm.addWidget(self.editLayout, 2, 1, 1, 2)
self.mainForm.addWidget(self.textExport, 3, 0, 1, 2) self.mainForm.addWidget(self.textExport, 3, 0, 1, 2)
self.mainForm.addWidget(self.editExport, 3, 2, 1, 1) self.mainForm.addWidget(self.editExport, 3, 2, 1, 1)
self.mainForm.setColumnStretch(0, 0) self.mainForm.setColumnStretch(0, 0)
self.mainForm.setColumnStretch(1, 1) self.mainForm.setColumnStretch(1, 1)
self.mainForm.setColumnStretch(2, 0) self.mainForm.setColumnStretch(2, 0)
+22 -14
View File
@@ -27,13 +27,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import nw import nw
import logging import logging
from PyQt5.QtCore import QCoreApplication, QUrl, QProcess from PyQt5.QtCore import QUrl, QProcess
from PyQt5.QtGui import QDesktopServices from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QMenuBar, QAction from PyQt5.QtWidgets import QMenuBar, QAction
from nw.constants import ( from nw.constants import (
nwItemType, nwItemClass, nwDocAction, nwDocInsert, nwKeyWords, nwLabels, trConst, nwItemType, nwItemClass, nwDocAction, nwDocInsert, nwKeyWords,
nwUnicode nwLabels, nwUnicode
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -566,7 +566,8 @@ class GuiMainMenu(QMenuBar):
# Insert > Figure Dash # Insert > Figure Dash
self.aInsFigDash = QAction(self.tr("Figure Dash"), self) self.aInsFigDash = QAction(self.tr("Figure Dash"), self)
self.aInsFigDash.setStatusTip( self.aInsFigDash.setStatusTip(
self.tr("Insert figure dash (same width as a number character)")) self.tr("Insert figure dash (same width as a number character)")
)
self.aInsFigDash.setShortcut("Ctrl+K, ~") self.aInsFigDash.setShortcut("Ctrl+K, ~")
self.aInsFigDash.triggered.connect(lambda: self._docInsert(nwUnicode.U_FGDASH)) self.aInsFigDash.triggered.connect(lambda: self._docInsert(nwUnicode.U_FGDASH))
self.mInsDashes.addAction(self.aInsFigDash) self.mInsDashes.addAction(self.aInsFigDash)
@@ -740,8 +741,7 @@ class GuiMainMenu(QMenuBar):
self.mInsKWItems[nwKeyWords.ENTITY_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, E") self.mInsKWItems[nwKeyWords.ENTITY_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, E")
self.mInsKWItems[nwKeyWords.CUSTOM_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, X") self.mInsKWItems[nwKeyWords.CUSTOM_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, X")
for n, keyWord in enumerate(self.mInsKWItems): for n, keyWord in enumerate(self.mInsKWItems):
self.mInsKWItems[keyWord][0].setText( self.mInsKWItems[keyWord][0].setText(trConst(nwLabels.KEY_NAME[keyWord]))
QCoreApplication.translate("Constant", nwLabels.KEY_NAME[keyWord]))
self.mInsKWItems[keyWord][0].setShortcut(self.mInsKWItems[keyWord][1]) self.mInsKWItems[keyWord][0].setShortcut(self.mInsKWItems[keyWord][1])
self.mInsKWItems[keyWord][0].triggered.connect( self.mInsKWItems[keyWord][0].triggered.connect(
lambda n, keyWord=keyWord: self._insertKeyWord(keyWord) lambda n, keyWord=keyWord: self._insertKeyWord(keyWord)
@@ -796,7 +796,8 @@ class GuiMainMenu(QMenuBar):
# Search > Replace Next # Search > Replace Next
self.aReplaceNext = QAction(self.tr("Replace Next"), self) self.aReplaceNext = QAction(self.tr("Replace Next"), self)
self.aReplaceNext.setStatusTip( self.aReplaceNext.setStatusTip(
self.tr("Find and replace next occurrence text in document")) self.tr("Find and replace next occurrence text in document")
)
self.aReplaceNext.setShortcut("Ctrl+Shift+1") self.aReplaceNext.setShortcut("Ctrl+Shift+1")
self.aReplaceNext.triggered.connect(lambda: self._docAction(nwDocAction.REPL_NEXT)) self.aReplaceNext.triggered.connect(lambda: self._docAction(nwDocAction.REPL_NEXT))
self.srcMenu.addAction(self.aReplaceNext) self.srcMenu.addAction(self.aReplaceNext)
@@ -898,14 +899,16 @@ 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 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)
# 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 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)
@@ -1031,7 +1034,8 @@ class GuiMainMenu(QMenuBar):
self.aHelpWeb = QAction(self.tr("Documentation (Online)"), self) self.aHelpWeb = QAction(self.tr("Documentation (Online)"), self)
self.aHelpWeb.setStatusTip( self.aHelpWeb.setStatusTip(
self.tr("View online documentation at {0}").format(nw.__docurl__)) self.tr("View online documentation at {0}").format(nw.__docurl__)
)
self.aHelpWeb.triggered.connect(lambda: self._openWebsite(nw.__docurl__)) self.aHelpWeb.triggered.connect(lambda: self._openWebsite(nw.__docurl__))
if self.mainConf.hasHelp and self.mainConf.hasAssistant: if self.mainConf.hasHelp and self.mainConf.hasAssistant:
self.aHelpWeb.setShortcut("Shift+F1") self.aHelpWeb.setShortcut("Shift+F1")
@@ -1045,28 +1049,32 @@ class GuiMainMenu(QMenuBar):
# Document > Report an Issue # Document > Report an Issue
self.aIssue = QAction(self.tr("Report an Issue (GitHub)"), self) self.aIssue = QAction(self.tr("Report an Issue (GitHub)"), self)
self.aIssue.setStatusTip( self.aIssue.setStatusTip(
self.tr("Report a bug or issue on GitHub at {0}").format(nw.__issuesurl__)) self.tr("Report a bug or issue on GitHub at {0}").format(nw.__issuesurl__)
)
self.aIssue.triggered.connect(lambda: self._openWebsite(nw.__issuesurl__)) self.aIssue.triggered.connect(lambda: self._openWebsite(nw.__issuesurl__))
self.helpMenu.addAction(self.aIssue) self.helpMenu.addAction(self.aIssue)
# Document > Ask a Question # Document > Ask a Question
self.aQuestion = QAction(self.tr("Ask a Question (GitHub)"), self) self.aQuestion = QAction(self.tr("Ask a Question (GitHub)"), self)
self.aQuestion.setStatusTip( self.aQuestion.setStatusTip(
self.tr("Ask a question on GitHub at {0}").format(nw.__helpurl__)) self.tr("Ask a question on GitHub at {0}").format(nw.__helpurl__)
)
self.aQuestion.triggered.connect(lambda: self._openWebsite(nw.__helpurl__)) self.aQuestion.triggered.connect(lambda: self._openWebsite(nw.__helpurl__))
self.helpMenu.addAction(self.aQuestion) self.helpMenu.addAction(self.aQuestion)
# Document > Latest Release # Document > Latest Release
self.aRelease = QAction(self.tr("Latest Release (GitHub)"), self) self.aRelease = QAction(self.tr("Latest Release (GitHub)"), self)
self.aRelease.setStatusTip( self.aRelease.setStatusTip(
self.tr("Open the Releases page on GitHub at {0}").format(nw.__releaseurl__)) self.tr("Open the Releases page on GitHub at {0}").format(nw.__releaseurl__)
)
self.aRelease.triggered.connect(lambda: self._openWebsite(nw.__releaseurl__)) self.aRelease.triggered.connect(lambda: self._openWebsite(nw.__releaseurl__))
self.helpMenu.addAction(self.aRelease) self.helpMenu.addAction(self.aRelease)
# Document > Main Website # Document > Main Website
self.aWebsite = QAction(self.tr("The novelWriter Website"), self) self.aWebsite = QAction(self.tr("The novelWriter Website"), self)
self.aWebsite.setStatusTip( self.aWebsite.setStatusTip(
self.tr("Open the novelWriter website at {0}").format(nw.__url__)) self.tr("Open the novelWriter website at {0}").format(nw.__url__)
)
self.aWebsite.triggered.connect(lambda: self._openWebsite(nw.__url__)) self.aWebsite.triggered.connect(lambda: self._openWebsite(nw.__url__))
self.helpMenu.addAction(self.aWebsite) self.helpMenu.addAction(self.aWebsite)
+5 -8
View File
@@ -29,12 +29,12 @@ import logging
from time import time from time import time
from PyQt5.QtCore import QCoreApplication, Qt, QSize from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QMenu, QAction, QAbstractItemView QTreeWidget, QTreeWidgetItem, QMenu, QAction, QAbstractItemView
) )
from nw.constants import nwKeyWords, nwLabels, nwOutline from nw.constants import trConst, nwKeyWords, nwLabels, nwOutline
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -149,8 +149,7 @@ class GuiOutline(QTreeWidget):
""" """
self.clear() self.clear()
self.setColumnCount(1) self.setColumnCount(1)
self.setHeaderLabel( self.setHeaderLabel(trConst(nwLabels.OUTLINE_COLS[nwOutline.TITLE]))
QCoreApplication.translate("Constant", nwLabels.OUTLINE_COLS[nwOutline.TITLE]))
self.treeOrder = [] self.treeOrder = []
self.colWidth = {} self.colWidth = {}
@@ -356,8 +355,7 @@ class GuiOutline(QTreeWidget):
if self.firstView: if self.firstView:
theLabels = [] theLabels = []
for i, hItem in enumerate(self.treeOrder): for i, hItem in enumerate(self.treeOrder):
theLabels.append( theLabels.append(trConst(nwLabels.OUTLINE_COLS[hItem]))
QCoreApplication.translate("Constant", nwLabels.OUTLINE_COLS[hItem]))
self.colIndex[hItem] = i self.colIndex[hItem] = i
self.setHeaderLabels(theLabels) self.setHeaderLabels(theLabels)
@@ -484,8 +482,7 @@ class GuiOutlineHeaderMenu(QMenu):
for hItem in nwOutline: for hItem in nwOutline:
if hItem == nwOutline.TITLE: if hItem == nwOutline.TITLE:
continue continue
self.actionMap[hItem] = QAction( self.actionMap[hItem] = QAction(trConst(nwLabels.OUTLINE_COLS[hItem]), self)
QCoreApplication.translate("Constant", nwLabels.OUTLINE_COLS[hItem]), self)
self.actionMap[hItem].setCheckable(True) self.actionMap[hItem].setCheckable(True)
self.actionMap[hItem].toggled.connect( self.actionMap[hItem].toggled.connect(
lambda isChecked, tItem=hItem : self._columnToggled(isChecked, tItem) lambda isChecked, tItem=hItem : self._columnToggled(isChecked, tItem)
+16 -24
View File
@@ -27,12 +27,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import nw import nw
import logging import logging
from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP, Qt from PyQt5.QtCore import Qt
from PyQt5.QtCore import QT_TRANSLATE_NOOP as QT_TRN
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QScrollArea, QWidget, QGridLayout, QHBoxLayout, QGroupBox, QLabel QScrollArea, QWidget, QGridLayout, QHBoxLayout, QGroupBox, QLabel
) )
from nw.constants import nwLabels, nwKeyWords from nw.constants import trConst, nwLabels, nwKeyWords
from nw.common import checkInt from nw.common import checkInt
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -40,10 +41,10 @@ logger = logging.getLogger(__name__)
class GuiOutlineDetails(QScrollArea): class GuiOutlineDetails(QScrollArea):
LVL_MAP = { LVL_MAP = {
"H1" : QT_TRANSLATE_NOOP("GuiOutlineDetails", "Title"), "H1" : QT_TRN("GuiOutlineDetails", "Title"),
"H2" : QT_TRANSLATE_NOOP("GuiOutlineDetails", "Chapter"), "H2" : QT_TRN("GuiOutlineDetails", "Chapter"),
"H3" : QT_TRANSLATE_NOOP("GuiOutlineDetails", "Scene"), "H3" : QT_TRN("GuiOutlineDetails", "Scene"),
"H4" : QT_TRANSLATE_NOOP("GuiOutlineDetails", "Section"), "H4" : QT_TRN("GuiOutlineDetails", "Section"),
} }
def __init__(self, theParent): def __init__(self, theParent):
@@ -104,24 +105,15 @@ class GuiOutlineDetails(QScrollArea):
self.synopLWrap.addWidget(self.synopValue, 1) self.synopLWrap.addWidget(self.synopValue, 1)
# Tags # Tags
self.povKeyLabel = QLabel("<b>%s</b>" % QCoreApplication.translate( self.povKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]))
"Constant", nwLabels.KEY_NAME[nwKeyWords.POV_KEY])) self.focKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY]))
self.focKeyLabel = QLabel("<b>%s</b>" % QCoreApplication.translate( self.chrKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY]))
"Constant", nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])) self.pltKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY]))
self.chrKeyLabel = QLabel("<b>%s</b>" % QCoreApplication.translate( self.timKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.TIME_KEY]))
"Constant", nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY])) self.wldKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY]))
self.pltKeyLabel = QLabel("<b>%s</b>" % QCoreApplication.translate( self.objKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY]))
"Constant", nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY])) self.entKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY]))
self.timKeyLabel = QLabel("<b>%s</b>" % QCoreApplication.translate( self.cstKeyLabel = QLabel("<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY]))
"Constant", nwLabels.KEY_NAME[nwKeyWords.TIME_KEY]))
self.wldKeyLabel = QLabel("<b>%s</b>" % QCoreApplication.translate(
"Constant", nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY]))
self.objKeyLabel = QLabel("<b>%s</b>" % QCoreApplication.translate(
"Constant", nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY]))
self.entKeyLabel = QLabel("<b>%s</b>" % QCoreApplication.translate(
"Constant", nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY]))
self.cstKeyLabel = QLabel("<b>%s</b>" % QCoreApplication.translate(
"Constant", nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY]))
self.povKeyLWrap = QHBoxLayout() self.povKeyLWrap = QHBoxLayout()
self.focKeyLWrap = QHBoxLayout() self.focKeyLWrap = QHBoxLayout()
+13 -9
View File
@@ -155,8 +155,11 @@ class GuiProjectDetailsMain(QWidget):
self.bookTitle.setAlignment(Qt.AlignHCenter) self.bookTitle.setAlignment(Qt.AlignHCenter)
self.bookTitle.setWordWrap(True) self.bookTitle.setWordWrap(True)
self.projName = QLabel(self.tr("{0}: {1}").format( self.projName = QLabel(
self.tr("Working Title"), self.theProject.projName)) self.tr("{0}: {1}").format(
self.tr("Working Title"), self.theProject.projName
)
)
workFont = self.projName.font() workFont = self.projName.font()
workFont.setPointSizeF(0.8*fPt) workFont.setPointSizeF(0.8*fPt)
workFont.setItalic(True) workFont.setItalic(True)
@@ -273,13 +276,14 @@ class GuiProjectDetailsContents(QWidget):
self.tocTree.setIndentation(0) self.tocTree.setIndentation(0)
self.tocTree.setColumnCount(6) self.tocTree.setColumnCount(6)
self.tocTree.setSelectionMode(QAbstractItemView.NoSelection) self.tocTree.setSelectionMode(QAbstractItemView.NoSelection)
self.tocTree.setHeaderLabels( self.tocTree.setHeaderLabels([
[self.tr("Title"), self.tr("Title"),
self.tr("Words"), self.tr("Words"),
self.tr("Pages"), self.tr("Pages"),
self.tr("Page"), self.tr("Page"),
self.tr("Progress"), self.tr("Progress"),
""]) ""
])
treeHeadItem = self.tocTree.headerItem() treeHeadItem = self.tocTree.headerItem()
treeHeadItem.setTextAlignment(self.C_WORDS, Qt.AlignRight) treeHeadItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
+6 -3
View File
@@ -192,7 +192,8 @@ class GuiProjectLoad(QDialog):
self, self.tr("Open novelWriter Project"), "", self, self.tr("Open novelWriter Project"), "",
";;".join([ ";;".join([
self.tr("{0} ({1})").format( self.tr("{0} ({1})").format(
self.tr("novelWriter Project File"), nwFiles.PROJ_FILE), self.tr("novelWriter Project File"), nwFiles.PROJ_FILE
),
self.tr("{0} ({1})").format(self.tr("All Files"), "*") self.tr("{0} ({1})").format(self.tr("All Files"), "*")
]), ]),
options=dlgOpt options=dlgOpt
@@ -233,8 +234,10 @@ class GuiProjectLoad(QDialog):
projName = selList[0].text(self.C_NAME) projName = selList[0].text(self.C_NAME)
msgYes = self.theParent.askQuestion( msgYes = self.theParent.askQuestion(
self.tr("Remove Entry"), self.tr("Remove Entry"),
self.tr("Remove '{0}' from the recent projects list? " self.tr(
"The project files will not be deleted.").format(projName) "Remove '{0}' from the recent projects list? "
"The project files will not be deleted."
).format(projName)
) )
if msgYes: if msgYes:
self.mainConf.removeFromRecentCache( self.mainConf.removeFromRecentCache(
+5 -3
View File
@@ -378,7 +378,8 @@ class GuiProjectEditStatus(QWidget):
self.colData[selIdx][4] self.colData[selIdx][4]
) )
selItem.setText(self.tr("{0} [{1}]").format( selItem.setText(self.tr("{0} [{1}]").format(
self.colData[selIdx][0], self.colCounts[selIdx])) self.colData[selIdx][0], self.colCounts[selIdx])
)
selItem.setIcon(self.colButton.icon()) selItem.setIcon(self.colButton.icon())
self.editName.setEnabled(False) self.editName.setEnabled(False)
self.colChanged = True self.colChanged = True
@@ -496,7 +497,8 @@ class GuiProjectEditReplace(QWidget):
self.bottomBox.addWidget(self.delButton) self.bottomBox.addWidget(self.delButton)
self.outerBox.addWidget( self.outerBox.addWidget(
QLabel("<b>%s</b>" % self.tr("Text Replace List for Preview and Export"))) QLabel("<b>%s</b>" % self.tr("Text Replace List for Preview and Export"))
)
self.outerBox.addWidget(self.listBox) self.outerBox.addWidget(self.listBox)
self.outerBox.addLayout(self.bottomBox) self.outerBox.addLayout(self.bottomBox)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
@@ -548,7 +550,7 @@ class GuiProjectEditReplace(QWidget):
saveKey = self._stripNotAllowed(newKey) saveKey = self._stripNotAllowed(newKey)
if len(saveKey) > 0 and len(newVal) > 0: if len(saveKey) > 0 and len(newVal) > 0:
selItem.setText(0, self.tr("<{0}>").format(saveKey)) selItem.setText(0, "<%s>" % saveKey)
selItem.setText(1, newVal) selItem.setText(1, newVal)
self.editKey.clear() self.editKey.clear()
self.editValue.clear() self.editValue.clear()
+16 -17
View File
@@ -30,7 +30,7 @@ import logging
from time import time from time import time
from PyQt5.QtCore import QCoreApplication, Qt, QSize, pyqtSignal from PyQt5.QtCore import Qt, QSize, pyqtSignal
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction
@@ -38,7 +38,8 @@ from PyQt5.QtWidgets import (
from nw.core import NWDoc from nw.core import NWDoc
from nw.constants import ( from nw.constants import (
nwLabels, nwItemType, nwItemClass, nwItemLayout, nwAlert, nwConst, nwLists trConst, nwLabels, nwItemType, nwItemClass, nwItemLayout, nwAlert,
nwConst, nwLists
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -214,8 +215,7 @@ class GuiProjectTree(QTreeWidget):
) )
if itemType == nwItemType.ROOT: if itemType == nwItemType.ROOT:
tHandle = self.theProject.newRoot( tHandle = self.theProject.newRoot(trConst(nwLabels.CLASS_NAME[itemClass]), itemClass)
QCoreApplication.translate("Constant", nwLabels.CLASS_NAME[itemClass]), itemClass)
if tHandle is None: if tHandle is None:
logger.error("No root item added") logger.error("No root item added")
return False return False
@@ -250,8 +250,7 @@ class GuiProjectTree(QTreeWidget):
if self.theProject.projTree.isTrashRoot(pHandle): if self.theProject.projTree.isTrashRoot(pHandle):
self.makeAlert( self.makeAlert(
self.tr("Cannot add new files or folders to the {0} folder.").format( self.tr("Cannot add new files or folders to the {0} folder.").format(
QCoreApplication.translate( trConst(nwLabels.CLASS_NAME[nwItemClass.TRASH])
"Constant", nwLabels.CLASS_NAME[nwItemClass.TRASH])
), nwAlert.ERROR ), nwAlert.ERROR
) )
return False return False
@@ -573,10 +572,10 @@ class GuiProjectTree(QTreeWidget):
self._deleteTreeItem(tHandle) self._deleteTreeItem(tHandle)
self._setTreeChanged(True) self._setTreeChanged(True)
else: else:
self.makeAlert(( self.makeAlert(self.tr(
self.tr("Cannot delete folder. It is not empty."), "Cannot delete folder. It is not empty. "
self.tr("Recursive deletion is not supported."), "Recursive deletion is not supported. "
self.tr("Please delete the content first."), "Please delete the content first."
), nwAlert.ERROR) ), nwAlert.ERROR)
return False return False
@@ -589,10 +588,10 @@ class GuiProjectTree(QTreeWidget):
self.theParent.mainMenu.setAvailableRoot() self.theParent.mainMenu.setAvailableRoot()
self._setTreeChanged(True) self._setTreeChanged(True)
else: else:
self.makeAlert(( self.makeAlert(self.tr(
self.tr("Cannot delete root folder. It is not empty."), "Cannot delete root folder. It is not empty. "
self.tr("Recursive deletion is not supported."), "Recursive deletion is not supported. "
self.tr("Please delete the content first."), "Please delete the content first."
), nwAlert.ERROR) ), nwAlert.ERROR)
return False return False
@@ -974,9 +973,9 @@ class GuiProjectTree(QTreeWidget):
self.addTopLevelItem(newItem) self.addTopLevelItem(newItem)
else: else:
self.makeAlert( self.makeAlert(
self.tr("There is nowhere to add item with name '{0}'").format( self.tr(
nwItem.itemName), "There is nowhere to add item with name '{0}'").format(nwItem.itemName
nwAlert.ERROR ), nwAlert.ERROR
) )
del self._treeMap[tHandle] del self._treeMap[tHandle]
return None return None
+42 -27
View File
@@ -28,7 +28,7 @@ import nw
import logging import logging
import os import os
from PyQt5.QtCore import QCoreApplication, Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QWizard, QWizardPage, QLabel, QVBoxLayout, QLineEdit, QPlainTextEdit, QWizard, QWizardPage, QLabel, QVBoxLayout, QLineEdit, QPlainTextEdit,
QPushButton, QFileDialog, QHBoxLayout, QRadioButton, QFormLayout, QPushButton, QFileDialog, QHBoxLayout, QRadioButton, QFormLayout,
@@ -36,7 +36,7 @@ from PyQt5.QtWidgets import (
) )
from nw.common import makeFileNameSafe from nw.common import makeFileNameSafe
from nw.constants import nwLabels, nwItemClass from nw.constants import trConst, nwLabels, nwItemClass
from nw.gui.custom import QSwitch from nw.gui.custom import QSwitch
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -96,10 +96,12 @@ class ProjWizardIntroPage(QWizardPage):
self.setTitle(self.tr("Create New Project")) self.setTitle(self.tr("Create New Project"))
self.theText = QLabel( self.theText = QLabel(
self.tr("Provide at least a working title. The working title should not " self.tr(
"be change beyond this point as it is used by the application for " "Provide at least a working title. The working title should not "
"generating file names for for instance backups. The other fields " "be change beyond this point as it is used by the application for "
"are optional and can be changed at any time in Project Settings.") "generating file names for for instance backups. The other fields "
"are optional and can be changed at any time in Project Settings."
)
) )
self.theText.setWordWrap(True) self.theText.setWordWrap(True)
@@ -166,8 +168,10 @@ class ProjWizardFolderPage(QWizardPage):
self.setTitle(self.tr("Select Project Folder")) self.setTitle(self.tr("Select Project Folder"))
self.theText = QLabel( self.theText = QLabel(
self.tr("Select a location to store the project. A new project folder " self.tr(
"will be created in the selected location.") "Select a location to store the project. A new project folder "
"will be created in the selected location."
)
) )
self.theText.setWordWrap(True) self.theText.setWordWrap(True)
@@ -240,9 +244,11 @@ class ProjWizardPopulatePage(QWizardPage):
self.setTitle(self.tr("Populate Project")) self.setTitle(self.tr("Populate Project"))
self.theText = QLabel( self.theText = QLabel(
self.tr("Choose how to pre-fill the project. Either with a minimal set of " self.tr(
"starter items, an example project explaining and showing many of " "Choose how to pre-fill the project. Either with a minimal set of "
"the features, or show further custom options on the next page.") "starter items, an example project explaining and showing many of "
"the features, or show further custom options on the next page."
)
) )
self.theText.setWordWrap(True) self.theText.setWordWrap(True)
@@ -295,9 +301,11 @@ class ProjWizardCustomPage(QWizardPage):
self.setTitle(self.tr("Custom Project Options")) self.setTitle(self.tr("Custom Project Options"))
self.theText = QLabel( self.theText = QLabel(
self.tr("Select which additional root folders to make, and how to populate " self.tr(
"the Novel folder. If you don't want to add chapters or scenes, set " "Select which additional root folders to make, and how to populate "
"the values to 0. You can add scenes without chapters.") "the Novel folder. If you don't want to add chapters or scenes, set "
"the values to 0. You can add scenes without chapters."
)
) )
self.theText.setWordWrap(True) self.theText.setWordWrap(True)
@@ -308,18 +316,24 @@ class ProjWizardCustomPage(QWizardPage):
self.rootForm = QGridLayout() self.rootForm = QGridLayout()
self.rootGroup.setLayout(self.rootForm) self.rootGroup.setLayout(self.rootForm)
self.lblPlot = QLabel(self.tr("{0} folder").format( self.lblPlot = QLabel(self.tr("{0} folder").format(
QCoreApplication.translate("Constant", nwLabels.CLASS_NAME[nwItemClass.PLOT]))) trConst(nwLabels.CLASS_NAME[nwItemClass.PLOT]))
self.lblChar = QLabel(self.tr("{0} folder").format( )
QCoreApplication.translate("Constant", nwLabels.CLASS_NAME[nwItemClass.CHARACTER]))) self.lblChar = QLabel(self.tr("{0} folder").format(
self.lblWorld = QLabel(self.tr("{0} folder").format( trConst(nwLabels.CLASS_NAME[nwItemClass.CHARACTER]))
QCoreApplication.translate("Constant", nwLabels.CLASS_NAME[nwItemClass.WORLD]))) )
self.lblTime = QLabel(self.tr("{0} folder").format( self.lblWorld = QLabel(self.tr("{0} folder").format(
QCoreApplication.translate("Constant", nwLabels.CLASS_NAME[nwItemClass.TIMELINE]))) trConst(nwLabels.CLASS_NAME[nwItemClass.WORLD]))
)
self.lblTime = QLabel(self.tr("{0} folder").format(
trConst(nwLabels.CLASS_NAME[nwItemClass.TIMELINE]))
)
self.lblObject = QLabel(self.tr("{0} folder").format( self.lblObject = QLabel(self.tr("{0} folder").format(
QCoreApplication.translate("Constant", nwLabels.CLASS_NAME[nwItemClass.OBJECT]))) trConst(nwLabels.CLASS_NAME[nwItemClass.OBJECT]))
)
self.lblEntity = QLabel(self.tr("{0} folder").format( self.lblEntity = QLabel(self.tr("{0} folder").format(
QCoreApplication.translate("Constant", nwLabels.CLASS_NAME[nwItemClass.ENTITY]))) trConst(nwLabels.CLASS_NAME[nwItemClass.ENTITY]))
)
self.addPlot = QSwitch() self.addPlot = QSwitch()
self.addChar = QSwitch() self.addChar = QSwitch()
@@ -407,9 +421,10 @@ class ProjWizardFinalPage(QWizardPage):
self.setTitle(self.tr("Finished")) self.setTitle(self.tr("Finished"))
self.theText = QLabel("".join([ self.theText = QLabel("".join([
("<p>%s</p>" % self.tr("All done.")), "<p>%s</p>" % self.tr("All done."),
("<p>%s</p>" % self.tr("Press '{0}' to create the new project.").format( "<p>%s</p>" % self.tr("Press '{0}' to create the new project.").format(
self.tr("Done") if self.mainConf.osDarwin else self.tr("Finish"))) self.tr("Done") if self.mainConf.osDarwin else self.tr("Finish")
)
])) ]))
self.theText.setWordWrap(True) self.theText.setWordWrap(True)
+9 -4
View File
@@ -31,8 +31,9 @@ import configparser
import os import os
from math import ceil from math import ceil
from functools import partial
from PyQt5.QtCore import Qt from PyQt5.QtCore import QCoreApplication, Qt
from PyQt5.QtWidgets import QStyle, qApp from PyQt5.QtWidgets import QStyle, qApp
from PyQt5.QtGui import ( from PyQt5.QtGui import (
QPalette, QColor, QIcon, QFont, QFontMetrics, QFontDatabase, QPixmap QPalette, QColor, QIcon, QFont, QFontMetrics, QFontDatabase, QPixmap
@@ -157,6 +158,10 @@ class GuiTheme:
logger.verbose("Text 'N' Height: %d" % self.textNHeight) logger.verbose("Text 'N' Height: %d" % self.textNHeight)
logger.verbose("Text 'N' Width: %d" % self.textNWidth) logger.verbose("Text 'N' Width: %d" % self.textNWidth)
# Internal Mapping
self.makeAlert = self.theParent.makeAlert
self.tr = partial(QCoreApplication.translate, "GuiTheme")
return return
## ##
@@ -392,7 +397,7 @@ class GuiTheme:
with open(themeConf, mode="r", encoding="utf8") as inFile: with open(themeConf, mode="r", encoding="utf8") as inFile:
confParser.read_file(inFile) confParser.read_file(inFile)
except Exception as e: except Exception as e:
self.theParent.makeAlert( self.makeAlert(
[self.tr("Could not load theme config file."), str(e)], nwAlert.ERROR [self.tr("Could not load theme config file."), str(e)], nwAlert.ERROR
) )
continue continue
@@ -425,7 +430,7 @@ class GuiTheme:
with open(syntaxPath, mode="r", encoding="utf8") as inFile: with open(syntaxPath, mode="r", encoding="utf8") as inFile:
confParser.read_file(inFile) confParser.read_file(inFile)
except Exception as e: except Exception as e:
self.theParent.makeAlert( self.makeAlert(
[self.tr("Could not load syntax file."), str(e)], nwAlert.ERROR [self.tr("Could not load syntax file."), str(e)], nwAlert.ERROR
) )
return [] return []
@@ -740,7 +745,7 @@ class GuiIcons:
with open(themeConf, mode="r", encoding="utf8") as inFile: with open(themeConf, mode="r", encoding="utf8") as inFile:
confParser.read_file(inFile) confParser.read_file(inFile)
except Exception as e: except Exception as e:
self.theParent.makeAlert( self.makeAlert(
[self.tr("Could not load theme config file."), str(e)], nwAlert.ERROR [self.tr("Could not load theme config file."), str(e)], nwAlert.ERROR
) )
continue continue
+15 -6
View File
@@ -159,18 +159,27 @@ class GuiWritingStats(QDialog):
self.totalWords.setFont(self.theTheme.guiFontFixed) self.totalWords.setFont(self.theTheme.guiFontFixed)
self.totalWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight) self.totalWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.infoForm.addWidget(QLabel(self.tr("{0}:").format(self.tr("Total Time"))), 0, 0) lblTTime = QLabel(self.tr("{0}:").format(self.tr("Total Time")))
self.infoForm.addWidget(QLabel(self.tr("{0}:").format(self.tr("Idle Time"))), 1, 0) lblITime = QLabel(self.tr("{0}:").format(self.tr("Idle Time")))
self.infoForm.addWidget(QLabel(self.tr("{0}:").format(self.tr("Filtered Time"))), 2, 0) lblFTime = QLabel(self.tr("{0}:").format(self.tr("Filtered Time")))
self.infoForm.addWidget(QLabel(self.tr("{0}:").format(self.tr("Novel Word Count"))), 3, 0) lblNvCount = QLabel(self.tr("{0}:").format(self.tr("Novel Word Count")))
self.infoForm.addWidget(QLabel(self.tr("{0}:").format(self.tr("Notes Word Count"))), 4, 0) lblNtCount = QLabel(self.tr("{0}:").format(self.tr("Notes Word Count")))
self.infoForm.addWidget(QLabel(self.tr("{0}:").format(self.tr("Total Word Count"))), 5, 0) lblTtCount = QLabel(self.tr("{0}:").format(self.tr("Total Word Count")))
self.infoForm.addWidget(lblTTime, 0, 0)
self.infoForm.addWidget(lblITime, 1, 0)
self.infoForm.addWidget(lblFTime, 2, 0)
self.infoForm.addWidget(lblNvCount, 3, 0)
self.infoForm.addWidget(lblNtCount, 4, 0)
self.infoForm.addWidget(lblTtCount, 5, 0)
self.infoForm.addWidget(self.labelTotal, 0, 1) self.infoForm.addWidget(self.labelTotal, 0, 1)
self.infoForm.addWidget(self.labelIdleT, 1, 1) self.infoForm.addWidget(self.labelIdleT, 1, 1)
self.infoForm.addWidget(self.labelFilter, 2, 1) self.infoForm.addWidget(self.labelFilter, 2, 1)
self.infoForm.addWidget(self.novelWords, 3, 1) self.infoForm.addWidget(self.novelWords, 3, 1)
self.infoForm.addWidget(self.notesWords, 4, 1) self.infoForm.addWidget(self.notesWords, 4, 1)
self.infoForm.addWidget(self.totalWords, 5, 1) self.infoForm.addWidget(self.totalWords, 5, 1)
self.infoForm.setRowStretch(6, 1) self.infoForm.setRowStretch(6, 1)
# Filter Options # Filter Options
+46 -27
View File
@@ -358,9 +358,10 @@ class GuiMain(QMainWindow):
if os.path.isfile(os.path.join(projPath, self.theProject.projFile)): if os.path.isfile(os.path.join(projPath, self.theProject.projFile)):
self.makeAlert( self.makeAlert(
self.tr("A project already exists in that location. " self.tr(
"Please choose another folder."), "A project already exists in that location. "
nwAlert.ERROR "Please choose another folder."
), nwAlert.ERROR
) )
return False return False
@@ -394,8 +395,10 @@ class GuiMain(QMainWindow):
if not isYes: if not isYes:
msgYes = self.askQuestion( msgYes = self.askQuestion(
self.tr("Close Project"), self.tr("Close Project"),
"%s<br>%s" % (self.tr("Close the current project?"), "%s<br>%s" % (
self.tr("Changes are saved automatically.")) self.tr("Close the current project?"),
self.tr("Changes are saved automatically.")
)
) )
if not msgYes: if not msgYes:
return False return False
@@ -461,9 +464,11 @@ class GuiMain(QMainWindow):
try: try:
lockDetails = ( lockDetails = (
"<br>%s" % self.tr("The project was locked by the computer " "<br>%s" % self.tr(
"'{computer_name}' ({os_name} {os_version}), " "The project was locked by the computer "
"last active on {time}") "'{computer_name}' ({os_name} {os_version}), "
"last active on {time}"
)
).format( ).format(
computer_name = self.theProject.lockedBy[0], computer_name = self.theProject.lockedBy[0],
os_name = self.theProject.lockedBy[1], os_name = self.theProject.lockedBy[1],
@@ -479,12 +484,16 @@ class GuiMain(QMainWindow):
msgRes = msgBox.warning( msgRes = msgBox.warning(
self, self.tr("Project Locked"), self, self.tr("Project Locked"),
"%s<br><br>%s<br>%s" % ( "%s<br><br>%s<br>%s" % (
self.tr("The project is already open by another instance of novelWriter, and " self.tr(
"is therefore locked. Override lock and continue anyway?"), "The project is already open by another instance of novelWriter, and "
self.tr("Note: If the program or the computer previously crashed, the lock " "is therefore locked. Override lock and continue anyway?"
"can safely be overridden. If, however, another instance of " ),
"novelWriter has the project open, overriding the lock may corrupt " self.tr(
"the project, and is not recommended."), "Note: If the program or the computer previously crashed, the lock "
"can safely be overridden. If, however, another instance of "
"novelWriter has the project open, overriding the lock may corrupt "
"the project, and is not recommended."
),
lockDetails lockDetails
), ),
QMessageBox.Yes | QMessageBox.No, QMessageBox.No QMessageBox.Yes | QMessageBox.No, QMessageBox.No
@@ -732,10 +741,13 @@ class GuiMain(QMainWindow):
return False return False
if not self.docEditor.isEmpty(): if not self.docEditor.isEmpty():
msgYes = self.askQuestion(self.tr("Import Document"), ( msgYes = self.askQuestion(
self.tr("Importing the file will overwrite the current content of the document. " self.tr("Import Document"),
"Do you want to proceed?") self.tr(
)) "Importing the file will overwrite the current content of the document. "
"Do you want to proceed?"
)
)
if not msgYes: if not msgYes:
return False return False
@@ -874,9 +886,12 @@ class GuiMain(QMainWindow):
if tItem is not None: if tItem is not None:
self.setStatus(self.tr("{0}: '{1}'").format(self.tr("Indexing"), tItem.itemName)) self.setStatus(self.tr("{0}: '{1}'").format(self.tr("Indexing"), tItem.itemName))
else: else:
self.setStatus(self.tr("{0}: {1}").format( self.setStatus(
self.tr("Indexing"), self.tr("{0}: {1}").format(
self.tr("Unknown item"))) self.tr("Indexing"),
self.tr("Unknown item")
)
)
if tItem is not None and tItem.itemType == nwItemType.FILE: if tItem is not None and tItem.itemType == nwItemType.FILE:
logger.verbose("Scanning: %s" % tItem.itemName) logger.verbose("Scanning: %s" % tItem.itemName)
@@ -894,14 +909,16 @@ class GuiMain(QMainWindow):
self.treeView.projectWordCount() self.treeView.projectWordCount()
tEnd = time() tEnd = time()
self.setStatus(self.tr("Indexing completed in {0} ms"). self.setStatus(
format(f"{(tEnd - tStart)*1000.0:.1f}")) self.tr("Indexing completed in {0} ms").format(f"{(tEnd - tStart)*1000.0:.1f}")
)
self.docEditor.updateTagHighLighting() self.docEditor.updateTagHighLighting()
qApp.restoreOverrideCursor() qApp.restoreOverrideCursor()
if not beQuiet: if not beQuiet:
self.makeAlert(self.tr("The project index has been successfully rebuilt."), self.makeAlert(
nwAlert.INFO) self.tr("The project index has been successfully rebuilt."), nwAlert.INFO
)
return True return True
@@ -1153,8 +1170,10 @@ class GuiMain(QMainWindow):
if self.hasProject: if self.hasProject:
msgYes = self.askQuestion( msgYes = self.askQuestion(
self.tr("Exit"), self.tr("Exit"),
"%s<br>%s" % (self.tr("Do you want to exit novelWriter?"), "%s<br>%s" % (
self.tr("Changes are saved automatically.")) self.tr("Do you want to exit novelWriter?"),
self.tr("Changes are saved automatically.")
)
) )
if not msgYes: if not msgYes:
return False return False
+4 -4
View File
@@ -1,13 +1,13 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.2b1" hexVersion="0x010200b1" fileVersion="1.2" timeStamp="2021-02-11 17:04:25"> <novelWriterXML appVersion="1.3a0" hexVersion="0x010300a0" fileVersion="1.2" timeStamp="2021-02-15 16:31:16">
<project> <project>
<name>Sample Project</name> <name>Sample Project</name>
<title>Sample Project</title> <title>Sample Project</title>
<author>Jane Smith</author> <author>Jane Smith</author>
<author>Jay Doh</author> <author>Jay Doh</author>
<saveCount>936</saveCount> <saveCount>1019</saveCount>
<autoCount>161</autoCount> <autoCount>161</autoCount>
<editTime>46791</editTime> <editTime>48272</editTime>
</project> </project>
<settings> <settings>
<doBackup>False</doBackup> <doBackup>False</doBackup>
@@ -120,7 +120,7 @@
<charCount>1810</charCount> <charCount>1810</charCount>
<wordCount>318</wordCount> <wordCount>318</wordCount>
<paraCount>8</paraCount> <paraCount>8</paraCount>
<cursorPos>3</cursorPos> <cursorPos>1112</cursorPos>
</item> </item>
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a"> <item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
<name>Another Scene</name> <name>Another Scene</name>