Merge branch 'master' into project_outline
This commit is contained in:
@@ -60,10 +60,16 @@ These are as following:
|
||||
:header: "Shortcut", "Description"
|
||||
:widths: 15, 50
|
||||
|
||||
":kbd:`Alt-1`", "Switch focus to tree view pane."
|
||||
":kbd:`Alt-2`", "Switch focus to document editor pane."
|
||||
":kbd:`Alt-3`", "Switch focus to document viewer pane."
|
||||
":kbd:`Ctrl-.`", "Correct word under cursor."
|
||||
":kbd:`Ctrl-1`", "Switch focus to tree view pane."
|
||||
":kbd:`Ctrl-2`", "Switch focus to document editor pane."
|
||||
":kbd:`Ctrl-3`", "Switch focus to document viewer pane."
|
||||
":kbd:`Ctrl-/`", "Change block format to comment."
|
||||
":kbd:`Ctrl-0`", "Remove block formatting for block under cursor."
|
||||
":kbd:`Ctrl-1`", "Change block format to header level 1."
|
||||
":kbd:`Ctrl-2`", "Change block format to header level 2."
|
||||
":kbd:`Ctrl-3`", "Change block format to header level 3."
|
||||
":kbd:`Ctrl-4`", "Change block format to header level 4."
|
||||
":kbd:`Ctrl-A`", "Select all text in document."
|
||||
":kbd:`Ctrl-B`", "Format selected text, or word under cursor, as bold."
|
||||
":kbd:`Ctrl-C`", "Copy selected text to clipboard."
|
||||
@@ -89,6 +95,7 @@ These are as following:
|
||||
":kbd:`Ctrl-Del`", "If in tree view, move a document to trash, or delete a folder."
|
||||
":kbd:`Ctrl-Enter`", "Open the tag or reference under the cursor in the view panel."
|
||||
":kbd:`Ctrl-Shift-,`", "Change project settings."
|
||||
":kbd:`Ctrl-Shift-/`", "Remove block formatting for block under cursor."
|
||||
":kbd:`Ctrl-Shift-1`", "Replace occurrence of word in current document, and search for next occurrence."
|
||||
":kbd:`Ctrl-Shift-A`", "Select all text in current paragraph."
|
||||
":kbd:`Ctrl-Shift-D`", "Wrap selected text, or word under cursor, in single quotes."
|
||||
|
||||
@@ -71,6 +71,12 @@ class nwDocAction(Enum):
|
||||
GO_NEXT = 15
|
||||
GO_PREV = 16
|
||||
REPL_NEXT = 17
|
||||
BLOCK_H1 = 18
|
||||
BLOCK_H2 = 19
|
||||
BLOCK_H3 = 20
|
||||
BLOCK_H4 = 21
|
||||
BLOCK_COM = 22
|
||||
BLOCK_TXT = 23
|
||||
|
||||
# END Enum nwDocAction
|
||||
|
||||
|
||||
+189
-89
@@ -440,8 +440,20 @@ class GuiDocEditor(QTextEdit):
|
||||
self._findPrev()
|
||||
elif theAction == nwDocAction.REPL_NEXT:
|
||||
self._replaceNext()
|
||||
elif theAction == nwDocAction.BLOCK_H1:
|
||||
self._formatBlock(nwDocAction.BLOCK_H1)
|
||||
elif theAction == nwDocAction.BLOCK_H2:
|
||||
self._formatBlock(nwDocAction.BLOCK_H2)
|
||||
elif theAction == nwDocAction.BLOCK_H3:
|
||||
self._formatBlock(nwDocAction.BLOCK_H3)
|
||||
elif theAction == nwDocAction.BLOCK_H4:
|
||||
self._formatBlock(nwDocAction.BLOCK_H4)
|
||||
elif theAction == nwDocAction.BLOCK_COM:
|
||||
self._formatBlock(nwDocAction.BLOCK_COM)
|
||||
elif theAction == nwDocAction.BLOCK_TXT:
|
||||
self._formatBlock(nwDocAction.BLOCK_TXT)
|
||||
else:
|
||||
logger.error("Unknown or unsupported document action %s" % str(theAction))
|
||||
logger.debug("Unknown or unsupported document action %s" % str(theAction))
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -515,59 +527,26 @@ class GuiDocEditor(QTextEdit):
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
# Signals and Slots
|
||||
##
|
||||
|
||||
def _followTag(self, theCursor=None):
|
||||
"""Activated by Ctrl+Enter. Checks that we're in a block
|
||||
starting with '@'. We then find the word under the cursor and
|
||||
check that it is after the ':'. If all this is fine, we have a
|
||||
tag and can tell the document viewer to try and find and load
|
||||
the file where the tag is defined.
|
||||
def _docChange(self, thePos, charsRemoved, charsAdded):
|
||||
"""Triggered by QTextDocument->contentsChanged. This also
|
||||
triggers the syntax highlighter.
|
||||
"""
|
||||
|
||||
if theCursor is None:
|
||||
theCursor = self.textCursor()
|
||||
|
||||
theBlock = theCursor.block()
|
||||
theText = theBlock.text()
|
||||
|
||||
if len(theText) == 0:
|
||||
return False
|
||||
|
||||
if theText.startswith("@"):
|
||||
|
||||
theCursor.select(QTextCursor.WordUnderCursor)
|
||||
theWord = theCursor.selectedText()
|
||||
cPos = theText.find(":")
|
||||
wPos = theCursor.selectionStart() - theBlock.position()
|
||||
if wPos <= cPos:
|
||||
return False
|
||||
|
||||
logger.verbose("Attempting to follow tag '%s'" % theWord)
|
||||
self.theParent.docViewer.loadFromTag(theWord)
|
||||
|
||||
return True
|
||||
|
||||
def _insertHardBreak(self):
|
||||
theCursor = self.textCursor()
|
||||
theCursor.beginEditBlock()
|
||||
theCursor.insertText(" \n")
|
||||
theCursor.endEditBlock()
|
||||
return
|
||||
|
||||
def _insertNonBreakingSpace(self):
|
||||
theCursor = self.textCursor()
|
||||
theCursor.beginEditBlock()
|
||||
theCursor.insertText(nwUnicode.U_NBSP)
|
||||
theCursor.endEditBlock()
|
||||
return
|
||||
|
||||
def _openSpellContext(self):
|
||||
self._openContextMenu(self.cursorRect().center())
|
||||
self.lastEdit = time()
|
||||
if not self.docChanged:
|
||||
self.setDocumentChanged(True)
|
||||
if not self.wcTimer.isActive():
|
||||
self.wcTimer.start()
|
||||
if self.mainConf.doReplace and not self.hasSelection:
|
||||
self._docAutoReplace(self.qDocument.findBlock(thePos))
|
||||
return
|
||||
|
||||
def _openContextMenu(self, thePos):
|
||||
"""Triggered by right click to open the context menu. Also
|
||||
triggered by the Ctrl+. shortcut.
|
||||
"""
|
||||
|
||||
if not self.spellCheck:
|
||||
return
|
||||
@@ -625,17 +604,88 @@ class GuiDocEditor(QTextEdit):
|
||||
self.hLight.rehighlightBlock(theCursor.block())
|
||||
return
|
||||
|
||||
def _docChange(self, thePos, charsRemoved, charsAdded):
|
||||
"""Triggered by QTextDocument->contentsChanged. This also
|
||||
triggers the syntax highlighter.
|
||||
def _runCounter(self):
|
||||
"""Decide whether to run the word counter, or stop the timer due
|
||||
to inactivity.
|
||||
"""
|
||||
self.lastEdit = time()
|
||||
if not self.docChanged:
|
||||
self.setDocumentChanged(True)
|
||||
if not self.wcTimer.isActive():
|
||||
self.wcTimer.start()
|
||||
if self.mainConf.doReplace and not self.hasSelection:
|
||||
self._docAutoReplace(self.qDocument.findBlock(thePos))
|
||||
sinceActive = time()-self.lastEdit
|
||||
if sinceActive > 5*self.wcInterval:
|
||||
logger.debug("Stopping word count timer: no activity last %.1f seconds" % sinceActive)
|
||||
self.wcTimer.stop()
|
||||
elif self.wCounter.isRunning():
|
||||
logger.verbose("Word counter thread is busy")
|
||||
else:
|
||||
logger.verbose("Starting word counter")
|
||||
self.wCounter.start()
|
||||
return
|
||||
|
||||
def _updateCounts(self):
|
||||
"""Slot for the word counter's finished signal
|
||||
"""
|
||||
logger.verbose("Updating word count")
|
||||
|
||||
tHandle = self.nwDocument.docHandle
|
||||
self.charCount = self.wCounter.charCount
|
||||
self.wordCount = self.wCounter.wordCount
|
||||
self.paraCount = self.wCounter.paraCount
|
||||
self.theParent.statusBar.setCounts(self.charCount,self.wordCount,self.paraCount)
|
||||
self.theParent.treeView.propagateCount(tHandle, self.wordCount)
|
||||
self.theParent.treeView.projectWordCount()
|
||||
self._checkDocSize(self.charCount)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _followTag(self, theCursor=None):
|
||||
"""Activated by Ctrl+Enter. Checks that we're in a block
|
||||
starting with '@'. We then find the word under the cursor and
|
||||
check that it is after the ':'. If all this is fine, we have a
|
||||
tag and can tell the document viewer to try and find and load
|
||||
the file where the tag is defined.
|
||||
"""
|
||||
|
||||
if theCursor is None:
|
||||
theCursor = self.textCursor()
|
||||
|
||||
theBlock = theCursor.block()
|
||||
theText = theBlock.text()
|
||||
|
||||
if len(theText) == 0:
|
||||
return False
|
||||
|
||||
if theText.startswith("@"):
|
||||
|
||||
theCursor.select(QTextCursor.WordUnderCursor)
|
||||
theWord = theCursor.selectedText()
|
||||
cPos = theText.find(":")
|
||||
wPos = theCursor.selectionStart() - theBlock.position()
|
||||
if wPos <= cPos:
|
||||
return False
|
||||
|
||||
logger.verbose("Attempting to follow tag '%s'" % theWord)
|
||||
self.theParent.docViewer.loadFromTag(theWord)
|
||||
|
||||
return True
|
||||
|
||||
def _insertHardBreak(self):
|
||||
theCursor = self.textCursor()
|
||||
theCursor.beginEditBlock()
|
||||
theCursor.insertText(" \n")
|
||||
theCursor.endEditBlock()
|
||||
return
|
||||
|
||||
def _insertNonBreakingSpace(self):
|
||||
theCursor = self.textCursor()
|
||||
theCursor.beginEditBlock()
|
||||
theCursor.insertText(nwUnicode.U_NBSP)
|
||||
theCursor.endEditBlock()
|
||||
return
|
||||
|
||||
def _openSpellContext(self):
|
||||
self._openContextMenu(self.cursorRect().center())
|
||||
return
|
||||
|
||||
def _docAutoReplace(self, theBlock):
|
||||
@@ -693,37 +743,6 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
return
|
||||
|
||||
def _runCounter(self):
|
||||
"""Decide whether to run the word counter, or stop the timer due
|
||||
to inactivity.
|
||||
"""
|
||||
sinceActive = time()-self.lastEdit
|
||||
if sinceActive > 5*self.wcInterval:
|
||||
logger.debug("Stopping word count timer: no activity last %.1f seconds" % sinceActive)
|
||||
self.wcTimer.stop()
|
||||
elif self.wCounter.isRunning():
|
||||
logger.verbose("Word counter thread is busy")
|
||||
else:
|
||||
logger.verbose("Starting word counter")
|
||||
self.wCounter.start()
|
||||
return
|
||||
|
||||
def _updateCounts(self):
|
||||
"""Slot for the word counter's finished signal
|
||||
"""
|
||||
logger.verbose("Updating word count")
|
||||
|
||||
tHandle = self.nwDocument.docHandle
|
||||
self.charCount = self.wCounter.charCount
|
||||
self.wordCount = self.wCounter.wordCount
|
||||
self.paraCount = self.wCounter.paraCount
|
||||
self.theParent.statusBar.setCounts(self.charCount,self.wordCount,self.paraCount)
|
||||
self.theParent.treeView.propagateCount(tHandle, self.wordCount)
|
||||
self.theParent.treeView.projectWordCount()
|
||||
self._checkDocSize(self.charCount)
|
||||
|
||||
return
|
||||
|
||||
def _checkDocSize(self, theSize):
|
||||
"""Check if document size crosses the big document limit set in
|
||||
config. If so, we will set the big document flag to True.
|
||||
@@ -761,6 +780,87 @@ class GuiDocEditor(QTextEdit):
|
||||
logger.warning("No selection made, nothing to do")
|
||||
return
|
||||
|
||||
def _formatBlock(self, docAction):
|
||||
"""Changes the block format of the block under the cursor.
|
||||
"""
|
||||
|
||||
theCursor = self.textCursor()
|
||||
theBlock = theCursor.block()
|
||||
if not theBlock.isValid():
|
||||
logger.debug("Invalid block selected for action %s" % str(docAction))
|
||||
return
|
||||
|
||||
theText = theBlock.text()
|
||||
if len(theText.strip()) == 0:
|
||||
logger.debug("Empty block selected for action %s" % str(docAction))
|
||||
return
|
||||
|
||||
# Remove existing format first, if any
|
||||
if theText.startswith("@"):
|
||||
logger.error("Cannot apply block format to keyword/value line")
|
||||
return
|
||||
elif theText.startswith("% "):
|
||||
newText = theText[2:]
|
||||
cOffset = 2
|
||||
elif theText.startswith("%"):
|
||||
newText = theText[1:]
|
||||
cOffset = 1
|
||||
elif theText.startswith("# "):
|
||||
newText = theText[2:]
|
||||
cOffset = 2
|
||||
elif theText.startswith("## "):
|
||||
newText = theText[3:]
|
||||
cOffset = 3
|
||||
elif theText.startswith("### "):
|
||||
newText = theText[4:]
|
||||
cOffset = 4
|
||||
elif theText.startswith("#### "):
|
||||
newText = theText[5:]
|
||||
cOffset = 5
|
||||
else:
|
||||
newText = theText
|
||||
cOffset = 0
|
||||
|
||||
# Apply new format
|
||||
if docAction == nwDocAction.BLOCK_COM:
|
||||
theText = "% "+newText
|
||||
cOffset -= 2
|
||||
elif docAction == nwDocAction.BLOCK_H1:
|
||||
theText = "# "+newText
|
||||
cOffset -= 2
|
||||
elif docAction == nwDocAction.BLOCK_H2:
|
||||
theText = "## "+newText
|
||||
cOffset -= 3
|
||||
elif docAction == nwDocAction.BLOCK_H3:
|
||||
theText = "### "+newText
|
||||
cOffset -= 4
|
||||
elif docAction == nwDocAction.BLOCK_H4:
|
||||
theText = "#### "+newText
|
||||
cOffset -= 5
|
||||
elif docAction == nwDocAction.BLOCK_TXT:
|
||||
theText = newText
|
||||
cOffset -= 0
|
||||
else:
|
||||
logger.error("Unknown or unsupported block format requested: %s" % str(docAction))
|
||||
return
|
||||
|
||||
# Replace the block text
|
||||
theCursor.beginEditBlock()
|
||||
posO = theCursor.position()
|
||||
theCursor.select(QTextCursor.BlockUnderCursor)
|
||||
posS = theCursor.selectionStart()
|
||||
theCursor.removeSelectedText()
|
||||
theCursor.setPosition(posS)
|
||||
if posS > 0:
|
||||
theCursor.insertBlock()
|
||||
theCursor.insertText(theText)
|
||||
if posO - cOffset >= 0:
|
||||
theCursor.setPosition(posO - cOffset)
|
||||
theCursor.endEditBlock()
|
||||
self.setTextCursor(theCursor)
|
||||
|
||||
return
|
||||
|
||||
def _makeSelection(self, selMode):
|
||||
theCursor = self.textCursor()
|
||||
theCursor.clearSelection()
|
||||
|
||||
@@ -15,10 +15,10 @@ import nw
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QTextBrowser
|
||||
from PyQt5.QtGui import QTextOption, QFont, QPalette, QColor
|
||||
from PyQt5.QtGui import QTextOption, QFont, QPalette, QColor, QTextCursor
|
||||
|
||||
from nw.convert import ToHtml
|
||||
from nw.constants import nwAlert, nwItemType
|
||||
from nw.constants import nwAlert, nwItemType, nwDocAction
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -47,6 +47,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.qDocument.setDefaultTextOption(theOpt)
|
||||
|
||||
self.anchorClicked.connect(self._linkClicked)
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
|
||||
logger.debug("DocViewer initialisation complete")
|
||||
|
||||
@@ -142,10 +143,35 @@ class GuiDocViewer(QTextBrowser):
|
||||
|
||||
return True
|
||||
|
||||
def docAction(self, theAction):
|
||||
logger.verbose("Requesting action: %s" % theAction.name)
|
||||
if self.theHandle is None:
|
||||
logger.error("No document open")
|
||||
return False
|
||||
if theAction == nwDocAction.CUT:
|
||||
self.copy()
|
||||
elif theAction == nwDocAction.COPY:
|
||||
self.copy()
|
||||
elif theAction == nwDocAction.SEL_ALL:
|
||||
self._makeSelection(QTextCursor.Document)
|
||||
elif theAction == nwDocAction.SEL_PARA:
|
||||
self._makeSelection(QTextCursor.BlockUnderCursor)
|
||||
else:
|
||||
logger.debug("Unknown or unsupported document action %s" % str(theAction))
|
||||
return False
|
||||
return True
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _makeSelection(self, selMode):
|
||||
theCursor = self.textCursor()
|
||||
theCursor.clearSelection()
|
||||
theCursor.select(selMode)
|
||||
self.setTextCursor(theCursor)
|
||||
return
|
||||
|
||||
def _linkClicked(self, theURL):
|
||||
|
||||
theLink = theURL.url()
|
||||
|
||||
+51
-6
@@ -40,7 +40,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self._buildHelpMenu()
|
||||
|
||||
# Function Pointers
|
||||
self._docAction = self.theParent.docEditor.docAction
|
||||
self._docAction = self.theParent.passDocumentAction
|
||||
self._moveTreeItem = self.theParent.treeView.moveTreeItem
|
||||
self._newTreeItem = self.theParent.treeView.newTreeItem
|
||||
|
||||
@@ -379,21 +379,21 @@ class GuiMainMenu(QMenuBar):
|
||||
# View > TreeView
|
||||
self.aFocusTree = QAction("TreeView", self)
|
||||
self.aFocusTree.setStatusTip("Move focus to project tree")
|
||||
self.aFocusTree.setShortcut("Ctrl+1")
|
||||
self.aFocusTree.setShortcut("Alt+1")
|
||||
self.aFocusTree.triggered.connect(lambda : self.theParent.setFocus(1))
|
||||
self.viewMenu.addAction(self.aFocusTree)
|
||||
|
||||
# View > Document Pane 1
|
||||
self.aFocusEditor = QAction("Left Document Pane", self)
|
||||
self.aFocusEditor.setStatusTip("Move focus to left document pane")
|
||||
self.aFocusEditor.setShortcut("Ctrl+2")
|
||||
self.aFocusEditor.setShortcut("Alt+2")
|
||||
self.aFocusEditor.triggered.connect(lambda : self.theParent.setFocus(2))
|
||||
self.viewMenu.addAction(self.aFocusEditor)
|
||||
|
||||
# View > Document Pane 2
|
||||
self.aFocusView = QAction("Right Document Pane", self)
|
||||
self.aFocusView.setStatusTip("Move focus to right document pane")
|
||||
self.aFocusView.setShortcut("Ctrl+3")
|
||||
self.aFocusView.setShortcut("Alt+3")
|
||||
self.aFocusView.triggered.connect(lambda : self.theParent.setFocus(3))
|
||||
self.viewMenu.addAction(self.aFocusView)
|
||||
|
||||
@@ -570,6 +570,51 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFmtSQuote.triggered.connect(lambda: self._docAction(nwDocAction.S_QUOTE))
|
||||
self.fmtMenu.addAction(self.aFmtSQuote)
|
||||
|
||||
# Edit > Separator
|
||||
self.fmtMenu.addSeparator()
|
||||
|
||||
# Format > Header 1
|
||||
self.aFmtHead1 = QAction("Header 1", self)
|
||||
self.aFmtHead1.setStatusTip("Change the block format to Header 1")
|
||||
self.aFmtHead1.setShortcut("Ctrl+1")
|
||||
self.aFmtHead1.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H1))
|
||||
self.fmtMenu.addAction(self.aFmtHead1)
|
||||
|
||||
# Format > Header 2
|
||||
self.aFmtHead2 = QAction("Header 2", self)
|
||||
self.aFmtHead2.setStatusTip("Change the block format to Header 2")
|
||||
self.aFmtHead2.setShortcut("Ctrl+2")
|
||||
self.aFmtHead2.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H2))
|
||||
self.fmtMenu.addAction(self.aFmtHead2)
|
||||
|
||||
# Format > Header 3
|
||||
self.aFmtHead3 = QAction("Header 3", self)
|
||||
self.aFmtHead3.setStatusTip("Change the block format to Header 3")
|
||||
self.aFmtHead3.setShortcut("Ctrl+3")
|
||||
self.aFmtHead3.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H3))
|
||||
self.fmtMenu.addAction(self.aFmtHead3)
|
||||
|
||||
# Format > Header 4
|
||||
self.aFmtHead4 = QAction("Header 4", self)
|
||||
self.aFmtHead4.setStatusTip("Change the block format to Header 4")
|
||||
self.aFmtHead4.setShortcut("Ctrl+4")
|
||||
self.aFmtHead4.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_H4))
|
||||
self.fmtMenu.addAction(self.aFmtHead4)
|
||||
|
||||
# Format > Comment
|
||||
self.aFmtComment = QAction("Comment", self)
|
||||
self.aFmtComment.setStatusTip("Change the block format to comment")
|
||||
self.aFmtComment.setShortcut("Ctrl+/")
|
||||
self.aFmtComment.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_COM))
|
||||
self.fmtMenu.addAction(self.aFmtComment)
|
||||
|
||||
# Format > Remove Format
|
||||
self.aFmtNoFormat = QAction("Remove Format", self)
|
||||
self.aFmtNoFormat.setStatusTip("Strips block format")
|
||||
self.aFmtNoFormat.setShortcuts(["Ctrl+0","Ctrl+Shift+/"])
|
||||
self.aFmtNoFormat.triggered.connect(lambda: self._docAction(nwDocAction.BLOCK_TXT))
|
||||
self.fmtMenu.addAction(self.aFmtNoFormat)
|
||||
|
||||
return
|
||||
|
||||
def _buildToolsMenu(self):
|
||||
@@ -657,8 +702,8 @@ class GuiMainMenu(QMenuBar):
|
||||
self.helpMenu.addSeparator()
|
||||
|
||||
# Document > Preview
|
||||
self.aHelp = QAction("Documentation", self)
|
||||
self.aHelp.setStatusTip("View documentation")
|
||||
self.aHelp = QAction("Online Documentation", self)
|
||||
self.aHelp.setStatusTip("View online documentation")
|
||||
self.aHelp.setShortcut("F1")
|
||||
self.aHelp.triggered.connect(self._openHelp)
|
||||
self.helpMenu.addAction(self.aHelp)
|
||||
|
||||
@@ -469,6 +469,18 @@ class GuiMain(QMainWindow):
|
||||
|
||||
return True
|
||||
|
||||
def passDocumentAction(self, theAction):
|
||||
"""Pass on document action theAction to whatever document has
|
||||
the focus. If no document has focus, the action is discarded.
|
||||
"""
|
||||
if self.docEditor.hasFocus():
|
||||
self.docEditor.docAction(theAction)
|
||||
elif self.docViewer.hasFocus():
|
||||
self.docViewer.docAction(theAction)
|
||||
else:
|
||||
logger.debug("Document action requested, but no document has focus")
|
||||
return True
|
||||
|
||||
##
|
||||
# Tree Item Actions
|
||||
##
|
||||
|
||||
Reference in New Issue
Block a user