Viewer: Fix copy to clipboard button in toolbar not working

Viewer: Fix copy to clipboard not copying text as HTML to clipboard in
addition to plain text

Fixes #1897297 [Copy in the viewer doesn't work properly](https://bugs.launchpad.net/calibre/+bug/1897297)
This commit is contained in:
Kovid Goyal 2020-09-27 09:48:44 +05:30
parent f11c874fb9
commit 13e4f17a50
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
8 changed files with 36 additions and 20 deletions

View File

@ -44,7 +44,7 @@ def all_actions():
'back': Action('back.png', _('Back')),
'forward': Action('forward.png', _('Forward')),
'open': Action('document_open.png', _('Open e-book')),
'copy': Action('edit-copy.png', _('Copy to clipboard')),
'copy': Action('edit-copy.png', _('Copy to clipboard'), 'copy_to_clipboard'),
'increase_font_size': Action('font_size_larger.png', _('Increase font size'), 'increase_font_size'),
'decrease_font_size': Action('font_size_smaller.png', _('Decrease font size'), 'decrease_font_size'),
'fullscreen': Action('page.png', _('Toggle full screen'), 'toggle_full_screen'),
@ -150,8 +150,7 @@ class ActionsToolBar(ToolBar):
a.setMenu(m)
m.aboutToShow.connect(self.populate_open_menu)
connect_lambda(a.triggered, self, lambda self: self.open_book_at_path.emit(None))
self.copy_action = a = page.action(QWebEnginePage.Copy)
a.setIcon(aa.copy.icon), a.setText(aa.copy.text)
self.copy_action = shortcut_action('copy')
self.increase_font_size_action = shortcut_action('increase_font_size')
self.decrease_font_size_action = shortcut_action('decrease_font_size')
self.fullscreen_action = shortcut_action('fullscreen')

View File

@ -7,10 +7,9 @@ import os
import shutil
import sys
from itertools import count
from PyQt5.Qt import (
QApplication, QBuffer, QByteArray, QFontDatabase, QFontInfo, QHBoxLayout, QSize, QT_VERSION,
Qt, QTimer, QUrl, QWidget, pyqtSignal
QT_VERSION, QApplication, QBuffer, QByteArray, QFontDatabase, QFontInfo,
QHBoxLayout, QMimeData, QSize, Qt, QTimer, QUrl, QWidget, pyqtSignal
)
from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler
from PyQt5.QtWebEngineWidgets import (
@ -251,7 +250,7 @@ class ViewerBridge(Bridge):
ask_for_open = from_js(object)
selection_changed = from_js(object, object)
autoscroll_state_changed = from_js(object)
copy_selection = from_js(object)
copy_selection = from_js(object, object)
view_image = from_js(object)
copy_image = from_js(object)
change_background_image = from_js(object)
@ -339,11 +338,13 @@ class WebPage(QWebEnginePage):
self.bridge = ViewerBridge(self)
self.bridge.copy_selection.connect(self.trigger_copy)
def trigger_copy(self, what):
if what:
QApplication.instance().clipboard().setText(what)
else:
self.triggerAction(self.Copy)
def trigger_copy(self, text, html):
if text:
md = QMimeData()
md.setText(text)
if html:
md.setHtml(html)
QApplication.instance().clipboard().setMimeData(md)
def javaScriptConsoleMessage(self, level, msg, linenumber, source_id):
prefix = {QWebEnginePage.InfoMessageLevel: 'INFO', QWebEnginePage.WarningMessageLevel: 'WARNING'}.get(

View File

@ -862,9 +862,13 @@ class IframeBoss:
select_crw(crw)
def copy_selection(self):
text = window.getSelection().toString()
s = window.getSelection()
text = s.toString()
if text:
self.send_message('copy_text_to_clipboard', text=text)
container = document.createElement('div')
for i in range(s.rangeCount):
container.appendChild(s.getRangeAt(i).cloneContents())
self.send_message('copy_text_to_clipboard', text=text, html=container.innerHTML)
def main():
main.boss = IframeBoss()

View File

@ -556,6 +556,8 @@ class SelectionBar:
sc_name = shortcut_for_key_event(ev, self.view.keyboard_shortcut_map)
if sc_name is 'show_chrome':
self.clear_selection()
elif sc_name is 'copy_to_clipboard':
self.copy_to_clipboard()
elif sc_name in ('up', 'down', 'pageup', 'pagedown', 'left', 'right'):
self.send_message('trigger-shortcut', name=sc_name)
elif sc_name is 'start_search':
@ -876,8 +878,7 @@ class SelectionBar:
# Actions {{{
def copy_to_clipboard(self):
if self.view.currently_showing.selection.text:
ui_operations.copy_selection(self.view.currently_showing.selection.text)
self.view.copy_to_clipboard()
def lookup(self):
if ui_operations.toggle_lookup:

View File

@ -190,6 +190,12 @@ def shortcuts_definition():
_('Show/hide Table of Contents'),
),
'copy_to_clipboard': desc(
'Ctrl+C',
'ui',
_('Copy to clipboard'),
),
'start_search': desc(
v"['/', 'Ctrl+f']",
'ui',

View File

@ -83,7 +83,7 @@ class ReadUI:
ui_operations.close_book = self.close_book.bind(self)
ui_operations.open_url = def(url):
window.open(url, '_blank')
ui_operations.copy_selection = def(text):
ui_operations.copy_selection = def(text, html):
if not window.navigator.clipboard:
return error_dialog(_('No clipboard access'), _(
'Your browser requires you to access the Content server over an HTTPS connection'

View File

@ -292,7 +292,7 @@ class View:
,
'annotations': self.on_annotations_message,
'copy_text_to_clipboard': def(data):
ui_operations.copy_selection(data.text)
ui_operations.copy_selection(data.text, data.html)
,
'view_image': def(data):
if ui_operations.view_image:
@ -326,6 +326,9 @@ class View:
def reference_mode_overlay(self):
return document.getElementById('reference-mode-overlay')
def copy_to_clipboard(self):
self.iframe_wrapper.send_message('copy_selection')
def set_scrollbar_visibility(self, visible):
sd = get_session_data()
sd.set('book_scrollbar', bool(visible))
@ -460,6 +463,8 @@ class View:
ui_operations.toggle_highlights()
elif data.name is 'new_bookmark':
self.new_bookmark()
elif data.name is 'copy_to_clipboard':
self.copy_to_clipboard()
elif data.name is 'toggle_inspector':
ui_operations.toggle_inspector()
elif data.name is 'toggle_lookup':

View File

@ -362,8 +362,8 @@ if window is window.top:
to_python.report_cfi(request_id, data)
ui_operations.ask_for_open = def(path):
to_python.ask_for_open(path)
ui_operations.copy_selection = def(text):
to_python.copy_selection(text or None)
ui_operations.copy_selection = def(text, html):
to_python.copy_selection(text or None, html or None)
ui_operations.view_image = def(name):
to_python.view_image(name)
ui_operations.copy_image = def(name):