def __init__(self, argv, name=None): if name is None: name = "luminos" super().__init__(argv, name) if QWebEngineUrlScheme is not None: if not QWebEngineUrlScheme.schemeByName(b"luminos").name(): scheme = QWebEngineUrlScheme(b"luminos") scheme.setFlags( QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | QWebEngineUrlScheme.ContentSecurityPolicyIgnored | QWebEngineUrlScheme.SecureScheme ) QWebEngineUrlScheme.registerScheme(scheme) self._initProfile() # self.interceptor = UrlRequestInterceptor() # self.profile.setRequestInterceptor(self.interceptor) log.init.debug("Initializing web setings...") config.instance.changed.connect(self._updateSettings) self.settings = WebEngineSettings(_SettingsWrapper(self.profile)) self.settings.initSettings() self._setupSchemeHandler() self.pluginManager = PluginManager() self.controller = Controller(self) self.controller.mainWindowChanged.connect(self._mainWindowChanged)
def main(): """ Main entry point into the application. """ global app from PyQt5.QtGui import QGuiApplication QGuiApplication.setDesktopFileName("eric6_browser.desktop") options = [ ("--config=configDir", "use the given directory as the one containing the config files"), ("--private", "start the browser in private browsing mode"), ("--qthelp", "start the browser with support for QtHelp"), ("--quiet", "don't show any startup error messages"), ("--search=word", "search for the given word"), ("--settings=settingsDir", "use the given directory to store the settings files"), ("--single", "start the browser as a single application"), ] appinfo = AppInfo.makeAppInfo(sys.argv, "eric6 Web Browser", "file", "web browser", options) # set the library paths for plugins Startup.setLibraryPaths() if qVersionTuple() >= (5, 12, 0): from PyQt5.QtWebEngineCore import QWebEngineUrlScheme scheme = QWebEngineUrlScheme(b"eric") scheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) scheme.setFlags(QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.ContentSecurityPolicyIgnored) QWebEngineUrlScheme.registerScheme(scheme) if "--qthelp" in sys.argv and qVersionTuple() >= (5, 12, 0): from PyQt5.QtWebEngineCore import QWebEngineUrlScheme scheme = QWebEngineUrlScheme(b"qthelp") scheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) scheme.setFlags(QWebEngineUrlScheme.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) app = E5Application(sys.argv) if "--private" not in sys.argv: client = WebBrowserSingleApplicationClient() res = client.connect() if res > 0: if len(sys.argv) > 1: client.processArgs(sys.argv[1:]) sys.exit(0) elif res < 0: print("eric6_browser: {0}".format(client.errstr())) # __IGNORE_WARNING_M801__ sys.exit(res) res = Startup.simpleAppStartup(sys.argv, appinfo, createMainWidget, installErrorHandler=True, app=app) sys.exit(res)
def init(self): """Initialize browser""" logger.debug("Initializing Browser Window") if web_greeter_config["config"]["greeter"]["debug_mode"]: os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = '12345' url_scheme = "web-greeter" self.url_scheme = QWebEngineUrlScheme(url_scheme.encode()) self.url_scheme.setDefaultPort(QWebEngineUrlScheme.PortUnspecified) self.url_scheme.setFlags(QWebEngineUrlScheme.SecureScheme or QWebEngineUrlScheme.LocalScheme or QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(self.url_scheme) self.profile = QWebEngineProfile.defaultProfile() self.interceptor = QtUrlRequestInterceptor(url_scheme) self.url_scheme_handler = QtUrlSchemeHandler() self.view = QWebEngineView(parent=self.window) self.page = WebPage() self.view.setPage(self.page) self.page.setObjectName("WebG Page") self.view.setObjectName("WebG View") self.channel = QWebChannel(self.page) self.bridge_initialized = False self.profile.installUrlSchemeHandler(url_scheme.encode(), self.url_scheme_handler) self._initialize_page() if web_greeter_config["config"]["greeter"]["debug_mode"]: self._initialize_devtools() else: self.view.setContextMenuPolicy(Qt.PreventContextMenu) self._init_actions() if web_greeter_config["app"]["frame"]: self._init_menu_bar() else: self.window.setWindowFlags(self.window.windowFlags() | Qt.FramelessWindowHint) if web_greeter_config["config"]["greeter"]["secure_mode"]: if hasattr(QWebEngineProfile, "setUrlRequestInterceptor"): self.profile.setUrlRequestInterceptor(self.interceptor) else: # Older Qt5 versions self.profile.setRequestInterceptor(self.interceptor) self.page.setBackgroundColor(QColor(0, 0, 0)) self.window.setStyleSheet("""QMainWindow, QWebEngineView { background: #000000; }""") self.window.setCentralWidget(self.view) logger.debug("Browser Window created")
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 EnvironmentError: 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('Not a valid --open-at value: {}'.format(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)
def init(): """Register the qute:// scheme. Note this needs to be called early, before constructing any QtWebEngine classes. """ if QWebEngineUrlScheme is not None: scheme = QWebEngineUrlScheme(b'qute') scheme.setFlags(QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(scheme)
def init(): """Register the qute:// scheme. Note this needs to be called early, before constructing any QtWebEngine classes. """ if QWebEngineUrlScheme is not None: scheme = QWebEngineUrlScheme(b'qute') scheme.setFlags(QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(scheme)
def registerUriScheme(cls, name: str, base_path: str): if not name in cls.schemes.keys(): cls.schemes[name] = base_path if not QWebEngineUrlScheme.schemeByName(name.encode()).name(): scheme = QWebEngineUrlScheme(name.encode()) scheme.setFlags( QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | QWebEngineUrlScheme.ContentSecurityPolicyIgnored | QWebEngineUrlScheme.SecureScheme ) QWebEngineUrlScheme.registerScheme(scheme)
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.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) override = 'calibre-ebook-viewer' if islinux else None 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)): raise SystemExit('Not a valid --open-at value: {}'.format(opts.open_at)) listener = None if get_session_pref('singleinstance', False): try: listener = ensure_single_instance(args, opts.open_at) except Exception as e: import traceback error_dialog(None, _('Failed to start viewer'), as_unicode(e), det_msg=traceback.format_exc(), show=True) raise SystemExit(1) 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) 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() main.msg_from_anotherinstance.connect(main.another_instance_wants_to_talk, type=Qt.QueuedConnection) if listener is not None: t = Thread(name='ConnListener', target=listen, args=(listener, main.msg_from_anotherinstance)) t.daemon = True t.start() QTimer.singleShot(0, acc.flush) if opts.raise_window: main.raise_() if opts.full_screen: main.set_full_screen(True) app.exec_() if listener is not None: listener.close()
def declareUrlScheme(name, flags=defaultSchemeFlags, syntax=QWebEngineUrlScheme.Syntax.Host, defaultPort=QWebEngineUrlScheme.PortUnspecified, schemeSection='core'): global urlSchemes scheme = QWebEngineUrlScheme(name.encode()) scheme.setFlags(flags) scheme.setSyntax(syntax) scheme.setDefaultPort(defaultPort) QWebEngineUrlScheme.registerScheme(scheme) urlSchemes.setdefault(schemeSection, {}) urlSchemes[schemeSection][name] = scheme return scheme
def registerSchemes(cls): if QWebEngineUrlScheme: appSchema = QWebEngineUrlScheme(b'app') appSchema.setFlags( QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.ContentSecurityPolicyIgnored) appSchema.setSyntax(QWebEngineUrlScheme.Syntax.Path) QWebEngineUrlScheme.registerScheme(appSchema) extensionScheme = QWebEngineUrlScheme(b'extension') extensionScheme.setFlags( QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.ContentSecurityPolicyIgnored) extensionScheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) QWebEngineUrlScheme.registerScheme(extensionScheme)
def _run(args, notify=None): # Ensure we 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.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) # The following two lines are needed to prevent circular imports causing # errors during initialization of plugins that use the polish container # infrastructure. importlib.import_module('calibre.customize.ui') from calibre.gui2.tweak_book import tprefs from calibre.gui2.tweak_book.ui import Main parser = option_parser() opts, args = parser.parse_args(args) decouple('edit-book-'), set_gui_prefs(tprefs) override = 'calibre-edit-book' if islinux else None app = Application(args, override_program_name=override, color_prefs=tprefs, windows_app_uid=EDITOR_APP_UID) app.file_event_hook = EventAccumulator() app.load_builtin_fonts() app.setWindowIcon(QIcon(I('tweak.png'))) main = Main(opts, notify=notify) main.set_exception_handler() main.show() app.shutdown_signal_received.connect(main.boss.quit) if len(args) > 1: main.boss.open_book(args[1], edit_file=args[2:], clear_notify_data=False) else: for path in reversed(app.file_event_hook.events): main.boss.open_book(path) break app.file_event_hook = main.boss.open_book app.exec_() # Ensure that the parse worker has quit so that temp files can be deleted # on windows st = time.time() from calibre.gui2.tweak_book.preview import parse_worker while parse_worker.is_alive() and time.time() - st < 120: time.sleep(0.1)
def specialize_options(self, log, opts, input_fmt): # Ensure Qt is setup to be used with WebEngine # specialize_options is called early enough in the pipeline # that hopefully no Qt application has been constructed as yet from PyQt5.QtWebEngineCore import QWebEngineUrlScheme from PyQt5.QtWebEngineWidgets import QWebEnginePage # noqa from ebook_converter.gui2 import must_use_qt from ebook_converter.constants_old import FAKE_PROTOCOL scheme = QWebEngineUrlScheme(FAKE_PROTOCOL.encode('ascii')) scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) scheme.setFlags(QWebEngineUrlScheme.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) must_use_qt() self.input_fmt = input_fmt if opts.pdf_use_document_margins: # Prevent the conversion pipeline from overwriting document margins opts.margin_left = opts.margin_right = opts.margin_top = opts.margin_bottom = -1
def add_provider(self, bundle_info, name, **kw): self.schemes.add(name) def is_true(value): return value and value.casefold() in ('true', '1', 'on') from PyQt5.QtWebEngineCore import QWebEngineUrlScheme scheme = QWebEngineUrlScheme(name.encode('utf-8')) port = kw.get('defaultPort', None) if port is not None: scheme.setDefaultPort(int(port)) syntax = kw.get('syntax', None) if syntax == "Path": scheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) elif syntax == "Host": scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) elif syntax == "HostAndPort": scheme.setSyntax(QWebEngineUrlScheme.Syntax.HostAndPort) elif syntax == "HostPortAndUserInformation": scheme.setSyntax( QWebEngineUrlScheme.Syntax.HostPortAndUserInformation) flags = 0 if is_true(kw.get("SecureScheme", None)): flags |= QWebEngineUrlScheme.SecureScheme if is_true(kw.get("LocalScheme", None)): flags |= QWebEngineUrlScheme.LocalScheme if is_true(kw.get("LocalAccessAllowed", None)): flags |= QWebEngineUrlScheme.LocalAccessAllowed if is_true(kw.get("NoAccessAllowed", None)): flags |= QWebEngineUrlScheme.NoAccessAllowed if is_true(kw.get("ServiceWorkersAllowed", None)): flags |= QWebEngineUrlScheme.ServiceWorkersAllowed if is_true(kw.get("ViewSourceAllowed", None)): flags |= QWebEngineUrlScheme.ViewSourceAllowed if is_true(kw.get("ContentSecurityPolicyIgnored", None)): flags |= QWebEngineUrlScheme.ContentSecurityPolicyIgnored if flags: scheme.setFlags(flags) QWebEngineUrlScheme.registerScheme(scheme)
def __init__(self): super(MainWindow, self).__init__() self._okToClose = False # systray = QSystemTrayIcon(self) # systray.setIcon(QIcon(":/icons/icon.png")) # systray.show() # def systray_activated(reason): # self.setVisible(self.isVisible() ^ True) # systray.activated.connect(systray_activated) # results self._incr_results = None self._fts_results = None self._found_items = None # status self._selection_pending = False self._loading_pending = False self._auto_fts_phrase = None # Lazy-loaded objects self._lazy = {} # Local URL scheme for name in _LOCAL_SCHEMES: scheme = QWebEngineUrlScheme(name.encode("ascii")) scheme.setFlags( QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | QWebEngineUrlScheme.CorsEnabled ) QWebEngineUrlScheme.registerScheme(scheme) self._scheme_handler = MyUrlSchemeHandler(self) profile = QWebEngineProfile.defaultProfile() for name in _LOCAL_SCHEMES: profile.installUrlSchemeHandler(name.encode("ascii"), self._scheme_handler) # Url request interceptor profile.setUrlRequestInterceptor(UrlRequestInterceptor(self)) # Setup self._setup_ui() self._restore_from_config() # Timers def _makeSingleShotTimer(slot): timer = QTimer(self) timer.setSingleShot(True) timer.timeout.connect(slot) return timer self._timerUpdateIndex = _makeSingleShotTimer(self._updateIndex) self._timerAutoFTS = _makeSingleShotTimer(self._onTimerAutoFullSearchTimeout) self._timerAutoPron = _makeSingleShotTimer(self._onTimerAutoPronTimeout) self._timerSpellCorrection = _makeSingleShotTimer(self._onTimerSpellCorrection) self._timerSearchingLabel = _makeSingleShotTimer(self._onTimerSearchingLabel) # Clipboard clipboard = QApplication.clipboard() clipboard.dataChanged.connect( partial(self._onClipboardChanged, mode=QClipboard.Clipboard) ) clipboard.selectionChanged.connect( partial(self._onClipboardChanged, mode=QClipboard.Selection) ) # Stylesheet for the item list pane try: self._ui.listWidgetIndex.setStyleSheet( _load_static_data("styles/list.css").decode("utf-8", "ignore") ) except EnvironmentError: pass # Check index QTimer.singleShot(0, self._check_index) # Show self.show() # Click the dock icon (macOS) if objc: def applicationShouldHandleReopen_hasVisibleWindows_(s, a, f): self.show() objc.classAddMethods( Cocoa.NSApplication.sharedApplication().delegate().class__(), [applicationShouldHandleReopen_hasVisibleWindows_], )
def registerVoceUrlScheme(cls): voceUrlScheme = QWebEngineUrlScheme(cls.schemeName) voceUrlScheme.setFlags(QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(voceUrlScheme)
def __init__(self, config=config(), **app_config): self.config = config for key, value in app_config.items(): config[key] = value QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) if config["debug"] or "--dev" in sys.argv: # Adding some command line arguments for testing purposes, # this MUST BE done before initializing QApplication sys.argv.append(f"--remote-debugging-port={config['debug_port']}") print("Debugging Mode On") if not config["debug"]: config["debug"] = True else: print("Production Mode On, use (--dev) for debugging") # Enable/Disable GPU acceleration if not config["disable_gpu"]: # Virtual machine detection using SystemD detect_virtual_machine = subprocess.Popen(["systemd-detect-virt"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # FIXME find a more reliable way of detecting NVIDIA cards detect_nvidia_pci = subprocess.Popen( "lspci | grep -i --color 'vga\|3d\|2d'", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) virtual = detect_virtual_machine.communicate() nvidia_pci = detect_nvidia_pci.communicate() nvidia_pci = nvidia_pci[0].decode("utf-8").lower() def disable_opengl(): # Disable GPU acceleration # https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/206307 QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL, True) if config["disable_gpu"]: disable_opengl() print("Disabling GPU, Software Rendering explicitly activated") else: if virtual[-1]: # Detect virtual machine print(f"Virtual machine detected:{virtual}") disable_opengl() elif nvidia_pci: # Detect NVIDIA cards if "nvidia" in nvidia_pci: print( "NVIDIA detected:Known bug - kernel rejected pushbuf") print("Falling back to Software Rendering") disable_opengl() else: print(f"Virtual Machine:{virtual[-1]}") super(JWebApp, self).__init__(sys.argv) # Desktop file must match application name in lowercase with dashes instead of white space. self.setDesktopFileName( f"{config['title'].lower().replace(' ', '-')}.desktop") self.setOrganizationDomain(config['web_contents']) self.setApplicationVersion(__version__) if not config['online']: if bindings() == "PyQt5": from PyQt5.QtWebEngineCore import QWebEngineUrlScheme else: from PySide2.QtWebEngineCore import QWebEngineUrlScheme QWebEngineUrlScheme.registerScheme( QWebEngineUrlScheme("ipc".encode()))
def __init__(self, config=Settings.config(), **app_config): super(JWebApp, self).__init__(sys.argv) self.config = config self.setAAttribute(Qt.AA_UseHighDpiPixmaps) self.setAAttribute(Qt.AA_EnableHighDpiScaling) self.applicationStateChanged.connect(self._applicationStateChanged_cb) for key, value in app_config.items(): if isinstance(value, dict): for subkey, subvalue in app_config[key].items(): config[key][subkey] = subvalue else: config[key] = value for attr in config["setAAttribute"]: self.setAAttribute(attr) if config["remote-debug"] or "--remote-debug" in sys.argv: sys.argv.append("--remote-debugging-port=9000") if config["debug"] or "--dev" in sys.argv: print("Debugging On") if not config["debug"]: config["debug"] = True else: print("Production Mode On, use (--dev) for debugging") # Enable/Disable GPU acceleration if not config["disableGPU"]: # Virtual machine detection using SystemD detect_virtual_machine = subprocess.Popen(["systemd-detect-virt"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # FIXME find a more reliable way of detecting NVIDIA cards detect_nvidia_pci = subprocess.Popen( "lspci | grep -i --color 'vga\|3d\|2d'", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) virtual = detect_virtual_machine.communicate() nvidia_pci = detect_nvidia_pci.communicate() nvidia_pci = nvidia_pci[0].decode("utf-8").lower() if config["disableGPU"]: self.disable_opengl() print("Disabling GPU, Software Rendering explicitly activated") else: if virtual[-1]: # Detect virtual machine print(f"Virtual machine detected:{virtual}") self.disable_opengl() elif nvidia_pci: # Detect NVIDIA cards if "nvidia" in nvidia_pci: print( "NVIDIA detected:Known bug - kernel rejected pushbuf") print("Falling back to Software Rendering") self.disable_opengl() else: print(f"Virtual Machine:{virtual[-1]}") # Desktop file must match application name in lowercase with dashes instead of white space. self.setDesktopFileName( f"{self.config['window']['title'].lower().replace(' ', '-')}.desktop" ) self.setOrganizationDomain(self.config['webview']['webContents']) self.setApplicationVersion(__version__) if not self.config['webview']['online'] and self.config['webview'][ 'IPC']: if bindings() == "PyQt5": from PyQt5.QtWebEngineCore import QWebEngineUrlScheme else: from PySide2.QtWebEngineCore import QWebEngineUrlScheme QWebEngineUrlScheme.registerScheme( QWebEngineUrlScheme("ipc".encode()))
def __init__(self, qthelp_file, parent = None): """ Constructor of HelpDialog :param qthelp_file: full path to qthelp helpfile """ super(HelpDialog,self).__init__(parent) # instantiate help engine helpEngine = QHelpEngine(qthelp_file) helpEngine.setupData() self._helpEngine = helpEngine # base dialog widget self.ui = QDialog(None, QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowMinMaxButtonsHint | QtCore.Qt.WindowCloseButtonHint ) self.ui.setWindowTitle("HelpViewer") self.ui.setWindowIcon(QIcon(":/images/prog_icons/help/help.ico")) # Create webview for help information # and assign a custom URL scheme handler for scheme "qthelp) self._wv = QWebEngineView(self.ui) if QWebEngineUrlScheme is not None: scheme = QWebEngineUrlScheme(b'qthelp') scheme.setFlags(QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(scheme) self._urlschemehandler = HelpSchemeHandler(self._helpEngine, self._wv.page().profile()) self._wv.page().profile().installUrlSchemeHandler(b'qthelp', self._urlschemehandler) # get help content overview widget self._helpContent = self._helpEngine.contentWidget() self._helpIndex = self._helpEngine.indexWidget() self._helpSearchQuery = self._helpEngine.searchEngine().queryWidget() self._helpSearchResult = self._helpEngine.searchEngine().resultWidget() self._se = self._helpEngine.searchEngine() self._se.reindexDocumentation() self._helpSearchQuery.search.connect(self.search) # create QSplitter self._splitterMain = QSplitter(QtCore.Qt.Vertical) self._splitterMain.setOpaqueResize(False) self._splitterSearch = QSplitter(QtCore.Qt.Horizontal) self._splitterSearch.setOpaqueResize(False) self._splitterUpper = QSplitter(QtCore.Qt.Horizontal) self._splitterUpper.setOpaqueResize(False) self._splitterLower = QSplitter(QtCore.Qt.Horizontal) self._splitterLower.setOpaqueResize(False) # create horzLayout self._horzLayoutSearch = QHBoxLayout() self._horzLayoutUpper = QHBoxLayout() self._horzLayoutLower = QHBoxLayout() # create vertLayout self._vertLayout = QVBoxLayout() # main widgets self._upperWidget = QWidget() self._lowerWidget = QWidget() self._btnReset = QPushButton() self._btnReset.setMaximumHeight(23) self._btnReset.setMaximumWidth(100) # build search structure self._splitterSearch.insertWidget(0, self._helpSearchQuery) self._splitterSearch.insertWidget(1, self._btnReset) # build upper inner structure self._splitterUpper.insertWidget(0, self._helpContent) self._splitterUpper.insertWidget(1, self._wv) self._horzLayoutUpper.addWidget(self._splitterUpper) self._upperWidget.setLayout(self._horzLayoutUpper) # build lower inner structure self._splitterLower.insertWidget(0, self._helpIndex) self._splitterLower.insertWidget(1, self._helpSearchResult) self._horzLayoutLower.addWidget(self._splitterLower) self._lowerWidget.setLayout(self._horzLayoutLower) # build outer structure self._splitterMain.insertWidget(0, self._splitterSearch) self._splitterMain.insertWidget(1, self._upperWidget) self._splitterMain.insertWidget(2, self._lowerWidget) self._helpSearchResult.hide() self._btnReset.hide() self._vertLayout.addWidget(self._splitterMain) self.ui.setLayout(self._vertLayout) # set splitter width w = self._splitterUpper.geometry().width() self._splitterUpper.setSizes([w*(1/4), w*(3/4)]) w = self._splitterLower.geometry().width() self._splitterLower.setSizes([w*(1/5), w*(4/5)]) h = self._splitterMain.geometry().height() self._splitterMain.setSizes([h*(1/9), h*(7/9), h*(1/9)]) self._helpContent.linkActivated.connect(self._wv.setUrl) self._helpIndex.linkActivated.connect(self._wv.setUrl) self._helpSearchResult.requestShowLink.connect(self._wv.setUrl) self._se.searchingFinished.connect(self.showResults) self._btnReset.clicked.connect(self.resetResult) self.retranslateMsg()