update editor, key handling in webview
keyPressEvent/etc no longer work with qwebengineview, so we need to install an event filter to catch things like ctrl+c. drag & drop doesn't seem to be supported until 5.7
This commit is contained in:
parent
9abc9fde9f
commit
d7339d9a27
247
aqt/editor.py
247
aqt/editor.py
@ -81,7 +81,7 @@ function sendState() {
|
||||
'sub': document.queryCommandState("subscript"),
|
||||
'col': document.queryCommandValue("forecolor")
|
||||
};
|
||||
py.run("state:" + JSON.stringify(r));
|
||||
pycmd("state:" + JSON.stringify(r));
|
||||
};
|
||||
|
||||
function setFormat(cmd, arg, nosave) {
|
||||
@ -100,7 +100,7 @@ function clearChangeTimer() {
|
||||
|
||||
function onFocus(elem) {
|
||||
currentField = elem;
|
||||
py.run("focus:" + currentField.id.substring(1));
|
||||
pycmd("focus:" + currentField.id.substring(1));
|
||||
// don't adjust cursor on mouse clicks
|
||||
if (mouseDown) { return; }
|
||||
// do this twice so that there's no flicker on newer versions
|
||||
@ -156,7 +156,7 @@ function saveField(type) {
|
||||
return;
|
||||
}
|
||||
// type is either 'blur' or 'key'
|
||||
py.run(type + ":" + currentField.innerHTML);
|
||||
pycmd(type + ":" + currentField.innerHTML);
|
||||
clearChangeTimer();
|
||||
};
|
||||
|
||||
@ -258,7 +258,7 @@ document.onclick = function (evt) {
|
||||
|
||||
</script></head><body>
|
||||
<div id="fields"></div>
|
||||
<div id="dupes"><a href="#" onclick="py.run('dupes');return false;">%s</a></div>
|
||||
<div id="dupes" style="display:none;"><a href="#" onclick="pycmd('dupes');return false;">%s</a></div>
|
||||
</body></html>
|
||||
"""
|
||||
|
||||
@ -279,14 +279,13 @@ class Editor(object):
|
||||
self.setupButtons()
|
||||
self.setupWeb()
|
||||
self.setupTags()
|
||||
self.setupKeyboard()
|
||||
|
||||
# Initial setup
|
||||
############################################################
|
||||
|
||||
def setupOuter(self):
|
||||
l = QVBoxLayout()
|
||||
l.setMargin(0)
|
||||
l.setContentsMargins(0,0,0,0)
|
||||
l.setSpacing(0)
|
||||
self.widget.setLayout(l)
|
||||
self.outerLayout = l
|
||||
@ -294,13 +293,15 @@ class Editor(object):
|
||||
def setupWeb(self):
|
||||
self.web = EditorWebView(self.widget, self)
|
||||
self.web.allowDrops = True
|
||||
self.web.setBridge(self.bridge)
|
||||
self.web.onBridgeCmd = self.onBridgeCmd
|
||||
self.outerLayout.addWidget(self.web, 1)
|
||||
# pick up the window colour
|
||||
p = self.web.palette()
|
||||
p.setBrush(QPalette.Base, Qt.transparent)
|
||||
self.web.page().setPalette(p)
|
||||
self.web.setAttribute(Qt.WA_OpaquePaintEvent, False)
|
||||
# pick up the window colour - missing on qt5.5
|
||||
if hasattr(self.web.page(), "setBackgroundColor"):
|
||||
self.web.page().setBackgroundColor(Qt.transparent)
|
||||
self.web.onLoadFinished = self._loadFinished
|
||||
self.web.stdHtml(_html % (
|
||||
getBase(self.mw.col), anki.js.jquery,
|
||||
_("Show Duplicates")))
|
||||
|
||||
# Top buttons
|
||||
######################################################################
|
||||
@ -309,9 +310,9 @@ class Editor(object):
|
||||
check=False, native=False, canDisable=True):
|
||||
b = QPushButton(text)
|
||||
if check:
|
||||
b.connect(b, SIGNAL("clicked(bool)"), func)
|
||||
b.clicked["bool"].connect(func)
|
||||
else:
|
||||
b.connect(b, SIGNAL("clicked()"), func)
|
||||
b.clicked.connect(func)
|
||||
if size:
|
||||
b.setFixedHeight(20)
|
||||
b.setFixedWidth(20)
|
||||
@ -348,10 +349,10 @@ class Editor(object):
|
||||
# icons
|
||||
self.iconsBox = QHBoxLayout()
|
||||
if not isMac:
|
||||
self.iconsBox.setMargin(6)
|
||||
self.iconsBox.setContentsMargins(6,6,6,6)
|
||||
self.iconsBox.setSpacing(0)
|
||||
else:
|
||||
self.iconsBox.setMargin(0)
|
||||
self.iconsBox.setContentsMargins(0,0,0,0)
|
||||
self.iconsBox.setSpacing(14)
|
||||
self.outerLayout.addLayout(self.iconsBox)
|
||||
b = self._addButton
|
||||
@ -386,24 +387,19 @@ class Editor(object):
|
||||
_("Cloze deletion (Ctrl+Shift+C)"), text="[...]")
|
||||
but.setFixedWidth(24)
|
||||
s = self.clozeShortcut2 = QShortcut(
|
||||
QKeySequence(_("Ctrl+Alt+Shift+C")), self.parentWindow)
|
||||
s.connect(s, SIGNAL("activated()"), self.onCloze)
|
||||
QKeySequence(_("Ctrl+Alt+Shift+C")), self.parentWindow,
|
||||
activated=self.onCloze)
|
||||
# fixme: better image names
|
||||
b("mail-attachment", self.onAddMedia, _("F3"),
|
||||
_("Attach pictures/audio/video (F3)"))
|
||||
b("media-record", self.onRecSound, _("F5"), _("Record audio (F5)"))
|
||||
b("adv", self.onAdvanced, text=downArrow())
|
||||
s = QShortcut(QKeySequence("Ctrl+T, T"), self.widget)
|
||||
s.connect(s, SIGNAL("activated()"), self.insertLatex)
|
||||
s = QShortcut(QKeySequence("Ctrl+T, E"), self.widget)
|
||||
s.connect(s, SIGNAL("activated()"), self.insertLatexEqn)
|
||||
s = QShortcut(QKeySequence("Ctrl+T, M"), self.widget)
|
||||
s.connect(s, SIGNAL("activated()"), self.insertLatexMathEnv)
|
||||
s = QShortcut(QKeySequence("Ctrl+Shift+X"), self.widget)
|
||||
s.connect(s, SIGNAL("activated()"), self.onHtmlEdit)
|
||||
s = QShortcut(QKeySequence("Ctrl+T, T"), self.widget, activated=self.insertLatex)
|
||||
s = QShortcut(QKeySequence("Ctrl+T, E"), self.widget, activated=self.insertLatexEqn)
|
||||
s = QShortcut(QKeySequence("Ctrl+T, M"), self.widget, activated=self.insertLatexMathEnv)
|
||||
s = QShortcut(QKeySequence("Ctrl+Shift+X"), self.widget, activated=self.onHtmlEdit)
|
||||
# tags
|
||||
s = QShortcut(QKeySequence("Ctrl+Shift+T"), self.widget)
|
||||
s.connect(s, SIGNAL("activated()"), lambda: self.tags.setFocus())
|
||||
s = QShortcut(QKeySequence("Ctrl+Shift+T"), self.widget, activated=lambda: self.tags.setFocus())
|
||||
runHook("setupEditorButtons", self)
|
||||
|
||||
def enableButtons(self, val=True):
|
||||
@ -432,20 +428,20 @@ class Editor(object):
|
||||
parent=self.parentWindow
|
||||
CardLayout(self.mw, self.note, ord=ord, parent=parent,
|
||||
addMode=self.addMode)
|
||||
self.loadNote()
|
||||
if isWin:
|
||||
self.parentWindow.activateWindow()
|
||||
|
||||
# JS->Python bridge
|
||||
######################################################################
|
||||
|
||||
def bridge(self, str):
|
||||
def onBridgeCmd(self, cmd):
|
||||
if not self.note or not runHook:
|
||||
# shutdown
|
||||
return
|
||||
# focus lost or key/button pressed?
|
||||
if str.startswith("blur") or str.startswith("key"):
|
||||
(type, txt) = str.split(":", 1)
|
||||
if cmd.startswith("blur") or cmd.startswith("key"):
|
||||
(type, txt) = cmd.split(":", 1)
|
||||
txt = urllib.parse.unquote(txt)
|
||||
txt = self.mungeHTML(txt)
|
||||
# misbehaving apps may include a null byte in the text
|
||||
txt = txt.replace("\x00", "")
|
||||
@ -474,24 +470,24 @@ class Editor(object):
|
||||
runHook("editTimer", self.note)
|
||||
self.checkValid()
|
||||
# focused into field?
|
||||
elif str.startswith("focus"):
|
||||
(type, num) = str.split(":", 1)
|
||||
elif cmd.startswith("focus"):
|
||||
(type, num) = cmd.split(":", 1)
|
||||
self.enableButtons()
|
||||
self.currentField = int(num)
|
||||
runHook("editFocusGained", self.note, self.currentField)
|
||||
# state buttons changed?
|
||||
elif str.startswith("state"):
|
||||
(cmd, txt) = str.split(":", 1)
|
||||
elif cmd.startswith("state"):
|
||||
(cmd, txt) = cmd.split(":", 1)
|
||||
r = json.loads(txt)
|
||||
self._buttons['text_bold'].setChecked(r['bold'])
|
||||
self._buttons['text_italic'].setChecked(r['italic'])
|
||||
self._buttons['text_under'].setChecked(r['under'])
|
||||
self._buttons['text_super'].setChecked(r['super'])
|
||||
self._buttons['text_sub'].setChecked(r['sub'])
|
||||
elif str.startswith("dupes"):
|
||||
elif cmd.startswith("dupes"):
|
||||
self.showDupes()
|
||||
else:
|
||||
print(str)
|
||||
print(cmd)
|
||||
|
||||
def mungeHTML(self, txt):
|
||||
if txt == "<br>":
|
||||
@ -501,7 +497,7 @@ class Editor(object):
|
||||
# Setting/unsetting the current note
|
||||
######################################################################
|
||||
|
||||
def _loadFinished(self, w):
|
||||
def _loadFinished(self):
|
||||
self._loaded = True
|
||||
if self.note:
|
||||
self.loadNote()
|
||||
@ -513,13 +509,8 @@ class Editor(object):
|
||||
self.disableButtons()
|
||||
if focus:
|
||||
self.stealFocus = True
|
||||
# change timer
|
||||
if self.note:
|
||||
self.web.setHtml(_html % (
|
||||
getBase(self.mw.col), anki.js.jquery,
|
||||
_("Show Duplicates")), loadCB=self._loadFinished)
|
||||
self.updateTags()
|
||||
self.updateKeyboard()
|
||||
self.loadNote()
|
||||
else:
|
||||
self.hideCompleters()
|
||||
if hide:
|
||||
@ -543,11 +534,13 @@ class Editor(object):
|
||||
self.web.eval("setFonts(%s);" % (
|
||||
json.dumps(self.fonts())))
|
||||
self.checkValid()
|
||||
self.updateTags()
|
||||
self.widget.show()
|
||||
if self.stealFocus:
|
||||
self.web.setFocus()
|
||||
self.stealFocus = False
|
||||
|
||||
|
||||
def focus(self):
|
||||
self.web.setFocus()
|
||||
|
||||
@ -560,9 +553,6 @@ class Editor(object):
|
||||
if not self.note:
|
||||
return
|
||||
self.saveTags()
|
||||
if self.mw.app.focusWidget() != self.web:
|
||||
# if no fields are focused, there's nothing to save
|
||||
return
|
||||
# move focus out of fields and save tags
|
||||
self.parentWindow.setFocus()
|
||||
# and process events so any focus-lost hooks fire
|
||||
@ -606,8 +596,7 @@ class Editor(object):
|
||||
d = QDialog(self.widget)
|
||||
form = aqt.forms.edithtml.Ui_Dialog()
|
||||
form.setupUi(d)
|
||||
d.connect(form.buttonBox, SIGNAL("helpRequested()"),
|
||||
lambda: openHelp("editor"))
|
||||
form.buttonBox.helpRequested.connect(lambda: openHelp("editor"))
|
||||
form.textEdit.setPlainText(self.note.fields[self.currentField])
|
||||
form.textEdit.moveCursor(QTextCursor.End)
|
||||
d.exec_()
|
||||
@ -630,13 +619,12 @@ class Editor(object):
|
||||
g.setFlat(True)
|
||||
tb = QGridLayout()
|
||||
tb.setSpacing(12)
|
||||
tb.setMargin(6)
|
||||
tb.setContentsMargins(6,6,6,6)
|
||||
# tags
|
||||
l = QLabel(_("Tags"))
|
||||
tb.addWidget(l, 1, 0)
|
||||
self.tags = aqt.tagedit.TagEdit(self.widget)
|
||||
self.tags.connect(self.tags, SIGNAL("lostFocus"),
|
||||
self.saveTags)
|
||||
self.tags.lostFocus.connect(self.saveTags)
|
||||
self.tags.setToolTip(shortcut(_("Jump to tags with Ctrl+Shift+T")))
|
||||
tb.addWidget(self.tags, 1, 1)
|
||||
g.setLayout(tb)
|
||||
@ -724,7 +712,7 @@ to a cloze type first, via Edit>Change Note Type."""))
|
||||
self.onColourChanged()
|
||||
hbox = QHBoxLayout()
|
||||
hbox.addWidget(self.foregroundFrame)
|
||||
hbox.setMargin(5)
|
||||
hbox.setContentsMargins(5,5,5,5)
|
||||
but.setLayout(hbox)
|
||||
|
||||
# use last colour
|
||||
@ -912,7 +900,7 @@ to a cloze type first, via Edit>Change Note Type."""))
|
||||
# from missing media
|
||||
pass
|
||||
# strip all other attributes, including implicit max-width
|
||||
for attr, val in tag.attrs:
|
||||
for attr, val in tag.attrs.items():
|
||||
if attr != "src":
|
||||
del tag[attr]
|
||||
# strip superfluous elements
|
||||
@ -928,17 +916,13 @@ to a cloze type first, via Edit>Change Note Type."""))
|
||||
def onAdvanced(self):
|
||||
m = QMenu(self.mw)
|
||||
a = m.addAction(_("LaTeX"))
|
||||
a.setShortcut(QKeySequence("Ctrl+T, T"))
|
||||
a.connect(a, SIGNAL("triggered()"), self.insertLatex)
|
||||
a.triggered.connect(self.insertLatex)
|
||||
a = m.addAction(_("LaTeX equation"))
|
||||
a.setShortcut(QKeySequence("Ctrl+T, E"))
|
||||
a.connect(a, SIGNAL("triggered()"), self.insertLatexEqn)
|
||||
a.triggered.connect(self.insertLatexEqn)
|
||||
a = m.addAction(_("LaTeX math env."))
|
||||
a.setShortcut(QKeySequence("Ctrl+T, M"))
|
||||
a.connect(a, SIGNAL("triggered()"), self.insertLatexMathEnv)
|
||||
a.triggered.connect(self.insertLatexMathEnv)
|
||||
a = m.addAction(_("Edit HTML"))
|
||||
a.setShortcut(QKeySequence("Ctrl+Shift+X"))
|
||||
a.connect(a, SIGNAL("triggered()"), self.onHtmlEdit)
|
||||
a.triggered.connect(self.onHtmlEdit)
|
||||
m.exec_(QCursor.pos())
|
||||
|
||||
# LaTeX
|
||||
@ -953,118 +937,65 @@ to a cloze type first, via Edit>Change Note Type."""))
|
||||
def insertLatexMathEnv(self):
|
||||
self.web.eval("wrap('[$$]', '[/$$]');")
|
||||
|
||||
# Keyboard layout
|
||||
######################################################################
|
||||
|
||||
def setupKeyboard(self):
|
||||
if isWin and self.mw.pm.profile['preserveKeyboard']:
|
||||
a = ctypes.windll.user32.ActivateKeyboardLayout
|
||||
a.restype = ctypes.c_void_p
|
||||
a.argtypes = [ctypes.c_void_p, ctypes.c_uint]
|
||||
g = ctypes.windll.user32.GetKeyboardLayout
|
||||
g.restype = ctypes.c_void_p
|
||||
g.argtypes = [ctypes.c_uint]
|
||||
else:
|
||||
a = g = None
|
||||
self.activateKeyboard = a
|
||||
self.getKeyboard = g
|
||||
|
||||
def updateKeyboard(self):
|
||||
self.keyboardLayouts = {}
|
||||
|
||||
def saveKeyboard(self):
|
||||
if not self.getKeyboard:
|
||||
return
|
||||
self.keyboardLayouts[self.currentField] = self.getKeyboard(0)
|
||||
|
||||
def restoreKeyboard(self):
|
||||
if not self.getKeyboard:
|
||||
return
|
||||
if self.currentField in self.keyboardLayouts:
|
||||
self.activateKeyboard(self.keyboardLayouts[self.currentField], 0)
|
||||
|
||||
# Pasting, drag & drop, and keyboard layouts
|
||||
######################################################################
|
||||
|
||||
# fixme: drag & drop
|
||||
# fixme: middle click to paste
|
||||
|
||||
class EditorWebView(AnkiWebView):
|
||||
|
||||
def __init__(self, parent, editor):
|
||||
AnkiWebView.__init__(self)
|
||||
self.editor = editor
|
||||
self.strip = self.editor.mw.pm.profile['stripHTML']
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
if evt.matches(QKeySequence.Paste):
|
||||
self.onPaste()
|
||||
return evt.accept()
|
||||
elif evt.matches(QKeySequence.Copy):
|
||||
self.onCopy()
|
||||
return evt.accept()
|
||||
elif evt.matches(QKeySequence.Cut):
|
||||
self.onCut()
|
||||
return evt.accept()
|
||||
QWebView.keyPressEvent(self, evt)
|
||||
self.setAcceptDrops(True)
|
||||
|
||||
def onCut(self):
|
||||
self.triggerPageAction(QWebPage.Cut)
|
||||
self.triggerPageAction(QWebEnginePage.Cut)
|
||||
self._flagAnkiText()
|
||||
|
||||
def onCopy(self):
|
||||
self.triggerPageAction(QWebPage.Copy)
|
||||
self.triggerPageAction(QWebEnginePage.Copy)
|
||||
self._flagAnkiText()
|
||||
|
||||
def onPaste(self):
|
||||
mime = self.mungeClip()
|
||||
self.triggerPageAction(QWebPage.Paste)
|
||||
self.triggerPageAction(QWebEnginePage.Paste)
|
||||
self.restoreClip()
|
||||
|
||||
def mouseReleaseEvent(self, evt):
|
||||
if not isMac and not isWin and evt.button() == Qt.MidButton:
|
||||
# middle click on x11; munge the clipboard before standard
|
||||
# handling
|
||||
mime = self.mungeClip(mode=QClipboard.Selection)
|
||||
AnkiWebView.mouseReleaseEvent(self, evt)
|
||||
self.restoreClip(mode=QClipboard.Selection)
|
||||
else:
|
||||
AnkiWebView.mouseReleaseEvent(self, evt)
|
||||
|
||||
def focusInEvent(self, evt):
|
||||
window = False
|
||||
if evt.reason() in (Qt.ActiveWindowFocusReason, Qt.PopupFocusReason):
|
||||
# editor area got focus again; need to tell js not to adjust cursor
|
||||
self.eval("mouseDown++;")
|
||||
window = True
|
||||
AnkiWebView.focusInEvent(self, evt)
|
||||
if evt.reason() == Qt.TabFocusReason:
|
||||
self.eval("focusField(0);")
|
||||
elif evt.reason() == Qt.BacktabFocusReason:
|
||||
n = len(self.editor.note.fields) - 1
|
||||
self.eval("focusField(%d);" % n)
|
||||
elif window:
|
||||
self.eval("mouseDown--;")
|
||||
|
||||
def dropEvent(self, evt):
|
||||
oldmime = evt.mimeData()
|
||||
# coming from this program?
|
||||
if evt.source():
|
||||
if oldmime.hasHtml():
|
||||
mime = QMimeData()
|
||||
mime.setHtml(self.editor._filterHTML(oldmime.html()))
|
||||
else:
|
||||
# old qt on linux won't give us html when dragging an image;
|
||||
# in that case just do the default action (which is to ignore
|
||||
# the drag)
|
||||
return AnkiWebView.dropEvent(self, evt)
|
||||
else:
|
||||
mime = self._processMime(oldmime)
|
||||
# create a new event with the new mime data and run it
|
||||
new = QDropEvent(evt.pos(), evt.possibleActions(), mime,
|
||||
evt.mouseButtons(), evt.keyboardModifiers())
|
||||
evt.accept()
|
||||
QWebView.dropEvent(self, new)
|
||||
# tell the drop target to take focus so the drop contents are saved
|
||||
self.eval("dropTarget.focus();")
|
||||
self.setFocus()
|
||||
# def mouseReleaseEvent(self, evt):
|
||||
# if not isMac and not isWin and evt.button() == Qt.MidButton:
|
||||
# # middle click on x11; munge the clipboard before standard
|
||||
# # handling
|
||||
# mime = self.mungeClip(mode=QClipboard.Selection)
|
||||
# AnkiWebView.mouseReleaseEvent(self, evt)
|
||||
# self.restoreClip(mode=QClipboard.Selection)
|
||||
# else:
|
||||
# AnkiWebView.mouseReleaseEvent(self, evt)
|
||||
#
|
||||
# def dropEvent(self, evt):
|
||||
# oldmime = evt.mimeData()
|
||||
# # coming from this program?
|
||||
# if evt.source():
|
||||
# if oldmime.hasHtml():
|
||||
# mime = QMimeData()
|
||||
# mime.setHtml(self.editor._filterHTML(oldmime.html()))
|
||||
# else:
|
||||
# # old qt on linux won't give us html when dragging an image;
|
||||
# # in that case just do the default action (which is to ignore
|
||||
# # the drag)
|
||||
# return AnkiWebView.dropEvent(self, evt)
|
||||
# else:
|
||||
# mime = self._processMime(oldmime)
|
||||
# # create a new event with the new mime data and run it
|
||||
# new = QDropEvent(evt.pos(), evt.possibleActions(), mime,
|
||||
# evt.mouseButtons(), evt.keyboardModifiers())
|
||||
# evt.accept()
|
||||
# AnkiWebView.dropEvent(self, new)
|
||||
# # tell the drop target to take focus so the drop contents are saved
|
||||
# self.eval("dropTarget.focus();")
|
||||
# self.setFocus()
|
||||
|
||||
def mungeClip(self, mode=QClipboard.Clipboard):
|
||||
clip = self.editor.mw.app.clipboard()
|
||||
@ -1207,10 +1138,10 @@ class EditorWebView(AnkiWebView):
|
||||
def contextMenuEvent(self, evt):
|
||||
m = QMenu(self)
|
||||
a = m.addAction(_("Cut"))
|
||||
a.connect(a, SIGNAL("triggered()"), self.onCut)
|
||||
a.triggered.connect(self.onCut)
|
||||
a = m.addAction(_("Copy"))
|
||||
a.connect(a, SIGNAL("triggered()"), self.onCopy)
|
||||
a.triggered.connect(self.onCopy)
|
||||
a = m.addAction(_("Paste"))
|
||||
a.connect(a, SIGNAL("triggered()"), self.onPaste)
|
||||
a.triggered.connect(self.onPaste)
|
||||
runHook("EditorWebView.contextMenuEvent", self, m)
|
||||
m.popup(QCursor.pos())
|
||||
|
@ -44,7 +44,6 @@ class Reviewer(object):
|
||||
self.web.resetHandlers()
|
||||
self.mw.keyHandler = self._keyHandler
|
||||
self.web.onBridgeCmd = self._linkHandler
|
||||
self.web.setKeyHandler(self._catchEsc)
|
||||
if isMac:
|
||||
self.bottom.web.setFixedHeight(46)
|
||||
else:
|
||||
@ -273,11 +272,6 @@ The front of this card is empty. Please run Tools>Empty Cards.""")
|
||||
# Handlers
|
||||
############################################################
|
||||
|
||||
def _catchEsc(self, evt):
|
||||
if evt.key() == Qt.Key_Escape:
|
||||
self.web.eval("$('#typeans').blur();")
|
||||
return True
|
||||
|
||||
def _keyHandler(self, evt):
|
||||
key = str(evt.text())
|
||||
if key == "e":
|
||||
|
@ -76,26 +76,43 @@ class AnkiWebView(QWebEngineView):
|
||||
self.setPage(self._page)
|
||||
self.resetHandlers()
|
||||
self.allowDrops = False
|
||||
# reset each time new html is set; used to detect if still in same state
|
||||
self.key = None
|
||||
self.setCanFocus(canFocus)
|
||||
self.installEventFilter(self)
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
def eventFilter(self, obj, evt):
|
||||
if not isinstance(evt, QKeyEvent) or obj != self:
|
||||
return False
|
||||
if evt.matches(QKeySequence.Copy):
|
||||
self.triggerPageAction(QWebEnginePage.Copy)
|
||||
evt.accept()
|
||||
# work around a bug with windows qt where shift triggers buttons
|
||||
if isWin and evt.modifiers() & Qt.ShiftModifier and not evt.text():
|
||||
evt.accept()
|
||||
return
|
||||
QWebEngineView.keyPressEvent(self, evt)
|
||||
self.onCopy()
|
||||
return True
|
||||
if evt.matches(QKeySequence.Cut):
|
||||
self.onCut()
|
||||
return True
|
||||
if evt.matches(QKeySequence.Paste):
|
||||
self.onPaste()
|
||||
return True
|
||||
if evt.matches(QKeySequence.Cancel):
|
||||
# cheap hack to work around webengine swallowing escape key that
|
||||
# usually closes dialogs
|
||||
w = self.parent()
|
||||
while w:
|
||||
if isinstance(w, QDialog) or isinstance(w, QMainWindow):
|
||||
from aqt import mw
|
||||
if w != mw:
|
||||
w.close()
|
||||
break
|
||||
w = w.parent()
|
||||
return True
|
||||
return False
|
||||
|
||||
def keyReleaseEvent(self, evt):
|
||||
if self._keyHandler:
|
||||
if self._keyHandler(evt):
|
||||
evt.accept()
|
||||
return
|
||||
QWebEngineView.keyReleaseEvent(self, evt)
|
||||
def onCopy(self):
|
||||
self.triggerPageAction(QWebEnginePage.Copy)
|
||||
|
||||
def onCut(self):
|
||||
self.triggerPageAction(QWebEnginePage.Cut)
|
||||
|
||||
def onPaste(self):
|
||||
self.triggerPageAction(QWebEnginePage.Paste)
|
||||
|
||||
def contextMenuEvent(self, evt):
|
||||
if not self._canFocus:
|
||||
@ -109,12 +126,7 @@ class AnkiWebView(QWebEngineView):
|
||||
def dropEvent(self, evt):
|
||||
pass
|
||||
|
||||
def setKeyHandler(self, handler=None):
|
||||
# handler should return true if event should be swallowed
|
||||
self._keyHandler = handler
|
||||
|
||||
def setHtml(self, html):
|
||||
self.key = None
|
||||
app = QApplication.instance()
|
||||
oldFocus = app.focusWidget()
|
||||
self._page.setHtml(html)
|
||||
@ -176,6 +188,5 @@ button {
|
||||
pass
|
||||
|
||||
def resetHandlers(self):
|
||||
self.setKeyHandler(None)
|
||||
self.onBridgeCmd = self.defaultOnBridgeCmd
|
||||
self.onLoadFinished = self.defaultOnLoadFinished
|
||||
|
Loading…
Reference in New Issue
Block a user