Test Coverage of the Editor (#787)

* Drop the _qDocument class variables
* Split up the current doceditor test file
* Add tests for editor init, load and save
* Add tests for editor meta functions and actions
* Add tests for editor insert functions
* Add tests for editor text manipulation and block formatting
* Fix code style
* Add text coverage for alignment and indent
This commit is contained in:
Veronica Berglyd Olsen
2021-07-05 16:10:52 +02:00
committed by GitHub
parent 1d16cc2a03
commit 36be7b0b33
7 changed files with 1892 additions and 657 deletions
+349 -331
View File
@@ -111,9 +111,9 @@ class GuiDocEditor(QTextEdit):
self._typPadChar = " "
# Core Elements and Signals
self._qDocument = self.document()
self._qDocument.contentsChange.connect(self._docChange)
self._qDocument.documentLayout().documentSizeChanged.connect(self._docSizeChanged)
qDoc = self.document()
qDoc.contentsChange.connect(self._docChange)
qDoc.documentLayout().documentSizeChanged.connect(self._docSizeChanged)
# Document Title
self.docHeader = GuiDocEditHeader(self)
@@ -121,7 +121,7 @@ class GuiDocEditor(QTextEdit):
self.docSearch = GuiDocEditSearch(self)
# Syntax
self.hLight = GuiDocHighlighter(self._qDocument, self.theParent)
self.hLight = GuiDocHighlighter(qDoc, self.theParent)
# Context Menu
self.setContextMenuPolicy(Qt.CustomContextMenu)
@@ -221,9 +221,10 @@ class GuiDocEditor(QTextEdit):
# Set font
theFont = QFont()
qDoc = self.document()
if self.mainConf.textFont is None:
# If none is defined, set the default back to config
self.mainConf.textFont = self._qDocument.defaultFont().family()
self.mainConf.textFont = qDoc.defaultFont().family()
theFont.setFamily(self.mainConf.textFont)
theFont.setPointSize(self.mainConf.textSize)
@@ -246,7 +247,7 @@ class GuiDocEditor(QTextEdit):
# Set default text margins
cM = self.mainConf.getTextMargin()
self._qDocument.setDocumentMargin(0)
qDoc.setDocumentMargin(0)
self.setViewportMargins(cM, cM, cM, cM)
# Also set the document text options for the document text flow
@@ -259,7 +260,7 @@ class GuiDocEditor(QTextEdit):
if self.mainConf.showLineEndings:
theOpt.setFlags(theOpt.flags() | QTextOption.ShowLineAndParagraphSeparators)
self._qDocument.setDefaultTextOption(theOpt)
qDoc.setDefaultTextOption(theOpt)
# Scroll bars
if self.mainConf.hideVScroll:
@@ -275,7 +276,7 @@ class GuiDocEditor(QTextEdit):
# Refresh the tab stops
if self.mainConf.verQtValue >= 51000:
self.setTabStopDistance(self.mainConf.getTabWidth())
else:
else: # pragma: no cover
self.setTabStopWidth(self.mainConf.getTabWidth())
# Initialise the syntax highlighter
@@ -370,7 +371,6 @@ class GuiDocEditor(QTextEdit):
self.setCursorLine(tLine)
self.docFooter.updateLineCount()
self.lengthLast = self._qDocument.characterCount()
self._docHeaders = self.theIndex.getHandleHeaders(self._docHandle)
qApp.processEvents()
@@ -378,7 +378,7 @@ class GuiDocEditor(QTextEdit):
qApp.restoreOverrideCursor()
# This is a hack to fix invisble cursor on an empty document
if self._qDocument.characterCount() <= 1:
if self.document().characterCount() <= 1:
self.setPlainText("\n")
self.setPlainText("")
self.setCursorPosition(0)
@@ -391,7 +391,7 @@ class GuiDocEditor(QTextEdit):
return True
def updateTagHighLighting(self, forceBigDoc=False):
def updateTagHighLighting(self):
"""Rerun the syntax highlighter on all meta data lines.
"""
self.hLight.rehighlightByType(GuiDocHighlighter.BLOCK_META)
@@ -400,7 +400,7 @@ class GuiDocEditor(QTextEdit):
def redrawText(self):
"""Redraw the text by marking the document content as "dirty".
"""
self._qDocument.markContentsDirty(0, self._qDocument.characterCount())
self.document().markContentsDirty(0, self.document().characterCount())
self.updateDocMargins()
return
@@ -532,9 +532,9 @@ class GuiDocEditor(QTextEdit):
tmpDocChanged = self._docChanged
if self.mainConf.scrollPastEnd:
docFrame = self._qDocument.rootFrame().frameFormat()
docFrame = self.document().rootFrame().frameFormat()
docFrame.setBottomMargin(max(0, 0.9*(wH - uM - lM - 4*tB)))
self._qDocument.rootFrame().setFrameFormat(docFrame)
self.document().rootFrame().setFrameFormat(docFrame)
# This is needed as the setFrameFormat function itself will
# trigger the contetsChanged signal which sets _docChanged, so we
@@ -576,7 +576,7 @@ class GuiDocEditor(QTextEdit):
def isEmpty(self):
"""Wrapper function to check if the current document is empty.
"""
return self._qDocument.isEmpty()
return self.document().isEmpty()
def currentDictionary(self):
"""Return the current dictionary object.
@@ -596,7 +596,7 @@ class GuiDocEditor(QTextEdit):
See: https://doc.qt.io/qt-5/qtextdocument.html#toPlainText
"""
if self.mainConf.verQtValue >= 50900:
theText = self._qDocument.toRawText()
theText = self.document().toRawText()
theText = theText.replace(nwUnicode.U_LSEP, "\n") # Line separators
theText = theText.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators
else:
@@ -628,7 +628,7 @@ class GuiDocEditor(QTextEdit):
if not isinstance(thePosition, int):
return False
nChars = self._qDocument.characterCount()
nChars = self.document().characterCount()
if nChars > 1:
theCursor = self.textCursor()
theCursor.setPosition(min(max(thePosition, 0), nChars-1))
@@ -652,7 +652,7 @@ class GuiDocEditor(QTextEdit):
return False
if theLine >= 0:
theBlock = self._qDocument.findBlockByLineNumber(theLine)
theBlock = self.document().findBlockByLineNumber(theLine)
if theBlock:
self.setCursorPosition(theBlock.position())
self.docFooter.updateLineCount()
@@ -710,7 +710,8 @@ class GuiDocEditor(QTextEdit):
def spellCheckDocument(self):
"""Rerun the highlighter to update spell checking status of the
currently loaded text. The fastest way to do this, at least as
of Qt 5.13, is to clear the text and put it back.
of Qt 5.13, is to clear the text and put it back. This clears
the undo stack, so we only do it for big documents.
"""
logger.verbose("Running spell checker")
if self._spellCheck:
@@ -739,11 +740,16 @@ class GuiDocEditor(QTextEdit):
passed to it without having to consider the internal logic of
this class when calling these actions from other classes.
"""
logger.verbose("Requesting action: '%s'", theAction.name)
if self._docHandle is None:
logger.error("No document open")
return False
if not isinstance(theAction, nwDocAction):
logger.error("Not a document action")
return False
logger.verbose("Requesting action: %s" % theAction.name)
self._allowAutoReplace(False)
if theAction == nwDocAction.UNDO:
self.undo()
@@ -1012,7 +1018,7 @@ class GuiDocEditor(QTextEdit):
self._lastEdit = time()
self._lastFind = None
if self._qDocument.characterCount() > nwConst.MAX_DOCSIZE:
if self.document().characterCount() > nwConst.MAX_DOCSIZE:
self.theParent.makeAlert(self.tr(
"The document has grown too big and you cannot add more text to it. "
"The maximum size of a single novelWriter document is {0} MB."
@@ -1029,7 +1035,7 @@ class GuiDocEditor(QTextEdit):
self.wcTimer.start()
if self._doReplace and chrAdd == 1:
self._docAutoReplace(self._qDocument.findBlock(thePos))
self._docAutoReplace(self.document().findBlock(thePos))
return
@@ -1198,7 +1204,7 @@ class GuiDocEditor(QTextEdit):
# Must not be emitted if docHandle is None!
self.docCountsChanged.emit(self._docHandle, cCount, wCount, pCount)
self._checkDocSize(self._qDocument.characterCount())
self._checkDocSize(self.document().characterCount())
self.docFooter.updateCounts()
return
@@ -1211,7 +1217,7 @@ class GuiDocEditor(QTextEdit):
moved to has been drawn before the move is made.
"""
if self._queuePos is not None:
thePos = self._qDocument.documentLayout().hitTest(
thePos = self.document().documentLayout().hitTest(
QPointF(theSize.width(), theSize.height()), Qt.FuzzyHit
)
if self._queuePos <= thePos:
@@ -1362,226 +1368,74 @@ class GuiDocEditor(QTextEdit):
return
##
# Internal Functions
# Internal Functions : Text Manipulation
##
def _followTag(self, theCursor=None, loadTag=True):
"""Activated by Ctrl+Enter. Checks that we're in a block
starting with '@'. We then find the word under the cursor and
check that it is after the ':'. If all this is fine, we have a
tag and can tell the document viewer to try and find and load
the file where the tag is defined.
def _toggleFormat(self, fLen, fChar):
"""Toggle the formatting of a specific type for a piece of text.
If more than one block is selected, the formatting is applied to
the first block.
"""
if theCursor is None:
theCursor = self.textCursor()
theBlock = theCursor.block()
theText = theBlock.text()
if len(theText) == 0:
theCursor = self._autoSelect()
if not theCursor.hasSelection():
logger.warning("No selection made, nothing to do")
return False
if theText.startswith("@"):
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
theCursor.select(QTextCursor.WordUnderCursor)
theWord = theCursor.selectedText()
cPos = theText.find(":")
wPos = theCursor.selectionStart() - theBlock.position()
if wPos <= cPos:
return False
blockS = self.document().findBlock(posS)
blockE = self.document().findBlock(posE)
if loadTag:
logger.verbose("Attempting to follow tag '%s'", theWord)
self.theParent.docViewer.loadFromTag(theWord)
if blockS != blockE:
posE = blockS.position() + blockS.length() - 1
theCursor.clearSelection()
theCursor.setPosition(posS, QTextCursor.MoveAnchor)
theCursor.setPosition(posE, QTextCursor.KeepAnchor)
self.setTextCursor(theCursor)
numB = 0
for n in range(fLen):
if self.document().characterAt(posS-n-1) == fChar:
numB += 1
else:
logger.verbose("Potential tag '%s'", theWord)
break
return True
return False
def _openSpellContext(self):
"""Opens the spell check context menu at the current point of
the cursor.
"""
self._openContextMenu(self.cursorRect().center())
return
def _docAutoReplace(self, theBlock):
"""Auto-replace text elements based on main configuration.
"""
if not theBlock.isValid():
return
theText = theBlock.text()
theCursor = self.textCursor()
thePos = theCursor.positionInBlock()
theLen = len(theText)
if theLen < 1 or thePos-1 > theLen:
return
theOne = theText[thePos-1:thePos]
theTwo = theText[thePos-2:thePos]
theThree = theText[thePos-3:thePos]
if not theOne: # Makes Neo sad
return
nDelete = 0
tInsert = theOne
if self.mainConf.doReplaceDQuote and theTwo == ' "':
nDelete = 1
tInsert = self._typDQOpen
elif self.mainConf.doReplaceDQuote and theOne == '"':
nDelete = 1
if thePos == 1:
tInsert = self._typDQOpen
numA = 0
for n in range(fLen):
if self.document().characterAt(posE+n) == fChar:
numA += 1
else:
tInsert = self._typDQClose
elif self.mainConf.doReplaceSQuote and theTwo == " '":
nDelete = 1
tInsert = self._typSQOpen
elif self.mainConf.doReplaceSQuote and theOne == "'":
nDelete = 1
if thePos == 1:
tInsert = self._typSQOpen
else:
tInsert = self._typSQClose
elif self.mainConf.doReplaceDash and theThree == "---":
nDelete = 3
tInsert = nwUnicode.U_EMDASH
elif self.mainConf.doReplaceDash and theTwo == "--":
nDelete = 2
tInsert = nwUnicode.U_ENDASH
elif self.mainConf.doReplaceDash and theTwo == nwUnicode.U_ENDASH + "-":
nDelete = 2
tInsert = nwUnicode.U_EMDASH
elif self.mainConf.doReplaceDots and theThree == "...":
nDelete = 3
tInsert = nwUnicode.U_HELLIP
tCheck = tInsert
if tCheck in self.mainConf.fmtPadBefore:
nDelete = max(nDelete, 1)
tInsert = self._typPadChar + tInsert
if tCheck in self.mainConf.fmtPadAfter:
nDelete = max(nDelete, 1)
tInsert = tInsert + self._typPadChar
if nDelete > 0:
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, nDelete)
theCursor.insertText(tInsert)
return
def _updateHeaders(self, checkPos=False, checkLevel=False):
"""Update the headers record and return True if anything
changed, if a check flag was provided.
"""
if self._docHandle is None:
return False
newHeaders = self.theIndex.getHandleHeaders(self._docHandle)
if checkPos:
newPos = [x[0] for x in newHeaders]
oldPos = [x[0] for x in self._docHeaders]
if checkLevel:
newLev = [x[1] for x in newHeaders]
oldLev = [x[1] for x in self._docHeaders]
self._docHeaders = newHeaders
if checkPos:
return newPos != oldPos
if checkLevel:
return newLev != oldLev
return False
def _replaceQuotes(self, sQuote, oQuote, cQuote):
"""Replace all straight quotes in the selected text.
"""
theCursor = self.textCursor()
if theCursor.hasSelection():
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
closeCheck = (
" ", "\n", nwUnicode.U_LSEP, nwUnicode.U_PSEP
)
self._allowAutoReplace(False)
for posC in range(posS, posE+1):
theCursor.setPosition(posC)
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 2)
selText = theCursor.selectedText()
nS = len(selText)
if nS == 2:
pC = selText[0]
cC = selText[1]
elif nS == 1:
pC = " "
cC = selText[0]
else:
continue
if cC != sQuote:
continue
theCursor.clearSelection()
theCursor.setPosition(posC)
if pC in closeCheck:
theCursor.beginEditBlock()
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 1)
theCursor.insertText(oQuote)
theCursor.endEditBlock()
else:
theCursor.beginEditBlock()
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 1)
theCursor.insertText(cQuote)
theCursor.endEditBlock()
self._allowAutoReplace(True)
break
if fLen == min(numA, numB):
self._clearSurrounding(theCursor, fLen)
else:
self.theParent.makeAlert(self.tr(
"Please select some text before calling replace quotes."
), nwAlert.ERROR)
self._wrapSelection(fChar*fLen)
return
return True
def _checkDocSize(self, theSize):
"""Check if document size crosses the big document limit set in
config. If so, we will set the big document flag to True.
def _clearSurrounding(self, theCursor, nChars):
"""Clears n characters before and after the cursor.
"""
bigLim = self.mainConf.bigDocLimit*1000
newState = theSize > bigLim
if not theCursor.hasSelection():
logger.warning("No selection made, nothing to do")
return False
if newState != self._bigDoc:
if newState:
logger.info(
f"The document size is {theSize:n} > {bigLim:n}, "
f"big doc mode has been enabled"
)
else:
logger.info(
f"The document size is {theSize:n} <= {bigLim:n}, "
f"big doc mode has been disabled"
)
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
theCursor.clearSelection()
theCursor.beginEditBlock()
theCursor.setPosition(posS)
for i in range(nChars):
theCursor.deletePreviousChar()
theCursor.setPosition(posE)
for i in range(nChars):
theCursor.deletePreviousChar()
theCursor.endEditBlock()
theCursor.clearSelection()
self._bigDoc = newState
return
return True
def _wrapSelection(self, tBefore, tAfter=None):
"""Wraps the selected text in whatever is in tBefore and tAfter.
@@ -1593,120 +1447,84 @@ class GuiDocEditor(QTextEdit):
tAfter = tBefore
theCursor = self._autoSelect()
if theCursor.hasSelection():
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
blockS = self._qDocument.findBlock(posS)
blockE = self._qDocument.findBlock(posE)
if blockS != blockE:
posE = blockS.position() + blockS.length() - 1
theCursor.clearSelection()
theCursor.beginEditBlock()
theCursor.setPosition(posE)
theCursor.insertText(tAfter)
theCursor.setPosition(posS)
theCursor.insertText(tBefore)
theCursor.endEditBlock()
theCursor.setPosition(posE + len(tBefore), QTextCursor.MoveAnchor)
theCursor.setPosition(posS + len(tBefore), QTextCursor.KeepAnchor)
self.setTextCursor(theCursor)
else:
if not theCursor.hasSelection():
logger.warning("No selection made, nothing to do")
return
return False
def _clearSurrounding(self, theCursor, nChars):
"""Clears n characters before and after the cursor.
"""
if theCursor.hasSelection():
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
theCursor.clearSelection()
theCursor.beginEditBlock()
theCursor.setPosition(posS)
for i in range(nChars):
theCursor.deletePreviousChar()
theCursor.setPosition(posE)
for i in range(nChars):
theCursor.deletePreviousChar()
theCursor.endEditBlock()
theCursor.clearSelection()
else:
logger.warning("No selection made, nothing to do")
return
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
def _autoSelect(self):
"""Returns a cursor which may or may not have a selection based
on user settings and document action.
qDoc = self.document()
blockS = qDoc.findBlock(posS)
blockE = qDoc.findBlock(posE)
if blockS != blockE:
posE = blockS.position() + blockS.length() - 1
theCursor.clearSelection()
theCursor.beginEditBlock()
theCursor.setPosition(posE)
theCursor.insertText(tAfter)
theCursor.setPosition(posS)
theCursor.insertText(tBefore)
theCursor.endEditBlock()
theCursor.setPosition(posE + len(tBefore), QTextCursor.MoveAnchor)
theCursor.setPosition(posS + len(tBefore), QTextCursor.KeepAnchor)
self.setTextCursor(theCursor)
return True
def _replaceQuotes(self, sQuote, oQuote, cQuote):
"""Replace all straight quotes in the selected text.
"""
theCursor = self.textCursor()
if self.mainConf.autoSelect and not theCursor.hasSelection():
theCursor.select(QTextCursor.WordUnderCursor)
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
if not theCursor.hasSelection():
self.theParent.makeAlert(self.tr(
"Please select some text before calling replace quotes."
), nwAlert.ERROR)
return False
# Underscore counts as a part of the word, so check that the
# selection isn't wrapped in italics markers.
reSelect = False
if self._qDocument.characterAt(posS) == "_":
posS += 1
reSelect = True
if self._qDocument.characterAt(posE) == "_":
posE -= 1
reSelect = True
if reSelect:
theCursor.clearSelection()
theCursor.setPosition(posS, QTextCursor.MoveAnchor)
theCursor.setPosition(posE-1, QTextCursor.KeepAnchor)
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
closeCheck = (
" ", "\n", nwUnicode.U_LSEP, nwUnicode.U_PSEP
)
self.setTextCursor(theCursor)
self._allowAutoReplace(False)
for posC in range(posS, posE+1):
theCursor.setPosition(posC)
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 2)
selText = theCursor.selectedText()
return theCursor
nS = len(selText)
if nS == 2:
pC = selText[0]
cC = selText[1]
elif nS == 1:
pC = " "
cC = selText[0]
else: # pragma: no cover
continue
def _toggleFormat(self, fLen, fChar):
"""Toggle the formatting of a specific type for a piece of text.
If more than one block is selected, the formatting is applied to
the first block.
"""
theCursor = self._autoSelect()
if theCursor.hasSelection():
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
if cC != sQuote:
continue
blockS = self._qDocument.findBlock(posS)
blockE = self._qDocument.findBlock(posE)
if blockS != blockE:
posE = blockS.position() + blockS.length() - 1
theCursor.clearSelection()
theCursor.setPosition(posS, QTextCursor.MoveAnchor)
theCursor.setPosition(posE, QTextCursor.KeepAnchor)
self.setTextCursor(theCursor)
numB = 0
for n in range(fLen):
if self._qDocument.characterAt(posS-n-1) == fChar:
numB += 1
else:
break
numA = 0
for n in range(fLen):
if self._qDocument.characterAt(posE+n) == fChar:
numA += 1
else:
break
cLevel = min(numB, numA)
if cLevel == fLen:
self._clearSurrounding(theCursor, fLen)
theCursor.clearSelection()
theCursor.setPosition(posC)
if pC in closeCheck:
theCursor.beginEditBlock()
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 1)
theCursor.insertText(oQuote)
theCursor.endEditBlock()
else:
self._wrapSelection(fChar*fLen)
theCursor.beginEditBlock()
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 1)
theCursor.insertText(cQuote)
theCursor.endEditBlock()
return
self._allowAutoReplace(True)
return True
def _formatBlock(self, docAction):
"""Changes the block format of the block under the cursor.
@@ -1874,6 +1692,206 @@ class GuiDocEditor(QTextEdit):
return True
##
# Internal Functions
##
def _followTag(self, theCursor=None, loadTag=True):
"""Activated by Ctrl+Enter. Checks that we're in a block
starting with '@'. We then find the word under the cursor and
check that it is after the ':'. If all this is fine, we have a
tag and can tell the document viewer to try and find and load
the file where the tag is defined.
"""
if theCursor is None:
theCursor = self.textCursor()
theBlock = theCursor.block()
theText = theBlock.text()
if len(theText) == 0:
return False
if theText.startswith("@"):
theCursor.select(QTextCursor.WordUnderCursor)
theWord = theCursor.selectedText()
cPos = theText.find(":")
wPos = theCursor.selectionStart() - theBlock.position()
if wPos <= cPos:
return False
if loadTag:
logger.verbose("Attempting to follow tag '%s'" % theWord)
self.theParent.docViewer.loadFromTag(theWord)
else:
logger.verbose("Potential tag '%s'" % theWord)
return True
return False
def _openSpellContext(self):
"""Opens the spell check context menu at the current point of
the cursor.
"""
self._openContextMenu(self.cursorRect().center())
return
def _docAutoReplace(self, theBlock):
"""Auto-replace text elements based on main configuration.
"""
if not theBlock.isValid():
return
theText = theBlock.text()
theCursor = self.textCursor()
thePos = theCursor.positionInBlock()
theLen = len(theText)
if theLen < 1 or thePos-1 > theLen:
return
theOne = theText[thePos-1:thePos]
theTwo = theText[thePos-2:thePos]
theThree = theText[thePos-3:thePos]
if not theOne:
# Sorry, Neo and Zathras
return
nDelete = 0
tInsert = theOne
if self.mainConf.doReplaceDQuote and theTwo == ' "':
nDelete = 1
tInsert = self._typDQOpen
elif self.mainConf.doReplaceDQuote and theOne == '"':
nDelete = 1
if thePos == 1:
tInsert = self._typDQOpen
else:
tInsert = self._typDQClose
elif self.mainConf.doReplaceSQuote and theTwo == " '":
nDelete = 1
tInsert = self._typSQOpen
elif self.mainConf.doReplaceSQuote and theOne == "'":
nDelete = 1
if thePos == 1:
tInsert = self._typSQOpen
else:
tInsert = self._typSQClose
elif self.mainConf.doReplaceDash and theThree == "---":
nDelete = 3
tInsert = nwUnicode.U_EMDASH
elif self.mainConf.doReplaceDash and theTwo == "--":
nDelete = 2
tInsert = nwUnicode.U_ENDASH
elif self.mainConf.doReplaceDash and theTwo == nwUnicode.U_ENDASH + "-":
nDelete = 2
tInsert = nwUnicode.U_EMDASH
elif self.mainConf.doReplaceDots and theThree == "...":
nDelete = 3
tInsert = nwUnicode.U_HELLIP
tCheck = tInsert
if tCheck in self.mainConf.fmtPadBefore:
nDelete = max(nDelete, 1)
tInsert = self._typPadChar + tInsert
if tCheck in self.mainConf.fmtPadAfter:
nDelete = max(nDelete, 1)
tInsert = tInsert + self._typPadChar
if nDelete > 0:
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, nDelete)
theCursor.insertText(tInsert)
return
def _updateHeaders(self, checkPos=False, checkLevel=False):
"""Update the headers record and return True if anything
changed, if a check flag was provided.
"""
if self._docHandle is None:
return False
newHeaders = self.theIndex.getHandleHeaders(self._docHandle)
if checkPos:
newPos = [x[0] for x in newHeaders]
oldPos = [x[0] for x in self._docHeaders]
if checkLevel:
newLev = [x[1] for x in newHeaders]
oldLev = [x[1] for x in self._docHeaders]
self._docHeaders = newHeaders
if checkPos:
return newPos != oldPos
if checkLevel:
return newLev != oldLev
return False
def _checkDocSize(self, theSize):
"""Check if document size crosses the big document limit set in
config. If so, we will set the big document flag to True.
"""
bigLim = round(self.mainConf.bigDocLimit*1000)
newState = theSize > bigLim
if newState != self._bigDoc:
if newState:
logger.info(
f"The document size is {theSize:n} > {bigLim:n}, "
f"big doc mode has been enabled"
)
else:
logger.info(
f"The document size is {theSize:n} <= {bigLim:n}, "
f"big doc mode has been disabled"
)
self._bigDoc = newState
return
def _autoSelect(self):
"""Returns a cursor which may or may not have a selection based
on user settings and document action.
"""
theCursor = self.textCursor()
if self.mainConf.autoSelect and not theCursor.hasSelection():
theCursor.select(QTextCursor.WordUnderCursor)
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
# Underscore counts as a part of the word, so check that the
# selection isn't wrapped in italics markers.
reSelect = False
qDoc = self.document()
if qDoc.characterAt(posS) == "_":
posS += 1
reSelect = True
if qDoc.characterAt(posE) == "_":
posE -= 1
reSelect = True
if reSelect:
theCursor.clearSelection()
theCursor.setPosition(posS, QTextCursor.MoveAnchor)
theCursor.setPosition(posE-1, QTextCursor.KeepAnchor)
self.setTextCursor(theCursor)
return theCursor
def _makeSelection(self, selMode):
"""Wrapper function to select text based on a selection mode.
"""
@@ -2753,7 +2771,7 @@ class GuiDocEditFooter(QWidget):
else:
theCursor = self.docEditor.textCursor()
iLine = theCursor.blockNumber() + 1
iDist = 100*iLine/self.docEditor._qDocument.blockCount()
iDist = 100*iLine/self.docEditor.document().blockCount()
self.linesText.setText(
self.tr("Line: {0} ({1})").format(f"{iLine:n}", f"{iDist:.0f} %")
@@ -2775,7 +2793,7 @@ class GuiDocEditFooter(QWidget):
self.tr("Words: {0} ({1})").format(f"{wCount:n}", f"{wDiff:+n}")
)
byteSize = self.docEditor._qDocument.characterCount()
byteSize = self.docEditor.document().characterCount()
self.wordsText.setToolTip(
self.tr("Document size is {0} bytes").format(f"{byteSize:n}")
)