From 0401b8556d7b9c3dabd1c8004d1510edc2c05661 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 1 Jan 2022 19:36:04 +0100
Subject: [PATCH] Add result count to search and rewrite scroll past end
feature (#946)
* Restore colours to dark theme search-replace icon
* Implement a working search result counter
* Disable scroll past end feature and clean up search/replace and update test
* Re-implement scroll past end feature as a static distance
* Stop the search box from resizing on every search
---
.../typicons_dark/mixed_search-replace.svg | 17 +-
novelwriter/config.py | 4 +-
novelwriter/dialogs/preferences.py | 12 +-
novelwriter/gui/doceditor.py | 176 ++++++++++++------
tests/reference/baseConfig_novelwriter.conf | 2 +-
.../reference/guiPreferences_novelwriter.conf | 2 +-
tests/test_dialogs/test_dlg_preferences.py | 8 +-
tests/test_gui/test_gui_doceditor.py | 102 ++++++----
tests/test_gui/test_gui_guimain.py | 1 -
9 files changed, 211 insertions(+), 113 deletions(-)
diff --git a/novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg b/novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg
index 193ffb49..784fb950 100644
--- a/novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg
+++ b/novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg
@@ -26,9 +26,14 @@
id="defs877" />
-
-
+ style="display:inline;fill:#6699cc;fill-opacity:1;stroke-width:1.19007"
+ d="m 10.330622,1.9999997 c -4.5924663,0 -8.3306193,3.738153 -8.3306193,8.3306193 0,1.391929 0.3467825,2.702587 0.9532665,3.857242 0.084308,-0.108411 0.1590865,-0.228838 0.2534294,-0.323181 L 4.7482003,12.323178 C 4.5237338,11.697056 4.378519,11.032991 4.3785189,10.330619 c 0,-3.2810129 2.6710902,-5.949778 5.9521031,-5.949778 0.702303,0 1.36649,0.1429324 1.992559,0.3673563 L 14.141363,2.9300158 C 12.997884,2.3384803 11.704084,1.9999997 10.330622,1.9999997 Z m 5.635898,3.4852355 -0.60451,0.6045104 2.545919,2.5482442 0.460357,-0.4626829 C 18.332278,8.0413114 18.299136,7.9066594 18.256684,7.7754 Z m 0.292955,4.4245521 c 0.0083,0.1189097 0.01733,0.2373427 0.01861,0.3580557 l 0.169728,-0.169728 z m 2.059986,2.6993717 -5.710299,5.710299 c 0.105352,-0.03032 0.217183,-0.04484 0.320855,-0.07906 l 0.892816,0.89049 1.799581,1.797261 0.07208,0.07208 0.07672,0.06743 C 16.486443,21.66984 17.375591,22 18.275281,22 c 2.054056,0 3.724716,-1.671795 3.724716,-3.72704 0,-0.999657 -0.390465,-1.936781 -1.099745,-2.638921 l -1.129969,-1.174145 -0.639387,-0.639386 -0.890489,-0.892815 c 0.03403,-0.103138 0.04885,-0.213757 0.07906,-0.318531 z m -11.7600542,2.28784 -0.4929085,0.492908 0.5417343,0.541734 0.57196,-0.571959 C 6.960254,15.221393 6.7588057,15.062002 6.5594068,14.896999 Z m 2.7179722,1.285747 -1.209021,1.209021 0.5417345,0.541734 1.6577535,-1.655429 c -0.3372847,-0.0036 -0.668706,-0.03764 -0.990467,-0.09533 z" />
+
+
+
\ No newline at end of file
diff --git a/novelwriter/config.py b/novelwriter/config.py
index 679e0dde..2676095f 100644
--- a/novelwriter/config.py
+++ b/novelwriter/config.py
@@ -137,7 +137,7 @@ class Config:
self.doReplaceDash = True # Replace multiple hyphens with dashes
self.doReplaceDots = True # Replace three dots with ellipsis
- self.scrollPastEnd = True # Allow scrolling past end of document
+ self.scrollPastEnd = 25 # Number of lines to scroll past end of document
self.autoScroll = False # Typewriter-like scrolling
self.autoScrollPos = 30 # Start point for typewriter-like scrolling
@@ -479,7 +479,7 @@ class Config:
self.doReplaceDQuote = theConf.rdBool(cnfSec, "repdquotes", self.doReplaceDQuote)
self.doReplaceDash = theConf.rdBool(cnfSec, "repdash", self.doReplaceDash)
self.doReplaceDots = theConf.rdBool(cnfSec, "repdots", self.doReplaceDots)
- self.scrollPastEnd = theConf.rdBool(cnfSec, "scrollpastend", self.scrollPastEnd)
+ self.scrollPastEnd = theConf.rdInt(cnfSec, "scrollpastend", self.scrollPastEnd)
self.autoScroll = theConf.rdBool(cnfSec, "autoscroll", self.autoScroll)
self.autoScrollPos = theConf.rdInt(cnfSec, "autoscrollpos", self.autoScrollPos)
self.fmtSingleQuotes = theConf.rdStrList(cnfSec, "fmtsinglequote", self.fmtSingleQuotes)
diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py
index 334f5930..763b0b53 100644
--- a/novelwriter/dialogs/preferences.py
+++ b/novelwriter/dialogs/preferences.py
@@ -761,12 +761,16 @@ class GuiPreferencesEditor(QWidget):
self.mainForm.addGroupLabel(self.tr("Scroll Behaviour"))
# Scroll Past End
- self.scrollPastEnd = QSwitch()
- self.scrollPastEnd.setChecked(self.mainConf.scrollPastEnd)
+ self.scrollPastEnd = QSpinBox(self)
+ self.scrollPastEnd.setMinimum(0)
+ self.scrollPastEnd.setMaximum(100)
+ self.scrollPastEnd.setSingleStep(1)
+ self.scrollPastEnd.setValue(int(self.mainConf.scrollPastEnd))
self.mainForm.addRow(
self.tr("Scroll past end of the document"),
self.scrollPastEnd,
- self.tr("Also improves typewriter scrolling for short documents.")
+ self.tr("Set to 0 to disable this feature."),
+ theUnit=self.tr("lines")
)
# Typewriter Scrolling
@@ -809,7 +813,7 @@ class GuiPreferencesEditor(QWidget):
self.mainConf.showLineEndings = self.showLineEndings.isChecked()
# Scroll Behaviour
- self.mainConf.scrollPastEnd = self.scrollPastEnd.isChecked()
+ self.mainConf.scrollPastEnd = self.scrollPastEnd.value()
self.mainConf.autoScroll = self.autoScroll.isChecked()
self.mainConf.autoScrollPos = self.autoScrollPos.value()
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index a042d029..76bfb46e 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -29,6 +29,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+import bisect
import logging
import novelwriter
@@ -39,8 +40,8 @@ from PyQt5.QtCore import (
QPointF, QObject, QRunnable, QPropertyAnimation
)
from PyQt5.QtGui import (
- QTextCursor, QTextOption, QKeySequence, QFont, QColor, QPalette,
- QTextDocument, QCursor, QPixmap
+ QFontMetrics, QTextCursor, QTextOption, QKeySequence, QFont, QColor,
+ QPalette, QTextDocument, QCursor, QPixmap
)
from PyQt5.QtWidgets import (
qApp, QTextEdit, QAction, QMenu, QShortcut, QMessageBox, QWidget, QLabel,
@@ -381,10 +382,17 @@ class GuiDocEditor(QTextEdit):
else:
self.setCursorLine(tLine)
+ if self.mainConf.scrollPastEnd > 0:
+ fSize = QFontMetrics(self.font()).lineSpacing()
+ docFrame = self.document().rootFrame().frameFormat()
+ docFrame.setBottomMargin(round(self.mainConf.scrollPastEnd * fSize))
+ self.document().rootFrame().setFrameFormat(docFrame)
+
self.docFooter.updateLineCount()
self._docHeaders = self.theIndex.getHandleHeaders(self._docHandle)
qApp.processEvents()
+ self.document().clearUndoRedoStacks()
self.setDocumentChanged(False)
qApp.restoreOverrideCursor()
@@ -546,17 +554,6 @@ class GuiDocEditor(QTextEdit):
lM = max(cM, fH)
self.setViewportMargins(tM, uM, tM, lM)
- tmpDocChanged = self._docChanged
- if self.mainConf.scrollPastEnd:
- docFrame = self.document().rootFrame().frameFormat()
- docFrame.setBottomMargin(max(0, 0.9*(wH - uM - lM - 4*tB)))
- self.document().rootFrame().setFrameFormat(docFrame)
-
- # This is needed as the setFrameFormat function itself will
- # trigger the contetsChanged signal which sets _docChanged, so we
- # set it back to whatever it was before.
- self.setDocumentChanged(tmpDocChanged)
-
return
def updateDocInfo(self, tHandle):
@@ -1322,6 +1319,7 @@ class GuiDocEditor(QTextEdit):
self._queuePos = None
else:
logger.verbose("Denied cursor move to %d > %d", self._queuePos, thePos)
+
return
##
@@ -1329,75 +1327,123 @@ class GuiDocEditor(QTextEdit):
##
def beginSearch(self):
- """Sets the selected text as the search text for the search bar.
+ """Set the selected text as the search text for the search bar.
"""
theCursor = self.textCursor()
if theCursor.hasSelection():
self.docSearch.setSearchText(theCursor.selectedText())
else:
self.docSearch.setSearchText(None)
- self.updateDocMargins()
+ resS, _ = self.findAllOccurences()
+ self.docSearch.setResultCount(None, len(resS))
return
def beginReplace(self):
- """Opens the replace line of the search bar and sets the find
- text if a selection has been made, and resets the replace text.
+ """Initialise the search box and reset the replace text box.
"""
- theCursor = self.textCursor()
- if theCursor.hasSelection():
- self.docSearch.setSearchText(theCursor.selectedText())
- else:
- self.docSearch.setSearchText(None)
+ self.beginSearch()
self.docSearch.setReplaceText("")
self.updateDocMargins()
return
def findNext(self, goBack=False):
- """Searches for the next or previous occurrence of the search
- bar text in the document. Wraps around if not found and loop is
- enabled, or continues to next file if next file is enabled.
+ """Search for the next or previous occurrence of the search bar
+ text in the document. Wrap around if not found and loop is
+ enabled, or continue to next file if next file is enabled.
"""
if not self.anyFocus():
logger.debug("Editor does not have focus")
- return False
+ return
if not self.docSearch.isVisible():
self.beginSearch()
return
- findOpt = QTextDocument.FindFlag(0)
+ resS, resE = self.findAllOccurences()
+ if len(resS) == 0:
+ self.docSearch.setResultCount(0, 0)
+ self._lastFind = None
+ if self.docSearch.doNextFile and not goBack:
+ self.theParent.openNextDocument(
+ self._docHandle, wrapAround=self.docSearch.doLoop
+ )
+ self.beginSearch()
+ return
+
+ theCursor = self.textCursor()
+ resIdx = bisect.bisect_left(resS, theCursor.position())
+
+ doLoop = self.docSearch.doLoop
+ maxIdx = len(resS) - 1
+
if goBack:
- findOpt |= QTextDocument.FindBackward
+ resIdx -= 2
+
+ if resIdx < 0:
+ resIdx = maxIdx if doLoop else 0
+
+ if resIdx > maxIdx:
+ if self.docSearch.doNextFile and not goBack:
+ self.theParent.openNextDocument(
+ self._docHandle, wrapAround=self.docSearch.doLoop
+ )
+ self.beginSearch()
+ return
+ else:
+ resIdx = 0 if doLoop else maxIdx
+
+ theCursor.setPosition(resS[resIdx], QTextCursor.MoveAnchor)
+ theCursor.setPosition(resE[resIdx], QTextCursor.KeepAnchor)
+ self.setTextCursor(theCursor)
+
+ self.docSearch.setResultCount(resIdx + 1, len(resS))
+ self._lastFind = (resS[resIdx], resE[resIdx])
+
+ return
+
+ def findAllOccurences(self):
+ """Create a list of all search results of the current search in
+ the document.
+ """
+ resS = []
+ resE = []
+ theCursor = self.textCursor()
+ hasSelection = theCursor.hasSelection()
+ if hasSelection:
+ origA = theCursor.selectionStart()
+ origB = theCursor.selectionEnd()
+ else:
+ origA = theCursor.position()
+
+ findOpt = QTextDocument.FindFlag(0)
if self.docSearch.isCaseSense:
findOpt |= QTextDocument.FindCaseSensitively
if self.docSearch.isWholeWord:
findOpt |= QTextDocument.FindWholeWords
searchFor = self.docSearch.getSearchObject()
- wasFound = self.find(searchFor, findOpt)
- if not wasFound:
- if self.docSearch.doNextFile and not goBack:
- self.theParent.openNextDocument(
- self._docHandle, wrapAround=self.docSearch.doLoop
- )
- elif self.docSearch.doLoop:
- theCursor = self.textCursor()
- theCursor.movePosition(
- QTextCursor.End if goBack else QTextCursor.Start
- )
- self.setTextCursor(theCursor)
- wasFound = self.find(searchFor, findOpt)
+ theCursor.setPosition(0)
+ self.setTextCursor(theCursor)
- if wasFound:
+ while self.find(searchFor, findOpt):
theCursor = self.textCursor()
- self._lastFind = (theCursor.selectionStart(), theCursor.selectionEnd())
+ resS.append(theCursor.selectionStart())
+ resE.append(theCursor.selectionEnd())
- return
+ if hasSelection:
+ theCursor.setPosition(origA, QTextCursor.MoveAnchor)
+ theCursor.setPosition(origB, QTextCursor.KeepAnchor)
+ else:
+ theCursor.setPosition(origA)
+
+ self.setTextCursor(theCursor)
+
+ return resS, resE
def replaceNext(self):
- """Searches for the next occurrence of the search bar text in
- the document and replaces it with the replace text. Calls search
- next automatically when done.
+ """Search for the next occurrence of the search bar text in the
+ document and replace it with the replace text. Call search next
+ automatically when done.
"""
if not self.anyFocus():
logger.debug("Editor does not have focus")
@@ -2131,8 +2177,8 @@ class GuiDocEditSearch(QFrame):
mPx = self.mainConf.pxInt(6)
tPx = int(0.8*self.theTheme.fontPixelSize)
- boxFont = self.theTheme.guiFont
- boxFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
+ self.boxFont = self.theTheme.guiFont
+ self.boxFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
self.setContentsMargins(0, 0, 0, 0)
self.setAutoFillBackground(True)
@@ -2143,13 +2189,14 @@ class GuiDocEditSearch(QFrame):
# Text Boxes
# ==========
+
self.searchBox = QLineEdit(self)
- self.searchBox.setFont(boxFont)
+ self.searchBox.setFont(self.boxFont)
self.searchBox.setPlaceholderText(self.tr("Search"))
self.searchBox.returnPressed.connect(self._doSearch)
self.replaceBox = QLineEdit(self)
- self.replaceBox.setFont(boxFont)
+ self.replaceBox.setFont(self.boxFont)
self.replaceBox.setPlaceholderText(self.tr("Replace"))
self.replaceBox.returnPressed.connect(self._doReplace)
@@ -2160,9 +2207,13 @@ class GuiDocEditSearch(QFrame):
self.searchOpt.setStyleSheet("QToolBar {padding: 0;}")
self.searchLabel = QLabel(self.tr("Search"))
- self.searchLabel.setFont(boxFont)
+ self.searchLabel.setFont(self.boxFont)
self.searchLabel.setIndent(self.mainConf.pxInt(6))
+ self.resultLabel = QLabel("?/?")
+ self.resultLabel.setFont(self.boxFont)
+ self.resultLabel.setMinimumWidth(self.theTheme.getTextWidth("?/?", self.boxFont))
+
self.toggleCase = QAction(self.tr("Case Sensitive"), self)
self.toggleCase.setToolTip(self.tr("Match case"))
self.toggleCase.setIcon(self.theTheme.getIcon("search_case"))
@@ -2223,6 +2274,7 @@ class GuiDocEditSearch(QFrame):
# Buttons
# =======
+
bPx = self.searchBox.sizeHint().height()
self.showReplace = QToolButton(self)
@@ -2243,18 +2295,20 @@ class GuiDocEditSearch(QFrame):
self.replaceButton.clicked.connect(self._doReplace)
self.mainBox.addWidget(self.searchLabel, 0, 0, 1, 2, Qt.AlignLeft)
- self.mainBox.addWidget(self.searchOpt, 0, 2, 1, 2, Qt.AlignRight)
+ self.mainBox.addWidget(self.searchOpt, 0, 2, 1, 3, Qt.AlignRight)
self.mainBox.addWidget(self.showReplace, 1, 0, 1, 1)
self.mainBox.addWidget(self.searchBox, 1, 1, 1, 2)
self.mainBox.addWidget(self.searchButton, 1, 3, 1, 1)
+ self.mainBox.addWidget(self.resultLabel, 1, 4, 1, 1)
self.mainBox.addWidget(self.replaceBox, 2, 1, 1, 2)
self.mainBox.addWidget(self.replaceButton, 2, 3, 1, 1)
- self.mainBox.setColumnStretch(0, 1)
+ self.mainBox.setColumnStretch(0, 0)
self.mainBox.setColumnStretch(1, 0)
- self.mainBox.setColumnStretch(2, 0)
+ self.mainBox.setColumnStretch(2, 1)
self.mainBox.setColumnStretch(3, 0)
self.mainBox.setColumnStretch(4, 0)
+ self.mainBox.setColumnStretch(5, 0)
self.mainBox.setSpacing(self.mainConf.pxInt(2))
self.mainBox.setContentsMargins(mPx, mPx, mPx, mPx)
@@ -2349,6 +2403,18 @@ class GuiDocEditSearch(QFrame):
self.replaceBox.setText(theText)
return True
+ def setResultCount(self, currRes, resCount):
+ """Set the count values for the current search.
+ """
+ currRes = "?" if currRes is None else currRes
+ resCount = "?" if resCount is None else resCount
+ minWidth = self.theTheme.getTextWidth(f"{resCount}//{resCount}", self.boxFont)
+ self.resultLabel.setText(f"{currRes}/{resCount}")
+ self.resultLabel.setMinimumWidth(minWidth)
+ self.adjustSize()
+ self.docEditor.updateDocMargins()
+ return
+
def getSearchObject(self):
"""Return the current search text either as text or as a regular
expression object.
diff --git a/tests/reference/baseConfig_novelwriter.conf b/tests/reference/baseConfig_novelwriter.conf
index eba5222c..8018b089 100644
--- a/tests/reference/baseConfig_novelwriter.conf
+++ b/tests/reference/baseConfig_novelwriter.conf
@@ -42,7 +42,7 @@ repsquotes = True
repdquotes = True
repdash = True
repdots = True
-scrollpastend = True
+scrollpastend = 25
autoscroll = False
autoscrollpos = 30
fmtsinglequote = ‘, ’
diff --git a/tests/reference/guiPreferences_novelwriter.conf b/tests/reference/guiPreferences_novelwriter.conf
index c993c11e..71c08fb1 100644
--- a/tests/reference/guiPreferences_novelwriter.conf
+++ b/tests/reference/guiPreferences_novelwriter.conf
@@ -42,7 +42,7 @@ repsquotes = True
repdquotes = True
repdash = True
repdots = True
-scrollpastend = False
+scrollpastend = 0
autoscroll = True
autoscrollpos = 30
fmtsinglequote = ‘, ’
diff --git a/tests/test_dialogs/test_dlg_preferences.py b/tests/test_dialogs/test_dlg_preferences.py
index a58897a6..aa33ba82 100644
--- a/tests/test_dialogs/test_dlg_preferences.py
+++ b/tests/test_dialogs/test_dlg_preferences.py
@@ -169,16 +169,14 @@ def testDlgPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir):
qtbot.mouseClick(tabEditor.showLineEndings, Qt.LeftButton)
assert tabEditor.showLineEndings.isChecked()
- qtbot.wait(keyDelay)
- assert tabEditor.scrollPastEnd.isChecked()
- qtbot.mouseClick(tabEditor.scrollPastEnd, Qt.LeftButton)
- assert not tabEditor.scrollPastEnd.isChecked()
-
qtbot.wait(keyDelay)
assert not tabEditor.autoScroll.isChecked()
qtbot.mouseClick(tabEditor.autoScroll, Qt.LeftButton)
assert tabEditor.autoScroll.isChecked()
+ qtbot.wait(keyDelay)
+ tabEditor.scrollPastEnd.setValue(0)
+
qtbot.wait(keyDelay)
tabEditor.bigDocLimit.setValue(500)
diff --git a/tests/test_gui/test_gui_doceditor.py b/tests/test_gui/test_gui_doceditor.py
index f287ce74..241acd24 100644
--- a/tests/test_gui/test_gui_doceditor.py
+++ b/tests/test_gui/test_gui_doceditor.py
@@ -1297,135 +1297,151 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.selectedText() == "est"
- # Activate Search
+ # Activate search
nwGUI.mainMenu.aFind.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.isVisible()
assert nwGUI.docEditor.docSearch.getSearchText() == "est"
- # Find Next by Enter
+ # Find next by enter key
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True)
qtbot.keyClick(nwGUI.docEditor.docSearch.searchBox, Qt.Key_Return, delay=keyDelay)
assert abs(nwGUI.docEditor.getCursorPosition() - 1284) < 3
- # Find Next by Button
+ # Find next by button
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
assert abs(nwGUI.docEditor.getCursorPosition() - 1498) < 3
- # Activate Loop Search
+ # Activate loop search
nwGUI.docEditor.docSearch.toggleLoop.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleLoop.isChecked()
- assert nwGUI.docEditor.docSearch.doLoop
+ assert nwGUI.docEditor.docSearch.doLoop is True
- # Find Next by Menu Search > Find Next
+ # Find next by menu Search > Find Next
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 632) < 3
- # Close Search
+ # Close search
nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.isVisible() is False
assert nwGUI.docEditor.setCursorPosition(15)
- # Toggle Search Again with Header Button
+ # Toggle search again with header button
qtbot.mouseClick(nwGUI.docEditor.docHeader.searchButton, Qt.LeftButton, delay=keyDelay)
assert nwGUI.docEditor.docSearch.setSearchText("")
assert nwGUI.docEditor.docSearch.isVisible() is True
- # Enable RegEx Search
+ # Search for non-existing
+ assert nwGUI.docEditor.setCursorPosition(0)
+ assert nwGUI.docEditor.docSearch.setSearchText("abcdef")
+ qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
+ assert nwGUI.docEditor.getCursorPosition() < 3 # No result
+
+ # Enable RegEx search
nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleRegEx.isChecked()
- assert nwGUI.docEditor.docSearch.isRegEx
+ assert nwGUI.docEditor.docSearch.isRegEx is True
- # Set Invalid RegEx
+ # Set invalid RegEx
+ assert nwGUI.docEditor.setCursorPosition(0)
assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus[")
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
assert nwGUI.docEditor.getCursorPosition() < 3 # No result
- # Set Valid RegEx
+ # Set valid RegEx
assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus")
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
assert abs(nwGUI.docEditor.getCursorPosition() - 208) < 3
- # Find Next and then Prev
+ # Find next and then prev
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 309) < 3
nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 208) < 3
- # Make RegEx Case Sensitive
+ # Make RegEx case sensitive
nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleCase.isChecked()
- assert nwGUI.docEditor.docSearch.isCaseSense
+ assert nwGUI.docEditor.docSearch.isCaseSense is True
- # Find Next (One Result)
+ # Find next/prev (one result)
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 611) < 3
+ nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 611) < 3
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 611) < 3
- # Trigger Replace
+ # Trigger replace
nwGUI.mainMenu.aReplace.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.setReplaceText("foo")
- # Disable RegEx Case Sensitive
+ # Disable RegEx case sensitive
nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger)
assert not nwGUI.docEditor.docSearch.toggleCase.isChecked()
- assert not nwGUI.docEditor.docSearch.isCaseSense
+ assert nwGUI.docEditor.docSearch.isCaseSense is False
- # Toggle Replace Preserve Case
+ # Toggle replace preserve case
nwGUI.docEditor.docSearch.toggleMatchCap.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleMatchCap.isChecked()
- assert nwGUI.docEditor.docSearch.doMatchCap
+ assert nwGUI.docEditor.docSearch.doMatchCap is True
- # Replace "Sus" with "Foo" via Menu
+ # Replace "Sus" with "Foo" via menu
+ assert nwGUI.docEditor.setCursorPosition(590)
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
nwGUI.mainMenu.aReplaceNext.activate(QAction.Trigger)
assert nwGUI.docEditor.getText()[608:619] == "Foopendisse"
- # Find Next to Loop File
+ # Find next/prev to loop file
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 208) < 3
+ nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 1790) < 3
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 208) < 3
- # Replace "sus" with "foo" via Replace Button
+ # Replace "sus" with "foo" via replace button
qtbot.mouseClick(nwGUI.docEditor.docSearch.replaceButton, Qt.LeftButton, delay=keyDelay)
assert nwGUI.docEditor.getText()[205:213] == "foocipit"
- # Revert Last Two Replaces
+ # Revert last two replaces
assert nwGUI.docEditor.docAction(nwDocAction.UNDO)
assert nwGUI.docEditor.docAction(nwDocAction.UNDO)
assert nwGUI.docEditor.getText() == origText
- # Disable RegEx Search
+ # Disable RegEx search
nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger)
assert not nwGUI.docEditor.docSearch.toggleRegEx.isChecked()
- assert not nwGUI.docEditor.docSearch.isRegEx
+ assert nwGUI.docEditor.docSearch.isRegEx is False
- # Close Search and Select "est" Again
+ # Close search and select "est" again
nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
assert nwGUI.docEditor.setCursorPosition(630)
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.selectedText() == "est"
- # Activate Search Again
+ # Activate search again
nwGUI.mainMenu.aFind.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.isVisible()
assert nwGUI.docEditor.docSearch.getSearchText() == "est"
- # Enable Full Word Search
+ # Enable full word search
nwGUI.docEditor.docSearch.toggleWord.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleWord.isChecked()
- assert nwGUI.docEditor.docSearch.isWholeWord
+ assert nwGUI.docEditor.docSearch.isWholeWord is True
- # Only One Match
+ # Only one match
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 632) < 3
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 632) < 3
- # Enable Next Doc Search
+ # Enable next doc search
nwGUI.docEditor.docSearch.toggleProject.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleProject.isChecked()
- assert nwGUI.docEditor.docSearch.doNextFile
+ assert nwGUI.docEditor.docSearch.doNextFile is True
- # Next Match
+ # Next match
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert nwGUI.docEditor.docHandle() == "2426c6f0ca922" # Next document
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
@@ -1433,6 +1449,16 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 1127) < 3
+ # Next doc, no match
+ assert nwGUI.docEditor.docSearch.doNextFile is True
+ assert nwGUI.docEditor.docSearch.setSearchText("abcdef")
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docHandle() != "2426c6f0ca922"
+ assert nwGUI.docEditor.docHandle() == "04468803b92e1"
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docHandle() != "04468803b92e1"
+ assert nwGUI.docEditor.docHandle() == "7a992350f3eb6"
+
# Toggle Replace
nwGUI.docEditor.beginReplace()
@@ -1441,16 +1467,16 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: True)
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False)
monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False)
- assert not nwGUI.docEditor.focusNextPrevChild(True)
+ assert nwGUI.docEditor.focusNextPrevChild(True) is False
monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: False)
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True)
monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False)
- assert nwGUI.docEditor.focusNextPrevChild(True)
+ assert nwGUI.docEditor.focusNextPrevChild(True) is True
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False)
monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: True)
- assert nwGUI.docEditor.focusNextPrevChild(True)
+ assert nwGUI.docEditor.focusNextPrevChild(True) is True
# qtbot.stopForInteraction()
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 4db9ed7e..34cfaffa 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -199,7 +199,6 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir):
# Change some settings
nwGUI.mainConf.hideHScroll = True
nwGUI.mainConf.hideVScroll = True
- nwGUI.mainConf.scrollPastEnd = True
nwGUI.mainConf.autoScrollPos = 80
nwGUI.mainConf.autoScroll = True