+11
-4
@@ -53,10 +53,11 @@ class NWItem():
|
||||
self.isExported = True
|
||||
|
||||
# Document Meta Data
|
||||
self.charCount = 0
|
||||
self.wordCount = 0
|
||||
self.paraCount = 0
|
||||
self.cursorPos = 0
|
||||
self.charCount = 0 # Current character count
|
||||
self.wordCount = 0 # Current word count
|
||||
self.paraCount = 0 # Current paragraph count
|
||||
self.initCount = 0 # Initial word count
|
||||
self.cursorPos = 0 # Last cursor position
|
||||
|
||||
return
|
||||
|
||||
@@ -274,4 +275,10 @@ class NWItem():
|
||||
self.cursorPos = checkInt(thePosition, 0)
|
||||
return
|
||||
|
||||
def saveInitialCount(self):
|
||||
"""Set the initial word count.
|
||||
"""
|
||||
self.initCount = self.wordCount
|
||||
return
|
||||
|
||||
# END Class NWItem
|
||||
|
||||
@@ -134,6 +134,7 @@ class NWTree():
|
||||
nwItem = NWItem(self.theProject)
|
||||
if nwItem.unpackXML(xItem):
|
||||
self.append(nwItem.itemHandle, nwItem.parHandle, nwItem)
|
||||
nwItem.saveInitialCount()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
+155
-6
@@ -36,8 +36,8 @@ from time import time
|
||||
|
||||
from PyQt5.QtCore import Qt, QSize, QThread, QTimer, pyqtSlot, QRegExp
|
||||
from PyQt5.QtGui import (
|
||||
QTextCursor, QTextOption, QKeySequence, QFont, QColor, QPalette,
|
||||
QTextDocument, QCursor
|
||||
QTextCursor, QTextOption, QKeySequence, QFont, QColor, QPalette, QIcon,
|
||||
QTextDocument, QCursor, QPixmap
|
||||
)
|
||||
from PyQt5.QtWidgets import (
|
||||
qApp, QTextEdit, QAction, QMenu, QShortcut, QMessageBox, QWidget, QLabel,
|
||||
@@ -49,7 +49,7 @@ from nw.core import NWDoc, NWSpellSimple, countWords
|
||||
from nw.gui.dochighlight import GuiDocHighlighter
|
||||
from nw.common import transferCase
|
||||
from nw.constants import (
|
||||
nwAlert, nwUnicode, nwDocAction, nwDocInsert, nwInsertSymbols
|
||||
nwAlert, nwUnicode, nwDocAction, nwDocInsert, nwInsertSymbols, nwItemClass
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -92,6 +92,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
# Document Title
|
||||
self.docHeader = GuiDocEditHeader(self)
|
||||
self.docFooter = GuiDocEditFooter(self)
|
||||
self.docSearch = GuiDocEditSearch(self)
|
||||
|
||||
# Syntax
|
||||
@@ -160,6 +161,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
self.setDocumentChanged(False)
|
||||
self.docHeader.setTitleFromHandle(self.theHandle)
|
||||
self.docFooter.setHandle(self.theHandle)
|
||||
|
||||
return True
|
||||
|
||||
@@ -277,6 +279,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
self.setReadOnly(False)
|
||||
self.docHeader.setTitleFromHandle(self.theHandle)
|
||||
self.docFooter.setHandle(self.theHandle)
|
||||
self.updateDocMargins()
|
||||
self.hLight.spellCheck = spTemp
|
||||
qApp.restoreOverrideCursor()
|
||||
@@ -342,7 +345,10 @@ class GuiDocEditor(QTextEdit):
|
||||
tB = self.frameWidth()
|
||||
tW = wW - 2*tB - sW
|
||||
tH = self.docHeader.height()
|
||||
fH = self.docFooter.height()
|
||||
fY = self.height() - fH - tB
|
||||
self.docHeader.setGeometry(tB, tB, tW, tH)
|
||||
self.docFooter.setGeometry(tB, fY, tW, fH)
|
||||
|
||||
if self.docSearch.isVisible():
|
||||
rH = self.docSearch.height()
|
||||
@@ -352,16 +358,17 @@ class GuiDocEditor(QTextEdit):
|
||||
else:
|
||||
rH = 0
|
||||
|
||||
self.setViewportMargins(tM, max(cM, tH, rH), tM, cM)
|
||||
self.setViewportMargins(tM, max(cM, tH, rH), tM, max(cM, fH))
|
||||
|
||||
return
|
||||
|
||||
def updateDocTitle(self, tHandle):
|
||||
def updateDocInfo(self, tHandle):
|
||||
"""Called when an item label is changed to check if the document
|
||||
title bar needs updating,
|
||||
"""
|
||||
if tHandle == self.theHandle:
|
||||
self.docHeader.setTitleFromHandle(self.theHandle)
|
||||
self.docFooter.updateInfo()
|
||||
self.updateDocMargins()
|
||||
return
|
||||
|
||||
@@ -763,13 +770,13 @@ class GuiDocEditor(QTextEdit):
|
||||
self.nwDocument.theItem.setWordCount(self.wordCount)
|
||||
self.nwDocument.theItem.setParaCount(self.paraCount)
|
||||
|
||||
self.theParent.statusBar.setCounts(self.charCount, self.wordCount, self.paraCount)
|
||||
self.theParent.treeView.propagateCount(self.theHandle, self.wordCount)
|
||||
self.theParent.treeView.projectWordCount()
|
||||
self.theParent.treeMeta.updateCounts(
|
||||
self.theHandle, self.charCount, self.wordCount, self.paraCount
|
||||
)
|
||||
self._checkDocSize(self.charCount)
|
||||
self.docFooter.updateCounts()
|
||||
|
||||
return
|
||||
|
||||
@@ -1819,3 +1826,145 @@ class GuiDocEditHeader(QWidget):
|
||||
return
|
||||
|
||||
# END Class GuiDocEditHeader
|
||||
|
||||
# =============================================================================================== #
|
||||
# The Embedded Document Footer
|
||||
# Only used by DocEditor, and is at a fixed position in the QTextEdit's viewport
|
||||
# =============================================================================================== #
|
||||
|
||||
class GuiDocEditFooter(QWidget):
|
||||
|
||||
def __init__(self, docEditor):
|
||||
QWidget.__init__(self, docEditor)
|
||||
|
||||
logger.debug("Initialising GuiDocEditFooter ...")
|
||||
|
||||
self.mainConf = nw.CONFIG
|
||||
self.docEditor = docEditor
|
||||
self.theParent = docEditor.theParent
|
||||
self.theProject = docEditor.theProject
|
||||
self.theTheme = docEditor.theTheme
|
||||
self.optState = docEditor.theProject.optState
|
||||
self.theHandle = None
|
||||
|
||||
# Make a QPalette that matches the Syntax Theme
|
||||
self.thePalette = QPalette()
|
||||
self.thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
|
||||
self.thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
|
||||
|
||||
self.sPx = int(round(0.9*self.theTheme.baseIconSize))
|
||||
fPx = int(0.9*self.theTheme.fontPixelSize)
|
||||
bSp = self.mainConf.pxInt(4)
|
||||
hSp = self.mainConf.pxInt(8)
|
||||
|
||||
lblFont = self.font()
|
||||
lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
|
||||
|
||||
# Main Widget Settings
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setAutoFillBackground(True)
|
||||
self.setPalette(self.thePalette)
|
||||
|
||||
buttonStyle = (
|
||||
"QToolButton {{border: none; background: transparent;}} "
|
||||
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
|
||||
).format(*self.theTheme.colText)
|
||||
|
||||
# Status
|
||||
self.statusIcon = QLabel("")
|
||||
self.statusIcon.setContentsMargins(0, 0, 0, 0)
|
||||
self.statusIcon.setFixedHeight(self.sPx)
|
||||
self.statusIcon.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
|
||||
self.statusText = QLabel("Status")
|
||||
self.statusText.setIndent(0)
|
||||
self.statusText.setMargin(0)
|
||||
self.statusText.setContentsMargins(0, 0, 0, 0)
|
||||
self.statusText.setAutoFillBackground(True)
|
||||
self.statusText.setFixedHeight(fPx)
|
||||
self.statusText.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
self.statusText.setPalette(self.thePalette)
|
||||
self.statusText.setFont(lblFont)
|
||||
|
||||
# Words
|
||||
self.wordsIcon = QLabel("")
|
||||
self.wordsIcon.setPixmap(self.theTheme.getPixmap("status_stats", (self.sPx, self.sPx)))
|
||||
self.wordsIcon.setContentsMargins(0, 0, 0, 0)
|
||||
self.wordsIcon.setFixedHeight(self.sPx)
|
||||
self.wordsIcon.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
|
||||
self.wordsText = QLabel("Words: 0")
|
||||
self.wordsText.setIndent(0)
|
||||
self.wordsText.setMargin(0)
|
||||
self.wordsText.setContentsMargins(0, 0, 0, 0)
|
||||
self.wordsText.setAutoFillBackground(True)
|
||||
self.wordsText.setFixedHeight(fPx)
|
||||
self.wordsText.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
self.wordsText.setPalette(self.thePalette)
|
||||
self.wordsText.setFont(lblFont)
|
||||
|
||||
# Assemble Layout
|
||||
self.outerBox = QHBoxLayout()
|
||||
self.outerBox.setSpacing(bSp)
|
||||
self.outerBox.addWidget(self.statusIcon)
|
||||
self.outerBox.addWidget(self.statusText)
|
||||
self.outerBox.addStretch(1)
|
||||
self.outerBox.addWidget(self.wordsIcon)
|
||||
self.outerBox.addWidget(self.wordsText)
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
logger.debug("GuiDocEditFooter initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def setHandle(self, tHandle):
|
||||
"""Set the handle that will populate the footer's data.
|
||||
"""
|
||||
self.theHandle = tHandle
|
||||
self.updateInfo()
|
||||
self.updateCounts()
|
||||
return
|
||||
|
||||
def updateInfo(self):
|
||||
"""Update the content of text labels.
|
||||
"""
|
||||
nwItem = self.theProject.projTree[self.theHandle]
|
||||
if nwItem is None:
|
||||
sIcon = QPixmap()
|
||||
sText = ""
|
||||
else:
|
||||
iStatus = nwItem.itemStatus
|
||||
if nwItem.itemClass == nwItemClass.NOVEL:
|
||||
iStatus = self.theProject.statusItems.checkEntry(iStatus)
|
||||
theIcon = self.theParent.statusIcons[iStatus]
|
||||
else:
|
||||
iStatus = self.theProject.importItems.checkEntry(iStatus)
|
||||
theIcon = self.theParent.importIcons[iStatus]
|
||||
sIcon = theIcon.pixmap(self.sPx, self.sPx)
|
||||
sText = nwItem.itemStatus
|
||||
|
||||
self.statusIcon.setPixmap(sIcon)
|
||||
self.statusText.setText(sText)
|
||||
|
||||
return
|
||||
|
||||
def updateCounts(self):
|
||||
"""Update the word counts.
|
||||
"""
|
||||
nwItem = self.theProject.projTree[self.theHandle]
|
||||
if nwItem is None:
|
||||
wCount = 0
|
||||
wDiff = 0
|
||||
else:
|
||||
wCount = nwItem.wordCount
|
||||
wDiff = wCount - nwItem.initCount
|
||||
|
||||
self.wordsText.setText("Words: {:n} ({:+n})".format(wCount, wDiff))
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiDocEditFooter
|
||||
|
||||
+1
-1
@@ -251,7 +251,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
|
||||
return
|
||||
|
||||
def updateDocTitle(self, tHandle):
|
||||
def updateDocInfo(self, tHandle):
|
||||
"""Called when an item label is changed to check if the document
|
||||
title bar needs updating,
|
||||
"""
|
||||
|
||||
+2
-16
@@ -51,9 +51,6 @@ class GuiMainStatus(QStatusBar):
|
||||
self.theTheme = theParent.theTheme
|
||||
self.refTime = None
|
||||
|
||||
self.charCount = 0
|
||||
self.wordCount = 0
|
||||
self.paraCount = 0
|
||||
self.projWords = 0
|
||||
self.sessWords = 0
|
||||
|
||||
@@ -134,7 +131,6 @@ class GuiMainStatus(QStatusBar):
|
||||
"""
|
||||
self.setRefTime(None)
|
||||
self.setStats(0, 0)
|
||||
self.setCounts(0, 0, 0)
|
||||
self.setProjectStatus(None)
|
||||
self.setDocumentStatus(None)
|
||||
self._updateTime()
|
||||
@@ -186,15 +182,6 @@ class GuiMainStatus(QStatusBar):
|
||||
self._updateStats()
|
||||
return
|
||||
|
||||
def setCounts(self, cC, wC, pC):
|
||||
"""Set the current document statistics.
|
||||
"""
|
||||
self.charCount = cC
|
||||
self.wordCount = wC
|
||||
self.paraCount = pC
|
||||
self._updateStats()
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
@@ -203,12 +190,11 @@ class GuiMainStatus(QStatusBar):
|
||||
"""Update statistics.
|
||||
"""
|
||||
self.statsText.setToolTip(
|
||||
"D: Document word count<br>P: Project word count (session change)"
|
||||
"Project word count (session change)"
|
||||
)
|
||||
self.statsText.setText((
|
||||
"D:{wC:n} P:{pWC:n} ({sWC:+n})"
|
||||
"Words: {pWC:n} ({sWC:+n})"
|
||||
).format(
|
||||
wC = self.wordCount,
|
||||
pWC = self.projWords,
|
||||
sWC = self.sessWords,
|
||||
))
|
||||
|
||||
+2
-2
@@ -676,8 +676,8 @@ class GuiMain(QMainWindow):
|
||||
if dlgProj.exec_():
|
||||
self.treeView.setTreeItemValues(tHandle)
|
||||
self.treeMeta.updateViewBox(tHandle)
|
||||
self.docEditor.updateDocTitle(tHandle)
|
||||
self.docViewer.updateDocTitle(tHandle)
|
||||
self.docEditor.updateDocInfo(tHandle)
|
||||
self.docViewer.updateDocInfo(tHandle)
|
||||
|
||||
return
|
||||
|
||||
|
||||
+1
-1
@@ -391,7 +391,7 @@ def testItemEditor(qtbot, nwTempGUI, nwRef, nwTemp):
|
||||
itemEdit._doClose()
|
||||
|
||||
# Check that the header is updated
|
||||
nwGUI.docEditor.updateDocTitle("31489056e0916")
|
||||
nwGUI.docEditor.updateDocInfo("31489056e0916")
|
||||
assert nwGUI.docEditor.docHeader.theTitle.text() == "Novel › New Chapter › Just a Page"
|
||||
assert not nwGUI.docEditor.setCursorLine("where?")
|
||||
assert nwGUI.docEditor.setCursorLine(2)
|
||||
|
||||
Reference in New Issue
Block a user