Merge pull request #272 from vkbo/gui_tweaks
Minor Improvements, Changes and Additions
This commit is contained in:
@@ -45,6 +45,7 @@ class nwFiles():
|
|||||||
INDEX_FILE = "tagsIndex.json"
|
INDEX_FILE = "tagsIndex.json"
|
||||||
OPTS_FILE = "guiOptions.json"
|
OPTS_FILE = "guiOptions.json"
|
||||||
RECENT_FILE = "recentProjects.json"
|
RECENT_FILE = "recentProjects.json"
|
||||||
|
BUILD_CACHE = "prevBuild.json"
|
||||||
|
|
||||||
# END Class nwFiles
|
# END Class nwFiles
|
||||||
|
|
||||||
|
|||||||
+132
-9
@@ -26,6 +26,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import json
|
||||||
import nw
|
import nw
|
||||||
|
|
||||||
from os import path
|
from os import path
|
||||||
@@ -45,19 +46,21 @@ from PyQt5.QtWidgets import (
|
|||||||
from nw.gui.additions import QSwitch
|
from nw.gui.additions import QSwitch
|
||||||
from nw.core import ToHtml
|
from nw.core import ToHtml
|
||||||
from nw.constants import (
|
from nw.constants import (
|
||||||
nwAlert, nwItemType, nwItemLayout, nwItemClass
|
nwAlert, nwFiles, nwItemType, nwItemLayout, nwItemClass
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class GuiBuildNovel(QDialog):
|
class GuiBuildNovel(QDialog):
|
||||||
|
|
||||||
FMT_ODT = 1
|
FMT_ODT = 1
|
||||||
FMT_PDF = 2
|
FMT_PDF = 2
|
||||||
FMT_HTM = 3
|
FMT_HTM = 3
|
||||||
FMT_MD = 4
|
FMT_MD = 4
|
||||||
FMT_NWD = 5
|
FMT_NWD = 5
|
||||||
FMT_TXT = 6
|
FMT_TXT = 6
|
||||||
|
FMT_JSON_H = 7
|
||||||
|
FMT_JSON_M = 8
|
||||||
|
|
||||||
def __init__(self, theParent, theProject):
|
def __init__(self, theParent, theProject):
|
||||||
QDialog.__init__(self, theParent)
|
QDialog.__init__(self, theParent)
|
||||||
@@ -333,7 +336,7 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.saveMD.triggered.connect(lambda: self._saveDocument(self.FMT_MD))
|
self.saveMD.triggered.connect(lambda: self._saveDocument(self.FMT_MD))
|
||||||
self.saveMenu.addAction(self.saveMD)
|
self.saveMenu.addAction(self.saveMD)
|
||||||
|
|
||||||
self.saveNWD = QAction("novelWriter Markdown (.nwd)", self)
|
self.saveNWD = QAction("%s Markdown (.nwd)" % nw.__package__, self)
|
||||||
self.saveNWD.triggered.connect(lambda: self._saveDocument(self.FMT_NWD))
|
self.saveNWD.triggered.connect(lambda: self._saveDocument(self.FMT_NWD))
|
||||||
self.saveMenu.addAction(self.saveNWD)
|
self.saveMenu.addAction(self.saveNWD)
|
||||||
|
|
||||||
@@ -341,6 +344,14 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.saveTXT.triggered.connect(lambda: self._saveDocument(self.FMT_TXT))
|
self.saveTXT.triggered.connect(lambda: self._saveDocument(self.FMT_TXT))
|
||||||
self.saveMenu.addAction(self.saveTXT)
|
self.saveMenu.addAction(self.saveTXT)
|
||||||
|
|
||||||
|
self.saveJsonH = QAction("JSON + %s HTML (.json)" % nw.__package__, self)
|
||||||
|
self.saveJsonH.triggered.connect(lambda: self._saveDocument(self.FMT_JSON_H))
|
||||||
|
self.saveMenu.addAction(self.saveJsonH)
|
||||||
|
|
||||||
|
self.saveJsonM = QAction("JSON + %s Markdown (.json)" % nw.__package__, self)
|
||||||
|
self.saveJsonM.triggered.connect(lambda: self._saveDocument(self.FMT_JSON_M))
|
||||||
|
self.saveMenu.addAction(self.saveJsonM)
|
||||||
|
|
||||||
self.btnClose = QPushButton("Close")
|
self.btnClose = QPushButton("Close")
|
||||||
self.btnClose.clicked.connect(self._doClose)
|
self.btnClose.clicked.connect(self._doClose)
|
||||||
|
|
||||||
@@ -372,6 +383,20 @@ class GuiBuildNovel(QDialog):
|
|||||||
|
|
||||||
logger.debug("GuiBuildNovel initialisation complete")
|
logger.debug("GuiBuildNovel initialisation complete")
|
||||||
|
|
||||||
|
# Load from Cache
|
||||||
|
if self._loadCache():
|
||||||
|
textFont = self.textFont.text()
|
||||||
|
textSize = self.textSize.value()
|
||||||
|
justifyText = self.justifyText.isChecked()
|
||||||
|
self.docView.setTextFont(textFont, textSize)
|
||||||
|
self.docView.setJustify(justifyText)
|
||||||
|
self.docView.setStyleSheet(self.htmlStyle)
|
||||||
|
self.docView.setContent(self.htmlText)
|
||||||
|
else:
|
||||||
|
self.htmlText = []
|
||||||
|
self.htmlStyle = []
|
||||||
|
self.nwdText = []
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -459,6 +484,8 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.docView.setStyleSheet(self.htmlStyle)
|
self.docView.setStyleSheet(self.htmlStyle)
|
||||||
self.docView.setContent(self.htmlText)
|
self.docView.setContent(self.htmlText)
|
||||||
|
|
||||||
|
self._saveCache()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _checkInclude(self, theItem, noteFiles, novelFiles, ignoreFlag):
|
def _checkInclude(self, theItem, noteFiles, novelFiles, ignoreFlag):
|
||||||
@@ -534,7 +561,7 @@ class GuiBuildNovel(QDialog):
|
|||||||
|
|
||||||
elif theFormat == self.FMT_NWD:
|
elif theFormat == self.FMT_NWD:
|
||||||
fileExt = "nwd"
|
fileExt = "nwd"
|
||||||
textFmt = "%s markdown" % nw.__package__
|
textFmt = "%s Markdown" % nw.__package__
|
||||||
outTool = "NW"
|
outTool = "NW"
|
||||||
|
|
||||||
elif theFormat == self.FMT_TXT:
|
elif theFormat == self.FMT_TXT:
|
||||||
@@ -543,6 +570,16 @@ class GuiBuildNovel(QDialog):
|
|||||||
textFmt = "Plain Text"
|
textFmt = "Plain Text"
|
||||||
outTool = "Qt"
|
outTool = "Qt"
|
||||||
|
|
||||||
|
elif theFormat == self.FMT_JSON_H:
|
||||||
|
fileExt = "json"
|
||||||
|
textFmt = "JSON + %s HTML" % nw.__package__
|
||||||
|
outTool = "NW"
|
||||||
|
|
||||||
|
elif theFormat == self.FMT_JSON_M:
|
||||||
|
fileExt = "json"
|
||||||
|
textFmt = "JSON + %s Markdown" % nw.__package__
|
||||||
|
outTool = "NW"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -616,6 +653,33 @@ class GuiBuildNovel(QDialog):
|
|||||||
for aLine in self.nwdText:
|
for aLine in self.nwdText:
|
||||||
outFile.write(aLine)
|
outFile.write(aLine)
|
||||||
|
|
||||||
|
elif theFormat == self.FMT_JSON_H or theFormat == self.FMT_JSON_M:
|
||||||
|
jsonData = {
|
||||||
|
"meta" : {
|
||||||
|
"workingTitle" : self.theProject.projName,
|
||||||
|
"novelTitle" : self.theProject.bookTitle,
|
||||||
|
"authors" : self.theProject.bookAuthors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if theFormat == self.FMT_JSON_H:
|
||||||
|
theBody = []
|
||||||
|
for htmlPage in self.htmlText:
|
||||||
|
theBody.append(htmlPage.rstrip("\n").split("\n"))
|
||||||
|
jsonData["text"] = {
|
||||||
|
"css" : self.htmlStyle,
|
||||||
|
"html" : theBody,
|
||||||
|
}
|
||||||
|
elif theFormat == self.FMT_JSON_M:
|
||||||
|
theBody = []
|
||||||
|
for nwdPage in self.nwdText:
|
||||||
|
theBody.append(nwdPage.split("\n"))
|
||||||
|
jsonData["text"] = {
|
||||||
|
"nwd" : theBody,
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile.write(json.dumps(jsonData, indent=2))
|
||||||
|
|
||||||
wSuccess = True
|
wSuccess = True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -683,6 +747,60 @@ class GuiBuildNovel(QDialog):
|
|||||||
self.textSize.setValue(theFont.pointSize())
|
self.textSize.setValue(theFont.pointSize())
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _loadCache(self):
|
||||||
|
"""Save the current data to cache.
|
||||||
|
"""
|
||||||
|
buildCache = path.join(self.theProject.projCache, nwFiles.BUILD_CACHE)
|
||||||
|
dataCount = 0
|
||||||
|
if path.isfile(buildCache):
|
||||||
|
|
||||||
|
logger.debug("Loading build cache")
|
||||||
|
try:
|
||||||
|
with open(buildCache, mode="r", encoding="utf8") as inFile:
|
||||||
|
theJson = inFile.read()
|
||||||
|
theData = json.loads(theJson)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Failed to load build cache")
|
||||||
|
logger.error(str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
if "htmlText" in theData.keys():
|
||||||
|
self.htmlText = theData["htmlText"]
|
||||||
|
dataCount += 1
|
||||||
|
if "htmlStyle" in theData.keys():
|
||||||
|
self.htmlStyle = theData["htmlStyle"]
|
||||||
|
dataCount += 1
|
||||||
|
if "nwdText" in theData.keys():
|
||||||
|
self.nwdText = theData["nwdText"]
|
||||||
|
dataCount += 1
|
||||||
|
|
||||||
|
return dataCount == 3
|
||||||
|
|
||||||
|
def _saveCache(self):
|
||||||
|
"""Save the current data to cache.
|
||||||
|
"""
|
||||||
|
buildCache = path.join(self.theProject.projCache, nwFiles.BUILD_CACHE)
|
||||||
|
|
||||||
|
if self.mainConf.debugInfo:
|
||||||
|
nIndent = 2
|
||||||
|
else:
|
||||||
|
nIndent = None
|
||||||
|
|
||||||
|
logger.debug("Saving build cache")
|
||||||
|
try:
|
||||||
|
with open(buildCache, mode="w+", encoding="utf8") as outFile:
|
||||||
|
outFile.write(json.dumps({
|
||||||
|
"htmlText" : self.htmlText,
|
||||||
|
"htmlStyle" : self.htmlStyle,
|
||||||
|
"nwdText" : self.nwdText,
|
||||||
|
}, indent=nIndent))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Failed to save build cache")
|
||||||
|
logger.error(str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def _doClose(self):
|
def _doClose(self):
|
||||||
"""Close button was clicked.
|
"""Close button was clicked.
|
||||||
"""
|
"""
|
||||||
@@ -762,6 +880,11 @@ class GuiBuildNovelDocView(QTextBrowser):
|
|||||||
|
|
||||||
self.qDocument = self.document()
|
self.qDocument = self.document()
|
||||||
self.qDocument.setDocumentMargin(self.mainConf.textMargin)
|
self.qDocument.setDocumentMargin(self.mainConf.textMargin)
|
||||||
|
self.setPlaceholderText(
|
||||||
|
"This area will show the content of the document to be "
|
||||||
|
"exported or printed. Press the \"Build Novel Project\" "
|
||||||
|
"button to generate content."
|
||||||
|
)
|
||||||
|
|
||||||
theFont = QFont()
|
theFont = QFont()
|
||||||
if self.mainConf.textFont is None:
|
if self.mainConf.textFont is None:
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class GuiDocDetails(QFrame):
|
|||||||
self.theParent = theParent
|
self.theParent = theParent
|
||||||
self.theProject = theProject
|
self.theProject = theProject
|
||||||
self.theTheme = theParent.theTheme
|
self.theTheme = theParent.theTheme
|
||||||
|
self.theHandle = None
|
||||||
|
|
||||||
self.mainBox = QGridLayout(self)
|
self.mainBox = QGridLayout(self)
|
||||||
self.mainBox.setVerticalSpacing(1)
|
self.mainBox.setVerticalSpacing(1)
|
||||||
@@ -189,9 +190,20 @@ class GuiDocDetails(QFrame):
|
|||||||
# Class Methods
|
# Class Methods
|
||||||
##
|
##
|
||||||
|
|
||||||
|
def updateCounts(self, tHandle, cC, wC, pC):
|
||||||
|
"""Just update the counts if the handle is the same as the one
|
||||||
|
we're already showing.
|
||||||
|
"""
|
||||||
|
if tHandle == self.theHandle:
|
||||||
|
self.cCountData.setText("{:n}".format(cC))
|
||||||
|
self.wCountData.setText("{:n}".format(wC))
|
||||||
|
self.pCountData.setText("{:n}".format(pC))
|
||||||
|
return
|
||||||
|
|
||||||
def updateViewBox(self, tHandle):
|
def updateViewBox(self, tHandle):
|
||||||
"""Populate the details box from a given handle.
|
"""Populate the details box from a given handle.
|
||||||
"""
|
"""
|
||||||
|
self.theHandle = tHandle
|
||||||
nwItem = self.theProject.projTree[tHandle]
|
nwItem = self.theProject.projTree[tHandle]
|
||||||
|
|
||||||
if nwItem is None:
|
if nwItem is None:
|
||||||
|
|||||||
@@ -300,15 +300,16 @@ class GuiDocEditor(QTextEdit):
|
|||||||
|
|
||||||
docText = self.getText()
|
docText = self.getText()
|
||||||
cursPos = self.getCursorPosition()
|
cursPos = self.getCursorPosition()
|
||||||
theItem = self.nwDocument.theItem
|
self.nwDocument.theItem.setCharCount(self.charCount)
|
||||||
theItem.setCharCount(self.charCount)
|
self.nwDocument.theItem.setWordCount(self.wordCount)
|
||||||
theItem.setWordCount(self.wordCount)
|
self.nwDocument.theItem.setParaCount(self.paraCount)
|
||||||
theItem.setParaCount(self.paraCount)
|
self.nwDocument.theItem.setCursorPos(cursPos)
|
||||||
theItem.setCursorPos(cursPos)
|
|
||||||
self.nwDocument.saveDocument(docText)
|
self.nwDocument.saveDocument(docText)
|
||||||
self.setDocumentChanged(False)
|
self.setDocumentChanged(False)
|
||||||
|
|
||||||
self.theParent.theIndex.scanText(theItem.itemHandle, docText)
|
self.theParent.theIndex.scanText(
|
||||||
|
self.nwDocument.theItem.itemHandle, docText
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -737,15 +738,24 @@ class GuiDocEditor(QTextEdit):
|
|||||||
def _updateCounts(self):
|
def _updateCounts(self):
|
||||||
"""Slot for the word counter's finished signal
|
"""Slot for the word counter's finished signal
|
||||||
"""
|
"""
|
||||||
|
if self.theHandle is None or self.nwDocument.theItem is None:
|
||||||
|
return
|
||||||
|
|
||||||
logger.verbose("Updating word count")
|
logger.verbose("Updating word count")
|
||||||
|
|
||||||
tHandle = self.nwDocument.docHandle
|
|
||||||
self.charCount = self.wCounter.charCount
|
self.charCount = self.wCounter.charCount
|
||||||
self.wordCount = self.wCounter.wordCount
|
self.wordCount = self.wCounter.wordCount
|
||||||
self.paraCount = self.wCounter.paraCount
|
self.paraCount = self.wCounter.paraCount
|
||||||
self.theParent.statusBar.setCounts(self.charCount,self.wordCount,self.paraCount)
|
self.nwDocument.theItem.setCharCount(self.charCount)
|
||||||
self.theParent.treeView.propagateCount(tHandle, self.wordCount)
|
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.treeView.projectWordCount()
|
||||||
|
self.theParent.treeMeta.updateCounts(
|
||||||
|
self.theHandle, self.charCount, self.wordCount, self.paraCount
|
||||||
|
)
|
||||||
self._checkDocSize(self.charCount)
|
self._checkDocSize(self.charCount)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
+1
-1
@@ -201,7 +201,7 @@ class GuiMainStatus(QStatusBar):
|
|||||||
"""Update statistics.
|
"""Update statistics.
|
||||||
"""
|
"""
|
||||||
self.statsText.setToolTip(
|
self.statsText.setToolTip(
|
||||||
"D: Document word count<br>P: Project word count"
|
"D: Document word count<br>P: Project word count (session change)"
|
||||||
)
|
)
|
||||||
self.statsText.setText((
|
self.statsText.setText((
|
||||||
"D:{wC:n} P:{pWC:n} ({sWC:+n})"
|
"D:{wC:n} P:{pWC:n} ({sWC:+n})"
|
||||||
|
|||||||
+19
-11
@@ -1019,25 +1019,33 @@ class GuiMain(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def _treeDoubleClick(self, tItem, colNo):
|
def _treeDoubleClick(self, tItem, colNo):
|
||||||
tHandle = tItem.text(3)
|
"""The user double-clicked an item in the tree. If it is a file,
|
||||||
|
we open it. Otherwise, we do nothing.
|
||||||
|
"""
|
||||||
|
tHandle = tItem.text(self.treeView.C_HANDLE)
|
||||||
logger.verbose("User double clicked tree item with handle %s" % tHandle)
|
logger.verbose("User double clicked tree item with handle %s" % tHandle)
|
||||||
nwItem = self.theProject.projTree[tHandle]
|
nwItem = self.theProject.projTree[tHandle]
|
||||||
if nwItem.itemType == nwItemType.FILE:
|
if nwItem is not None:
|
||||||
logger.verbose("Requested item %s is a file" % tHandle)
|
if nwItem.itemType == nwItemType.FILE:
|
||||||
self.openDocument(tHandle)
|
logger.verbose("Requested item %s is a file" % tHandle)
|
||||||
else:
|
self.openDocument(tHandle)
|
||||||
logger.verbose("Requested item %s is a folder" % tHandle)
|
else:
|
||||||
|
logger.verbose("Requested item %s is a folder" % tHandle)
|
||||||
return
|
return
|
||||||
|
|
||||||
def _treeKeyPressReturn(self):
|
def _treeKeyPressReturn(self):
|
||||||
|
"""The user pressed return an item in the tree. If it is a file,
|
||||||
|
we open it. Otherwise, we do nothing.
|
||||||
|
"""
|
||||||
tHandle = self.treeView.getSelectedHandle()
|
tHandle = self.treeView.getSelectedHandle()
|
||||||
logger.verbose("User pressed return on tree item with handle %s" % tHandle)
|
logger.verbose("User pressed return on tree item with handle %s" % tHandle)
|
||||||
nwItem = self.theProject.projTree[tHandle]
|
nwItem = self.theProject.projTree[tHandle]
|
||||||
if nwItem.itemType == nwItemType.FILE:
|
if nwItem is not None:
|
||||||
logger.verbose("Requested item %s is a file" % tHandle)
|
if nwItem.itemType == nwItemType.FILE:
|
||||||
self.openDocument(tHandle)
|
logger.verbose("Requested item %s is a file" % tHandle)
|
||||||
else:
|
self.openDocument(tHandle)
|
||||||
logger.verbose("Requested item %s is a folder" % tHandle)
|
else:
|
||||||
|
logger.verbose("Requested item %s is a folder" % tHandle)
|
||||||
return
|
return
|
||||||
|
|
||||||
def _keyPressEscape(self):
|
def _keyPressEscape(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user