コード例 #1
0
ファイル: web_view.py プロジェクト: zwpaper/calibre
 def __init__(self, parent=None):
     self._host_widget = None
     self.callback_id_counter = count()
     self.callback_map = {}
     self.current_cfi = self.current_content_file = None
     RestartingWebEngineView.__init__(self, parent)
     self.tts = TTS(self)
     self.tts.settings_changed.connect(self.tts_settings_changed)
     self.tts.event_received.connect(self.tts_event_received)
     self.dead_renderer_error_shown = False
     self.render_process_failed.connect(self.render_process_died)
     w = QApplication.instance().desktop().availableGeometry(self).width()
     QApplication.instance().palette_changed.connect(self.palette_changed)
     self.show_home_page_on_ready = True
     self._size_hint = QSize(int(w/3), int(w/2))
     self._page = WebPage(self)
     self._page.linkHovered.connect(self.link_hovered)
     self.view_is_ready = False
     self.bridge.bridge_ready.connect(self.on_bridge_ready)
     self.bridge.view_created.connect(self.on_view_created)
     self.bridge.content_file_changed.connect(self.on_content_file_changed)
     self.bridge.set_session_data.connect(self.set_session_data)
     self.bridge.set_local_storage.connect(self.set_local_storage)
     self.bridge.reload_book.connect(self.reload_book)
     self.bridge.toggle_toc.connect(self.toggle_toc)
     self.bridge.show_search.connect(self.show_search)
     self.bridge.search_result_not_found.connect(self.search_result_not_found)
     self.bridge.find_next.connect(self.find_next)
     self.bridge.toggle_bookmarks.connect(self.toggle_bookmarks)
     self.bridge.toggle_highlights.connect(self.toggle_highlights)
     self.bridge.new_bookmark.connect(self.new_bookmark)
     self.bridge.toggle_inspector.connect(self.toggle_inspector)
     self.bridge.toggle_lookup.connect(self.toggle_lookup)
     self.bridge.quit.connect(self.quit)
     self.bridge.update_current_toc_nodes.connect(self.update_current_toc_nodes)
     self.bridge.toggle_full_screen.connect(self.toggle_full_screen)
     self.bridge.ask_for_open.connect(self.ask_for_open)
     self.bridge.selection_changed.connect(self.selection_changed)
     self.bridge.autoscroll_state_changed.connect(self.autoscroll_state_changed)
     self.bridge.read_aloud_state_changed.connect(self.read_aloud_state_changed)
     self.bridge.view_image.connect(self.view_image)
     self.bridge.copy_image.connect(self.copy_image)
     self.bridge.overlay_visibility_changed.connect(self.overlay_visibility_changed)
     self.bridge.reference_mode_changed.connect(self.reference_mode_changed)
     self.bridge.show_loading_message.connect(self.show_loading_message)
     self.bridge.show_error.connect(self.show_error)
     self.bridge.print_book.connect(self.print_book)
     self.bridge.clear_history.connect(self.clear_history)
     self.bridge.reset_interface.connect(self.reset_interface)
     self.bridge.quit.connect(self.quit)
     self.bridge.customize_toolbar.connect(self.customize_toolbar)
     self.bridge.scrollbar_context_menu.connect(self.scrollbar_context_menu)
     self.bridge.close_prep_finished.connect(self.close_prep_finished)
     self.bridge.highlights_changed.connect(self.highlights_changed)
     self.bridge.open_url.connect(safe_open_url)
     self.bridge.speak_simple_text.connect(self.tts.speak_simple_text)
     self.bridge.tts.connect(self.tts.action)
     self.bridge.export_shortcut_map.connect(self.set_shortcut_map)
     self.shortcut_map = {}
     self.bridge.report_cfi.connect(self.call_callback)
     self.bridge.change_background_image.connect(self.change_background_image)
     self.pending_bridge_ready_actions = {}
     self.setPage(self._page)
     self.setAcceptDrops(False)
     self.setUrl(QUrl('{}://{}/'.format(FAKE_PROTOCOL, FAKE_HOST)))
     self.urlChanged.connect(self.url_changed)
     if parent is not None:
         self.inspector = Inspector(parent.inspector_dock.toggleViewAction(), self)
         parent.inspector_dock.setWidget(self.inspector)
