From cfa95af72283e34188a389863c40621048e77c17 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 4 May 2012 23:54:36 +0900 Subject: [PATCH] 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 --- aqt/editor.py | 69 ++++++++++++++++++++++++-------------------------- aqt/webview.py | 28 +++++++++++++++----- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/aqt/editor.py b/aqt/editor.py index e3284c07b..c87352058 100644 --- a/aqt/editor.py +++ b/aqt/editor.py @@ -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(""): @@ -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" % ( diff --git a/aqt/webview.py b/aqt/webview.py index 9f6d4749d..d15f12f46 100644 --- a/aqt/webview.py +++ b/aqt/webview.py @@ -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 { %s""" % ( 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: