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/dochighlight.py b/nw/gui/dochighlight.py index c99fa3ba..848f60a3 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(( + "<(\S+?)>", { + 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") @@ -179,7 +187,6 @@ class GuiDocHighlighter(QSyntaxHighlighter): def highlightBlock(self, theText): if self.theHandle is None: - self.setCurrentBlockState(0) return if theText.startswith("@"): @@ -213,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 @@ -226,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 diff --git a/nw/gui/projecteditor.py b/nw/gui/projecteditor.py index 0fdb1fb8..b148dc25 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, QTreeWidget, QTreeWidgetItem ) 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) 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) @@ -91,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() @@ -292,3 +297,80 @@ 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.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 diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index be42d461..c13d2d01 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__) @@ -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/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/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 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 ecc8f9ce..4111f856 100644 --- a/sample/sampleNovel/meta/sessionInfo.log +++ b/sample/sampleNovel/meta/sessionInfo.log @@ -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: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 +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 diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx index 7cad49d7..7fc31a8e 100644 --- a/sample/sampleNovel/nwProject.nwx +++ b/sample/sampleNovel/nwProject.nwx @@ -1,5 +1,5 @@ - + Sample Project Sample Project @@ -8,9 +8,13 @@ True - bc0cbd2a407f3 - None - 565 + 636b6aa9b697b + 636b6aa9b697b + 581 + + B + D + New Notes @@ -73,10 +77,10 @@ Notes False SCENE - 656 - 121 - 5 - 77 + 736 + 137 + 6 + 725 New File 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..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,6 +11,9 @@ None None 0 + + With This Stuff + 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..7226f6d3 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) @@ -299,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) @@ -311,13 +313,30 @@ 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 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"