コード例 #2
0
ファイル: web_view.py プロジェクト: zwpaper/calibre
class WebView(RestartingWebEngineView):

    cfi_changed = pyqtSignal(object)
    reload_book = pyqtSignal()
    toggle_toc = pyqtSignal()
    show_search = pyqtSignal(object, object)
    search_result_not_found = pyqtSignal(object)
    find_next = pyqtSignal(object)
    toggle_bookmarks = pyqtSignal()
    toggle_highlights = pyqtSignal()
    new_bookmark = pyqtSignal(object)
    toggle_inspector = pyqtSignal()
    toggle_lookup = pyqtSignal(object)
    quit = pyqtSignal()
    update_current_toc_nodes = pyqtSignal(object)
    toggle_full_screen = pyqtSignal()
    ask_for_open = pyqtSignal(object)
    selection_changed = pyqtSignal(object, object)
    autoscroll_state_changed = pyqtSignal(object)
    read_aloud_state_changed = pyqtSignal(object)
    view_image = pyqtSignal(object)
    copy_image = pyqtSignal(object)
    overlay_visibility_changed = pyqtSignal(object)
    reference_mode_changed = pyqtSignal(object)
    show_loading_message = pyqtSignal(object)
    show_error = pyqtSignal(object, object, object)
    print_book = pyqtSignal()
    reset_interface = pyqtSignal()
    quit = pyqtSignal()
    customize_toolbar = pyqtSignal()
    scrollbar_context_menu = pyqtSignal(object, object, object)
    close_prep_finished = pyqtSignal(object)
    highlights_changed = pyqtSignal(object)
    shortcuts_changed = pyqtSignal(object)
    paged_mode_changed = pyqtSignal()
    standalone_misc_settings_changed = pyqtSignal(object)
    view_created = pyqtSignal(object)

    def __init__(self, parent=None):
        self._host_widget = None
        self.callback_id_counter = count()
        self.callback_map = {}
        self.current_cfi = self.current_content_file = None
        RestartingWebEngineView.__init__(self, parent)
        self.tts = TTS(self)
        self.tts.settings_changed.connect(self.tts_settings_changed)
        self.tts.event_received.connect(self.tts_event_received)
        self.dead_renderer_error_shown = False
        self.render_process_failed.connect(self.render_process_died)
        w = QApplication.instance().desktop().availableGeometry(self).width()
        QApplication.instance().palette_changed.connect(self.palette_changed)
        self.show_home_page_on_ready = True
        self._size_hint = QSize(int(w/3), int(w/2))
        self._page = WebPage(self)
        self._page.linkHovered.connect(self.link_hovered)
        self.view_is_ready = False
        self.bridge.bridge_ready.connect(self.on_bridge_ready)
        self.bridge.view_created.connect(self.on_view_created)
        self.bridge.content_file_changed.connect(self.on_content_file_changed)
        self.bridge.set_session_data.connect(self.set_session_data)
        self.bridge.set_local_storage.connect(self.set_local_storage)
        self.bridge.reload_book.connect(self.reload_book)
        self.bridge.toggle_toc.connect(self.toggle_toc)
        self.bridge.show_search.connect(self.show_search)
        self.bridge.search_result_not_found.connect(self.search_result_not_found)
        self.bridge.find_next.connect(self.find_next)
        self.bridge.toggle_bookmarks.connect(self.toggle_bookmarks)
        self.bridge.toggle_highlights.connect(self.toggle_highlights)
        self.bridge.new_bookmark.connect(self.new_bookmark)
        self.bridge.toggle_inspector.connect(self.toggle_inspector)
        self.bridge.toggle_lookup.connect(self.toggle_lookup)
        self.bridge.quit.connect(self.quit)
        self.bridge.update_current_toc_nodes.connect(self.update_current_toc_nodes)
        self.bridge.toggle_full_screen.connect(self.toggle_full_screen)
        self.bridge.ask_for_open.connect(self.ask_for_open)
        self.bridge.selection_changed.connect(self.selection_changed)
        self.bridge.autoscroll_state_changed.connect(self.autoscroll_state_changed)
        self.bridge.read_aloud_state_changed.connect(self.read_aloud_state_changed)
        self.bridge.view_image.connect(self.view_image)
        self.bridge.copy_image.connect(self.copy_image)
        self.bridge.overlay_visibility_changed.connect(self.overlay_visibility_changed)
        self.bridge.reference_mode_changed.connect(self.reference_mode_changed)
        self.bridge.show_loading_message.connect(self.show_loading_message)
        self.bridge.show_error.connect(self.show_error)
        self.bridge.print_book.connect(self.print_book)
        self.bridge.clear_history.connect(self.clear_history)
        self.bridge.reset_interface.connect(self.reset_interface)
        self.bridge.quit.connect(self.quit)
        self.bridge.customize_toolbar.connect(self.customize_toolbar)
        self.bridge.scrollbar_context_menu.connect(self.scrollbar_context_menu)
        self.bridge.close_prep_finished.connect(self.close_prep_finished)
        self.bridge.highlights_changed.connect(self.highlights_changed)
        self.bridge.open_url.connect(safe_open_url)
        self.bridge.speak_simple_text.connect(self.tts.speak_simple_text)
        self.bridge.tts.connect(self.tts.action)
        self.bridge.export_shortcut_map.connect(self.set_shortcut_map)
        self.shortcut_map = {}
        self.bridge.report_cfi.connect(self.call_callback)
        self.bridge.change_background_image.connect(self.change_background_image)
        self.pending_bridge_ready_actions = {}
        self.setPage(self._page)
        self.setAcceptDrops(False)
        self.setUrl(QUrl('{}://{}/'.format(FAKE_PROTOCOL, FAKE_HOST)))
        self.urlChanged.connect(self.url_changed)
        if parent is not None:
            self.inspector = Inspector(parent.inspector_dock.toggleViewAction(), self)
            parent.inspector_dock.setWidget(self.inspector)

    def link_hovered(self, url):
        if url == 'javascript:void(0)':
            url = ''
        self.generic_action('show-status-message', {'text': url})

    def shutdown(self):
        self.tts.shutdown()

    def set_shortcut_map(self, smap):
        self.shortcut_map = smap
        self.shortcuts_changed.emit(smap)

    def url_changed(self, url):
        if url.hasFragment():
            frag = url.fragment(QUrl.ComponentFormattingOption.FullyDecoded)
            if frag and frag.startswith('bookpos='):
                cfi = frag[len('bookpos='):]
                if cfi:
                    self.current_cfi = cfi
                    self.cfi_changed.emit(cfi)

    @property
    def host_widget(self):
        ans = self._host_widget
        if ans is not None and not sip.isdeleted(ans):
            return ans

    def render_process_died(self):
        if self.dead_renderer_error_shown:
            return
        self.dead_renderer_error_shown = True
        error_dialog(self, _('Render process crashed'), _(
            'The Qt WebEngine Render process has crashed.'
            ' You should try restarting the viewer.') , show=True)

    def event(self, event):
        if event.type() == QEvent.Type.ChildPolished:
            child = event.child()
            if 'HostView' in child.metaObject().className():
                self._host_widget = child
                self._host_widget.setFocus(Qt.FocusReason.OtherFocusReason)
        return QWebEngineView.event(self, event)

    def sizeHint(self):
        return self._size_hint

    def refresh(self):
        self.pageAction(QWebEnginePage.WebAction.ReloadAndBypassCache).trigger()

    @property
    def bridge(self):
        return self._page.bridge

    def on_bridge_ready(self):
        f = QApplication.instance().font()
        fi = QFontInfo(f)
        family = f.family()
        if family in ('.AppleSystemUIFont', 'MS Shell Dlg 2'):
            family = 'system-ui'
        ui_data = {
            'all_font_families': QFontDatabase().families(),
            'ui_font_family': family,
            'ui_font_sz': '{}px'.format(fi.pixelSize()),
            'show_home_page_on_ready': self.show_home_page_on_ready,
            'system_colors': system_colors(),
            'QT_VERSION': QT_VERSION,
            'short_time_fmt': QLocale.system().timeFormat(QLocale.FormatType.ShortFormat),
        }
        self.bridge.create_view(
            vprefs['session_data'], vprefs['local_storage'], field_metadata.all_metadata(), ui_data)
        for func, args in iteritems(self.pending_bridge_ready_actions):
            getattr(self.bridge, func)(*args)

    def on_view_created(self, data):
        self.view_created.emit(data)
        self.view_is_ready = True

    def on_content_file_changed(self, data):
        self.current_content_file = data

    def start_book_load(self, initial_position=None, highlights=None, current_book_data=None):
        key = (set_book_path.path,)
        book_url = link_prefix_for_location_links(add_open_at=False)
        self.execute_when_ready('start_book_load', key, initial_position, set_book_path.pathtoebook, highlights or [], book_url)

    def execute_when_ready(self, action, *args):
        if self.bridge.ready:
            getattr(self.bridge, action)(*args)
        else:
            self.pending_bridge_ready_actions[action] = args

    def goto_toc_node(self, node_id):
        self.execute_when_ready('goto_toc_node', node_id)

    def goto_cfi(self, cfi):
        self.execute_when_ready('goto_cfi', cfi)

    def notify_full_screen_state_change(self, in_fullscreen_mode):
        self.execute_when_ready('full_screen_state_changed', in_fullscreen_mode)

    def set_session_data(self, key, val):
        if key == '*' and val is None:
            vprefs['session_data'] = {}
            apply_font_settings(self)
            self.paged_mode_changed.emit()
            self.standalone_misc_settings_changed.emit()
        elif key != '*':
            sd = vprefs['session_data']
            sd[key] = val
            vprefs['session_data'] = sd
            if key in ('standalone_font_settings', 'base_font_size'):
                apply_font_settings(self)
            elif key == 'read_mode':
                self.paged_mode_changed.emit()
            elif key == 'standalone_misc_settings':
                self.standalone_misc_settings_changed.emit(val)

    def set_local_storage(self, key, val):
        if key == '*' and val is None:
            vprefs['local_storage'] = {}
        elif key != '*':
            sd = vprefs['local_storage']
            sd[key] = val
            vprefs['local_storage'] = sd

    def do_callback(self, func_name, callback):
        cid = unicode_type(next(self.callback_id_counter))
        self.callback_map[cid] = callback
        self.execute_when_ready('get_current_cfi', cid)

    def call_callback(self, request_id, data):
        callback = self.callback_map.pop(request_id, None)
        if callback is not None:
            callback(data)

    def get_current_cfi(self, callback):
        self.do_callback('get_current_cfi', callback)

    def show_home_page(self):
        self.execute_when_ready('show_home_page')

    def change_background_image(self, img_id):
        files = choose_images(self, 'viewer-background-image', _('Choose background image'), formats=['png', 'gif', 'jpg', 'jpeg'])
        if files:
            img = files[0]
            with open(img, 'rb') as src, open(os.path.join(viewer_config_dir, 'bg-image.data'), 'wb') as dest:
                dest.write(as_bytes(guess_type(img)[0] or 'image/jpeg') + b'|')
                shutil.copyfileobj(src, dest)
            background_image.ans = None
            self.execute_when_ready('background_image_changed', img_id)

    def goto_frac(self, frac):
        self.execute_when_ready('goto_frac', frac)

    def clear_history(self):
        self._page.history().clear()

    def clear_caches(self):
        self._page.profile().clearHttpCache()

    def trigger_shortcut(self, which):
        self.execute_when_ready('trigger_shortcut', which)

    def show_search_result(self, sr):
        self.execute_when_ready('show_search_result', sr)

    def palette_changed(self):
        self.execute_when_ready('set_system_palette', system_colors())

    def prepare_for_close(self):
        self.execute_when_ready('prepare_for_close')

    def highlight_action(self, uuid, which):
        self.execute_when_ready('highlight_action', uuid, which)
        self.setFocus(Qt.FocusReason.OtherFocusReason)

    def generic_action(self, which, data):
        self.execute_when_ready('generic_action', which, data)

    def tts_event_received(self, which, data):
        self.execute_when_ready('tts_event', which, data)

    def tts_settings_changed(self, ui_settings):
        self.execute_when_ready('tts_event', 'configured', ui_settings)