Merge pull request #503 from vkbo/issue501_insert_kewords
Issue #501: Insert Keywords from Menu
This commit is contained in:
@@ -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:`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:`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."
|
||||
|
||||
@@ -167,7 +167,7 @@ class nwLabels():
|
||||
nwKeyWords.POV_KEY : "Point of View",
|
||||
nwKeyWords.CHAR_KEY : "Characters",
|
||||
nwKeyWords.PLOT_KEY : "Plot",
|
||||
nwKeyWords.TIME_KEY : "Time",
|
||||
nwKeyWords.TIME_KEY : "Timeline",
|
||||
nwKeyWords.WORLD_KEY : "Locations",
|
||||
nwKeyWords.OBJECT_KEY : "Objects",
|
||||
nwKeyWords.ENTITY_KEY : "Entities",
|
||||
|
||||
+31
-1
@@ -54,7 +54,8 @@ from nw.core import NWDoc, NWSpellSimple, countWords
|
||||
from nw.gui.dochighlight import GuiDocHighlighter
|
||||
from nw.common import transferCase
|
||||
from nw.constants import (
|
||||
nwConst, nwAlert, nwUnicode, nwDocAction, nwDocInsert, nwItemClass
|
||||
nwConst, nwAlert, nwUnicode, nwDocAction, nwDocInsert, nwItemClass,
|
||||
nwKeyWords
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -755,6 +756,35 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
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):
|
||||
"""Close the search box.
|
||||
"""
|
||||
|
||||
+50
-24
@@ -32,7 +32,9 @@ from PyQt5.QtCore import QUrl, QProcess
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
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__)
|
||||
|
||||
@@ -61,10 +63,11 @@ class GuiMainMenu(QMenuBar):
|
||||
self._buildHelpMenu()
|
||||
|
||||
# Function Pointers
|
||||
self._docAction = self.theParent.passDocumentAction
|
||||
self._moveTreeItem = self.theParent.treeView.moveTreeItem
|
||||
self._newTreeItem = self.theParent.treeView.newTreeItem
|
||||
self._docInsert = self.theParent.docEditor.insertText
|
||||
self._docAction = self.theParent.passDocumentAction
|
||||
self._moveTreeItem = self.theParent.treeView.moveTreeItem
|
||||
self._newTreeItem = self.theParent.treeView.newTreeItem
|
||||
self._docInsert = self.theParent.docEditor.insertText
|
||||
self._insertKeyWord = self.theParent.docEditor.insertKeyWord
|
||||
|
||||
logger.debug("GuiMainMenu initialisation complete")
|
||||
|
||||
@@ -499,98 +502,121 @@ class GuiMainMenu(QMenuBar):
|
||||
# Insert
|
||||
self.insertMenu = self.addMenu("&Insert")
|
||||
|
||||
# Insert > Dashes and Dots
|
||||
self.mInsDashes = self.insertMenu.addMenu("Dashes and Dots")
|
||||
|
||||
# Insert > Short Dash
|
||||
self.aInsENDash = QAction("Short Dash", self)
|
||||
self.aInsENDash.setStatusTip("Insert short dash")
|
||||
self.aInsENDash.setShortcut("Ctrl+K, -")
|
||||
self.aInsENDash.triggered.connect(lambda: self._docInsert(nwDocInsert.SHORT_DASH))
|
||||
self.insertMenu.addAction(self.aInsENDash)
|
||||
self.mInsDashes.addAction(self.aInsENDash)
|
||||
|
||||
# Insert > Long Dash
|
||||
self.aInsEMDash = QAction("Long Dash", self)
|
||||
self.aInsEMDash.setStatusTip("Insert long dash")
|
||||
self.aInsEMDash.setShortcut("Ctrl+K, _")
|
||||
self.aInsEMDash.triggered.connect(lambda: self._docInsert(nwDocInsert.LONG_DASH))
|
||||
self.insertMenu.addAction(self.aInsEMDash)
|
||||
self.mInsDashes.addAction(self.aInsEMDash)
|
||||
|
||||
# Insert > Ellipsis
|
||||
self.aInsEllipsis = QAction("Ellipsis", self)
|
||||
self.aInsEllipsis.setStatusTip("Insert ellipsis")
|
||||
self.aInsEllipsis.setShortcut("Ctrl+K, .")
|
||||
self.aInsEllipsis.triggered.connect(lambda: self._docInsert(nwDocInsert.ELLIPSIS))
|
||||
self.insertMenu.addAction(self.aInsEllipsis)
|
||||
self.mInsDashes.addAction(self.aInsEllipsis)
|
||||
|
||||
# Insert > Separator
|
||||
self.insertMenu.addSeparator()
|
||||
# Insert > Quote Marks
|
||||
self.mInsQuotes = self.insertMenu.addMenu("Quote Marks")
|
||||
|
||||
# Insert > Left Single Quote
|
||||
self.aInsQuoteLS = QAction("Left Single Quote", self)
|
||||
self.aInsQuoteLS.setStatusTip("Insert left single quote")
|
||||
self.aInsQuoteLS.setShortcut("Ctrl+K, 1")
|
||||
self.aInsQuoteLS.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_LS))
|
||||
self.insertMenu.addAction(self.aInsQuoteLS)
|
||||
self.mInsQuotes.addAction(self.aInsQuoteLS)
|
||||
|
||||
# Insert > Right Single Quote
|
||||
self.aInsQuoteRS = QAction("Right Single Quote", self)
|
||||
self.aInsQuoteRS.setStatusTip("Insert right single quote")
|
||||
self.aInsQuoteRS.setShortcut("Ctrl+K, 2")
|
||||
self.aInsQuoteRS.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_RS))
|
||||
self.insertMenu.addAction(self.aInsQuoteRS)
|
||||
self.mInsQuotes.addAction(self.aInsQuoteRS)
|
||||
|
||||
# Insert > Left Double Quote
|
||||
self.aInsQuoteLD = QAction("Left Double Quote", self)
|
||||
self.aInsQuoteLD.setStatusTip("Insert left double quote")
|
||||
self.aInsQuoteLD.setShortcut("Ctrl+K, 3")
|
||||
self.aInsQuoteLD.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_LD))
|
||||
self.insertMenu.addAction(self.aInsQuoteLD)
|
||||
self.mInsQuotes.addAction(self.aInsQuoteLD)
|
||||
|
||||
# Insert > Right Double Quote
|
||||
self.aInsQuoteRD = QAction("Right Double Quote", self)
|
||||
self.aInsQuoteRD.setStatusTip("Insert right double quote")
|
||||
self.aInsQuoteRD.setShortcut("Ctrl+K, 4")
|
||||
self.aInsQuoteRD.triggered.connect(lambda: self._docInsert(nwDocInsert.QUOTE_RD))
|
||||
self.insertMenu.addAction(self.aInsQuoteRD)
|
||||
|
||||
# Insert > Separator
|
||||
self.insertMenu.addSeparator()
|
||||
self.mInsQuotes.addAction(self.aInsQuoteRD)
|
||||
|
||||
# Insert > Alternative Apostrophe
|
||||
self.aInsMSApos = QAction("Alternative Apostrophe", self)
|
||||
self.aInsMSApos.setStatusTip("Insert unicode modifier letter single apostrophe")
|
||||
self.aInsMSApos.setShortcut("Ctrl+K, '")
|
||||
self.aInsMSApos.triggered.connect(lambda: self._docInsert(nwDocInsert.MODAPOS_S))
|
||||
self.insertMenu.addAction(self.aInsMSApos)
|
||||
self.mInsQuotes.addAction(self.aInsMSApos)
|
||||
|
||||
# Insert > Separator
|
||||
self.insertMenu.addSeparator()
|
||||
# Insert > Breaks and Spaces
|
||||
self.mInsBreaks = self.insertMenu.addMenu("Breaks and Spaces")
|
||||
|
||||
# Insert > Hard Line Break
|
||||
self.aInsHardBreak = QAction("Hard Line Break", self)
|
||||
self.aInsHardBreak.setStatusTip("Insert a hard line break")
|
||||
self.aInsHardBreak.setShortcut("Ctrl+K, Return")
|
||||
self.aInsHardBreak.triggered.connect(lambda: self._docInsert(nwDocInsert.HARD_BREAK))
|
||||
self.insertMenu.addAction(self.aInsHardBreak)
|
||||
self.mInsBreaks.addAction(self.aInsHardBreak)
|
||||
|
||||
# Insert > Non-Breaking Space
|
||||
self.aInsNBSpace = QAction("Non-Breaking Space", self)
|
||||
self.aInsNBSpace.setStatusTip("Insert a non-breaking space")
|
||||
self.aInsNBSpace.setShortcut("Ctrl+K, Space")
|
||||
self.aInsNBSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.NB_SPACE))
|
||||
self.insertMenu.addAction(self.aInsNBSpace)
|
||||
self.mInsBreaks.addAction(self.aInsNBSpace)
|
||||
|
||||
# Insert > Thin Space
|
||||
self.aInsThinSpace = QAction("Thin Space", self)
|
||||
self.aInsThinSpace.setStatusTip("Insert a thin space")
|
||||
self.aInsThinSpace.setShortcut("Ctrl+K, Shift+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
|
||||
self.aInsThinNBSpace = QAction("Thin Non-Breaking Space", self)
|
||||
self.aInsThinNBSpace.setStatusTip("Insert a thin non-breaking space")
|
||||
self.aInsThinNBSpace.setShortcut("Ctrl+K, Ctrl+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
|
||||
|
||||
|
||||
@@ -1143,6 +1143,9 @@ class GuiMain(QMainWindow):
|
||||
self.addAction(self.mainMenu.aInsThinSpace)
|
||||
self.addAction(self.mainMenu.aInsThinNBSpace)
|
||||
|
||||
for mAction, _ in self.mainMenu.mInsKWItems.values():
|
||||
self.addAction(mAction)
|
||||
|
||||
# Format
|
||||
self.addAction(self.mainMenu.aFmtEmph)
|
||||
self.addAction(self.mainMenu.aFmtStrong)
|
||||
|
||||
+52
-2
@@ -12,13 +12,14 @@ from shutil import copyfile
|
||||
from nwtools import cmpFiles
|
||||
|
||||
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 (
|
||||
qApp, QAction, QTreeWidgetItem, QStyle, QFileDialog, QMessageBox
|
||||
)
|
||||
|
||||
from nw.constants import (
|
||||
nwItemType, nwItemClass, nwUnicode, nwOutline, nwDocAction, nwDocInsert
|
||||
nwItemType, nwItemClass, nwUnicode, nwOutline, nwDocAction, nwDocInsert,
|
||||
nwKeyWords
|
||||
)
|
||||
|
||||
keyDelay = 2
|
||||
@@ -1098,9 +1099,58 @@ def testInsertMenu(qtbot, monkeypatch, nwFuncTemp, nwTemp):
|
||||
assert nwGUI.docEditor.getText() == " "
|
||||
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
|
||||
##
|
||||
|
||||
nwGUI.closeDocument()
|
||||
|
||||
# First, with no path
|
||||
|
||||
Reference in New Issue
Block a user