+16
-2
@@ -11,6 +11,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
import nw
|
import nw
|
||||||
|
|
||||||
from nw.convert.tokenizer import Tokenizer
|
from nw.convert.tokenizer import Tokenizer
|
||||||
@@ -24,6 +25,19 @@ class ToHtml(Tokenizer):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def doAutoReplace(self):
|
||||||
|
Tokenizer.doAutoReplace(self)
|
||||||
|
|
||||||
|
theDict = {
|
||||||
|
"<" : "<",
|
||||||
|
">" : ">",
|
||||||
|
"&" : "&",
|
||||||
|
}
|
||||||
|
xRep = re.compile("|".join([re.escape(k) for k in theDict.keys()]), flags=re.DOTALL)
|
||||||
|
self.theText = xRep.sub(lambda x: theDict[x.group(0)], self.theText)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
def doConvert(self):
|
def doConvert(self):
|
||||||
|
|
||||||
htmlTags = {
|
htmlTags = {
|
||||||
@@ -31,8 +45,8 @@ class ToHtml(Tokenizer):
|
|||||||
self.FMT_B_E : "</strong>",
|
self.FMT_B_E : "</strong>",
|
||||||
self.FMT_I_B : "<em>",
|
self.FMT_I_B : "<em>",
|
||||||
self.FMT_I_E : "</em>",
|
self.FMT_I_E : "</em>",
|
||||||
self.FMT_U_B : "<mark>",
|
self.FMT_U_B : "<u>",
|
||||||
self.FMT_U_E : "</mark>",
|
self.FMT_U_E : "</u>",
|
||||||
}
|
}
|
||||||
|
|
||||||
self.theResult = ""
|
self.theResult = ""
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
import nw
|
import nw
|
||||||
|
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
@@ -57,6 +58,15 @@ class Tokenizer():
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def doAutoReplace(self):
|
||||||
|
if len(self.theProject.autoReplace) > 0:
|
||||||
|
theDict = {}
|
||||||
|
for aKey, aVal in self.theProject.autoReplace.items():
|
||||||
|
theDict["<%s>" % aKey] = aVal
|
||||||
|
xRep = re.compile("|".join([re.escape(k) for k in theDict.keys()]), flags=re.DOTALL)
|
||||||
|
self.theText = xRep.sub(lambda x: theDict[x.group(0)], self.theText)
|
||||||
|
return
|
||||||
|
|
||||||
def tokenizeText(self):
|
def tokenizeText(self):
|
||||||
"""Scan the text for either lines starting with specific characters that indicate headers,
|
"""Scan the text for either lines starting with specific characters that indicate headers,
|
||||||
comments, commands etc, or just contains plain text. in the case of plain text, apply the
|
comments, commands etc, or just contains plain text. in the case of plain text, apply the
|
||||||
|
|||||||
+13
-7
@@ -45,6 +45,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|||||||
self.colVal = QColor(*self.theTheme.colVal)
|
self.colVal = QColor(*self.theTheme.colVal)
|
||||||
self.colSpell = QColor(*self.theTheme.colSpell)
|
self.colSpell = QColor(*self.theTheme.colSpell)
|
||||||
self.colTagErr = QColor(*self.theTheme.colTagErr)
|
self.colTagErr = QColor(*self.theTheme.colTagErr)
|
||||||
|
self.colRepTag = QColor(*self.theTheme.colRepTag)
|
||||||
|
|
||||||
self.hStyles = {
|
self.hStyles = {
|
||||||
"header1" : self._makeFormat(self.colHead, "bold",1.8),
|
"header1" : self._makeFormat(self.colHead, "bold",1.8),
|
||||||
@@ -62,6 +63,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|||||||
"dialogue1" : self._makeFormat(self.colDialN),
|
"dialogue1" : self._makeFormat(self.colDialN),
|
||||||
"dialogue2" : self._makeFormat(self.colDialD),
|
"dialogue2" : self._makeFormat(self.colDialD),
|
||||||
"dialogue3" : self._makeFormat(self.colDialS),
|
"dialogue3" : self._makeFormat(self.colDialS),
|
||||||
|
"replace" : self._makeFormat(self.colRepTag),
|
||||||
"hidden" : self._makeFormat(self.colComm),
|
"hidden" : self._makeFormat(self.colComm),
|
||||||
"keyword" : self._makeFormat(self.colKey),
|
"keyword" : self._makeFormat(self.colKey),
|
||||||
"value" : self._makeFormat(self.colVal),
|
"value" : self._makeFormat(self.colVal),
|
||||||
@@ -148,6 +150,12 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
|
self.hRules.append((
|
||||||
|
"<(\S+?)>", {
|
||||||
|
0 : self.hStyles["replace"],
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
# Build a QRegExp for each pattern and for the spell checker
|
# Build a QRegExp for each pattern and for the spell checker
|
||||||
self.rules = [(QRegularExpression(a),b) for (a,b) in self.hRules]
|
self.rules = [(QRegularExpression(a),b) for (a,b) in self.hRules]
|
||||||
self.spellRx = QRegularExpression(r"\b[^\s]+\b")
|
self.spellRx = QRegularExpression(r"\b[^\s]+\b")
|
||||||
@@ -179,7 +187,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|||||||
def highlightBlock(self, theText):
|
def highlightBlock(self, theText):
|
||||||
|
|
||||||
if self.theHandle is None:
|
if self.theHandle is None:
|
||||||
self.setCurrentBlockState(0)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if theText.startswith("@"):
|
if theText.startswith("@"):
|
||||||
@@ -213,8 +220,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|||||||
xLen = rxMatch.capturedLength(xM)
|
xLen = rxMatch.capturedLength(xM)
|
||||||
self.setFormat(xPos, xLen, xFmt[xM])
|
self.setFormat(xPos, xLen, xFmt[xM])
|
||||||
|
|
||||||
self.setCurrentBlockState(0)
|
|
||||||
|
|
||||||
if self.theDict is None or not self.spellCheck or theText.startswith("@"):
|
if self.theDict is None or not self.spellCheck or theText.startswith("@"):
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -226,10 +231,11 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|||||||
continue
|
continue
|
||||||
xPos = rxMatch.capturedStart(0)
|
xPos = rxMatch.capturedStart(0)
|
||||||
xLen = rxMatch.capturedLength(0)
|
xLen = rxMatch.capturedLength(0)
|
||||||
spFmt = self.format(xPos)
|
for x in range(xLen):
|
||||||
spFmt.setUnderlineColor(self.colSpell)
|
spFmt = self.format(xPos+x)
|
||||||
spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
|
spFmt.setUnderlineColor(self.colSpell)
|
||||||
self.setFormat(xPos, xLen, spFmt)
|
spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
|
||||||
|
self.setFormat(xPos+x, 1, spFmt)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
+90
-8
@@ -16,12 +16,12 @@ import nw
|
|||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush
|
from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush, QStandardItemModel
|
||||||
from PyQt5.QtSvg import QSvgWidget
|
from PyQt5.QtSvg import QSvgWidget
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, QLabel,
|
QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, QLabel,
|
||||||
QWidget, QTabWidget, QDialogButtonBox, QListWidget, QListWidgetItem, QPushButton,
|
QWidget, QTabWidget, QDialogButtonBox, QListWidget, QListWidgetItem, QPushButton,
|
||||||
QColorDialog, QAbstractItemView
|
QColorDialog, QAbstractItemView, QTreeWidget, QTreeWidgetItem
|
||||||
)
|
)
|
||||||
from nw.enum import nwAlert
|
from nw.enum import nwAlert
|
||||||
|
|
||||||
@@ -47,14 +47,16 @@ class GuiProjectEditor(QDialog):
|
|||||||
self.svgGradient.setFixedWidth(80)
|
self.svgGradient.setFixedWidth(80)
|
||||||
|
|
||||||
self.theProject.countStatus()
|
self.theProject.countStatus()
|
||||||
self.tabMain = GuiProjectEditMain(self.theParent, self.theProject)
|
self.tabMain = GuiProjectEditMain(self.theParent, self.theProject)
|
||||||
self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject.statusItems)
|
self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject.statusItems)
|
||||||
self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject.importItems)
|
self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject.importItems)
|
||||||
|
self.tabReplace = GuiProjectEditReplace(self.theParent, self.theProject)
|
||||||
|
|
||||||
self.tabWidget = QTabWidget()
|
self.tabWidget = QTabWidget()
|
||||||
self.tabWidget.addTab(self.tabMain, "Settings")
|
self.tabWidget.addTab(self.tabMain, "Settings")
|
||||||
self.tabWidget.addTab(self.tabStatus,"Status")
|
self.tabWidget.addTab(self.tabStatus, "Status")
|
||||||
self.tabWidget.addTab(self.tabImport,"Importance")
|
self.tabWidget.addTab(self.tabImport, "Importance")
|
||||||
|
self.tabWidget.addTab(self.tabReplace,"Auto-Replace")
|
||||||
|
|
||||||
self.setLayout(self.outerBox)
|
self.setLayout(self.outerBox)
|
||||||
self.outerBox.addWidget(self.svgGradient)
|
self.outerBox.addWidget(self.svgGradient)
|
||||||
@@ -91,6 +93,9 @@ class GuiProjectEditor(QDialog):
|
|||||||
self.theProject.setImportColours(importCol)
|
self.theProject.setImportColours(importCol)
|
||||||
if self.tabStatus.colChanged or self.tabImport.colChanged:
|
if self.tabStatus.colChanged or self.tabImport.colChanged:
|
||||||
self.theParent.rebuildTree()
|
self.theParent.rebuildTree()
|
||||||
|
if self.tabReplace.arChanged:
|
||||||
|
newList = self.tabReplace.getNewList()
|
||||||
|
self.theProject.setAutoReplace(newList)
|
||||||
|
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
@@ -292,3 +297,80 @@ class GuiProjectEditStatus(QWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# END Class GuiProjectEditStatus
|
# END Class GuiProjectEditStatus
|
||||||
|
|
||||||
|
class GuiProjectEditReplace(QWidget):
|
||||||
|
|
||||||
|
def __init__(self, theParent, theProject):
|
||||||
|
QWidget.__init__(self, theParent)
|
||||||
|
|
||||||
|
self.theParent = theParent
|
||||||
|
self.theProject = theProject
|
||||||
|
self.arChanged = False
|
||||||
|
|
||||||
|
self.outerBox = QVBoxLayout()
|
||||||
|
self.bottomBox = QHBoxLayout()
|
||||||
|
self.listBox = QTreeWidget()
|
||||||
|
self.listBox.setHeaderLabels(["Keyword","Replace With"])
|
||||||
|
self.listBox.setIndentation(0)
|
||||||
|
|
||||||
|
for aKey, aVal in self.theProject.autoReplace.items():
|
||||||
|
newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
|
||||||
|
self.listBox.addTopLevelItem(newItem)
|
||||||
|
|
||||||
|
self.editKey = QLineEdit()
|
||||||
|
self.editValue = QLineEdit()
|
||||||
|
self.addButton = QPushButton(QIcon.fromTheme("list-add"),"")
|
||||||
|
self.delButton = QPushButton(QIcon.fromTheme("list-remove"),"")
|
||||||
|
|
||||||
|
self.addButton.clicked.connect(self._addEntry)
|
||||||
|
self.delButton.clicked.connect(self._delEntry)
|
||||||
|
|
||||||
|
self.bottomBox.addWidget(self.editKey, 2)
|
||||||
|
self.bottomBox.addWidget(self.editValue, 3)
|
||||||
|
self.bottomBox.addWidget(self.addButton)
|
||||||
|
self.bottomBox.addWidget(self.delButton)
|
||||||
|
|
||||||
|
self.outerBox.addWidget(self.listBox)
|
||||||
|
self.outerBox.addLayout(self.bottomBox)
|
||||||
|
self.setLayout(self.outerBox)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def _addEntry(self):
|
||||||
|
|
||||||
|
newKey = self.editKey.text()
|
||||||
|
newVal = self.editValue.text()
|
||||||
|
|
||||||
|
saveKey = ""
|
||||||
|
for c in newKey:
|
||||||
|
if not c .isspace():
|
||||||
|
saveKey += c
|
||||||
|
|
||||||
|
if len(saveKey) > 0 and len(newVal) > 0:
|
||||||
|
newItem = QTreeWidgetItem(["<%s>" % saveKey, newVal])
|
||||||
|
self.listBox.addTopLevelItem(newItem)
|
||||||
|
self.editKey.clear()
|
||||||
|
self.editValue.clear()
|
||||||
|
self.arChanged = True
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _delEntry(self):
|
||||||
|
selItem = self.listBox.selectedItems()
|
||||||
|
if len(selItem) == 0:
|
||||||
|
return False
|
||||||
|
self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(selItem[0]))
|
||||||
|
self.arChanged = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
def getNewList(self):
|
||||||
|
newList = {}
|
||||||
|
for n in range(self.listBox.topLevelItemCount()):
|
||||||
|
tItem = self.listBox.topLevelItem(n)
|
||||||
|
aKey = tItem.text(0)
|
||||||
|
aVal = tItem.text(1)
|
||||||
|
if len(aKey) > 2:
|
||||||
|
newList[aKey[1:-1]] = aVal
|
||||||
|
return newList
|
||||||
|
|
||||||
|
# END Class GuiProjectEditReplace
|
||||||
|
|||||||
+4
-4
@@ -22,7 +22,6 @@ from PyQt5.QtWidgets import (
|
|||||||
QShortcut, QMessageBox, QProgressDialog
|
QShortcut, QMessageBox, QProgressDialog
|
||||||
)
|
)
|
||||||
|
|
||||||
from nw.theme import Theme
|
|
||||||
from nw.gui.doctree import GuiDocTree
|
from nw.gui.doctree import GuiDocTree
|
||||||
from nw.gui.doceditor import GuiDocEditor
|
from nw.gui.doceditor import GuiDocEditor
|
||||||
from nw.gui.docviewer import GuiDocViewer
|
from nw.gui.docviewer import GuiDocViewer
|
||||||
@@ -38,9 +37,10 @@ from nw.project.item import NWItem
|
|||||||
from nw.project.index import NWIndex
|
from nw.project.index import NWIndex
|
||||||
from nw.convert.tokenizer import Tokenizer
|
from nw.convert.tokenizer import Tokenizer
|
||||||
from nw.convert.tohtml import ToHtml
|
from nw.convert.tohtml import ToHtml
|
||||||
|
from nw.tools.wordcount import countWords
|
||||||
|
from nw.theme import Theme
|
||||||
from nw.enum import nwItemType, nwAlert
|
from nw.enum import nwItemType, nwAlert
|
||||||
from nw.constants import nwFiles
|
from nw.constants import nwFiles
|
||||||
from nw.tools.wordcount import countWords
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -246,6 +246,7 @@ class GuiMain(QMainWindow):
|
|||||||
self.docEditor.setSpellCheck(self.theProject.spellCheck)
|
self.docEditor.setSpellCheck(self.theProject.spellCheck)
|
||||||
self.statusBar.setRefTime(self.theProject.projOpened)
|
self.statusBar.setRefTime(self.theProject.projOpened)
|
||||||
self.mainMenu.updateMenu()
|
self.mainMenu.updateMenu()
|
||||||
|
self.hasProject = True
|
||||||
|
|
||||||
# Restore previously open documents, if any
|
# Restore previously open documents, if any
|
||||||
if self.theProject.lastEdited is not None:
|
if self.theProject.lastEdited is not None:
|
||||||
@@ -253,8 +254,6 @@ class GuiMain(QMainWindow):
|
|||||||
if self.theProject.lastViewed is not None:
|
if self.theProject.lastViewed is not None:
|
||||||
self.viewDocument(self.theProject.lastViewed)
|
self.viewDocument(self.theProject.lastViewed)
|
||||||
|
|
||||||
self.hasProject = True
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def saveProject(self):
|
def saveProject(self):
|
||||||
@@ -329,6 +328,7 @@ class GuiMain(QMainWindow):
|
|||||||
logger.debug("Generating preview for item %s" % tHandle)
|
logger.debug("Generating preview for item %s" % tHandle)
|
||||||
aDoc = ToHtml(self.theProject, self)
|
aDoc = ToHtml(self.theProject, self)
|
||||||
aDoc.setText(tHandle)
|
aDoc.setText(tHandle)
|
||||||
|
aDoc.doAutoReplace()
|
||||||
aDoc.tokenizeText()
|
aDoc.tokenizeText()
|
||||||
aDoc.doConvert()
|
aDoc.doConvert()
|
||||||
self.docViewer.setHtml(aDoc.theResult)
|
self.docViewer.setHtml(aDoc.theResult)
|
||||||
|
|||||||
+44
-29
@@ -32,37 +32,40 @@ class NWProject():
|
|||||||
def __init__(self, theParent):
|
def __init__(self, theParent):
|
||||||
|
|
||||||
# Internal
|
# Internal
|
||||||
self.theParent = theParent
|
self.theParent = theParent
|
||||||
self.mainConf = self.theParent.mainConf
|
self.mainConf = self.theParent.mainConf
|
||||||
self.projChanged = None
|
self.projChanged = None
|
||||||
self.projOpened = None
|
self.projOpened = None
|
||||||
|
|
||||||
# Debug
|
# Debug
|
||||||
self.handleSeed = None
|
self.handleSeed = None
|
||||||
|
|
||||||
# Class Settings
|
# Class Settings
|
||||||
self.projTree = None
|
self.projTree = None
|
||||||
self.treeOrder = None
|
self.treeOrder = None
|
||||||
self.treeRoots = None
|
self.treeRoots = None
|
||||||
self.trashRoot = None
|
self.trashRoot = None
|
||||||
self.projPath = None
|
self.projPath = None
|
||||||
self.projMeta = None
|
self.projMeta = None
|
||||||
self.projCache = None
|
self.projCache = None
|
||||||
self.projFile = None
|
self.projFile = None
|
||||||
|
|
||||||
# Project Meta
|
# Project Meta
|
||||||
self.projName = None
|
self.projName = None
|
||||||
self.bookTitle = None
|
self.bookTitle = None
|
||||||
self.bookAuthors = None
|
self.bookAuthors = None
|
||||||
|
|
||||||
|
# Various
|
||||||
|
self.autoReplace = None
|
||||||
|
|
||||||
# Project Settings
|
# Project Settings
|
||||||
self.spellCheck = False
|
self.spellCheck = False
|
||||||
self.statusItems = None
|
self.statusItems = None
|
||||||
self.importItems = None
|
self.importItems = None
|
||||||
self.lastEdited = None
|
self.lastEdited = None
|
||||||
self.lastViewed = None
|
self.lastViewed = None
|
||||||
self.lastWCount = 0
|
self.lastWCount = 0
|
||||||
self.currWCount = 0
|
self.currWCount = 0
|
||||||
|
|
||||||
# Set Defaults
|
# Set Defaults
|
||||||
self.clearProject()
|
self.clearProject()
|
||||||
@@ -150,6 +153,7 @@ class NWProject():
|
|||||||
self.projName = ""
|
self.projName = ""
|
||||||
self.bookTitle = ""
|
self.bookTitle = ""
|
||||||
self.bookAuthors = []
|
self.bookAuthors = []
|
||||||
|
self.autoReplace = {}
|
||||||
self.spellCheck = False
|
self.spellCheck = False
|
||||||
self.statusItems = NWStatus()
|
self.statusItems = NWStatus()
|
||||||
self.statusItems.addEntry("New", (100,100,100))
|
self.statusItems.addEntry("New", (100,100,100))
|
||||||
@@ -220,16 +224,19 @@ class NWProject():
|
|||||||
if xItem.text is None: continue
|
if xItem.text is None: continue
|
||||||
if xItem.tag == "spellCheck":
|
if xItem.tag == "spellCheck":
|
||||||
self.spellCheck = checkBool(xItem.text,False)
|
self.spellCheck = checkBool(xItem.text,False)
|
||||||
if xItem.tag == "lastEdited":
|
elif xItem.tag == "lastEdited":
|
||||||
self.lastEdited = checkString(xItem.text,None,True)
|
self.lastEdited = checkString(xItem.text,None,True)
|
||||||
if xItem.tag == "lastViewed":
|
elif xItem.tag == "lastViewed":
|
||||||
self.lastViewed = checkString(xItem.text,None,True)
|
self.lastViewed = checkString(xItem.text,None,True)
|
||||||
if xItem.tag == "lastWordCount":
|
elif xItem.tag == "lastWordCount":
|
||||||
self.lastWCount = checkInt(xItem.text,0,False)
|
self.lastWCount = checkInt(xItem.text,0,False)
|
||||||
if xItem.tag == "status":
|
elif xItem.tag == "status":
|
||||||
self.statusItems.unpackEntries(xItem)
|
self.statusItems.unpackEntries(xItem)
|
||||||
if xItem.tag == "importance":
|
elif xItem.tag == "importance":
|
||||||
self.importItems.unpackEntries(xItem)
|
self.importItems.unpackEntries(xItem)
|
||||||
|
elif xItem.tag == "autoReplace":
|
||||||
|
for xEntry in xItem:
|
||||||
|
self.autoReplace[xEntry.tag] = checkString(xEntry.text,None,False)
|
||||||
elif xChild.tag == "content":
|
elif xChild.tag == "content":
|
||||||
logger.debug("Found project content")
|
logger.debug("Found project content")
|
||||||
for xItem in xChild:
|
for xItem in xChild:
|
||||||
@@ -292,6 +299,10 @@ class NWProject():
|
|||||||
self._saveProjectValue(xSettings,"lastEdited", self.lastEdited)
|
self._saveProjectValue(xSettings,"lastEdited", self.lastEdited)
|
||||||
self._saveProjectValue(xSettings,"lastViewed", self.lastViewed)
|
self._saveProjectValue(xSettings,"lastViewed", self.lastViewed)
|
||||||
self._saveProjectValue(xSettings,"lastWordCount",self.currWCount)
|
self._saveProjectValue(xSettings,"lastWordCount",self.currWCount)
|
||||||
|
xAutoRep = etree.SubElement(xSettings,"autoReplace")
|
||||||
|
for aKey, aValue in self.autoReplace.items():
|
||||||
|
if len(aKey) > 0:
|
||||||
|
self._saveProjectValue(xAutoRep,aKey,aValue)
|
||||||
|
|
||||||
xStatus = etree.SubElement(xSettings,"status")
|
xStatus = etree.SubElement(xSettings,"status")
|
||||||
self.statusItems.packEntries(xStatus)
|
self.statusItems.packEntries(xStatus)
|
||||||
@@ -401,7 +412,7 @@ class NWProject():
|
|||||||
self.setProjectChanged(True)
|
self.setProjectChanged(True)
|
||||||
return
|
return
|
||||||
|
|
||||||
def setImportColours(self, newCols,):
|
def setImportColours(self, newCols):
|
||||||
replaceMap = self.importItems.setNewEntries(newCols)
|
replaceMap = self.importItems.setNewEntries(newCols)
|
||||||
if self.projTree is not None:
|
if self.projTree is not None:
|
||||||
for nwItem in self.projTree.values():
|
for nwItem in self.projTree.values():
|
||||||
@@ -411,6 +422,10 @@ class NWProject():
|
|||||||
self.setProjectChanged(True)
|
self.setProjectChanged(True)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def setAutoReplace(self, autoReplace):
|
||||||
|
self.autoReplace = autoReplace
|
||||||
|
return
|
||||||
|
|
||||||
def setProjectChanged(self, bValue):
|
def setProjectChanged(self, bValue):
|
||||||
self.projChanged = bValue
|
self.projChanged = bValue
|
||||||
self.theParent.setProjectStatus(self.projChanged)
|
self.theParent.setProjectStatus(self.projChanged)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class Theme:
|
|||||||
self.colVal = [0,0,0]
|
self.colVal = [0,0,0]
|
||||||
self.colSpell = [0,0,0]
|
self.colSpell = [0,0,0]
|
||||||
self.colTagErr = [0,0,0]
|
self.colTagErr = [0,0,0]
|
||||||
|
self.colRepTag = [0,0,0]
|
||||||
|
|
||||||
# Changeable Settings
|
# Changeable Settings
|
||||||
self.guiTheme = None
|
self.guiTheme = None
|
||||||
@@ -96,6 +97,7 @@ class Theme:
|
|||||||
self.colVal = self._loadColour(confParser,cnfSec,"value")
|
self.colVal = self._loadColour(confParser,cnfSec,"value")
|
||||||
self.colSpell = self._loadColour(confParser,cnfSec,"spellcheckline")
|
self.colSpell = self._loadColour(confParser,cnfSec,"spellcheckline")
|
||||||
self.colTagErr = self._loadColour(confParser,cnfSec,"tagerror")
|
self.colTagErr = self._loadColour(confParser,cnfSec,"tagerror")
|
||||||
|
self.colRepTag = self._loadColour(confParser,cnfSec,"replacetag")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ keyword = 200, 46, 0
|
|||||||
value = 184, 200, 0
|
value = 184, 200, 0
|
||||||
spellcheckline = 200, 46, 0
|
spellcheckline = 200, 46, 0
|
||||||
tagerror = 46, 200, 0
|
tagerror = 46, 200, 0
|
||||||
|
replacetag = 0, 184, 46
|
||||||
|
|||||||
@@ -18,3 +18,6 @@ This paragraph is also meaningless. At least a bit. It’s also very short. But
|
|||||||
|
|
||||||
This one is a bit longer. “It also has some dialogue in it” she said, before she moved on to check if the spellchecker worked. It did. “Cool,” she concluded.
|
This one is a bit longer. “It also has some dialogue in it” she said, before she moved on to check if the spellchecker worked. It did. “Cool,” she concluded.
|
||||||
|
|
||||||
|
Let’s auto-replace this A with <A>, and this C with <C>. While <E> is just <E>.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -153,3 +153,37 @@ Start: 2019-05-31 19:58:24 End: 2019-05-31 19:59:04 Words: 0
|
|||||||
Start: 2019-05-31 20:11:22 End: 2019-05-31 20:11:56 Words: 0
|
Start: 2019-05-31 20:11:22 End: 2019-05-31 20:11:56 Words: 0
|
||||||
Start: 2019-05-31 20:23:06 End: 2019-05-31 20:23:18 Words: 0
|
Start: 2019-05-31 20:23:06 End: 2019-05-31 20:23:18 Words: 0
|
||||||
Start: 2019-05-31 20:23:56 End: 2019-05-31 20:27:02 Words: 7
|
Start: 2019-05-31 20:23:56 End: 2019-05-31 20:27:02 Words: 7
|
||||||
|
Start: 2019-06-03 21:19:48 End: 2019-06-03 21:20:32 Words: 0
|
||||||
|
Start: 2019-06-04 20:40:13 End: 2019-06-04 21:06:44 Words: 0
|
||||||
|
Start: 2019-06-04 21:24:03 End: 2019-06-04 21:24:38 Words: 0
|
||||||
|
Start: 2019-06-04 21:24:42 End: 2019-06-04 21:25:04 Words: 0
|
||||||
|
Start: 2019-06-04 21:25:09 End: 2019-06-04 21:25:18 Words: 0
|
||||||
|
Start: 2019-06-04 21:25:31 End: 2019-06-04 21:25:36 Words: 0
|
||||||
|
Start: 2019-06-04 21:25:44 End: 2019-06-04 21:26:07 Words: 0
|
||||||
|
Start: 2019-06-04 21:55:47 End: 2019-06-04 21:59:57 Words: 0
|
||||||
|
Start: 2019-06-04 22:00:21 End: 2019-06-04 22:00:29 Words: 0
|
||||||
|
Start: 2019-06-04 22:00:54 End: 2019-06-04 22:01:03 Words: 0
|
||||||
|
Start: 2019-06-04 22:01:21 End: 2019-06-04 22:01:36 Words: 0
|
||||||
|
Start: 2019-06-04 22:02:48 End: 2019-06-04 22:02:55 Words: 0
|
||||||
|
Start: 2019-06-04 22:08:26 End: 2019-06-04 22:08:33 Words: 0
|
||||||
|
Start: 2019-06-04 23:00:20 End: 2019-06-04 23:00:35 Words: 0
|
||||||
|
Start: 2019-06-04 23:01:25 End: 2019-06-04 23:02:29 Words: 0
|
||||||
|
Start: 2019-06-04 23:09:01 End: 2019-06-04 23:10:26 Words: 0
|
||||||
|
Start: 2019-06-04 23:12:15 End: 2019-06-04 23:16:42 Words: 0
|
||||||
|
Start: 2019-06-04 23:18:50 End: 2019-06-04 23:19:16 Words: 0
|
||||||
|
Start: 2019-06-08 16:44:12 End: 2019-06-08 16:45:11 Words: -565
|
||||||
|
Start: 2019-06-08 18:54:03 End: 2019-06-08 18:54:45 Words: -565
|
||||||
|
Start: 2019-06-08 18:57:25 End: 2019-06-08 18:57:37 Words: -565
|
||||||
|
Start: 2019-06-08 19:03:33 End: 2019-06-08 19:04:20 Words: 0
|
||||||
|
Start: 2019-06-08 19:05:20 End: 2019-06-08 19:05:46 Words: 0
|
||||||
|
Start: 2019-06-08 19:06:44 End: 2019-06-08 19:07:35 Words: 0
|
||||||
|
Start: 2019-06-08 19:14:43 End: 2019-06-08 19:15:11 Words: 0
|
||||||
|
Start: 2019-06-08 19:20:15 End: 2019-06-08 19:20:41 Words: 0
|
||||||
|
Start: 2019-06-08 19:54:27 End: 2019-06-08 19:54:38 Words: 0
|
||||||
|
Start: 2019-06-08 19:58:46 End: 2019-06-08 19:58:50 Words: 0
|
||||||
|
Start: 2019-06-08 20:01:07 End: 2019-06-08 20:01:18 Words: 0
|
||||||
|
Start: 2019-06-08 20:26:26 End: 2019-06-08 20:28:18 Words: 572
|
||||||
|
Start: 2019-06-08 20:30:24 End: 2019-06-08 20:42:10 Words: 9
|
||||||
|
Start: 2019-06-08 20:42:14 End: 2019-06-08 20:42:37 Words: 0
|
||||||
|
Start: 2019-06-08 20:42:41 End: 2019-06-08 20:43:25 Words: 0
|
||||||
|
Start: 2019-06-08 20:43:29 End: 2019-06-08 20:43:42 Words: 0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-31 20:26:54">
|
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-06-08 20:43:42">
|
||||||
<project>
|
<project>
|
||||||
<name>Sample Project</name>
|
<name>Sample Project</name>
|
||||||
<title>Sample Project</title>
|
<title>Sample Project</title>
|
||||||
@@ -8,9 +8,13 @@
|
|||||||
</project>
|
</project>
|
||||||
<settings>
|
<settings>
|
||||||
<spellCheck>True</spellCheck>
|
<spellCheck>True</spellCheck>
|
||||||
<lastEdited>bc0cbd2a407f3</lastEdited>
|
<lastEdited>636b6aa9b697b</lastEdited>
|
||||||
<lastViewed>None</lastViewed>
|
<lastViewed>636b6aa9b697b</lastViewed>
|
||||||
<lastWordCount>565</lastWordCount>
|
<lastWordCount>581</lastWordCount>
|
||||||
|
<autoReplace>
|
||||||
|
<A>B</A>
|
||||||
|
<C>D</C>
|
||||||
|
</autoReplace>
|
||||||
<status>
|
<status>
|
||||||
<entry blue="100" green="100" red="100">New</entry>
|
<entry blue="100" green="100" red="100">New</entry>
|
||||||
<entry blue="0" green="50" red="200">Notes</entry>
|
<entry blue="0" green="50" red="200">Notes</entry>
|
||||||
@@ -73,10 +77,10 @@
|
|||||||
<status>Notes</status>
|
<status>Notes</status>
|
||||||
<expanded>False</expanded>
|
<expanded>False</expanded>
|
||||||
<layout>SCENE</layout>
|
<layout>SCENE</layout>
|
||||||
<charCount>656</charCount>
|
<charCount>736</charCount>
|
||||||
<wordCount>121</wordCount>
|
<wordCount>137</wordCount>
|
||||||
<paraCount>5</paraCount>
|
<paraCount>6</paraCount>
|
||||||
<cursorPos>77</cursorPos>
|
<cursorPos>725</cursorPos>
|
||||||
</item>
|
</item>
|
||||||
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
|
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
|
||||||
<name>New File</name>
|
<name>New File</name>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:29:02">
|
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-06-08 20:45:49">
|
||||||
<project>
|
<project>
|
||||||
<name></name>
|
<name></name>
|
||||||
<title></title>
|
<title></title>
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
<lastEdited>None</lastEdited>
|
<lastEdited>None</lastEdited>
|
||||||
<lastViewed>None</lastViewed>
|
<lastViewed>None</lastViewed>
|
||||||
<lastWordCount>0</lastWordCount>
|
<lastWordCount>0</lastWordCount>
|
||||||
|
<autoReplace/>
|
||||||
<status>
|
<status>
|
||||||
<entry blue="100" green="100" red="100">New</entry>
|
<entry blue="100" green="100" red="100">New</entry>
|
||||||
<entry blue="0" green="50" red="200">Note</entry>
|
<entry blue="0" green="50" red="200">Note</entry>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-06-01 20:57:28">
|
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-06-08 20:46:34">
|
||||||
<project>
|
<project>
|
||||||
<name></name>
|
<name></name>
|
||||||
<title></title>
|
<title></title>
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
<lastEdited>31489056e0916</lastEdited>
|
<lastEdited>31489056e0916</lastEdited>
|
||||||
<lastViewed>31489056e0916</lastViewed>
|
<lastViewed>31489056e0916</lastViewed>
|
||||||
<lastWordCount>86</lastWordCount>
|
<lastWordCount>86</lastWordCount>
|
||||||
|
<autoReplace/>
|
||||||
<status>
|
<status>
|
||||||
<entry blue="100" green="100" red="100">New</entry>
|
<entry blue="100" green="100" red="100">New</entry>
|
||||||
<entry blue="0" green="50" red="200">Note</entry>
|
<entry blue="0" green="50" red="200">Note</entry>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:31:12">
|
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-06-08 21:05:51">
|
||||||
<project>
|
<project>
|
||||||
<name>Project Name</name>
|
<name>Project Name</name>
|
||||||
<title>Project Title</title>
|
<title>Project Title</title>
|
||||||
@@ -11,6 +11,9 @@
|
|||||||
<lastEdited>None</lastEdited>
|
<lastEdited>None</lastEdited>
|
||||||
<lastViewed>None</lastViewed>
|
<lastViewed>None</lastViewed>
|
||||||
<lastWordCount>0</lastWordCount>
|
<lastWordCount>0</lastWordCount>
|
||||||
|
<autoReplace>
|
||||||
|
<This>With This Stuff </This>
|
||||||
|
</autoReplace>
|
||||||
<status>
|
<status>
|
||||||
<entry blue="100" green="100" red="100">New</entry>
|
<entry blue="100" green="100" red="100">New</entry>
|
||||||
<entry blue="0" green="50" red="200">Note</entry>
|
<entry blue="0" green="50" red="200">Note</entry>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:31:45">
|
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-06-08 20:49:50">
|
||||||
<project>
|
<project>
|
||||||
<name></name>
|
<name></name>
|
||||||
<title></title>
|
<title></title>
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
<lastEdited>None</lastEdited>
|
<lastEdited>None</lastEdited>
|
||||||
<lastViewed>None</lastViewed>
|
<lastViewed>None</lastViewed>
|
||||||
<lastWordCount>0</lastWordCount>
|
<lastWordCount>0</lastWordCount>
|
||||||
|
<autoReplace/>
|
||||||
<status>
|
<status>
|
||||||
<entry blue="100" green="100" red="100">New</entry>
|
<entry blue="100" green="100" red="100">New</entry>
|
||||||
<entry blue="0" green="50" red="200">Note</entry>
|
<entry blue="0" green="50" red="200">Note</entry>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:25:27">
|
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-06-08 20:52:21">
|
||||||
<project>
|
<project>
|
||||||
<name></name>
|
<name></name>
|
||||||
<title></title>
|
<title></title>
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
<lastEdited>None</lastEdited>
|
<lastEdited>None</lastEdited>
|
||||||
<lastViewed>None</lastViewed>
|
<lastViewed>None</lastViewed>
|
||||||
<lastWordCount>0</lastWordCount>
|
<lastWordCount>0</lastWordCount>
|
||||||
|
<autoReplace/>
|
||||||
<status>
|
<status>
|
||||||
<entry blue="100" green="100" red="100">New</entry>
|
<entry blue="100" green="100" red="100">New</entry>
|
||||||
<entry blue="0" green="50" red="200">Note</entry>
|
<entry blue="0" green="50" red="200">Note</entry>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:26:15">
|
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-06-08 20:53:03">
|
||||||
<project>
|
<project>
|
||||||
<name></name>
|
<name></name>
|
||||||
<title></title>
|
<title></title>
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
<lastEdited>None</lastEdited>
|
<lastEdited>None</lastEdited>
|
||||||
<lastViewed>None</lastViewed>
|
<lastViewed>None</lastViewed>
|
||||||
<lastWordCount>0</lastWordCount>
|
<lastWordCount>0</lastWordCount>
|
||||||
|
<autoReplace/>
|
||||||
<status>
|
<status>
|
||||||
<entry blue="100" green="100" red="100">New</entry>
|
<entry blue="100" green="100" red="100">New</entry>
|
||||||
<entry blue="0" green="50" red="200">Note</entry>
|
<entry blue="0" green="50" red="200">Note</entry>
|
||||||
|
|||||||
+22
-3
@@ -48,6 +48,8 @@ def testMainWindows(qtbot, nwTempGUI, nwRef):
|
|||||||
assert cmpFiles(projFile, path.join(nwRef,"gui","0_nwProject.nwx"), [2])
|
assert cmpFiles(projFile, path.join(nwRef,"gui","0_nwProject.nwx"), [2])
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
|
# qtbot.stopForInteraction()
|
||||||
|
|
||||||
# Re-open project
|
# Re-open project
|
||||||
assert nwGUI.openProject(nwTempGUI)
|
assert nwGUI.openProject(nwTempGUI)
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
@@ -299,7 +301,7 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef):
|
|||||||
for c in "John Doh":
|
for c in "John Doh":
|
||||||
qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=keyDelay)
|
qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=keyDelay)
|
||||||
|
|
||||||
#Test Status Tab
|
# Test Status Tab
|
||||||
projEdit.tabWidget.setCurrentWidget(projEdit.tabStatus)
|
projEdit.tabWidget.setCurrentWidget(projEdit.tabStatus)
|
||||||
projEdit.tabStatus.listBox.item(2).setSelected(True)
|
projEdit.tabStatus.listBox.item(2).setSelected(True)
|
||||||
qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton)
|
qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton)
|
||||||
@@ -311,13 +313,30 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef):
|
|||||||
qtbot.keyClick(projEdit.tabStatus.editName, c, delay=keyDelay)
|
qtbot.keyClick(projEdit.tabStatus.editName, c, delay=keyDelay)
|
||||||
qtbot.mouseClick(projEdit.tabStatus.saveButton, Qt.LeftButton)
|
qtbot.mouseClick(projEdit.tabStatus.saveButton, Qt.LeftButton)
|
||||||
|
|
||||||
|
# Auto-Replace Tab
|
||||||
|
projEdit.tabWidget.setCurrentWidget(projEdit.tabReplace)
|
||||||
|
for c in "Th is ":
|
||||||
|
qtbot.keyClick(projEdit.tabReplace.editKey, c, delay=keyDelay)
|
||||||
|
for c in "With This Stuff ":
|
||||||
|
qtbot.keyClick(projEdit.tabReplace.editValue, c, delay=keyDelay)
|
||||||
|
qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton)
|
||||||
|
|
||||||
|
for c in "Delete":
|
||||||
|
qtbot.keyClick(projEdit.tabReplace.editKey, c, delay=keyDelay)
|
||||||
|
for c in "This Stuff":
|
||||||
|
qtbot.keyClick(projEdit.tabReplace.editValue, c, delay=keyDelay)
|
||||||
|
qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton)
|
||||||
|
|
||||||
|
projEdit.tabReplace.listBox.topLevelItem(1).setSelected(True)
|
||||||
|
qtbot.mouseClick(projEdit.tabReplace.delButton, Qt.LeftButton)
|
||||||
|
|
||||||
projEdit._doSave()
|
projEdit._doSave()
|
||||||
|
|
||||||
# Open again, and check project settings
|
# Open again, and check project settings
|
||||||
projEdit = GuiProjectEditor(nwGUI, nwGUI.theProject)
|
projEdit = GuiProjectEditor(nwGUI, nwGUI.theProject)
|
||||||
qtbot.addWidget(projEdit)
|
qtbot.addWidget(projEdit)
|
||||||
assert projEdit.tabMain.editName.text() == "Project Name"
|
assert projEdit.tabMain.editName.text() == "Project Name"
|
||||||
assert projEdit.tabMain.editTitle.text() == "Project Title"
|
assert projEdit.tabMain.editTitle.text() == "Project Title"
|
||||||
theAuth = projEdit.tabMain.editAuthors.toPlainText().strip().splitlines()
|
theAuth = projEdit.tabMain.editAuthors.toPlainText().strip().splitlines()
|
||||||
assert len(theAuth) == 2
|
assert len(theAuth) == 2
|
||||||
assert theAuth[0] == "Jane Doe"
|
assert theAuth[0] == "Jane Doe"
|
||||||
|
|||||||
Reference in New Issue
Block a user