%PDF- %PDF-
Direktori : /usr/lib/calibre/calibre/gui2/viewer/ |
Current File : //usr/lib/calibre/calibre/gui2/viewer/main.py |
#!/usr/bin/env python3 # License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net> import json import os import sys from qt.core import QIcon, QObject, Qt, QTimer, pyqtSignal from qt.webengine import QWebEngineUrlScheme from contextlib import closing from calibre.constants import FAKE_PROTOCOL, VIEWER_APP_UID, islinux from calibre.gui2 import Application, error_dialog, setup_gui_option_parser from calibre.gui2.viewer.config import get_session_pref, vprefs from calibre.gui2.viewer.ui import EbookViewer, is_float from calibre.gui2.listener import send_message_in_process from calibre.ptempfile import reset_base_dir from calibre.utils.config import JSONConfig from calibre.utils.ipc import viewer_socket_address singleinstance_name = 'calibre_viewer' def migrate_previous_viewer_prefs(): new_prefs = vprefs if new_prefs['old_prefs_migrated']: return old_vprefs = JSONConfig('viewer') old_prefs = JSONConfig('viewer.py') with new_prefs: sd = new_prefs['session_data'] fs = sd.get('standalone_font_settings', {}) for k in ('serif', 'sans', 'mono'): defval = 'Liberation ' + k.capitalize() k += '_family' if old_prefs.get(k) and old_prefs[k] != defval: fs[k] = old_prefs[k] if old_prefs.get('standard_font') in ('serif', 'sans', 'mono'): fs['standard_font'] = old_prefs['standard_font'] if old_prefs.get('minimum_font_size') is not None and old_prefs['minimum_font_size'] != 8: fs['minimum_font_size'] = old_prefs['minimum_font_size'] sd['standalone_font_settings'] = fs ms = sd.get('standalone_misc_settings', {}) ms['remember_window_geometry'] = bool(old_prefs.get('remember_window_size', False)) ms['remember_last_read'] = bool(old_prefs.get('remember_current_page', True)) ms['save_annotations_in_ebook'] = bool(old_prefs.get('copy_bookmarks_to_file', False)) ms['singleinstance'] = bool(old_vprefs.get('singleinstance', False)) sd['standalone_misc_settings'] = ms for k in ('top', 'bottom'): v = old_prefs.get(k + '_margin') if v != 20 and v is not None: sd['margin_' + k] = v v = old_prefs.get('side_margin') if v is not None and v != 40: sd['margin_left'] = sd['margin_right'] = v // 2 if old_prefs.get('user_css'): sd['user_stylesheet'] = old_prefs['user_css'] cps = {'portrait': 0, 'landscape': 0} cp = old_prefs.get('cols_per_screen_portrait') if cp and cp > 1: cps['portrait'] = cp cl = old_prefs.get('cols_per_screen_landscape') if cl and cl > 1: cps['landscape'] = cp if cps['portrait'] or cps['landscape']: sd['columns_per_screen'] = cps if old_vprefs.get('in_paged_mode') is False: sd['read_mode'] = 'flow' new_prefs.set('session_data', sd) new_prefs.set('old_prefs_migrated', True) class EventAccumulator(QObject): got_file = pyqtSignal(object) def __init__(self, parent): QObject.__init__(self, parent) self.events = [] def __call__(self, paths): for path in paths: if os.path.exists(path): self.events.append(path) self.got_file.emit(path) def flush(self): if self.events: self.got_file.emit(self.events[-1]) self.events = [] def send_message_to_viewer_instance(args, open_at): if len(args) > 1: msg = json.dumps((os.path.abspath(args[1]), open_at)) try: send_message_in_process(msg, address=viewer_socket_address()) except Exception as err: error_dialog(None, _('Connecting to E-book viewer failed'), _( 'Unable to connect to existing E-book viewer window, try restarting the viewer.'), det_msg=str(err), show=True) raise SystemExit(1) print('Opened book in existing viewer instance') def option_parser(): from calibre.gui2.main_window import option_parser parser = option_parser(_('''\ %prog [options] file View an e-book. ''')) a = parser.add_option a('--raise-window', default=False, action='store_true', help=_('If specified, the E-book viewer window will try to come to the ' 'front when started.')) a('--full-screen', '--fullscreen', '-f', default=False, action='store_true', help=_('If specified, the E-book viewer window will try to open ' 'full screen when started.')) a('--force-reload', default=False, action='store_true', help=_('Force reload of all opened books')) a('--open-at', default=None, help=_( 'The position at which to open the specified book. The position is ' 'a location or position you can get by using the Go to->Location action in the viewer controls. ' 'Alternately, you can use the form toc:something and it will open ' 'at the location of the first Table of Contents entry that contains ' 'the string "something". The form toc-href:something will match the ' 'href (internal link destination) of toc nodes. The matching is exact. ' 'If you want to match a substring, use the form toc-href-contains:something. ' 'The form ref:something will use Reference mode references.')) a('--continue', default=False, action='store_true', dest='continue_reading', help=_('Continue reading the last opened book')) setup_gui_option_parser(parser) return parser def run_gui(app, opts, args, internal_book_data, listener=None): acc = EventAccumulator(app) app.file_event_hook = acc app.load_builtin_fonts() app.setWindowIcon(QIcon(I('viewer.png'))) migrate_previous_viewer_prefs() main = EbookViewer( open_at=opts.open_at, continue_reading=opts.continue_reading, force_reload=opts.force_reload, calibre_book_data=internal_book_data) main.set_exception_handler() if len(args) > 1: acc.events.append(os.path.abspath(args[-1])) acc.got_file.connect(main.handle_commandline_arg) main.show() if listener is not None: listener.message_received.connect(main.message_from_other_instance, type=Qt.ConnectionType.QueuedConnection) QTimer.singleShot(0, acc.flush) if opts.raise_window: main.raise_() if opts.full_screen: main.set_full_screen(True) app.exec() def main(args=sys.argv): # Ensure viewer can continue to function if GUI is closed os.environ.pop('CALIBRE_WORKER_TEMP_DIR', None) reset_base_dir() scheme = QWebEngineUrlScheme(FAKE_PROTOCOL.encode('ascii')) scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) override = 'calibre-ebook-viewer' if islinux else None processed_args = [] internal_book_data = internal_book_data_path = None for arg in args: if arg.startswith('--internal-book-data='): internal_book_data_path = arg.split('=', 1)[1] continue processed_args.append(arg) if internal_book_data_path: try: with lopen(internal_book_data_path, 'rb') as f: internal_book_data = json.load(f) finally: try: os.remove(internal_book_data_path) except OSError: pass args = processed_args app = Application(args, override_program_name=override, windows_app_uid=VIEWER_APP_UID) parser = option_parser() opts, args = parser.parse_args(args) oat = opts.open_at if oat and not ( oat.startswith('toc:') or oat.startswith('toc-href:') or oat.startswith('toc-href-contains:') or oat.startswith('epubcfi(/') or is_float(oat) or oat.startswith('ref:')): raise SystemExit(f'Not a valid --open-at value: {opts.open_at}') if get_session_pref('singleinstance', False): from calibre.utils.lock import SingleInstance from calibre.gui2.listener import Listener with SingleInstance(singleinstance_name) as si: if si: try: listener = Listener(address=viewer_socket_address(), parent=app) listener.start_listening() except Exception as err: error_dialog(None, _('Failed to start listener'), _( 'Could not start the listener used for single instance viewers. Try rebooting your computer.'), det_msg=str(err), show=True) else: with closing(listener): run_gui(app, opts, args, internal_book_data, listener=listener) else: send_message_to_viewer_instance(args, opts.open_at) else: run_gui(app, opts, args, internal_book_data) if __name__ == '__main__': sys.exit(main())