Merge pull request #503 from vkbo/issue501_insert_kewords

Issue #501: Insert Keywords from Menu
This commit is contained in:
Veronica K. Berglyd Olsen
2020-11-21 15:25:29 +01:00
committed by GitHub
6 changed files with 146 additions and 28 deletions
+9
View File
@@ -422,3 +422,12 @@ combination for the inserted character or punctuation.
":kbd:`Ctrl`:kbd:`K`, :kbd:`Space`", "Insert a non-breaking space." ":kbd:`Ctrl`:kbd:`K`, :kbd:`Space`", "Insert a non-breaking space."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Shift`:kbd:`Space`", "Insert a thin space." ":kbd:`Ctrl`:kbd:`K`, :kbd:`Shift`:kbd:`Space`", "Insert a thin space."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`Space`", "Insert a thin non-breaking space." ":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`Space`", "Insert a thin non-breaking space."
":kbd:`Ctrl`:kbd:`K`, :kbd:`G`", "Insert a @tag keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`V`", "Insert a @pov keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`C`", "Insert a @char keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`P`", "Insert a @plot keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`T`", "Insert a @time keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`L`", "Insert a @location keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`O`", "Insert a @object keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`E`", "Insert a @entity keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`X`", "Insert a @custom keyword."
+1 -1
View File
@@ -167,7 +167,7 @@ class nwLabels():
nwKeyWords.POV_KEY : "Point of View", nwKeyWords.POV_KEY : "Point of View",
nwKeyWords.CHAR_KEY : "Characters", nwKeyWords.CHAR_KEY : "Characters",
nwKeyWords.PLOT_KEY : "Plot", nwKeyWords.PLOT_KEY : "Plot",
nwKeyWords.TIME_KEY : "Time", nwKeyWords.TIME_KEY : "Timeline",
nwKeyWords.WORLD_KEY : "Locations", nwKeyWords.WORLD_KEY : "Locations",
nwKeyWords.OBJECT_KEY : "Objects", nwKeyWords.OBJECT_KEY : "Objects",
nwKeyWords.ENTITY_KEY : "Entities", nwKeyWords.ENTITY_KEY : "Entities",
+31 -1
View File
@@ -54,7 +54,8 @@ from nw.core import NWDoc, NWSpellSimple, countWords
from nw.gui.dochighlight import GuiDocHighlighter from nw.gui.dochighlight import GuiDocHighlighter
from nw.common import transferCase from nw.common import transferCase
from nw.constants import ( from nw.constants import (
nwConst, nwAlert, nwUnicode, nwDocAction, nwDocInsert, nwItemClass nwConst, nwAlert, nwUnicode, nwDocAction, nwDocInsert, nwItemClass,
nwKeyWords
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -755,6 +756,35 @@ class GuiDocEditor(QTextEdit):
return True return True
def insertKeyWord(self, keyWord):
"""Insert a keyword in the text editor, at the cursor position.
If the insert line is not blank, a new line is started.
"""
if keyWord not in nwKeyWords.VALID_KEYS:
logger.error("Invalid keyword '%s'" % keyWord)
return False
logger.verbose("Inserting keyword '%s'" % keyWord)
theCursor = self.textCursor()
theBlock = theCursor.block()
if not theBlock.isValid():
logger.error("Filed to insert keyword '%s'" % keyWord)
return False
theCursor.beginEditBlock()
if theBlock.length() > 1:
theCursor.setPosition(theBlock.position() + theBlock.length() - 1)
theCursor.insertText("\n")
theCursor.insertText("%s: " % keyWord)
theCursor.endEditBlock()
self.setTextCursor(theCursor)
return True
def closeSearch(self): def closeSearch(self):
"""Close the search box. """Close the search box.
""" """
+50 -24
View File
@@ -32,7 +32,9 @@ from PyQt5.QtCore import QUrl, QProcess
from PyQt5.QtGui import QDesktopServices from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QMenuBar, QAction from PyQt5.QtWidgets import QMenuBar, QAction
from nw.constants import nwItemType, nwItemClass, nwDocAction, nwDocInsert from nw.constants import (
nwItemType, nwItemClass, nwDocAction, nwDocInsert, nwKeyWords, nwLabels
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -61,10 +63,11 @@ class GuiMainMenu(QMenuBar):
self._buildHelpMenu() self._buildHelpMenu()
# Function Pointers # Function Pointers
self._docAction = self.theParent.passDocumentAction self._docAction = self.theParent.passDocumentAction
self._moveTreeItem = self.theParent.treeView.moveTreeItem self._moveTreeItem = self.theParent.treeView.moveTreeItem
self._newTreeItem = self.theParent.treeView.newTreeItem self._newTreeItem = self.theParent.treeView.newTreeItem
self._docInsert = self.theParent.docEditor.insertText self._docInsert = self.theParent.docEditor.insertText
self._insertKeyWord = self.theParent.docEditor.insertKeyWord
logger.debug("GuiMainMenu initialisation complete") logger.debug("GuiMainMenu initialisation complete")
@@ -499,98 +502,121 @@ class GuiMainMenu(QMenuBar):
# Insert # Insert
self.insertMenu = self.addMenu("&Insert") self.insertMenu = self.addMenu("&Insert")
# Insert > Dashes and Dots
self.mInsDashes = self.insertMenu.addMenu("Dashes and Dots")
# Insert > Short Dash # Insert > Short Dash
self.aInsENDash = QAction("Short Dash", self) self.aInsENDash = QAction("Short Dash", self)
self.aInsENDash.setStatusTip("Insert short dash") self.aInsENDash.setStatusTip("Insert short dash")
self.aInsENDash.setShortcut("Ctrl+K, -") self.aInsENDash.setShortcut("Ctrl+K, -")
self.aInsENDash.triggered.connect(lambda: self._docInsert(nwDocInsert.SHORT_DASH)) self.aInsENDash.triggered.connect(lambda: self._docInsert(nwDocInsert.SHORT_DASH))
self.insertMenu.addAction(self.aInsENDash) self.mInsDashes.addAction(self.aInsENDash)
# Insert > Long Dash # Insert > Long Dash
self.aInsEMDash = QAction("Long Dash", self) self.aInsEMDash = QAction("Long Dash", self)
self.aInsEMDash.setStatusTip("Insert long dash") self.aInsEMDash.setStatusTip("Insert long dash")
self.aInsEMDash.setShortcut("Ctrl+K, _") self.aInsEMDash.setShortcut("Ctrl+K, _")
self.aInsEMDash.triggered.connect(lambda: self._docInsert(nwDocInsert.LONG_DASH)) self.aInsEMDash.triggered.connect(lambda: self._docInsert(nwDocInsert.LONG_DASH))
self.insertMenu.addAction(self.aInsEMDash) self.mInsDashes.addAction(self.aInsEMDash)
# Insert > Ellipsis # Insert > Ellipsis
self.aInsEllipsis = QAction("Ellipsis", self) self.aInsEllipsis = QAction("Ellipsis", self)
self.aInsEllipsis.setStatusTip("Insert ellipsis") self.aInsEllipsis.setStatusTip("Insert ellipsis")
self.aInsEllipsis.setShortcut("Ctrl+K, .") self.aInsEllipsis.setShortcut("Ctrl+K, .")
self.aInsEllipsis.triggered.connect(lambda: self._docInsert(nwDocInsert.ELLIPSIS)) self.aInsEllipsis.triggered.connect(lambda: self._docInsert(nwDocInsert.ELLIPSIS))
self.insertMenu.addAction(self.aInsEllipsis) self.mInsDashes.addAction(self.aInsEllipsis)
# Insert > Separator # Insert > Quote Marks
self.insertMenu.addSeparator() self.mInsQuotes = self.insertMenu.addMenu("Quote Marks")
# Insert > Left Single Quote # Insert > Left Single Quote
self.aInsQuoteLS = QAction("Left Single Quote", self) self.aInsQuoteLS = QAction("Left Single Quote", self)
self.aInsQuoteLS.setStatusTip("Insert left single quote") self.aInsQuoteLS.setStatusTip("Insert left single quote")
self.aInsQuoteLS.setShortcut("Ctrl+K, 1") self.aInsQuoteLS.setShortcut("Ctrl+K, 1")
self.aInsQuoteLS.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_LS)) self.aInsQuoteLS.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_LS))
self.insertMenu.addAction(self.aInsQuoteLS) self.mInsQuotes.addAction(self.aInsQuoteLS)
# Insert > Right Single Quote # Insert > Right Single Quote
self.aInsQuoteRS = QAction("Right Single Quote", self) self.aInsQuoteRS = QAction("Right Single Quote", self)
self.aInsQuoteRS.setStatusTip("Insert right single quote") self.aInsQuoteRS.setStatusTip("Insert right single quote")
self.aInsQuoteRS.setShortcut("Ctrl+K, 2") self.aInsQuoteRS.setShortcut("Ctrl+K, 2")
self.aInsQuoteRS.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_RS)) self.aInsQuoteRS.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_RS))
self.insertMenu.addAction(self.aInsQuoteRS) self.mInsQuotes.addAction(self.aInsQuoteRS)
# Insert > Left Double Quote # Insert > Left Double Quote
self.aInsQuoteLD = QAction("Left Double Quote", self) self.aInsQuoteLD = QAction("Left Double Quote", self)
self.aInsQuoteLD.setStatusTip("Insert left double quote") self.aInsQuoteLD.setStatusTip("Insert left double quote")
self.aInsQuoteLD.setShortcut("Ctrl+K, 3") self.aInsQuoteLD.setShortcut("Ctrl+K, 3")
self.aInsQuoteLD.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_LD)) self.aInsQuoteLD.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_LD))
self.insertMenu.addAction(self.aInsQuoteLD) self.mInsQuotes.addAction(self.aInsQuoteLD)
# Insert > Right Double Quote # Insert > Right Double Quote
self.aInsQuoteRD = QAction("Right Double Quote", self) self.aInsQuoteRD = QAction("Right Double Quote", self)
self.aInsQuoteRD.setStatusTip("Insert right double quote") self.aInsQuoteRD.setStatusTip("Insert right double quote")
self.aInsQuoteRD.setShortcut("Ctrl+K, 4") self.aInsQuoteRD.setShortcut("Ctrl+K, 4")
self.aInsQuoteRD.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_RD)) self.aInsQuoteRD.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_RD))
self.insertMenu.addAction(self.aInsQuoteRD) self.mInsQuotes.addAction(self.aInsQuoteRD)
# Insert > Separator
self.insertMenu.addSeparator()
# Insert > Alternative Apostrophe # Insert > Alternative Apostrophe
self.aInsMSApos = QAction("Alternative Apostrophe", self) self.aInsMSApos = QAction("Alternative Apostrophe", self)
self.aInsMSApos.setStatusTip("Insert unicode modifier letter single apostrophe") self.aInsMSApos.setStatusTip("Insert unicode modifier letter single apostrophe")
self.aInsMSApos.setShortcut("Ctrl+K, '") self.aInsMSApos.setShortcut("Ctrl+K, '")
self.aInsMSApos.triggered.connect(lambda: self._docInsert(nwDocInsert.MODAPOS_S)) self.aInsMSApos.triggered.connect(lambda: self._docInsert(nwDocInsert.MODAPOS_S))
self.insertMenu.addAction(self.aInsMSApos) self.mInsQuotes.addAction(self.aInsMSApos)
# Insert > Separator # Insert > Breaks and Spaces
self.insertMenu.addSeparator() self.mInsBreaks = self.insertMenu.addMenu("Breaks and Spaces")
# Insert > Hard Line Break # Insert > Hard Line Break
self.aInsHardBreak = QAction("Hard Line Break", self) self.aInsHardBreak = QAction("Hard Line Break", self)
self.aInsHardBreak.setStatusTip("Insert a hard line break") self.aInsHardBreak.setStatusTip("Insert a hard line break")
self.aInsHardBreak.setShortcut("Ctrl+K, Return") self.aInsHardBreak.setShortcut("Ctrl+K, Return")
self.aInsHardBreak.triggered.connect(lambda: self._docInsert(nwDocInsert.HARD_BREAK)) self.aInsHardBreak.triggered.connect(lambda: self._docInsert(nwDocInsert.HARD_BREAK))
self.insertMenu.addAction(self.aInsHardBreak) self.mInsBreaks.addAction(self.aInsHardBreak)
# Insert > Non-Breaking Space # Insert > Non-Breaking Space
self.aInsNBSpace = QAction("Non-Breaking Space", self) self.aInsNBSpace = QAction("Non-Breaking Space", self)
self.aInsNBSpace.setStatusTip("Insert a non-breaking space") self.aInsNBSpace.setStatusTip("Insert a non-breaking space")
self.aInsNBSpace.setShortcut("Ctrl+K, Space") self.aInsNBSpace.setShortcut("Ctrl+K, Space")
self.aInsNBSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.NB_SPACE)) self.aInsNBSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.NB_SPACE))
self.insertMenu.addAction(self.aInsNBSpace) self.mInsBreaks.addAction(self.aInsNBSpace)
# Insert > Thin Space # Insert > Thin Space
self.aInsThinSpace = QAction("Thin Space", self) self.aInsThinSpace = QAction("Thin Space", self)
self.aInsThinSpace.setStatusTip("Insert a thin space") self.aInsThinSpace.setStatusTip("Insert a thin space")
self.aInsThinSpace.setShortcut("Ctrl+K, Shift+Space") self.aInsThinSpace.setShortcut("Ctrl+K, Shift+Space")
self.aInsThinSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.THIN_SPACE)) self.aInsThinSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.THIN_SPACE))
self.insertMenu.addAction(self.aInsThinSpace) self.mInsBreaks.addAction(self.aInsThinSpace)
# Insert > Thin Non-Breaking Space # Insert > Thin Non-Breaking Space
self.aInsThinNBSpace = QAction("Thin Non-Breaking Space", self) self.aInsThinNBSpace = QAction("Thin Non-Breaking Space", self)
self.aInsThinNBSpace.setStatusTip("Insert a thin non-breaking space") self.aInsThinNBSpace.setStatusTip("Insert a thin non-breaking space")
self.aInsThinNBSpace.setShortcut("Ctrl+K, Ctrl+Space") self.aInsThinNBSpace.setShortcut("Ctrl+K, Ctrl+Space")
self.aInsThinNBSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.THIN_NB_SPACE)) self.aInsThinNBSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.THIN_NB_SPACE))
self.insertMenu.addAction(self.aInsThinNBSpace) self.mInsBreaks.addAction(self.aInsThinNBSpace)
# Insert > Separator
self.insertMenu.addSeparator()
# Insert > Keywords and Tags
self.mInsKeywords = self.insertMenu.addMenu("Keywords and Tags")
self.mInsKWItems = {}
self.mInsKWItems[nwKeyWords.TAG_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, G")
self.mInsKWItems[nwKeyWords.POV_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, V")
self.mInsKWItems[nwKeyWords.CHAR_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, C")
self.mInsKWItems[nwKeyWords.PLOT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, P")
self.mInsKWItems[nwKeyWords.TIME_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, T")
self.mInsKWItems[nwKeyWords.WORLD_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, L")
self.mInsKWItems[nwKeyWords.OBJECT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, O")
self.mInsKWItems[nwKeyWords.ENTITY_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, E")
self.mInsKWItems[nwKeyWords.CUSTOM_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, X")
for n, keyWord in enumerate(self.mInsKWItems):
self.mInsKWItems[keyWord][0].setText(nwLabels.KEY_NAME[keyWord])
self.mInsKWItems[keyWord][0].setShortcut(self.mInsKWItems[keyWord][1])
self.mInsKWItems[keyWord][0].triggered.connect(
lambda n, keyWord=keyWord: self._insertKeyWord(keyWord)
)
self.mInsKeywords.addAction(self.mInsKWItems[keyWord][0])
return return
+3
View File
@@ -1143,6 +1143,9 @@ class GuiMain(QMainWindow):
self.addAction(self.mainMenu.aInsThinSpace) self.addAction(self.mainMenu.aInsThinSpace)
self.addAction(self.mainMenu.aInsThinNBSpace) self.addAction(self.mainMenu.aInsThinNBSpace)
for mAction, _ in self.mainMenu.mInsKWItems.values():
self.addAction(mAction)
# Format # Format
self.addAction(self.mainMenu.aFmtEmph) self.addAction(self.mainMenu.aFmtEmph)
self.addAction(self.mainMenu.aFmtStrong) self.addAction(self.mainMenu.aFmtStrong)
+52 -2
View File
@@ -12,13 +12,14 @@ from shutil import copyfile
from nwtools import cmpFiles from nwtools import cmpFiles
from PyQt5.QtCore import Qt, QUrl, QPoint, QItemSelectionModel from PyQt5.QtCore import Qt, QUrl, QPoint, QItemSelectionModel
from PyQt5.QtGui import QTextCursor, QColor, QPixmap, QIcon from PyQt5.QtGui import QTextCursor, QColor, QPixmap, QIcon, QTextBlock
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
qApp, QAction, QTreeWidgetItem, QStyle, QFileDialog, QMessageBox qApp, QAction, QTreeWidgetItem, QStyle, QFileDialog, QMessageBox
) )
from nw.constants import ( from nw.constants import (
nwItemType, nwItemClass, nwUnicode, nwOutline, nwDocAction, nwDocInsert nwItemType, nwItemClass, nwUnicode, nwOutline, nwDocAction, nwDocInsert,
nwKeyWords
) )
keyDelay = 2 keyDelay = 2
@@ -1098,9 +1099,58 @@ def testInsertMenu(qtbot, monkeypatch, nwFuncTemp, nwTemp):
assert nwGUI.docEditor.getText() == " " assert nwGUI.docEditor.getText() == " "
nwGUI.docEditor.clear() nwGUI.docEditor.clear()
##
# Insert Keywords
##
nwGUI.docEditor.setText("Stuff")
nwGUI.mainMenu.mInsKWItems[nwKeyWords.TAG_KEY][0].activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.TAG_KEY
nwGUI.docEditor.setText("Stuff")
nwGUI.mainMenu.mInsKWItems[nwKeyWords.POV_KEY][0].activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.POV_KEY
nwGUI.docEditor.setText("Stuff")
nwGUI.mainMenu.mInsKWItems[nwKeyWords.CHAR_KEY][0].activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.CHAR_KEY
nwGUI.docEditor.setText("Stuff")
nwGUI.mainMenu.mInsKWItems[nwKeyWords.PLOT_KEY][0].activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.PLOT_KEY
nwGUI.docEditor.setText("Stuff")
nwGUI.mainMenu.mInsKWItems[nwKeyWords.TIME_KEY][0].activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.TIME_KEY
nwGUI.docEditor.setText("Stuff")
nwGUI.mainMenu.mInsKWItems[nwKeyWords.WORLD_KEY][0].activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.WORLD_KEY
nwGUI.docEditor.setText("Stuff")
nwGUI.mainMenu.mInsKWItems[nwKeyWords.OBJECT_KEY][0].activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.OBJECT_KEY
nwGUI.docEditor.setText("Stuff")
nwGUI.mainMenu.mInsKWItems[nwKeyWords.ENTITY_KEY][0].activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.ENTITY_KEY
nwGUI.docEditor.setText("Stuff")
nwGUI.mainMenu.mInsKWItems[nwKeyWords.CUSTOM_KEY][0].activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.CUSTOM_KEY
# Faulty Keyword Inserts
assert not nwGUI.docEditor.insertKeyWord("blabla")
monkeypatch.setattr(QTextBlock, "isValid", lambda *args, **kwards: False)
assert not nwGUI.docEditor.insertKeyWord(nwKeyWords.TAG_KEY)
monkeypatch.undo()
nwGUI.docEditor.clear()
## ##
# Insert text from file # Insert text from file
## ##
nwGUI.closeDocument() nwGUI.closeDocument()
# First, with no path # First, with no path