From ec6937beebf14b0e437a30a010a4048eddcd1c95 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Tue, 4 Jun 2019 21:28:39 +0200 Subject: [PATCH 1/9] Added highlighting for replace tags --- nw/gui/dochighlight.py | 8 ++++++++ nw/theme.py | 2 ++ nw/themes/default/theme.conf | 1 + 3 files changed, 11 insertions(+) diff --git a/nw/gui/dochighlight.py b/nw/gui/dochighlight.py index c99fa3ba..20af5d01 100644 --- a/nw/gui/dochighlight.py +++ b/nw/gui/dochighlight.py @@ -45,6 +45,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): self.colVal = QColor(*self.theTheme.colVal) self.colSpell = QColor(*self.theTheme.colSpell) self.colTagErr = QColor(*self.theTheme.colTagErr) + self.colRepTag = QColor(*self.theTheme.colRepTag) self.hStyles = { "header1" : self._makeFormat(self.colHead, "bold",1.8), @@ -62,6 +63,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): "dialogue1" : self._makeFormat(self.colDialN), "dialogue2" : self._makeFormat(self.colDialD), "dialogue3" : self._makeFormat(self.colDialS), + "replace" : self._makeFormat(self.colRepTag), "hidden" : self._makeFormat(self.colComm), "keyword" : self._makeFormat(self.colKey), "value" : self._makeFormat(self.colVal), @@ -148,6 +150,12 @@ class GuiDocHighlighter(QSyntaxHighlighter): } )) + self.hRules.append(( + "<(.+?)>", { + 0 : self.hStyles["replace"], + } + )) + # Build a QRegExp for each pattern and for the spell checker self.rules = [(QRegularExpression(a),b) for (a,b) in self.hRules] self.spellRx = QRegularExpression(r"\b[^\s]+\b") diff --git a/nw/theme.py b/nw/theme.py index a34a2895..88fe121d 100644 --- a/nw/theme.py +++ b/nw/theme.py @@ -38,6 +38,7 @@ class Theme: self.colVal = [0,0,0] self.colSpell = [0,0,0] self.colTagErr = [0,0,0] + self.colRepTag = [0,0,0] # Changeable Settings self.guiTheme = None @@ -96,6 +97,7 @@ class Theme: self.colVal = self._loadColour(confParser,cnfSec,"value") self.colSpell = self._loadColour(confParser,cnfSec,"spellcheckline") self.colTagErr = self._loadColour(confParser,cnfSec,"tagerror") + self.colRepTag = self._loadColour(confParser,cnfSec,"replacetag") return True diff --git a/nw/themes/default/theme.conf b/nw/themes/default/theme.conf index bac88942..b230f3a5 100644 --- a/nw/themes/default/theme.conf +++ b/nw/themes/default/theme.conf @@ -10,3 +10,4 @@ keyword = 200, 46, 0 value = 184, 200, 0 spellcheckline = 200, 46, 0 tagerror = 46, 200, 0 +replacetag = 0, 184, 46 From f5af655956f4380433bed983832fe266f50dc659 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Tue, 4 Jun 2019 23:17:06 +0200 Subject: [PATCH 2/9] Started adding the autoreplace tab to project settings --- nw/gui/projecteditor.py | 49 ++++++++++++++++++++++++++++++++++------- nw/gui/winmain.py | 4 ++-- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/nw/gui/projecteditor.py b/nw/gui/projecteditor.py index 0fdb1fb8..515f709b 100644 --- a/nw/gui/projecteditor.py +++ b/nw/gui/projecteditor.py @@ -16,12 +16,12 @@ import nw from os import path 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.QtWidgets import ( QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, QLabel, QWidget, QTabWidget, QDialogButtonBox, QListWidget, QListWidgetItem, QPushButton, - QColorDialog, QAbstractItemView + QColorDialog, QAbstractItemView, QTableView, QHeaderView, QAbstractItemView ) from nw.enum import nwAlert @@ -47,14 +47,16 @@ class GuiProjectEditor(QDialog): self.svgGradient.setFixedWidth(80) self.theProject.countStatus() - self.tabMain = GuiProjectEditMain(self.theParent, self.theProject) - self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject.statusItems) - self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject.importItems) + self.tabMain = GuiProjectEditMain(self.theParent, self.theProject) + self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject.statusItems) + self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject.importItems) + self.tabReplace = GuiProjectEditReplace(self.theParent, self.theProject.importItems) self.tabWidget = QTabWidget() - self.tabWidget.addTab(self.tabMain, "Settings") - self.tabWidget.addTab(self.tabStatus,"Status") - self.tabWidget.addTab(self.tabImport,"Importance") + self.tabWidget.addTab(self.tabMain, "Settings") + self.tabWidget.addTab(self.tabStatus, "Status") + self.tabWidget.addTab(self.tabImport, "Importance") + self.tabWidget.addTab(self.tabReplace,"Auto-Replace") self.setLayout(self.outerBox) self.outerBox.addWidget(self.svgGradient) @@ -73,6 +75,12 @@ class GuiProjectEditor(QDialog): return + # def keyPressEvent(self, theEvent): + # if theEvent.key() == Qt.Key_Enter or theEvent.key() == Qt.Key_Return: + # return + # QDialog.keyPressEvent(self, theEvent) + # return + def _doSave(self): logger.verbose("ProjectEditor save button clicked") @@ -292,3 +300,28 @@ class GuiProjectEditStatus(QWidget): return # END Class GuiProjectEditStatus + +class GuiProjectEditReplace(QWidget): + + def __init__(self, theParent, theProject): + QWidget.__init__(self, theParent) + + self.theParent = theParent + self.theProject = theProject + + self.outerBox = QVBoxLayout() + self.mainTable = QTableView() + self.mainModel = QStandardItemModel() + self.mainTable.setModel(self.mainModel) + self.mainTable.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) + self.mainTable.setEditTriggers(QAbstractItemView.DoubleClicked) + + self.mainModel.setHorizontalHeaderLabels(["Keyword","Value"]) + self.mainModel.setRowCount(3) + + self.outerBox.addWidget(self.mainTable) + self.setLayout(self.outerBox) + + return + +# END Class GuiProjectEditReplace diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index a4cbec70..bbf2cb0b 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -22,7 +22,6 @@ from PyQt5.QtWidgets import ( QShortcut, QMessageBox, QProgressDialog ) -from nw.theme import Theme from nw.gui.doctree import GuiDocTree from nw.gui.doceditor import GuiDocEditor from nw.gui.docviewer import GuiDocViewer @@ -38,9 +37,10 @@ from nw.project.item import NWItem from nw.project.index import NWIndex from nw.convert.tokenizer import Tokenizer 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.constants import nwFiles -from nw.tools.wordcount import countWords logger = logging.getLogger(__name__) From ac044fc434074aa3664cb0029267f00e900cd300 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sat, 8 Jun 2019 15:15:06 +0200 Subject: [PATCH 3/9] Trying an editable table --- nw/gui/projecteditor.py | 4 +++- sample/sampleNovel/meta/sessionInfo.log | 18 ++++++++++++++++++ sample/sampleNovel/nwProject.nwx | 6 +++--- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/nw/gui/projecteditor.py b/nw/gui/projecteditor.py index 515f709b..7837240e 100644 --- a/nw/gui/projecteditor.py +++ b/nw/gui/projecteditor.py @@ -314,7 +314,9 @@ class GuiProjectEditReplace(QWidget): self.mainModel = QStandardItemModel() self.mainTable.setModel(self.mainModel) self.mainTable.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.mainTable.setEditTriggers(QAbstractItemView.DoubleClicked) + self.mainTable.setEditTriggers( + QAbstractItemView.DoubleClicked | QAbstractItemView.SelectedClicked | QAbstractItemView.AnyKeyPressed + ) self.mainModel.setHorizontalHeaderLabels(["Keyword","Value"]) self.mainModel.setRowCount(3) diff --git a/sample/sampleNovel/meta/sessionInfo.log b/sample/sampleNovel/meta/sessionInfo.log index ecc8f9ce..87aa2b2d 100644 --- a/sample/sampleNovel/meta/sessionInfo.log +++ b/sample/sampleNovel/meta/sessionInfo.log @@ -153,3 +153,21 @@ 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: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-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 diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx index 7cad49d7..f10a9cc7 100644 --- a/sample/sampleNovel/nwProject.nwx +++ b/sample/sampleNovel/nwProject.nwx @@ -1,5 +1,5 @@ - + Sample Project Sample Project @@ -8,7 +8,7 @@ True - bc0cbd2a407f3 + 636b6aa9b697b None 565 @@ -76,7 +76,7 @@ 656 121 5 - 77 + 442 New File From f219d1f8bbf7c17e9f10b79b836963d1179e55de Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sat, 8 Jun 2019 19:29:43 +0200 Subject: [PATCH 4/9] Updated the auto-replace GUI --- nw/gui/projecteditor.py | 58 +++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/nw/gui/projecteditor.py b/nw/gui/projecteditor.py index 7837240e..fb80793a 100644 --- a/nw/gui/projecteditor.py +++ b/nw/gui/projecteditor.py @@ -21,7 +21,7 @@ from PyQt5.QtSvg import QSvgWidget from PyQt5.QtWidgets import ( QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, QLabel, QWidget, QTabWidget, QDialogButtonBox, QListWidget, QListWidgetItem, QPushButton, - QColorDialog, QAbstractItemView, QTableView, QHeaderView, QAbstractItemView + QColorDialog, QAbstractItemView, QTreeWidget, QTreeWidgetItem ) from nw.enum import nwAlert @@ -308,22 +308,58 @@ class GuiProjectEditReplace(QWidget): self.theParent = theParent self.theProject = theProject + self.arChanged = False self.outerBox = QVBoxLayout() - self.mainTable = QTableView() - self.mainModel = QStandardItemModel() - self.mainTable.setModel(self.mainModel) - self.mainTable.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.mainTable.setEditTriggers( - QAbstractItemView.DoubleClicked | QAbstractItemView.SelectedClicked | QAbstractItemView.AnyKeyPressed - ) + self.bottomBox = QHBoxLayout() + self.listBox = QTreeWidget() + self.listBox.setHeaderLabels(["Keyword","Value"]) + self.listBox.setIndentation(0) - self.mainModel.setHorizontalHeaderLabels(["Keyword","Value"]) - self.mainModel.setRowCount(3) + self.editKey = QLineEdit() + self.editValue = QLineEdit() + self.addButton = QPushButton(QIcon.fromTheme("list-add"),"") + self.delButton = QPushButton(QIcon.fromTheme("list-remove"),"") - self.outerBox.addWidget(self.mainTable) + 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 + # END Class GuiProjectEditReplace From 2d55ec06cca8643472b57628081cc2f229d8c704 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sat, 8 Jun 2019 20:02:09 +0200 Subject: [PATCH 5/9] Auto-replace values now loaded and saved. --- nw/gui/projecteditor.py | 27 ++++++--- nw/project/project.py | 73 +++++++++++++++---------- sample/sampleNovel/meta/sessionInfo.log | 11 ++++ sample/sampleNovel/nwProject.nwx | 8 ++- 4 files changed, 80 insertions(+), 39 deletions(-) diff --git a/nw/gui/projecteditor.py b/nw/gui/projecteditor.py index fb80793a..b148dc25 100644 --- a/nw/gui/projecteditor.py +++ b/nw/gui/projecteditor.py @@ -50,7 +50,7 @@ class GuiProjectEditor(QDialog): self.tabMain = GuiProjectEditMain(self.theParent, self.theProject) self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject.statusItems) self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject.importItems) - self.tabReplace = GuiProjectEditReplace(self.theParent, self.theProject.importItems) + self.tabReplace = GuiProjectEditReplace(self.theParent, self.theProject) self.tabWidget = QTabWidget() self.tabWidget.addTab(self.tabMain, "Settings") @@ -75,12 +75,6 @@ class GuiProjectEditor(QDialog): return - # def keyPressEvent(self, theEvent): - # if theEvent.key() == Qt.Key_Enter or theEvent.key() == Qt.Key_Return: - # return - # QDialog.keyPressEvent(self, theEvent) - # return - def _doSave(self): logger.verbose("ProjectEditor save button clicked") @@ -99,6 +93,9 @@ class GuiProjectEditor(QDialog): self.theProject.setImportColours(importCol) if self.tabStatus.colChanged or self.tabImport.colChanged: self.theParent.rebuildTree() + if self.tabReplace.arChanged: + newList = self.tabReplace.getNewList() + self.theProject.setAutoReplace(newList) self.close() @@ -313,9 +310,13 @@ class GuiProjectEditReplace(QWidget): self.outerBox = QVBoxLayout() self.bottomBox = QHBoxLayout() self.listBox = QTreeWidget() - self.listBox.setHeaderLabels(["Keyword","Value"]) + 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"),"") @@ -362,4 +363,14 @@ class GuiProjectEditReplace(QWidget): 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 diff --git a/nw/project/project.py b/nw/project/project.py index dce45ef3..81979f2e 100644 --- a/nw/project/project.py +++ b/nw/project/project.py @@ -32,37 +32,40 @@ class NWProject(): def __init__(self, theParent): # Internal - self.theParent = theParent - self.mainConf = self.theParent.mainConf - self.projChanged = None - self.projOpened = None + self.theParent = theParent + self.mainConf = self.theParent.mainConf + self.projChanged = None + self.projOpened = None # Debug - self.handleSeed = None + self.handleSeed = None # Class Settings - self.projTree = None - self.treeOrder = None - self.treeRoots = None - self.trashRoot = None - self.projPath = None - self.projMeta = None - self.projCache = None - self.projFile = None + self.projTree = None + self.treeOrder = None + self.treeRoots = None + self.trashRoot = None + self.projPath = None + self.projMeta = None + self.projCache = None + self.projFile = None # Project Meta - self.projName = None - self.bookTitle = None - self.bookAuthors = None + self.projName = None + self.bookTitle = None + self.bookAuthors = None + + # Various + self.autoReplace = None # Project Settings - self.spellCheck = False - self.statusItems = None - self.importItems = None - self.lastEdited = None - self.lastViewed = None - self.lastWCount = 0 - self.currWCount = 0 + self.spellCheck = False + self.statusItems = None + self.importItems = None + self.lastEdited = None + self.lastViewed = None + self.lastWCount = 0 + self.currWCount = 0 # Set Defaults self.clearProject() @@ -150,6 +153,7 @@ class NWProject(): self.projName = "" self.bookTitle = "" self.bookAuthors = [] + self.autoReplace = {} self.spellCheck = False self.statusItems = NWStatus() self.statusItems.addEntry("New", (100,100,100)) @@ -220,16 +224,19 @@ class NWProject(): if xItem.text is None: continue if xItem.tag == "spellCheck": self.spellCheck = checkBool(xItem.text,False) - if xItem.tag == "lastEdited": + elif xItem.tag == "lastEdited": self.lastEdited = checkString(xItem.text,None,True) - if xItem.tag == "lastViewed": + elif xItem.tag == "lastViewed": self.lastViewed = checkString(xItem.text,None,True) - if xItem.tag == "lastWordCount": + elif xItem.tag == "lastWordCount": self.lastWCount = checkInt(xItem.text,0,False) - if xItem.tag == "status": + elif xItem.tag == "status": self.statusItems.unpackEntries(xItem) - if xItem.tag == "importance": + elif xItem.tag == "importance": 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": logger.debug("Found project content") for xItem in xChild: @@ -292,6 +299,10 @@ class NWProject(): self._saveProjectValue(xSettings,"lastEdited", self.lastEdited) self._saveProjectValue(xSettings,"lastViewed", self.lastViewed) 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") self.statusItems.packEntries(xStatus) @@ -401,7 +412,7 @@ class NWProject(): self.setProjectChanged(True) return - def setImportColours(self, newCols,): + def setImportColours(self, newCols): replaceMap = self.importItems.setNewEntries(newCols) if self.projTree is not None: for nwItem in self.projTree.values(): @@ -411,6 +422,10 @@ class NWProject(): self.setProjectChanged(True) return + def setAutoReplace(self, autoReplace): + self.autoReplace = autoReplace + return + def setProjectChanged(self, bValue): self.projChanged = bValue self.theParent.setProjectStatus(self.projChanged) diff --git a/sample/sampleNovel/meta/sessionInfo.log b/sample/sampleNovel/meta/sessionInfo.log index 87aa2b2d..7d118aff 100644 --- a/sample/sampleNovel/meta/sessionInfo.log +++ b/sample/sampleNovel/meta/sessionInfo.log @@ -171,3 +171,14 @@ 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 diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx index f10a9cc7..0d012aa1 100644 --- a/sample/sampleNovel/nwProject.nwx +++ b/sample/sampleNovel/nwProject.nwx @@ -1,5 +1,5 @@ - + Sample Project Sample Project @@ -10,7 +10,11 @@ True 636b6aa9b697b None - 565 + 0 + + B + D + New Notes From dcf4903c64d5813c25c8cd37aff9aad6941b413a Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sat, 8 Jun 2019 20:44:10 +0200 Subject: [PATCH 6/9] Implemented the auto-replace code in the doc viewer. --- nw/convert/tohtml.py | 18 ++++++++++++++++-- nw/convert/tokenizer.py | 10 ++++++++++ nw/gui/winmain.py | 4 ++-- .../sampleNovel/data_6/36b6aa9b697b_main.nwd | 3 +++ sample/sampleNovel/meta/sessionInfo.log | 5 +++++ sample/sampleNovel/nwProject.nwx | 14 +++++++------- 6 files changed, 43 insertions(+), 11 deletions(-) diff --git a/nw/convert/tohtml.py b/nw/convert/tohtml.py index 280c6d0c..3225c4bb 100644 --- a/nw/convert/tohtml.py +++ b/nw/convert/tohtml.py @@ -11,6 +11,7 @@ """ import logging +import re import nw from nw.convert.tokenizer import Tokenizer @@ -24,6 +25,19 @@ class ToHtml(Tokenizer): 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): htmlTags = { @@ -31,8 +45,8 @@ class ToHtml(Tokenizer): self.FMT_B_E : "", self.FMT_I_B : "", self.FMT_I_E : "", - self.FMT_U_B : "", - self.FMT_U_E : "", + self.FMT_U_B : "", + self.FMT_U_E : "", } self.theResult = "" diff --git a/nw/convert/tokenizer.py b/nw/convert/tokenizer.py index 5fe3cf9e..59365ec1 100644 --- a/nw/convert/tokenizer.py +++ b/nw/convert/tokenizer.py @@ -11,6 +11,7 @@ """ import logging +import re import nw from operator import itemgetter @@ -57,6 +58,15 @@ class Tokenizer(): 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): """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 diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index c6963083..c13d2d01 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -246,6 +246,7 @@ class GuiMain(QMainWindow): self.docEditor.setSpellCheck(self.theProject.spellCheck) self.statusBar.setRefTime(self.theProject.projOpened) self.mainMenu.updateMenu() + self.hasProject = True # Restore previously open documents, if any if self.theProject.lastEdited is not None: @@ -253,8 +254,6 @@ class GuiMain(QMainWindow): if self.theProject.lastViewed is not None: self.viewDocument(self.theProject.lastViewed) - self.hasProject = True - return True def saveProject(self): @@ -329,6 +328,7 @@ class GuiMain(QMainWindow): logger.debug("Generating preview for item %s" % tHandle) aDoc = ToHtml(self.theProject, self) aDoc.setText(tHandle) + aDoc.doAutoReplace() aDoc.tokenizeText() aDoc.doConvert() self.docViewer.setHtml(aDoc.theResult) diff --git a/sample/sampleNovel/data_6/36b6aa9b697b_main.nwd b/sample/sampleNovel/data_6/36b6aa9b697b_main.nwd index a084c76f..e4c4beb8 100644 --- a/sample/sampleNovel/data_6/36b6aa9b697b_main.nwd +++ b/sample/sampleNovel/data_6/36b6aa9b697b_main.nwd @@ -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. +Let’s auto-replace this A with , and this C with . While is just . + + diff --git a/sample/sampleNovel/meta/sessionInfo.log b/sample/sampleNovel/meta/sessionInfo.log index 7d118aff..4111f856 100644 --- a/sample/sampleNovel/meta/sessionInfo.log +++ b/sample/sampleNovel/meta/sessionInfo.log @@ -182,3 +182,8 @@ 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 diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx index 0d012aa1..7fc31a8e 100644 --- a/sample/sampleNovel/nwProject.nwx +++ b/sample/sampleNovel/nwProject.nwx @@ -1,5 +1,5 @@ - + Sample Project Sample Project @@ -9,8 +9,8 @@ True 636b6aa9b697b - None - 0 + 636b6aa9b697b + 581 B D @@ -77,10 +77,10 @@ Notes False SCENE - 656 - 121 - 5 - 442 + 736 + 137 + 6 + 725 New File From 49ef736b28cec697087a7572f09fd4c075f1a440 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sat, 8 Jun 2019 20:54:23 +0200 Subject: [PATCH 7/9] Updated tests --- tests/reference/gui/0_nwProject.nwx | 3 ++- tests/reference/gui/1_nwProject.nwx | 3 ++- tests/reference/gui/2_nwProject.nwx | 3 ++- tests/reference/gui/3_nwProject.nwx | 3 ++- tests/reference/proj/1_nwProject.nwx | 3 ++- tests/reference/proj/2_nwProject.nwx | 3 ++- tests/test_gui.py | 6 ++++-- 7 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/reference/gui/0_nwProject.nwx b/tests/reference/gui/0_nwProject.nwx index e1685c0f..19443161 100644 --- a/tests/reference/gui/0_nwProject.nwx +++ b/tests/reference/gui/0_nwProject.nwx @@ -1,5 +1,5 @@ - + @@ -9,6 +9,7 @@ None None 0 + New Note diff --git a/tests/reference/gui/1_nwProject.nwx b/tests/reference/gui/1_nwProject.nwx index fa8698ba..67cd383d 100644 --- a/tests/reference/gui/1_nwProject.nwx +++ b/tests/reference/gui/1_nwProject.nwx @@ -1,5 +1,5 @@ - + @@ -9,6 +9,7 @@ 31489056e0916 31489056e0916 86 + New Note diff --git a/tests/reference/gui/2_nwProject.nwx b/tests/reference/gui/2_nwProject.nwx index 8d2ab8f5..a4aea14a 100644 --- a/tests/reference/gui/2_nwProject.nwx +++ b/tests/reference/gui/2_nwProject.nwx @@ -1,5 +1,5 @@ - + Project Name Project Title @@ -11,6 +11,7 @@ None None 0 + New Note diff --git a/tests/reference/gui/3_nwProject.nwx b/tests/reference/gui/3_nwProject.nwx index d499a736..7ae54e07 100644 --- a/tests/reference/gui/3_nwProject.nwx +++ b/tests/reference/gui/3_nwProject.nwx @@ -1,5 +1,5 @@ - + @@ -9,6 +9,7 @@ None None 0 + New Note diff --git a/tests/reference/proj/1_nwProject.nwx b/tests/reference/proj/1_nwProject.nwx index 40ec363c..a9c82564 100644 --- a/tests/reference/proj/1_nwProject.nwx +++ b/tests/reference/proj/1_nwProject.nwx @@ -1,5 +1,5 @@ - + @@ -9,6 +9,7 @@ None None 0 + New Note diff --git a/tests/reference/proj/2_nwProject.nwx b/tests/reference/proj/2_nwProject.nwx index 314a4f75..f7bd904d 100644 --- a/tests/reference/proj/2_nwProject.nwx +++ b/tests/reference/proj/2_nwProject.nwx @@ -1,5 +1,5 @@ - + @@ -9,6 +9,7 @@ None None 0 + New Note diff --git a/tests/test_gui.py b/tests/test_gui.py index 3cecee17..2640d943 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -48,6 +48,8 @@ def testMainWindows(qtbot, nwTempGUI, nwRef): assert cmpFiles(projFile, path.join(nwRef,"gui","0_nwProject.nwx"), [2]) qtbot.wait(stepDelay) + # qtbot.stopForInteraction() + # Re-open project assert nwGUI.openProject(nwTempGUI) qtbot.wait(stepDelay) @@ -316,8 +318,8 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef): # Open again, and check project settings projEdit = GuiProjectEditor(nwGUI, nwGUI.theProject) qtbot.addWidget(projEdit) - assert projEdit.tabMain.editName.text() == "Project Name" - assert projEdit.tabMain.editTitle.text() == "Project Title" + assert projEdit.tabMain.editName.text() == "Project Name" + assert projEdit.tabMain.editTitle.text() == "Project Title" theAuth = projEdit.tabMain.editAuthors.toPlainText().strip().splitlines() assert len(theAuth) == 2 assert theAuth[0] == "Jane Doe" From 32cf37c7202484585c9a867b08ab5b9d2d6770dd Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sat, 8 Jun 2019 21:08:27 +0200 Subject: [PATCH 8/9] Added test coverage for autoreplace --- tests/reference/gui/2_nwProject.nwx | 6 ++++-- tests/test_gui.py | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/reference/gui/2_nwProject.nwx b/tests/reference/gui/2_nwProject.nwx index a4aea14a..dd2b6333 100644 --- a/tests/reference/gui/2_nwProject.nwx +++ b/tests/reference/gui/2_nwProject.nwx @@ -1,5 +1,5 @@ - + Project Name Project Title @@ -11,7 +11,9 @@ None None 0 - + + With This Stuff + New Note diff --git a/tests/test_gui.py b/tests/test_gui.py index 2640d943..7226f6d3 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -301,7 +301,7 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef): for c in "John Doh": qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=keyDelay) - #Test Status Tab + # Test Status Tab projEdit.tabWidget.setCurrentWidget(projEdit.tabStatus) projEdit.tabStatus.listBox.item(2).setSelected(True) qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton) @@ -313,6 +313,23 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef): qtbot.keyClick(projEdit.tabStatus.editName, c, delay=keyDelay) 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() # Open again, and check project settings From 1bc2abaa41498a375577d4071ec808a1a07e9ae8 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sat, 8 Jun 2019 22:00:12 +0200 Subject: [PATCH 9/9] Some changes to the syntax highlighter to match the rules in the autoreplace code --- nw/gui/dochighlight.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/nw/gui/dochighlight.py b/nw/gui/dochighlight.py index 20af5d01..848f60a3 100644 --- a/nw/gui/dochighlight.py +++ b/nw/gui/dochighlight.py @@ -151,7 +151,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): )) self.hRules.append(( - "<(.+?)>", { + "<(\S+?)>", { 0 : self.hStyles["replace"], } )) @@ -187,7 +187,6 @@ class GuiDocHighlighter(QSyntaxHighlighter): def highlightBlock(self, theText): if self.theHandle is None: - self.setCurrentBlockState(0) return if theText.startswith("@"): @@ -221,8 +220,6 @@ class GuiDocHighlighter(QSyntaxHighlighter): xLen = rxMatch.capturedLength(xM) self.setFormat(xPos, xLen, xFmt[xM]) - self.setCurrentBlockState(0) - if self.theDict is None or not self.spellCheck or theText.startswith("@"): return @@ -234,10 +231,11 @@ class GuiDocHighlighter(QSyntaxHighlighter): continue xPos = rxMatch.capturedStart(0) xLen = rxMatch.capturedLength(0) - spFmt = self.format(xPos) - spFmt.setUnderlineColor(self.colSpell) - spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) - self.setFormat(xPos, xLen, spFmt) + for x in range(xLen): + spFmt = self.format(xPos+x) + spFmt.setUnderlineColor(self.colSpell) + spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) + self.setFormat(xPos+x, 1, spFmt) return