mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 15:02:21 -04:00
copy/paste updates
- unify handling of shortcut key and context menu cut/copy/paste - don't adjust selection on window/popup focus, so context works on win32 now - remove undocumented shift to keep behaviour
This commit is contained in:
parent
1794c69fe7
commit
cfa95af722
2 changed files with 54 additions and 43 deletions
|
@ -917,49 +917,54 @@ class EditorWebView(AnkiWebView):
|
|||
self.strip = self.editor.mw.pm.profile['stripHTML']
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
self._curKey = True
|
||||
self.origClip = None
|
||||
shiftPaste = (evt.modifiers() == (Qt.ShiftModifier | Qt.ControlModifier)
|
||||
and evt.key() == Qt.Key_V)
|
||||
if evt.matches(QKeySequence.Paste) or shiftPaste:
|
||||
self.prepareClip(shiftPaste)
|
||||
if shiftPaste:
|
||||
self.triggerPageAction(QWebPage.Paste)
|
||||
if evt.matches(QKeySequence.Paste):
|
||||
self.onPaste()
|
||||
return evt.accept()
|
||||
elif evt.matches(QKeySequence.Copy):
|
||||
self.triggerPageAction(QWebPage.Copy)
|
||||
self._flagAnkiText()
|
||||
self.onCopy()
|
||||
return evt.accept()
|
||||
elif evt.matches(QKeySequence.Cut):
|
||||
self.triggerPageAction(QWebPage.Cut)
|
||||
self._flagAnkiText()
|
||||
self.onCut()
|
||||
return evt.accept()
|
||||
QWebView.keyPressEvent(self, evt)
|
||||
self.restoreClip()
|
||||
|
||||
def onCut(self):
|
||||
self.triggerPageAction(QWebPage.Cut)
|
||||
self._flagAnkiText()
|
||||
|
||||
def onCopy(self):
|
||||
self.triggerPageAction(QWebPage.Copy)
|
||||
self._flagAnkiText()
|
||||
|
||||
def onPaste(self):
|
||||
mime = self.prepareClip()
|
||||
self.triggerPageAction(QWebPage.Paste)
|
||||
self.restoreClip(mime)
|
||||
|
||||
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
|
||||
self.prepareClip(mode=QClipboard.Selection)
|
||||
mime = self.prepareClip(mode=QClipboard.Selection)
|
||||
AnkiWebView.mouseReleaseEvent(self, evt)
|
||||
self.restoreClip(mode=QClipboard.Selection)
|
||||
self.restoreClip(mime, 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)
|
||||
|
||||
# Buggy; disable for now.
|
||||
# def contextMenuEvent(self, evt):
|
||||
# # adjust in case the user is going to paste
|
||||
# self.prepareClip()
|
||||
# QWebView.contextMenuEvent(self, evt)
|
||||
# self.restoreClip()
|
||||
elif window:
|
||||
self.eval("mouseDown--;")
|
||||
|
||||
def dropEvent(self, evt):
|
||||
oldmime = evt.mimeData()
|
||||
|
@ -983,7 +988,7 @@ class EditorWebView(AnkiWebView):
|
|||
# tell the drop target to take focus so the drop contents are saved
|
||||
self.eval("dropTarget.focus();")
|
||||
|
||||
def prepareClip(self, keep=False, mode=QClipboard.Clipboard):
|
||||
def prepareClip(self, mode=QClipboard.Clipboard):
|
||||
clip = self.editor.mw.app.clipboard()
|
||||
mime = clip.mimeData(mode=mode)
|
||||
if mime.hasHtml() and mime.html().startswith("<!--anki-->"):
|
||||
|
@ -993,22 +998,14 @@ class EditorWebView(AnkiWebView):
|
|||
mime.setHtml(html)
|
||||
return
|
||||
self.saveClip(mode=mode)
|
||||
if keep:
|
||||
new = QMimeData()
|
||||
if mime.hasHtml():
|
||||
new.setHtml(_filterHTML(mime.html()))
|
||||
else:
|
||||
new.setText(mime.text())
|
||||
mime = new
|
||||
else:
|
||||
mime = self._processMime(mime)
|
||||
mime = self._processMime(mime)
|
||||
clip.setMimeData(mime, mode=mode)
|
||||
|
||||
def restoreClip(self, mode=QClipboard.Clipboard):
|
||||
if not self.origClip:
|
||||
def restoreClip(self, mime, mode=QClipboard.Clipboard):
|
||||
if not mime:
|
||||
return
|
||||
clip = self.editor.mw.app.clipboard()
|
||||
clip.setMimeData(self.origClip, mode=mode)
|
||||
clip.setMimeData(mime, mode=mode)
|
||||
|
||||
def saveClip(self, mode):
|
||||
# we don't own the clipboard object, so we need to copy it
|
||||
|
@ -1022,7 +1019,7 @@ class EditorWebView(AnkiWebView):
|
|||
n.setUrls(mime.urls())
|
||||
if mime.hasImage():
|
||||
n.setImageData(mime.imageData())
|
||||
self.origClip = n
|
||||
return n
|
||||
|
||||
def _processMime(self, mime):
|
||||
# print "html=%s image=%s urls=%s txt=%s" % (
|
||||
|
|
|
@ -39,6 +39,7 @@ class AnkiWebPage(QWebPage):
|
|||
##########################################################################
|
||||
|
||||
class AnkiWebView(QWebView):
|
||||
|
||||
def __init__(self):
|
||||
QWebView.__init__(self)
|
||||
self.setObjectName("mainText")
|
||||
|
@ -51,8 +52,8 @@ class AnkiWebView(QWebView):
|
|||
self.setKeyHandler()
|
||||
self.connect(self, SIGNAL("linkClicked(QUrl)"), self._linkHandler)
|
||||
self.connect(self, SIGNAL("loadFinished(bool)"), self._loadFinished)
|
||||
self._curKey = None
|
||||
self.allowDrops = False
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
if evt.matches(QKeySequence.Copy):
|
||||
self.triggerPageAction(QWebPage.Copy)
|
||||
|
@ -62,35 +63,42 @@ class AnkiWebView(QWebView):
|
|||
evt.accept()
|
||||
return
|
||||
QWebView.keyPressEvent(self, evt)
|
||||
|
||||
def keyReleaseEvent(self, evt):
|
||||
if self._keyHandler:
|
||||
if self._keyHandler(evt):
|
||||
evt.accept()
|
||||
return
|
||||
QWebView.keyPressEvent(self, evt)
|
||||
|
||||
def contextMenuEvent(self, evt):
|
||||
if isWin:
|
||||
# broken on windows for now; events are being fired at the popup
|
||||
return
|
||||
m = QMenu(self)
|
||||
m.addAction(self.pageAction(QWebPage.Cut))
|
||||
m.addAction(self.pageAction(QWebPage.Copy))
|
||||
m.addAction(self.pageAction(QWebPage.Paste))
|
||||
a = m.addAction(_("Cut"))
|
||||
a.connect(a, SIGNAL("activated()"), self.onCut)
|
||||
a = m.addAction(_("Copy"))
|
||||
a.connect(a, SIGNAL("activated()"), self.onCopy)
|
||||
a = m.addAction(_("Paste"))
|
||||
a.connect(a, SIGNAL("activated()"), self.onPaste)
|
||||
m.popup(QCursor.pos())
|
||||
|
||||
def dropEvent(self, evt):
|
||||
pass
|
||||
|
||||
def setLinkHandler(self, handler=None):
|
||||
if handler:
|
||||
self.linkHandler = handler
|
||||
else:
|
||||
self.linkHandler = self._openLinksExternally
|
||||
self._bridge.setLinkHandler(self.linkHandler)
|
||||
|
||||
def setKeyHandler(self, handler=None):
|
||||
# handler should return true if event should be swallowed
|
||||
self._keyHandler = handler
|
||||
|
||||
def setHtml(self, html, loadCB=None):
|
||||
self._loadFinishedCB = loadCB
|
||||
QWebView.setHtml(self, html)
|
||||
|
||||
def stdHtml(self, body, css="", bodyClass="", loadCB=None, js=None, head=""):
|
||||
if isMac:
|
||||
button = "font-weight: bold; height: 24px;"
|
||||
|
@ -110,20 +118,26 @@ button {
|
|||
<body class="%s">%s</body></html>""" % (
|
||||
fontForPlatform(), button, css, js or anki.js.jquery+anki.js.browserSel,
|
||||
head, bodyClass, body), loadCB)
|
||||
|
||||
def setBridge(self, bridge):
|
||||
self._bridge.setBridge(bridge)
|
||||
|
||||
def eval(self, js):
|
||||
self.page().mainFrame().evaluateJavaScript(js)
|
||||
|
||||
def _openLinksExternally(self, url):
|
||||
openLink(url)
|
||||
|
||||
def _jsErr(self, msg, line, srcID):
|
||||
if getattr(sys, 'frozen', None):
|
||||
obj = sys.stderr
|
||||
else:
|
||||
obj = sys.stdout
|
||||
obj.write(_("JS error on line %(a)d: %(b)s") % dict(a=line, b=msg+"\n"))
|
||||
|
||||
def _linkHandler(self, url):
|
||||
self.linkHandler(url.toString())
|
||||
|
||||
def _loadFinished(self):
|
||||
self.page().mainFrame().addToJavaScriptWindowObject("py", self._bridge)
|
||||
if self._loadFinishedCB:
|
||||
|
|
Loading…
Reference in a new issue