Merge pull request #508 from vkbo/latest_release

Release Notes
This commit is contained in:
Veronica K. Berglyd Olsen
2020-11-24 20:14:55 +01:00
committed by GitHub
9 changed files with 113 additions and 18 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
# novelWriter ChangeLog # novelWriter Change Log
## Version 1.0 Release Candidate 1 [2020-11-16] ## Version 1.0 Release Candidate 1 [2020-11-16]
+35
View File
@@ -0,0 +1,35 @@
<!DOCTYPE html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
<h2>Release Notes for 1.0 RC1</h2>
<p>This is the first release candidate for the upcoming release of novelWriter 1.0.</p>
<p>Since the fifth beta release about four weeks ago, not much has been changed in novelWriter. A
few minor tweaks have been made to the GUI.</p>
<p>A number of features and tools are now automatically switched off when there is no project or
document open for those features to act upon. Previously, this was a bit inconsistent, although no
serious bugs have been reported or encountered.</p>
<p>Most of the minor changes in this release should not be noticeable to most users. However, there
are a couple of noticeable changes.</p>
<h3>Typewriter Mode</h3>
<p>The "Typewriter Mode" of the editor has been improved. Essentially, this feature is a sort of
smart scroll. It tries to keep the cursor stationary in the vertical direction, and will try to
scroll the document up when the cursor skips to a new line while typing (or down in case of
backspaces). This is similar to the way a typewriter scrolls the paper when hitting the return key.
It improves the writing experience as the current active line will stay at the same eye height
level on the screen.</p>
<p>Previously, the feature would lock the cursor to a given vertical position defined by the user.
Now, instead, the cursor will remain stationary in the vertical direction at any position the user
sets it to by mouse click or keyboard navigation. The user can define a minimum distance from the
top where this feature is activated. These changes makes it more flexible in terms of where the
focus is in the editor. The feature can be controlled from the main Preferences.</p>
<h3>Switching Syntax Theme</h3>
<p>It is now possible to switch syntax highlighting theme without restarting novelWriter.
Previously, changing the theme would only half-way update the document, header and footer
background and text colours. The new settings would not be fully applied until the application was
shut down and started again, thus making it a bit tedious to look through syntax themes to find the
one you want.</p>
<p>Switching main GUI theme still requires a restart.</p>
<p><i>The full changelog is available
<a href="https://github.com/vkbo/novelWriter/blob/main/CHANGELOG.md">here</a>.</i></p>
</body>
</html>
+5
View File
@@ -91,6 +91,7 @@ class Config:
self.guiFont = "" # Defaults to system default font self.guiFont = "" # Defaults to system default font
self.guiFontSize = 11 self.guiFontSize = 11
self.guiScale = 1.0 # Set automatically by Theme class self.guiScale = 1.0 # Set automatically by Theme class
self.lastNotes = "" # The latest release notes that have been shown
## Sizes ## Sizes
self.winGeometry = [1200, 650] self.winGeometry = [1200, 650]
@@ -380,6 +381,9 @@ class Config:
self.guiFontSize = self._parseLine( self.guiFontSize = self._parseLine(
cnfParse, cnfSec, "guifontsize", self.CNF_INT, self.guiFontSize cnfParse, cnfSec, "guifontsize", self.CNF_INT, self.guiFontSize
) )
self.lastNotes = self._parseLine(
cnfParse, cnfSec, "lastnotes", self.CNF_STR, self.lastNotes
)
## Sizes ## Sizes
cnfSec = "Sizes" cnfSec = "Sizes"
@@ -584,6 +588,7 @@ class Config:
cnfParse.set(cnfSec, "guidark", str(self.guiDark)) cnfParse.set(cnfSec, "guidark", str(self.guiDark))
cnfParse.set(cnfSec, "guifont", str(self.guiFont)) cnfParse.set(cnfSec, "guifont", str(self.guiFont))
cnfParse.set(cnfSec, "guifontsize", str(self.guiFontSize)) cnfParse.set(cnfSec, "guifontsize", str(self.guiFontSize))
cnfParse.set(cnfSec, "lastnotes", str(self.lastNotes))
## Sizes ## Sizes
cnfSec = "Sizes" cnfSec = "Sizes"
+38 -7
View File
@@ -32,8 +32,9 @@ import os
from datetime import datetime from datetime import datetime
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QDialog, QHBoxLayout, QVBoxLayout, QDialogButtonBox, QTabWidget, qApp, QDialog, QHBoxLayout, QVBoxLayout, QDialogButtonBox, QTabWidget,
QTextBrowser, QLabel QTextBrowser, QLabel
) )
@@ -80,6 +81,10 @@ class GuiAbout(QDialog):
self.pageAbout.setOpenExternalLinks(True) self.pageAbout.setOpenExternalLinks(True)
self.pageAbout.document().setDocumentMargin(self.mainConf.pxInt(16)) self.pageAbout.document().setDocumentMargin(self.mainConf.pxInt(16))
self.pageNotes = QTextBrowser()
self.pageNotes.setOpenExternalLinks(True)
self.pageNotes.document().setDocumentMargin(self.mainConf.pxInt(16))
self.pageLicense = QTextBrowser() self.pageLicense = QTextBrowser()
self.pageLicense.setOpenExternalLinks(True) self.pageLicense.setOpenExternalLinks(True)
self.pageLicense.document().setDocumentMargin(self.mainConf.pxInt(16)) self.pageLicense.document().setDocumentMargin(self.mainConf.pxInt(16))
@@ -87,6 +92,7 @@ class GuiAbout(QDialog):
# Main Tab Area # Main Tab Area
self.tabBox = QTabWidget() self.tabBox = QTabWidget()
self.tabBox.addTab(self.pageAbout, "About") self.tabBox.addTab(self.pageAbout, "About")
self.tabBox.addTab(self.pageNotes, "Release")
self.tabBox.addTab(self.pageLicense, "License") self.tabBox.addTab(self.pageLicense, "License")
self.innerBox.addWidget(self.tabBox) self.innerBox.addWidget(self.tabBox)
@@ -98,14 +104,27 @@ class GuiAbout(QDialog):
self.outerBox.addWidget(self.buttonBox) self.outerBox.addWidget(self.buttonBox)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
self._setStyleSheet()
self._fillAboutPage()
self._fillLicensePage()
logger.debug("GuiAbout initialisation complete") logger.debug("GuiAbout initialisation complete")
return return
def populateGUI(self):
"""Populate tabs with text.
"""
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
self._setStyleSheet()
self._fillAboutPage()
self._fillNotesPage()
self._fillLicensePage()
qApp.restoreOverrideCursor()
return
def showReleaseNotes(self):
"""Show the release notes.
"""
self.tabBox.setCurrentWidget(self.pageNotes)
return
## ##
# Internal Functions # Internal Functions
## ##
@@ -192,11 +211,22 @@ class GuiAbout(QDialog):
return return
def _fillNotesPage(self):
"""Load the content for the Release Notes page.
"""
docPath = os.path.join(self.mainConf.assetPath, "text", "release_notes.htm")
if os.path.isfile(docPath):
with open(docPath, mode="r", encoding="utf8") as inFile:
helpText = inFile.read()
self.pageNotes.setHtml(helpText)
else:
self.pageNotes.setHtml("Error loading release notes text ...")
return
def _fillLicensePage(self): def _fillLicensePage(self):
"""Load the content for the License page. """Load the content for the License page.
""" """
docName = "gplv3_%s.htm" % self.mainConf.guiLang docPath = os.path.join(self.mainConf.assetPath, "text", "gplv3_en.htm")
docPath = os.path.join(self.mainConf.assetPath, "text", docName)
if os.path.isfile(docPath): if os.path.isfile(docPath):
with open(docPath, mode="r", encoding="utf8") as inFile: with open(docPath, mode="r", encoding="utf8") as inFile:
helpText = inFile.read() helpText = inFile.read()
@@ -221,6 +251,7 @@ class GuiAbout(QDialog):
hColB = self.theParent.theTheme.colHead[2], hColB = self.theParent.theTheme.colHead[2],
) )
self.pageAbout.document().setDefaultStyleSheet(styleSheet) self.pageAbout.document().setDefaultStyleSheet(styleSheet)
self.pageNotes.document().setDefaultStyleSheet(styleSheet)
self.pageLicense.document().setDefaultStyleSheet(styleSheet) self.pageLicense.document().setDefaultStyleSheet(styleSheet)
return return
+15 -2
View File
@@ -238,6 +238,12 @@ class GuiMain(QMainWindow):
if self.mainConf.showGUI: if self.mainConf.showGUI:
self.showProjectLoadDialog() self.showProjectLoadDialog()
# Show the latest release notes, if they haven't been shown before
if self.mainConf.lastNotes != nw.__version__:
if self.mainConf.showGUI:
self.showAboutNWDialog(showNotes=True)
self.mainConf.lastNotes = nw.__version__
logger.debug("novelWriter is ready ...") logger.debug("novelWriter is ready ...")
self.setStatus("novelWriter is ready ...") self.setStatus("novelWriter is ready ...")
@@ -915,11 +921,18 @@ class GuiMain(QMainWindow):
return return
def showAboutNWDialog(self): def showAboutNWDialog(self, showNotes=False):
"""Show the about dialog for novelWriter. """Show the about dialog for novelWriter.
""" """
dlgAbout = GuiAbout(self) dlgAbout = GuiAbout(self)
dlgAbout.exec_() dlgAbout.setModal(True)
dlgAbout.show()
qApp.processEvents()
dlgAbout.populateGUI()
if showNotes:
dlgAbout.showReleaseNotes()
return return
def showAboutQtDialog(self): def showAboutQtDialog(self):
+1
View File
@@ -6,6 +6,7 @@ icons = typicons_colour_light
guidark = False guidark = False
guifont = guifont =
guifontsize = 11 guifontsize = 11
lastnotes = 1.0
[Sizes] [Sizes]
geometry = 1200, 650 geometry = 1200, 650
+1
View File
@@ -6,6 +6,7 @@ icons = typicons_colour_light
guidark = True guidark = True
guifont = Cantarell guifont = Cantarell
guifontsize = 12 guifontsize = 12
lastnotes = 1.0
[Sizes] [Sizes]
geometry = 1100, 650 geometry = 1100, 650
+5 -5
View File
@@ -14,7 +14,7 @@ def testConfigCore(tmpConf, nwTemp, nwRef):
assert tmpConf.confPath == nwTemp assert tmpConf.confPath == nwTemp
assert tmpConf.saveConfig() assert tmpConf.saveConfig()
assert cmpFiles(testConf, refConf, [2]) assert cmpFiles(testConf, refConf, [2, 9])
assert not tmpConf.confChanged assert not tmpConf.confChanged
assert tmpConf.loadConfig() assert tmpConf.loadConfig()
@@ -51,7 +51,7 @@ def testConfigSetWinSize(tmpConf, nwTemp, nwRef):
assert tmpConf.setWinSize(1200, 650) assert tmpConf.setWinSize(1200, 650)
assert tmpConf.saveConfig() assert tmpConf.saveConfig()
assert cmpFiles(testConf, refConf, [2]) assert cmpFiles(testConf, refConf, [2, 9])
assert not tmpConf.confChanged assert not tmpConf.confChanged
@pytest.mark.core @pytest.mark.core
@@ -73,7 +73,7 @@ def testConfigSetTreeColWidths(tmpConf, nwTemp, nwRef):
assert tmpConf.confChanged assert tmpConf.confChanged
assert tmpConf.saveConfig() assert tmpConf.saveConfig()
assert cmpFiles(testConf, refConf, [2]) assert cmpFiles(testConf, refConf, [2, 9])
assert not tmpConf.confChanged assert not tmpConf.confChanged
@pytest.mark.core @pytest.mark.core
@@ -109,7 +109,7 @@ def testConfigSetPanePos(tmpConf, nwTemp, nwRef):
assert tmpConf.confChanged assert tmpConf.confChanged
assert tmpConf.saveConfig() assert tmpConf.saveConfig()
assert cmpFiles(testConf, refConf, [2]) assert cmpFiles(testConf, refConf, [2, 9])
assert not tmpConf.confChanged assert not tmpConf.confChanged
@pytest.mark.core @pytest.mark.core
@@ -133,7 +133,7 @@ def testConfigFlags(tmpConf, nwTemp, nwRef):
assert tmpConf.confChanged assert tmpConf.confChanged
assert tmpConf.saveConfig() assert tmpConf.saveConfig()
assert cmpFiles(testConf, refConf, [2]) assert cmpFiles(testConf, refConf, [2, 9])
assert not tmpConf.confChanged assert not tmpConf.confChanged
@pytest.mark.core @pytest.mark.core
+12 -3
View File
@@ -374,12 +374,20 @@ def testAboutBox(qtbot, monkeypatch, nwFuncTemp, nwTemp):
msgAbout.show() msgAbout.show()
assert msgAbout.pageAbout.document().characterCount() > 100 assert msgAbout.pageAbout.document().characterCount() > 100
assert msgAbout.pageNotes.document().characterCount() > 100
assert msgAbout.pageLicense.document().characterCount() > 100 assert msgAbout.pageLicense.document().characterCount() > 100
msgAbout.mainConf.guiLang = "whatever" msgAbout.mainConf.assetPath = "whatever"
msgAbout._fillNotesPage()
assert msgAbout.pageNotes.toPlainText() == "Error loading release notes text ..."
msgAbout._fillLicensePage() msgAbout._fillLicensePage()
assert msgAbout.pageLicense.toPlainText() == "Error loading license text ..." assert msgAbout.pageLicense.toPlainText() == "Error loading license text ..."
msgAbout.showReleaseNotes()
assert msgAbout.tabBox.currentWidget() == msgAbout.pageNotes
# Qt About # Qt About
monkeypatch.setattr(QMessageBox, "aboutQt", lambda *args, **kwargs: None) monkeypatch.setattr(QMessageBox, "aboutQt", lambda *args, **kwargs: None)
nwGUI.mainMenu.aAboutQt.activate(QAction.Trigger) nwGUI.mainMenu.aAboutQt.activate(QAction.Trigger)
@@ -1201,8 +1209,9 @@ def testPreferences(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp, nwRef, tmpC
copyfile(projConf, testConf) copyfile(projConf, testConf)
ignoreLines = [ ignoreLines = [
2, # Timestamp 2, # Timestamp
11, 12, 13, 14, 15, 16, 17, # Window sizes 9, # Release Notes
7, 27, # Fonts (depends on system default) 12, 13, 14, 15, 16, 17, 18, # Window sizes
7, 28, # Fonts (depends on system default)
] ]
assert cmpFiles(testConf, refConf, ignoreLines) assert cmpFiles(testConf, refConf, ignoreLines)