Merge pull request #468 from vkbo/scrolling

Scrolling Options
This commit is contained in:
Veronica K. Berglyd Olsen
2020-10-11 21:27:53 +02:00
committed by GitHub
12 changed files with 385 additions and 115 deletions
+23
View File
@@ -102,6 +102,10 @@ class Config:
self.outlnPanePos = [500, 150]
self.isFullScreen = False
## Features
self.hideVScroll = False # Hide vertical scroll bars on main widgets
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
## Project
self.autoSaveProj = 60
self.autoSaveDoc = 30
@@ -122,6 +126,9 @@ class Config:
self.doReplaceDQuote = True
self.doReplaceDash = True
self.doReplaceDots = True
self.scrollPastEnd = True
self.scollWithCursor = False
self.wordCountTimer = 5.0
self.showTabsNSpaces = False
self.showLineEndings = False
@@ -391,6 +398,12 @@ class Config:
self.isFullScreen = self._parseLine(
cnfParse, cnfSec, "fullscreen", self.CNF_BOOL, self.isFullScreen
)
self.hideVScroll = self._parseLine(
cnfParse, cnfSec, "hidevscroll", self.CNF_BOOL, self.hideVScroll
)
self.hideHScroll = self._parseLine(
cnfParse, cnfSec, "hidehscroll", self.CNF_BOOL, self.hideHScroll
)
## Project
cnfSec = "Project"
@@ -448,6 +461,12 @@ class Config:
self.doReplaceDots = self._parseLine(
cnfParse, cnfSec, "repdots", self.CNF_BOOL, self.doReplaceDots
)
self.scrollPastEnd = self._parseLine(
cnfParse, cnfSec, "scrollpastend", self.CNF_BOOL, self.scrollPastEnd
)
self.scollWithCursor = self._parseLine(
cnfParse, cnfSec, "scollwithcursor", self.CNF_BOOL, self.scollWithCursor
)
self.fmtSingleQuotes = self._parseLine(
cnfParse, cnfSec, "fmtsinglequote", self.CNF_LIST, self.fmtSingleQuotes
)
@@ -565,6 +584,8 @@ class Config:
cnfParse.set(cnfSec, "viewpane", self._packList(self.viewPanePos))
cnfParse.set(cnfSec, "outlinepane", self._packList(self.outlnPanePos))
cnfParse.set(cnfSec, "fullscreen", str(self.isFullScreen))
cnfParse.set(cnfSec, "hidevscroll", str(self.hideVScroll))
cnfParse.set(cnfSec, "hidehscroll", str(self.hideHScroll))
## Project
cnfSec = "Project"
@@ -590,6 +611,8 @@ class Config:
cnfParse.set(cnfSec, "repdquotes", str(self.doReplaceDQuote))
cnfParse.set(cnfSec, "repdash", str(self.doReplaceDash))
cnfParse.set(cnfSec, "repdots", str(self.doReplaceDots))
cnfParse.set(cnfSec, "scrollpastend", str(self.scrollPastEnd))
cnfParse.set(cnfSec, "scollwithcursor", str(self.scollWithCursor))
cnfParse.set(cnfSec, "fmtsinglequote", self._packList(self.fmtSingleQuotes))
cnfParse.set(cnfSec, "fmtdoublequote", self._packList(self.fmtDoubleQuotes))
cnfParse.set(cnfSec, "spelltool", str(self.spellTool))
+21 -2
View File
@@ -450,11 +450,19 @@ class GuiBuildNovel(QDialog):
# Tool Box Scroll Area
self.toolsArea = QScrollArea()
self.toolsArea.setMinimumWidth(self.mainConf.pxInt(250))
self.toolsArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.toolsArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.toolsArea.setWidgetResizable(True)
self.toolsArea.setWidget(self.toolsWidget)
if self.mainConf.hideVScroll:
self.toolsArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.toolsArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
if self.mainConf.hideHScroll:
self.toolsArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.toolsArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# Tools and Buttons Layout
self.innerBox = QVBoxLayout()
self.innerBox.addWidget(self.toolsArea)
@@ -1116,6 +1124,17 @@ class GuiBuildNovelDocView(QTextBrowser):
else:
self.setTabStopWidth(self.mainConf.getTabWidth())
# Scroll bars
if self.mainConf.hideVScroll:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
if self.mainConf.hideHScroll:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
docPalette = self.palette()
docPalette.setColor(QPalette.Base, QColor(255, 255, 255))
docPalette.setColor(QPalette.Text, QColor(0, 0, 0))
+66 -2
View File
@@ -88,6 +88,8 @@ class GuiDocEditor(QTextEdit):
self.bigDoc = False # Flag for very large document size
self.doReplace = False # Switch to temporarily disable auto-replace
self.queuePos = None # Used for delayed change of cursor position
self.cursorLast = 0 # The last known vertical position of the cursor
self.lengthLast = 0
# Typography
self.typDQOpen = self.mainConf.fmtDoubleQuotes[0]
@@ -100,6 +102,8 @@ class GuiDocEditor(QTextEdit):
self.qDocument.contentsChange.connect(self._docChange)
self.qDocument.documentLayout().documentSizeChanged.connect(self._docSizeChanged)
self.verticalScrollBar().sliderMoved.connect(self._doVerticalScroll)
# Document Title
self.docHeader = GuiDocEditHeader(self)
self.docFooter = GuiDocEditFooter(self)
@@ -224,6 +228,17 @@ class GuiDocEditor(QTextEdit):
self.qDocument.setDefaultTextOption(theOpt)
# Scroll bars
if self.mainConf.hideVScroll:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
if self.mainConf.hideHScroll:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# Refresh the tab stops
if self.mainConf.verQtValue >= 51000:
self.setTabStopDistance(self.mainConf.getTabWidth())
@@ -313,6 +328,7 @@ class GuiDocEditor(QTextEdit):
self.setCursorLine(tLine)
self.docFooter.updateLineCount()
self.lengthLast = self.qDocument.characterCount()
qApp.restoreOverrideCursor()
@@ -360,9 +376,14 @@ class GuiDocEditor(QTextEdit):
return False
docText = self.getText()
cC, wC, pC = countWords(docText)
self._updateCounts(cC, wC, pC)
theItem.setCharCount(self.charCount)
theItem.setWordCount(self.wordCount)
theItem.setParaCount(self.paraCount)
self.saveCursorPosition()
self.nwDocument.saveDocument(docText)
self.setDocumentChanged(False)
@@ -377,6 +398,7 @@ class GuiDocEditor(QTextEdit):
just ensure the margins are set correctly.
"""
wW = self.width()
wH = self.height()
cM = self.mainConf.getTextMargin()
vBar = self.verticalScrollBar()
@@ -400,7 +422,7 @@ class GuiDocEditor(QTextEdit):
tW = wW - 2*tB - sW
tH = self.docHeader.height()
fH = self.docFooter.height()
fY = self.height() - fH - tB - sH
fY = wH - fH - tB - sH
self.docHeader.setGeometry(tB, tB, tW, tH)
self.docFooter.setGeometry(tB, fY, tW, fH)
@@ -412,7 +434,14 @@ class GuiDocEditor(QTextEdit):
else:
rH = 0
self.setViewportMargins(tM, max(cM, tH, rH), tM, max(cM, fH))
uM = max(cM, tH, rH)
lM = max(cM, fH)
self.setViewportMargins(tM, uM, tM, lM)
if self.mainConf.scrollPastEnd:
docFrame = self.qDocument.rootFrame().frameFormat()
docFrame.setBottomMargin(wH - uM - lM - 4*tB - self.theTheme.fontPixelSize)
self.qDocument.rootFrame().setFrameFormat(docFrame)
return
@@ -460,11 +489,14 @@ class GuiDocEditor(QTextEdit):
"""
if not isinstance(thePosition, int):
return False
if thePosition >= 0:
theCursor = self.textCursor()
theCursor.setPosition(thePosition)
self.setTextCursor(theCursor)
self.docFooter.updateLineCount()
self.cursorLast = self.cursorRect().center().y()
return True
def getCursorPosition(self):
@@ -743,6 +775,22 @@ class GuiDocEditor(QTextEdit):
QTextEdit.keyPressEvent(self, keyEvent)
self.docFooter.updateLineCount()
if self.mainConf.scollWithCursor:
docLen = self.qDocument.characterCount()
if docLen == self.lengthLast:
# No change, so just update last position
self.cursorLast = self.cursorRect().center().y()
else:
# The user typed something, so check if we need to
# scroll, and move the scroll bar the same distance
self.lengthLast = docLen
self.ensureCursorVisible()
cPos = self.cursorRect().center().y()
if cPos != self.cursorLast:
vBar = self.verticalScrollBar()
vBar.setValue(vBar.value() + cPos - self.cursorLast)
self.cursorLast = self.cursorRect().center().y()
return
def focusNextPrevChild(self, toNext):
@@ -768,9 +816,18 @@ class GuiDocEditor(QTextEdit):
QTextEdit.mouseReleaseEvent(self, mEvent)
self.docFooter.updateLineCount()
self.cursorLast = self.cursorRect().center().y()
return
def wheelEvent(self, theEvent):
"""Briefly capture the mouse wheel event to capture the cursor
position.
"""
QTextEdit.wheelEvent(self, theEvent)
self.cursorLast = self.cursorRect().center().y()
return
def resizeEvent(self, theEvent):
"""If the text editor is resize, we must make sure the document
has its margins adjusted according to user preferences.
@@ -805,6 +862,13 @@ class GuiDocEditor(QTextEdit):
self._docAutoReplace(self.qDocument.findBlock(thePos))
return
@pyqtSlot(int)
def _doVerticalScroll(self, theChange):
"""Update the cursor position on vertical scrolling.
"""
self.cursorLast = self.cursorRect().center().y()
return
@pyqtSlot("QPoint")
def _openContextMenu(self, thePos):
"""Triggered by right click to open the context menu. Also
+11
View File
@@ -124,6 +124,17 @@ class GuiDocViewer(QTextBrowser):
theOpt.setAlignment(Qt.AlignJustify)
self.qDocument.setDefaultTextOption(theOpt)
# Scroll bars
if self.mainConf.hideVScroll:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
if self.mainConf.hideHScroll:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# Refresh the tab stops
if self.mainConf.verQtValue >= 51000:
self.setTabStopDistance(self.mainConf.getTabWidth())
+17
View File
@@ -118,6 +118,7 @@ class GuiOutline(QTreeWidget):
self.colIndex = {}
self.treeNCols = 0
self.initOutline()
self.clearOutline()
self.headerMenu.setHiddenState(self.colHidden)
@@ -125,6 +126,22 @@ class GuiOutline(QTreeWidget):
return
def initOutline(self):
"""Set or update outline settings.
"""
# Scroll bars
if self.mainConf.hideVScroll:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
if self.mainConf.hideHScroll:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
return
def clearOutline(self):
"""Clear the tree and header and set the default values for the
columns arrays.
+18
View File
@@ -224,10 +224,28 @@ class GuiOutlineDetails(QScrollArea):
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.setWidgetResizable(True)
self.initDetails()
logger.debug("GuiOutlineDetails initialisation complete")
return
def initDetails(self):
"""Set or update outline settings.
"""
# Scroll bars
if self.mainConf.hideVScroll:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
if self.mainConf.hideHScroll:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
return
def showItem(self, tHandle, sTitle):
"""Update the content of the tree with the given handle and line
number pointing to a header.
+123 -40
View File
@@ -55,15 +55,17 @@ class GuiPreferences(PagedDialog):
self.setWindowTitle("Preferences")
self.tabGeneral = GuiConfigEditGeneralTab(self.theParent)
self.tabLayout = GuiConfigEditLayoutTab(self.theParent)
self.tabEditing = GuiConfigEditEditingTab(self.theParent)
self.tabAutoRep = GuiConfigEditAutoReplaceTab(self.theParent)
self.tabGeneral = GuiConfigEditGeneralTab(self.theParent)
self.tabProjects = GuiConfigEditProjectsTab(self.theParent)
self.tabLayout = GuiConfigEditLayoutTab(self.theParent)
self.tabEditing = GuiConfigEditEditingTab(self.theParent)
self.tabAutoRep = GuiConfigEditAutoReplaceTab(self.theParent)
self.addTab(self.tabGeneral, "General")
self.addTab(self.tabLayout, "Text Layout")
self.addTab(self.tabEditing, "Editor")
self.addTab(self.tabAutoRep, "Auto-Replace")
self.addTab(self.tabGeneral, "General")
self.addTab(self.tabProjects, "Projects")
self.addTab(self.tabLayout, "Text Layout")
self.addTab(self.tabEditing, "Editor")
self.addTab(self.tabAutoRep, "Auto-Replace")
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.buttonBox.accepted.connect(self._doSave)
@@ -91,6 +93,10 @@ class GuiPreferences(PagedDialog):
validEntries &= retA
needsRestart |= retB
retA, retB = self.tabProjects.saveValues()
validEntries &= retA
needsRestart |= retB
retA, retB = self.tabLayout.saveValues()
validEntries &= retA
needsRestart |= retB
@@ -219,9 +225,94 @@ class GuiConfigEditGeneralTab(QWidget):
self.showFullPath.setChecked(self.mainConf.showFullPath)
self.mainForm.addRow(
"Show full path in document header",
self.showFullPath
self.showFullPath,
"Shows the document title and parent folder names."
)
self.hideVScroll = QSwitch()
self.hideVScroll.setChecked(self.mainConf.hideVScroll)
self.mainForm.addRow(
"Hide vertical scroll bars in main windows",
self.hideVScroll,
"Scrolling with mouse wheel and keys only."
)
self.hideHScroll = QSwitch()
self.hideHScroll.setChecked(self.mainConf.hideHScroll)
self.mainForm.addRow(
"Hide horizontal scroll bars in main windows",
self.hideHScroll,
"Scrolling with mouse wheel and keys only."
)
return
def saveValues(self):
"""Save the values set for this tab.
"""
validEntries = True
needsRestart = False
guiTheme = self.selectTheme.currentData()
guiIcons = self.selectIcons.currentData()
guiDark = self.preferDarkIcons.isChecked()
guiFont = self.guiFont.text()
guiFontSize = self.guiFontSize.value()
showFullPath = self.showFullPath.isChecked()
hideVScroll = self.hideVScroll.isChecked()
hideHScroll = self.hideHScroll.isChecked()
# Check if restart is needed
needsRestart |= self.mainConf.guiTheme != guiTheme
needsRestart |= self.mainConf.guiIcons != guiIcons
needsRestart |= self.mainConf.guiFont != guiFont
needsRestart |= self.mainConf.guiFontSize != guiFontSize
self.mainConf.guiTheme = guiTheme
self.mainConf.guiIcons = guiIcons
self.mainConf.guiDark = guiDark
self.mainConf.guiFont = guiFont
self.mainConf.guiFontSize = guiFontSize
self.mainConf.showFullPath = showFullPath
self.mainConf.hideVScroll = hideVScroll
self.mainConf.hideHScroll = hideHScroll
self.mainConf.confChanged = True
return validEntries, needsRestart
##
# Slots
##
def _selectFont(self):
"""Open the QFontDialog and set a font for the font style.
"""
currFont = QFont()
currFont.setFamily(self.mainConf.guiFont)
currFont.setPointSize(self.mainConf.guiFontSize)
theFont, theStatus = QFontDialog.getFont(currFont, self)
if theStatus:
self.guiFont.setText(theFont.family())
self.guiFontSize.setValue(theFont.pointSize())
return
# END Class GuiConfigEditGeneralTab
class GuiConfigEditProjectsTab(QWidget):
def __init__(self, theParent):
QWidget.__init__(self, theParent)
self.mainConf = nw.CONFIG
self.theParent = theParent
self.theTheme = theParent.theTheme
# The Form
self.mainForm = QConfigLayout()
self.mainForm.setHelpTextStyle(self.theTheme.helpText)
self.setLayout(self.mainForm)
# AutoSave Settings
# =================
self.mainForm.addGroupLabel("Automatic Save")
@@ -292,30 +383,12 @@ class GuiConfigEditGeneralTab(QWidget):
validEntries = True
needsRestart = False
guiTheme = self.selectTheme.currentData()
guiIcons = self.selectIcons.currentData()
guiDark = self.preferDarkIcons.isChecked()
guiFont = self.guiFont.text()
guiFontSize = self.guiFontSize.value()
showFullPath = self.showFullPath.isChecked()
autoSaveDoc = self.autoSaveDoc.value()
autoSaveProj = self.autoSaveProj.value()
backupPath = self.backupPath
backupOnClose = self.backupOnClose.isChecked()
askBeforeBackup = self.askBeforeBackup.isChecked()
# Check if restart is needed
needsRestart |= self.mainConf.guiTheme != guiTheme
needsRestart |= self.mainConf.guiIcons != guiIcons
needsRestart |= self.mainConf.guiFont != guiFont
needsRestart |= self.mainConf.guiFontSize != guiFontSize
self.mainConf.guiTheme = guiTheme
self.mainConf.guiIcons = guiIcons
self.mainConf.guiDark = guiDark
self.mainConf.guiFont = guiFont
self.mainConf.guiFontSize = guiFontSize
self.mainConf.showFullPath = showFullPath
self.mainConf.autoSaveDoc = autoSaveDoc
self.mainConf.autoSaveProj = autoSaveProj
self.mainConf.backupPath = backupPath
@@ -357,19 +430,7 @@ class GuiConfigEditGeneralTab(QWidget):
self.askBeforeBackup.setEnabled(theState)
return
def _selectFont(self):
"""Open the QFontDialog and set a font for the font style.
"""
currFont = QFont()
currFont.setFamily(self.mainConf.guiFont)
currFont.setPointSize(self.mainConf.guiFontSize)
theFont, theStatus = QFontDialog.getFont(currFont, self)
if theStatus:
self.guiFont.setText(theFont.family())
self.guiFontSize.setValue(theFont.pointSize())
return
# END Class GuiConfigEditGeneralTab
# END Class GuiConfigEditProjectsTab
class GuiConfigEditLayoutTab(QWidget):
@@ -494,6 +555,24 @@ class GuiConfigEditLayoutTab(QWidget):
theUnit="px"
)
## Scroll Past End
self.scrollPastEnd = QSwitch()
self.scrollPastEnd.setChecked(self.mainConf.scrollPastEnd)
self.mainForm.addRow(
"Scroll past end of the document",
self.scrollPastEnd,
"Allows scrolling until last line is at the top."
)
## Typewriter Scrolling
self.scollWithCursor = QSwitch()
self.scollWithCursor.setChecked(self.mainConf.scollWithCursor)
self.mainForm.addRow(
"Typewriter style scrolling",
self.scollWithCursor,
"Scrolls up when the cursor moves to a new line."
)
return
def saveValues(self):
@@ -511,6 +590,8 @@ class GuiConfigEditLayoutTab(QWidget):
doJustify = self.textJustify.isChecked()
textMargin = self.textMargin.value()
tabWidth = self.tabWidth.value()
scrollPastEnd = self.scrollPastEnd.isChecked()
scollWithCursor = self.scollWithCursor.isChecked()
self.mainConf.textFont = textFont
self.mainConf.textSize = textSize
@@ -521,6 +602,8 @@ class GuiConfigEditLayoutTab(QWidget):
self.mainConf.doJustify = doJustify
self.mainConf.textMargin = textMargin
self.mainConf.tabWidth = tabWidth
self.mainConf.scrollPastEnd = scrollPastEnd
self.mainConf.scollWithCursor = scollWithCursor
self.mainConf.confChanged = True
+21 -1
View File
@@ -115,6 +115,9 @@ class GuiProjectTree(QTreeWidget):
# The last column should just auto-scale
self.resizeColumnToContents(self.C_FLAGS)
# Set custom settings
self.initTree()
logger.debug("GuiProjectTree initialisation complete")
# Internal Mapping
@@ -122,6 +125,22 @@ class GuiProjectTree(QTreeWidget):
return
def initTree(self):
"""Set or update tree widget settings.
"""
# Scroll bars
if self.mainConf.hideVScroll:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
if self.mainConf.hideHScroll:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
else:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
return
##
# Class Methods
##
@@ -241,7 +260,8 @@ class GuiProjectTree(QTreeWidget):
# Add the new item to the tree
if tHandle is not None:
self.revealNewTreeItem(tHandle, nHandle)
self.theParent.editItem(tHandle)
if self.mainConf.showGUI:
self.theParent.editItem(tHandle)
return True
+3
View File
@@ -790,6 +790,9 @@ class GuiMain(QMainWindow):
self.saveDocument()
self.docEditor.initEditor()
self.docViewer.initViewer()
self.treeView.initTree()
self.projView.initOutline()
self.projMeta.initDetails()
return
+5 -1
View File
@@ -1,5 +1,5 @@
[Main]
timestamp = 2020-06-29 17:34:15
timestamp = 2020-10-11 18:29:34
theme = default
syntax = default_light
icons = typicons_colour_light
@@ -16,6 +16,8 @@ docpane = 400, 400
viewpane = 500, 150
outlinepane = 500, 150
fullscreen = False
hidevscroll = False
hidehscroll = False
[Project]
autosaveproject = 60
@@ -37,6 +39,8 @@ repsquotes = True
repdquotes = True
repdash = True
repdots = True
scrollpastend = True
scollwithcursor = False
fmtsinglequote = ,
fmtdoublequote = “, ”
spelltool = internal
+4
View File
@@ -16,6 +16,8 @@ docpane = 400, 400
viewpane = 500, 150
outlinepane = 500, 150
fullscreen = False
hidevscroll = True
hidehscroll = True
[Project]
autosaveproject = 40
@@ -37,6 +39,8 @@ repsquotes = True
repdquotes = True
repdash = True
repdots = True
scrollpastend = False
scollwithcursor = True
fmtsinglequote = ,
fmtdoublequote = “, ”
spelltool = internal
+73 -69
View File
@@ -23,7 +23,7 @@ from nw.gui import (
GuiProjectLoad, GuiPreferences
)
from nw.gui.custom import QuotesDialog
from nw.constants import nwItemType, nwItemLayout, nwItemClass
from nw.constants import nwItemLayout, nwItemClass, nwFiles
keyDelay = 2
typeDelay = 1
@@ -228,48 +228,20 @@ def testWritingStatsExport(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTemp):
# Create new, save, close project
nwGUI.theProject.projTree.setSeed(42)
assert nwGUI.newProject({"projPath": nwFuncTemp})
qtbot.wait(200)
assert nwGUI.saveProject()
assert nwGUI.closeProject()
qtbot.wait(stepDelay)
# Check that we cannot open when there is no project
nwGUI.mainMenu.aWritingStats.activate(QAction.Trigger)
assert getGuiItem("GuiWritingStats") is None
assert nwGUI.openProject(nwFuncTemp)
qtbot.wait(stepDelay)
# Add some text to the scene file
assert nwGUI.openDocument("0e17daca5f3e1")
assert nwGUI.docEditor.insertText(
"# Scene One\n\n"
"It was the best of times, it was the worst of times, it was the age of wisdom, it was "
"the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it "
"was the season of Light, it was the season of Darkness, it was the spring of hope, it "
"was the winter of despair, we had everything before us, we had nothing before us, we "
"were all going direct to Heaven, we were all going direct the other way in short, the "
"period was so far like the present period, that some of its noisiest authorities "
"insisted on its being received, for good or for evil, in the superlative degree of "
"comparison only.\n\n"
)
assert nwGUI.saveDocument()
# Add a note file with some text
nwGUI.setFocus(1)
nwGUI.treeView.clearSelection()
nwGUI.treeView._getTreeItem("71ee45a3c0db9").setSelected(True)
nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
assert nwGUI.openSelectedItem()
assert nwGUI.docEditor.insertText(
"# Jane Doe\n\n"
"All about Jane.\n\n"
)
assert nwGUI.saveDocument()
qtbot.wait(500) # Ensures that the session length is > 0
assert nwGUI.saveProject()
assert nwGUI.closeProject()
qtbot.wait(stepDelay)
sessFile = os.path.join(nwFuncTemp, "meta", nwFiles.SESS_STATS)
with open(sessFile, mode="w+", encoding="utf-8") as outFile:
outFile.write(
"# Start Time End Time Novel Notes\n"
"2020-01-01 21:00:00 2020-01-01 21:00:05 6 0\n"
"2020-01-03 21:00:00 2020-01-03 21:00:15 125 0\n"
"2020-01-03 21:30:00 2020-01-03 21:30:15 125 5\n"
"2020-01-06 21:00:00 2020-01-06 21:00:10 125 5\n"
)
# Open again, and check the stats
assert nwGUI.openProject(nwFuncTemp)
@@ -288,19 +260,21 @@ def testWritingStatsExport(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTemp):
monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda ss, tt, pp, options: (pp, ""))
assert sessLog._saveData(sessLog.FMT_CSV)
qtbot.wait(stepDelay)
qtbot.wait(100)
assert sessLog._saveData(sessLog.FMT_JSON)
qtbot.wait(stepDelay)
qtbot.wait(100)
jsonStats = os.path.join(nwFuncTemp, "sessionStats.json")
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.loads(inFile.read())
assert len(jsonData) == 2
assert jsonData[1]["length"] >= 0
assert jsonData[1]["newWords"] == 126
assert jsonData[1]["novelWords"] == 127
assert jsonData[1]["noteWords"] == 5
qtbot.wait(stepDelay)
assert len(jsonData) == 3
assert jsonData[1]["length"] >= 14.0
assert jsonData[1]["newWords"] == 119
assert jsonData[1]["novelWords"] == 125
assert jsonData[1]["noteWords"] == 0
# No Novel Files
qtbot.mouseClick(sessLog.incNovel, Qt.LeftButton)
@@ -313,9 +287,9 @@ def testWritingStatsExport(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTemp):
jsonData = json.loads(inFile.read())
assert len(jsonData) == 1
assert jsonData[0]["length"] >= 0
assert jsonData[0]["length"] >= 14.0
assert jsonData[0]["newWords"] == 5
assert jsonData[0]["novelWords"] == 127
assert jsonData[0]["novelWords"] == 125
assert jsonData[0]["noteWords"] == 5
# No Note Files
@@ -330,10 +304,10 @@ def testWritingStatsExport(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTemp):
jsonData = json.loads(inFile.read())
assert len(jsonData) == 2
assert jsonData[1]["length"] >= 0
assert jsonData[1]["newWords"] == 121
assert jsonData[1]["novelWords"] == 127
assert jsonData[1]["noteWords"] == 5
assert jsonData[1]["length"] >= 14.0
assert jsonData[1]["newWords"] == 119
assert jsonData[1]["novelWords"] == 125
assert jsonData[1]["noteWords"] == 0
# No Negative Entries
qtbot.mouseClick(sessLog.incNotes, Qt.LeftButton)
@@ -346,7 +320,7 @@ def testWritingStatsExport(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTemp):
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.loads(inFile.read())
assert len(jsonData) == 2
assert len(jsonData) == 3
# Un-hide Zero Entries
qtbot.mouseClick(sessLog.hideNegative, Qt.LeftButton)
@@ -359,7 +333,7 @@ def testWritingStatsExport(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTemp):
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.loads(inFile.read())
assert len(jsonData) == 2
assert len(jsonData) == 4
# Group by Day
qtbot.mouseClick(sessLog.groupByDay, Qt.LeftButton)
@@ -373,11 +347,13 @@ def testWritingStatsExport(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTemp):
# Check against both 1 and 2 as this can be 2 if test was started just before midnight.
# A failed test should in any case produce a 4
assert len(jsonData) in (1, 2)
assert len(jsonData) == 3
# qtbot.stopForInteraction()
sessLog._doClose()
assert nwGUI.closeProject()
qtbot.wait(stepDelay)
nwGUI.closeMain()
@pytest.mark.gui
@@ -1057,6 +1033,7 @@ def testPreferences(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp, nwRef, tmpC
nwGUI.mainConf = tmpConf
nwPrefs.mainConf = tmpConf
nwPrefs.tabGeneral.mainConf = tmpConf
nwPrefs.tabProjects.mainConf = tmpConf
nwPrefs.tabLayout.mainConf = tmpConf
nwPrefs.tabEditing.mainConf = tmpConf
nwPrefs.tabAutoRep.mainConf = tmpConf
@@ -1065,7 +1042,6 @@ def testPreferences(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp, nwRef, tmpC
qtbot.wait(keyDelay)
tabGeneral = nwPrefs.tabGeneral
nwPrefs._tabBox.setCurrentWidget(tabGeneral)
tabGeneral.backupPath = "no/where"
qtbot.wait(keyDelay)
assert not tabGeneral.preferDarkIcons.isChecked()
@@ -1077,27 +1053,45 @@ def testPreferences(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp, nwRef, tmpC
qtbot.mouseClick(tabGeneral.showFullPath, Qt.LeftButton)
assert not tabGeneral.showFullPath.isChecked()
# Check Browse button
monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *args, **kwargs: "")
assert not tabGeneral._backupFolder()
monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *args, **kwargs: "some/dir")
qtbot.mouseClick(tabGeneral.backupGetPath, Qt.LeftButton)
qtbot.wait(keyDelay)
assert not tabGeneral.hideVScroll.isChecked()
qtbot.mouseClick(tabGeneral.hideVScroll, Qt.LeftButton)
assert tabGeneral.hideVScroll.isChecked()
qtbot.wait(keyDelay)
assert not tabGeneral.hideHScroll.isChecked()
qtbot.mouseClick(tabGeneral.hideHScroll, Qt.LeftButton)
assert tabGeneral.hideHScroll.isChecked()
# Check font button
monkeypatch.setattr(QFontDialog, "getFont", lambda font, obj: (font, True))
qtbot.mouseClick(tabGeneral.fontButton, Qt.LeftButton)
qtbot.wait(keyDelay)
assert not tabGeneral.backupOnClose.isChecked()
qtbot.mouseClick(tabGeneral.backupOnClose, Qt.LeftButton)
assert tabGeneral.backupOnClose.isChecked()
tabGeneral.guiFontSize.setValue(12)
# Projects Settings
qtbot.wait(keyDelay)
tabProjects = nwPrefs.tabProjects
nwPrefs._tabBox.setCurrentWidget(tabProjects)
tabProjects.backupPath = "no/where"
qtbot.wait(keyDelay)
tabGeneral.guiFontSize.setValue(12)
tabGeneral.autoSaveDoc.setValue(20)
tabGeneral.autoSaveProj.setValue(40)
assert not tabProjects.backupOnClose.isChecked()
qtbot.mouseClick(tabProjects.backupOnClose, Qt.LeftButton)
assert tabProjects.backupOnClose.isChecked()
# Text Layour Settings
# Check Browse button
monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *args, **kwargs: "")
assert not tabProjects._backupFolder()
monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *args, **kwargs: "some/dir")
qtbot.mouseClick(tabProjects.backupGetPath, Qt.LeftButton)
qtbot.wait(keyDelay)
tabProjects.autoSaveDoc.setValue(20)
tabProjects.autoSaveProj.setValue(40)
# Text Layout Settings
qtbot.wait(keyDelay)
tabLayout = nwPrefs.tabLayout
nwPrefs._tabBox.setCurrentWidget(tabLayout)
@@ -1127,6 +1121,16 @@ def testPreferences(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp, nwRef, tmpC
qtbot.mouseClick(tabLayout.textJustify, Qt.LeftButton)
assert not tabLayout.textJustify.isChecked()
qtbot.wait(keyDelay)
assert tabLayout.scrollPastEnd.isChecked()
qtbot.mouseClick(tabLayout.scrollPastEnd, Qt.LeftButton)
assert not tabLayout.scrollPastEnd.isChecked()
qtbot.wait(keyDelay)
assert not tabLayout.scollWithCursor.isChecked()
qtbot.mouseClick(tabLayout.scollWithCursor, Qt.LeftButton)
assert tabLayout.scollWithCursor.isChecked()
# Editor Settings
qtbot.wait(keyDelay)
tabEditing = nwPrefs.tabEditing
@@ -1198,7 +1202,7 @@ def testPreferences(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp, nwRef, tmpC
ignoreLines = [
2, # Timestamp
11, 12, 13, 14, 15, 16, 17, # Window sizes
7, 25, # Fonts (depends on system default)
7, 27, # Fonts (depends on system default)
]
assert cmpFiles(testConf, refConf, ignoreLines)