Merge branch 'release'

This commit is contained in:
Veronica Berglyd Olsen
2024-05-02 21:16:42 +02:00
7 changed files with 108 additions and 167 deletions
+36 -95
View File
@@ -2198,57 +2198,57 @@
<context>
<name>GuiManuscriptBuild</name>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
<source>Build Manuscript</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
<source>Output Format</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
<source>Table of Contents</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
<source>Path</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
<source>File Name</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
<source>Reset file name to default</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
<source>Open Folder</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
<source>&amp;Build</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
<source>Select Folder</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
<source>Output folder does not exist.</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
<source>The file already exists. Do you want to overwrite it?</source>
<translation type="unfinished" />
</message>
@@ -2415,7 +2415,7 @@
<context>
<name>GuiOutlineToolBar</name>
<message>
<location filename="../novelwriter/gui/outline.py" line="223" />
<location filename="../novelwriter/gui/outline.py" line="222" />
<source>Outline of</source>
<translation type="unfinished" />
</message>
@@ -3860,65 +3860,6 @@
<translation type="unfinished" />
</message>
</context>
<context>
<name>QWizard</name>
<message>
<location filename="qtbase.py" line="54" />
<source>Go Back</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="55" />
<source>&lt; &amp;Back</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="56" />
<source>Continue</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="57" />
<source>&amp;Next</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="58" />
<source>&amp;Next &gt;</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="59" />
<source>Commit</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="60" />
<source>Done</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="61" />
<source>&amp;Finish</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="63" />
<location filename="qtbase.py" line="62" />
<source>Cancel</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="64" />
<source>Help</source>
<translation type="unfinished" />
</message>
<message>
<location filename="qtbase.py" line="65" />
<source>&amp;Help</source>
<translation type="unfinished" />
</message>
</context>
<context>
<name>SharedData</name>
<message>
@@ -4041,32 +3982,32 @@
<context>
<name>_DetailsWidget</name>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="522" />
<location filename="../novelwriter/tools/manuscript.py" line="533" />
<source>Setting</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="522" />
<location filename="../novelwriter/tools/manuscript.py" line="533" />
<source>Value</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="589" />
<location filename="../novelwriter/tools/manuscript.py" line="600" />
<source>Name</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="595" />
<location filename="../novelwriter/tools/manuscript.py" line="606" />
<source>Selection</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="611" />
<location filename="../novelwriter/tools/manuscript.py" line="622" />
<source>Title</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="612" />
<location filename="../novelwriter/tools/manuscript.py" line="623" />
<source>Hidden</source>
<translation type="unfinished" />
</message>
@@ -4438,27 +4379,27 @@
<context>
<name>_PreviewWidget</name>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="757" />
<location filename="../novelwriter/tools/manuscript.py" line="769" />
<source>Press the "Preview" button to generate ...</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="855" />
<location filename="../novelwriter/tools/manuscript.py" line="867" />
<source>Processing ...</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="877" />
<location filename="../novelwriter/tools/manuscript.py" line="888" />
<source>Done</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="927" />
<location filename="../novelwriter/tools/manuscript.py" line="938" />
<source>Unknown</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="928" />
<location filename="../novelwriter/tools/manuscript.py" line="939" />
<source>Built</source>
<translation type="unfinished" />
</message>
@@ -4557,59 +4498,59 @@
<context>
<name>_StatsWidget</name>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
<source>Words</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
<source>Characters</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
<source>Words in Headings</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
<source>Words in Text</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
<source>Headings</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
<source>Paragraphs</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
<source>Characters in Headings</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
<source>Characters in Text</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
<source>Characters, No Spaces</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
<source>Characters in Headings, No Spaces</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
<source>Characters in Text, No Spaces</source>
<translation type="unfinished" />
</message>
-16
View File
@@ -47,19 +47,3 @@ QT_TRANSLATE_NOOP("QPlatformTheme", "Help")
QT_TRANSLATE_NOOP("QPlatformTheme", "Apply")
QT_TRANSLATE_NOOP("QPlatformTheme", "Reset")
QT_TRANSLATE_NOOP("QPlatformTheme", "Restore Defaults")
# QWizard
# =======
QT_TRANSLATE_NOOP("QWizard", "Go Back")
QT_TRANSLATE_NOOP("QWizard", "< &Back")
QT_TRANSLATE_NOOP("QWizard", "Continue")
QT_TRANSLATE_NOOP("QWizard", "&Next")
QT_TRANSLATE_NOOP("QWizard", "&Next >")
QT_TRANSLATE_NOOP("QWizard", "Commit")
QT_TRANSLATE_NOOP("QWizard", "Done")
QT_TRANSLATE_NOOP("QWizard", "&Finish")
QT_TRANSLATE_NOOP("QWizard", "Cancel")
QT_TRANSLATE_NOOP("QWizard", "Cancel")
QT_TRANSLATE_NOOP("QWizard", "Help")
QT_TRANSLATE_NOOP("QWizard", "&Help")
+16 -4
View File
@@ -26,21 +26,21 @@ from __future__ import annotations
import logging
from pathlib import Path
from time import time
from typing import TYPE_CHECKING, TypeVar
from pathlib import Path
from PyQt5.QtCore import QObject, QRunnable, QThreadPool, QTimer, pyqtSignal
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QWidget
from novelwriter.common import formatFileFilter
from novelwriter.common import formatFileFilter
from novelwriter.constants import nwFiles
from novelwriter.core.spellcheck import NWSpellEnchant
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
from novelwriter.gui.theme import GuiTheme
from novelwriter.core.project import NWProject
from novelwriter.gui.theme import GuiTheme
from novelwriter.guimain import GuiMain
logger = logging.getLogger(__name__)
@@ -198,6 +198,7 @@ class SharedData(QObject):
def closeProject(self) -> None:
"""Close the current project."""
self._closeDialogs()
self.project.closeProject(self._idleTime)
self._resetProject()
self._resetIdleTimer()
@@ -356,6 +357,17 @@ class SharedData(QObject):
self._idleTime = 0.0
return
def _closeDialogs(self) -> None:
"""Close non-modal dialogs."""
from novelwriter.tools.manuscript import GuiManuscript
from novelwriter.tools.writingstats import GuiWritingStats
for widget in self.mainGui.children():
if isinstance(widget, (GuiManuscript, GuiWritingStats)):
widget.close()
return
# END Class SharedData
+4 -3
View File
@@ -44,9 +44,7 @@ from novelwriter.core.item import NWItem
from novelwriter.enum import nwBuildFmt
from novelwriter.extensions.modified import NIconToolButton
from novelwriter.extensions.simpleprogress import NProgressSimple
from novelwriter.types import (
QtAlignCenter, QtDialogClose, QtRoleAction, QtRoleReject, QtUserRole
)
from novelwriter.types import QtAlignCenter, QtDialogClose, QtRoleAction, QtRoleReject, QtUserRole
logger = logging.getLogger(__name__)
@@ -328,6 +326,9 @@ class GuiManuscriptBuild(QDialog):
):
return False
# Make sure editor content is saved before we start
SHARED.mainGui.saveDocument()
docBuild = NWBuildDocument(SHARED.project, self._build)
docBuild.queueAll()
+9 -5
View File
@@ -334,6 +334,9 @@ class GuiManuscript(NToolDialog):
if not (build := self._getSelectedBuild()):
return
# Make sure editor content is saved before we start
SHARED.mainGui.saveDocument()
docBuild = NWBuildDocument(SHARED.project, build)
docBuild.setPreviewMode(True)
docBuild.queueAll()
@@ -737,6 +740,7 @@ class _PreviewWidget(QTextBrowser):
self._docTime = 0
self._buildName = ""
self._scrollPos = 0
# Document Setup
dPalette = self.palette()
@@ -833,6 +837,7 @@ class _PreviewWidget(QTextBrowser):
self.buildProgress.setValue(0)
self.buildProgress.setCentreText(None)
self.buildProgress.setVisible(True)
self._scrollPos = self.verticalScrollBar().value()
self.setPlaceholderText("")
self.clear()
return
@@ -845,7 +850,6 @@ class _PreviewWidget(QTextBrowser):
def setContent(self, data: dict) -> None:
"""Set the content of the preview widget."""
sPos = self.verticalScrollBar().value()
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
self.buildProgress.setCentreText(self.tr("Processing ..."))
@@ -862,7 +866,6 @@ class _PreviewWidget(QTextBrowser):
cursor = self.textCursor()
cursor.insertText("\t")
self.verticalScrollBar().setValue(sPos)
self._docTime = checkInt(data.get("time"), 0)
self._updateBuildAge()
@@ -873,7 +876,7 @@ class _PreviewWidget(QTextBrowser):
self.buildProgress.setCentreText(self.tr("Done"))
QApplication.restoreOverrideCursor()
QApplication.processEvents()
QTimer.singleShot(300, self._hideProgress)
QTimer.singleShot(300, self._postUpdate)
return
@@ -928,9 +931,10 @@ class _PreviewWidget(QTextBrowser):
return
@pyqtSlot()
def _hideProgress(self) -> None:
"""Clean up the build progress bar."""
def _postUpdate(self) -> None:
"""Run tasks after content update."""
self.buildProgress.setVisible(False)
self.verticalScrollBar().setValue(self._scrollPos)
return
##
+33 -33
View File
@@ -25,13 +25,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import os
import sys
import shutil
import zipfile
import datetime
import subprocess
import email.utils
import os
import shutil
import subprocess
import sys
import zipfile
from pathlib import Path
@@ -328,59 +328,59 @@ def buildQtI18nTS(sysArgs: list[str]) -> None:
print("Scanning Source Tree:")
print("")
srcList = [os.path.join("i18n", "qtbase.py")]
for nRoot, _, nFiles in os.walk("novelwriter"):
if os.path.isdir(nRoot):
for aFile in nFiles:
aPath = os.path.join(nRoot, aFile)
if os.path.isfile(aPath) and aFile.endswith(".py"):
srcList.append(aPath)
sources = [os.path.join("i18n", "qtbase.py")]
for root, _, files in os.walk("novelwriter"):
if os.path.isdir(root):
for file in files:
source = os.path.join(root, file)
if os.path.isfile(source) and file.endswith(".py"):
sources.append(source)
for aSource in srcList:
print(aSource)
for source in sources:
print(source)
print("")
print("TS Files to Update:")
print("")
tsList = []
translations = []
if len(sysArgs) >= 2:
for anArg in sysArgs[1:]:
if not (anArg.startswith("i18n") and anArg.endswith(".ts")):
for arg in sysArgs[1:]:
if not (arg.startswith("i18n") and arg.endswith(".ts")):
continue
fName = os.path.basename(anArg)
if not fName.startswith("nw_") and len(fName) > 6:
print("Skipping non-novelWriter TS file %s" % fName)
file = os.path.basename(arg)
if not file.startswith("nw_") and len(file) > 6:
print("Skipping non-novelWriter TS file %s" % file)
continue
if os.path.isfile(anArg):
tsList.append(anArg)
elif os.path.exists(anArg):
if os.path.isfile(arg):
translations.append(arg)
elif os.path.exists(arg):
pass
else: # Create an empty new language file
lCode = fName[3:-3]
writeFile(anArg, (
langCode = file[3:-3]
writeFile(arg, (
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<!DOCTYPE TS>\n"
f"<TS version=\"2.0\" language=\"{lCode}\" sourcelanguage=\"en_GB\"/>\n"
f"<TS version=\"2.0\" language=\"{langCode}\" sourcelanguage=\"en_GB\"/>\n"
))
tsList.append(anArg)
translations.append(arg)
else:
print("No translation files selected for update ...")
print("")
return
for aTS in tsList:
print(aTS)
for translation in translations:
print(translation)
print("")
print("Updating Language Files:")
print("")
# Using the pylupdate tool from PyQt6 as it supports TS file format 2.1.
lupdate(srcList, tsList, no_obsolete=True, no_summary=False)
lupdate(sources, translations, no_obsolete=True, no_summary=False)
print("")
@@ -561,7 +561,7 @@ def importI18nUpdates(sysArgs: list[str]) -> None:
def makeWindowsZip() -> None:
"""Pack the core source file in a single zip file."""
from zipfile import ZipFile, ZIP_DEFLATED
from zipfile import ZIP_DEFLATED, ZipFile
print("")
print("Building Windows ZIP File")
@@ -881,8 +881,8 @@ def makeForLaunchpad(doSign: bool = False, isFirst: bool = False) -> None:
def makeAppImage(sysArgs: list[str]) -> list[str]:
"""Build an AppImage."""
import glob
import argparse
import glob
try:
import python_appimage # noqa: F401 # type: ignore
@@ -1092,9 +1092,9 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
"""Set up a package with embedded Python and dependencies for
Windows installation.
"""
import compileall
import urllib.request
import zipfile
import compileall
print("")
print("Build Standalone Windows Package")
+10 -11
View File
@@ -22,29 +22,26 @@ from __future__ import annotations
import sys
from pathlib import Path
import pytest
from mocked import causeOSError
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtPrintSupport import QPrintPreviewDialog
from PyQt5.QtWidgets import QAction, QListWidgetItem
from pytestqt.qtbot import QtBot
from tools import C, buildTestProject
from novelwriter import CONFIG, SHARED
from novelwriter.constants import nwHeadFmt
from novelwriter.core.buildsettings import BuildSettings
from novelwriter.guimain import GuiMain
from novelwriter.tools.manusbuild import GuiManuscriptBuild
from novelwriter.tools.manuscript import GuiManuscript
from novelwriter.tools.manussettings import GuiBuildSettings
from novelwriter.types import QtAlignAbsolute, QtAlignJustify, QtDialogApply, QtDialogSave
from tests.mocked import causeOSError
from tests.tools import C, buildTestProject
@pytest.mark.gui
def testManuscript_Init(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd):
def testManuscript_Init(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
"""Test the init/main functionality of the GuiManuscript dialog."""
buildTestProject(nwGUI, projPath)
nwGUI.openProject(projPath)
@@ -81,7 +78,9 @@ def testManuscript_Init(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: Pat
manus.show()
manus.loadContent()
assert manus.docPreview.toPlainText().strip() == ""
manus.close()
nwGUI.closeProject() # This should auto-close the manuscript tool
assert manus.isHidden()
# qtbot.stop()
@@ -89,7 +88,7 @@ def testManuscript_Init(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: Pat
@pytest.mark.gui
def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path):
def testManuscript_Builds(qtbot, nwGUI, projPath):
"""Test the handling of builds in the GuiManuscript dialog."""
buildTestProject(nwGUI, projPath)
nwGUI.openProject(projPath)
@@ -278,7 +277,7 @@ def testManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
assert manus.docPreview.document().defaultTextOption().alignment() == QtAlignAbsolute
# Tests are too fast to trigger this one, so we trigger it manually to ensure it isn't failing
manus.docPreview._hideProgress()
manus.docPreview._postUpdate()
# Builds
# ======
@@ -306,7 +305,7 @@ def testManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
@pytest.mark.gui
@pytest.mark.skipif(sys.platform.startswith("darwin"), reason="Not running on Darwin")
def testManuscript_Print(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: Path):
def testManuscript_Print(monkeypatch, qtbot, nwGUI, projPath):
"""Test the print feature of the GuiManuscript dialog."""
buildTestProject(nwGUI, projPath)
nwGUI.openProject(projPath)