Esempio n. 1
0
class WebEngineView(QWebEngineView):
    def __init__(self, *args, **kwargs):
        super(WebEngineView, self).__init__(*args, **kwargs)

        self.interceptor = Interceptor(self)
        self.cid_handler = CidSchemeHandler(self)

        self.profile = QWebEngineProfile(self)
        self.profile.setRequestInterceptor(self.interceptor)
        self.profile.installUrlSchemeHandler(b'cid', self.cid_handler)

        self.setPage(WebEnginePage(self.profile, self))
        self.page().contentsSizeChanged.connect(self._pageSizeChanged)

        self._restrict()

        # warning: the signal is emitted with an empty string if the link isn't hovered anymore
        self.page().linkHovered.connect(self.window().statusBar().showMessage)

    def _restrict(self):
        self.settings().setAttribute(QWebEngineSettings.JavascriptEnabled,
                                     False)

    @Slot(QSizeF)
    def _pageSizeChanged(self, size):
        self.updateGeometry()

    def minimumSizeHint(self):
        return self.page().contentsSize().toSize()

    def setMessage(self, pymessage):
        self.cid_handler.setMessage(pymessage)
Esempio n. 2
0
        def __init__(self, parent=None):
            super().__init__(parent=parent)

            # Configure the intercepter for adding headers
            interceptor = TyphosWebRequestInterceptor(self)
            profile = QWebEngineProfile(self)
            profile.setRequestInterceptor(interceptor)

            # Use our custom page that will allow us to filter out javascript
            # log messages
            page = TyphosWebEnginePage(profile, self)
            self.setPage(page)
Esempio n. 3
0
class MainWindow(QMainWindow):
    #urlsingal = pyqtSignal(str)
    #start=False
    # noinspection PyUnresolvedReferences
    def __init__(self,url,*args, **kwargs):
        super().__init__(*args, **kwargs)
        # 设置窗口标题
        self.setui(url)
        #self.urlsingal.connect()
#        self.browser.page().profile().downloadRequested.connect(self._downloadRequested)

    def setui(self,url):
        os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = "9000"#127.0.0.1:9000调试
        self.setWindowTitle('游戏')

        self.resize(1000, 600)
        #self.setWindowFlags()
        #self.setWindowFlags(Qt.WindowStaysOnTopHint)
        self.setWindowFlags(Qt.WindowCloseButtonHint)
        # 设置窗口图标
        cur_path = os.path.dirname(os.path.realpath(__file__))
        config_path = os.path.join(cur_path, '')
        self.setWindowIcon(QIcon(config_path))
        # 设置窗口大小900*600

        self.show()
        self.browser = QWebEngineView()
        self.interceptor = WebEngineUrlRequestInterceptor()
        self.profile = QWebEngineProfile()
        self.profile.setRequestInterceptor(self.interceptor)
        self.page = MyWebEnginePage(self.profile, self.browser)
        self.page.setUrl(QUrl(url))
        self.browser.setPage(self.page)
        self.browser.show()
        self.setCentralWidget(self.browser)
        #self.browser.page().runJavaScript()

        #os.environ
        # 设置浏览器
        # self.browser = QWebEngineView()
        # # 指定打开界面的 URL
        # self.browser.setUrl(QUrl(url))
        # # 添加浏览器到窗口中
        # self.setCentralWidget(self.browser)
    def goto(self,url):
        self.browser.setUrl(QUrl(url))

    def _downloadRequested(item):  # QWebEngineDownloadItem
        print('downloading to', item.path())
        item.accept()
Esempio n. 4
0
    def _provider_browser(self, window):
        from PyQt5.QtWebEngineWidgets import QWebEngineProfile

        from .gui.browser.webview import WebEngineUrlRequestInterceptor
        from .gui.browser.webview import MyWebEnginePage
        from .gui.browser.webview import MyWebEngineView

        browser = MyWebEngineView()
        profile = QWebEngineProfile(window)
        interceptor = WebEngineUrlRequestInterceptor(window)
        profile.setRequestInterceptor(interceptor)
        page = MyWebEnginePage(profile, window)
        browser.setPage(page)

        return browser
Esempio n. 5
0
class InSilicoDBDialog(InSilicoDBDialogDialogBase, InSilicoDBDialogUI):
    url = None
    title = None
    icon = None

    def __init__(self, parent, mz, spectrum):
        super().__init__(parent)

        self.setupUi(self)
        self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint)
        if self.title is not None:
            self.setWindowTitle(self.title)
        if self.icon is not None:
            self.setWindowIcon(self.icon)

        self.mz = mz
        self.spectrum = '\\n'.join(" ".join(f'{x:.4f}' for x in peak)
                                   for peak in spectrum)

        self.interceptor = WebEngineUrlRequestInterceptor(self.url)
        self.profile = QWebEngineProfile()
        self.profile.setRequestInterceptor(self.interceptor)
        self.browser.setPage(WebEnginePage(self.profile, self.browser))
        if self.url is not None:
            self.browser.load(self.url)
        self.browser.loadFinished.connect(self.on_load_finished)

    def page(self):
        return self.browser.page()

    def on_load_finished(self, ok):
        raise NotImplementedError

    def ready(self, returnValue):
        print(returnValue)

    def closeEvent(self, event: QCloseEvent) -> None:
        super().closeEvent(event)

        # QWebEnginePage should be deleted before QWebEngineProfile
        # or 'Release of profile requested but WebEnginePage still not deleted. Expect troubles !' error occurs
        self.browser.page().deleteLater()
Esempio n. 6
0
ip = res.text.split(":")
port = ip[1]
ip = ip[0]

proxy = QtNetwork.QNetworkProxy()
# Http访问代理
proxy.setType(QtNetwork.QNetworkProxy.HttpProxy)
# 代理ip地址HttpProxy
proxy.setHostName(ip)
# 端口号
proxy.setPort(int(port))
QtNetwork.QNetworkProxy.setApplicationProxy(proxy)

interceptor = TwitchInterceptor()
profile = QWebEngineProfile()
profile.clearHttpCache()
profile.clearAllVisitedLinks()
pCookie = profile.cookieStore()
pCookie.deleteAllCookies()
pCookie.deleteSessionCookies()
profile.setRequestInterceptor(interceptor)

profile.setPersistentCookiesPolicy(QWebEngineProfile.ForcePersistentCookies)

page = QWebEnginePage(profile, view)
page.loadFinished.connect(on_done)
view.setPage(page)
page.setUrl(QUrl(twitch_url))
view.show()
sys.exit(app.exec_())
Esempio n. 7
0
class Hrobot(QObject):

    asyncFinished = pyqtSignal()

    def __init__(self,
                 base_url=None,
                 private=True,
                 profile_name=None,
                 gui=False):
        super().__init__()
        self.base_url = QUrl(base_url)
        self.__interceptor = Interceptor(self)
        if private:
            self.__profile = QWebEngineProfile()
        elif profile_name:
            self.__profile = QWebEngineProfile(profile_name)
        else:
            raise Exception(
                'please pass `profile_name` in case of `private` flag set to False'
            )
        self.__profile.setRequestInterceptor(self.__interceptor)
        self.__page = Page(self.__profile, None)
        self.__cookie_store = self.__profile.cookieStore()
        self.__cookie_store.cookieAdded.connect(self.__on_cookie_added)
        self.__cookies = []
        self.__async_result = None
        self.__loading = False

        self.__view = QWebEngineView()

        self.__page.setView(self.__view)
        self._qt_invocation = QtInvocation(self.__page)
        self.__channel = QWebChannel(self)
        self.__channel.registerObject("QtInvocation", self._qt_invocation)
        self.__page.setWebChannel(self.__channel)

        self.__page.loadStarted.connect(self.__load_started)
        self.__page.loadFinished.connect(self.__load_finished)
        self.__view.loadProgress.connect(self.__prg)
        self.__page.navigationRequested.connect(self.__navigation_requested)
        # self._qt_invocation.js_navigation_requested.connect(self.__page._js_gap_eventloop)
        self.__page.settings().setAttribute(
            self.__page.settings().LocalContentCanAccessRemoteUrls, True)
        self.__page.setUrl(QUrl('about:blank'))

        self.__view.setWindowState(Qt.WindowMaximized)
        if gui:
            self.__view.show()

    def __prg(self, p):
        print('progress: ', p)

    def __load_started(self):
        print('load started')

    def __load_finished(self, ok):
        print('load finished', ok)

    def __node(self, node_id):
        return Node(self, self.__page, node_id)

    def __navigation_requested(self):
        print('navvvvvvvvvvvvv', self.__loading)
        if not self.__loading:
            self.__loading = True
            print('navigation event loop started')
            loop = QEventLoop()
            self.__page.loadFinished.connect(loop.quit)
            loop.exec()
            print('navigation event loop ended')
            loop_js = QEventLoop()
            self._qt_invocation.js_ready.connect(loop_js.quit)
            self.__register_js()
            loop_js.exec()
            self.__loading = False
            print('js register event loop ended')

    def __register_js(self):
        channel_file = QFile(":/qtwebchannel/qwebchannel.js")
        if channel_file.open(QIODevice.ReadOnly):
            content = channel_file.readAll()
            channel_file.close()
            print('runjssssssssssssssssssssssssssssssssssssssss 1')
            self.__run_js(content.data().decode())
            print('runjssssssssssssssssssssssssssssssssssssssss 2',
                  BASE_APP_PATH)
        qt_file = QFile(
            '{0}/extensions/hrobot/v_2_0/qt.js'.format(BASE_APP_PATH))
        if qt_file.open(QIODevice.ReadOnly):
            content = qt_file.readAll()
            qt_file.close()
            print('runjssssssssssssssssssssssssssssssssssssssss 3')
            self.__run_js(content.data().decode())
            print('runjssssssssssssssssssssssssssssssssssssssss 4')

    def __async_callback(self, result):
        self.__async_result = result
        self.asyncFinished.emit()
        print('async js emit')

    def __run_js(self, script):
        loop = QEventLoop()
        self.asyncFinished.connect(loop.quit)
        self.__page.runJavaScript(script, self.__async_callback)
        loop.exec()
        print('run js finished')
        return self.__async_result

    def __on_cookie_added(self, cookie):
        print('on add cookie', cookie.toRawForm(1))
        for c in self.__cookies:
            if c.hasSameIdentifier(cookie):
                return
        print('coocke', cookie)
        print('net cookie', QNetworkCookie(cookie))
        self.__cookies.append(QNetworkCookie(cookie))

    def set_cookie(self, cookie):
        self.__cookie_store.setCookie(cookie)

    def __set_browser_attribute(self, attr, value):
        self.__page.settings().setAttribute(attr, value)

    def go_to(self, url: Union[QUrl, str]) -> bool:
        """ Goes to a given URL. """
        url = QUrl(url)
        if self.base_url:
            url = self.base_url.resolved(url)
        loop = QEventLoop()
        self.__page.loadFinished.connect(loop.exit)
        self.__page.load(url)
        return True if loop.exec() else False

    def go_back(self):
        self.__view.back()

    def get_body(self):
        """ Return the current DOM as HTML. """
        loop = QEventLoop()
        self.asyncFinished.connect(loop.quit)
        self.__page.toHtml(self.__async_callback)
        loop.exec()
        return self.__async_result

    def get_cookies(self, as_json=False):
        if as_json:
            return self.__cookie_to_json()
        return self.__cookies

    def __cookie_to_json(self):
        cookies_list_info = []
        for c in self.__cookies:
            c = QNetworkCookie(c)
            data = {
                "name": bytearray(c.name()).decode(),
                "domain": c.domain(),
                "value": bytearray(c.value()).decode(),
                "path": c.path(),
                "expirationDate": c.expirationDate().toString(Qt.ISODate),
                "secure": c.isSecure(),
                "httponly": c.isHttpOnly()
            }
            cookies_list_info.append(data)
        return cookies_list_info

    def json_to_cookie(self, json_cookie_list):
        cookies_list_info = []
        for json_cookie in json_cookie_list:
            c = QNetworkCookie()
            print(json_cookie, '** json_cookie')
            for k, v in json_cookie.items():
                if k == 'path':
                    c.setPath(v)
                elif k == 'domain':
                    c.setPath(v)
                elif k == 'expirationDate':
                    print(v, type(v))
                    qdate = QDateTime(2019, 12, 20, 11, 59, 59)
                    print(qdate)
                    c.setExpirationDate(qdate)
                elif k == 'httponly':
                    c.setHttpOnly(v)
                elif k == 'secure':
                    c.setSecure(v)
                elif k == 'value':
                    c.setValue(v.encode())
                elif k == 'name':
                    c.setName(v.encode())
            print('c', c.expirationDate())
            cookies_list_info.append(c)
        return cookies_list_info

    def eval_script(self, script):
        """ Evaluates a piece of Javascript in the context of the current page and returns its value. """
        return self.__run_js(script)

    def exec_script(self, script):
        """ Executes a piece of Javascript in the context of the current page. """
        self.__run_js(script)

    def block_url(self, url):
        raise NotImplementedError

    def allow_url(self, url):
        raise NotImplementedError

    def get_url(self):
        """ Returns the current location. """
        return self.__page.url()

    def reload(self):
        self.go_to(self.current_url())

    def is_private(self):
        return self.__page.profile().isOffTheRecord()

    def set_skip_image_loading(self, value):
        """ Specifies whether images are automatically loaded in web pages. This is disabled by default."""
        # self.browser.set_attribute('auto_load_images', value)
        self.__set_browser_attribute(self.__page.settings().AutoLoadImages,
                                     not value)

    def save_as_pdf(self, name):
        loop = QEventLoop()
        self.__page.pdfPrintingFinished.connect(loop.quit)
        self.__page.printToPdf(name)
        loop.exec()

    def scroll_to_end(self, lazy_load=True):
        loop = QEventLoop()
        self._qt_invocation.async_js_finished.connect(loop.quit)
        self.__run_js(
            'Qt.scrollToEnd({0})'.format('true' if lazy_load else 'false'))
        loop.exec()

    def find_by_css(self, selector):
        """ Return the first node matching the given CSSv3 expression or None. """
        nodes = self.find_all_by_css(selector)
        return None if not nodes else nodes[0]

    def find_by_xpath(self, xpath):
        """ Return the first node matching the given XPath 2.0 expression or None. """
        nodes = self.find_all_by_xpath(xpath)
        return None if not nodes else nodes[0]

    def find_all_by_css(self, selector):
        """ Return all nodes matching the given CSSv3 expression. """
        try:
            return [
                self.__node(node_id) for node_id in self.__run_js(
                    Utils.qt_js_prepare('Qt.findCss("{0}")'.format(
                        Utils.normalize_quotes(selector)))).split(",")
                if node_id
            ]
        except AttributeError:
            return None

    def find_all_by_xpath(self, xpath):
        """ Return all nodes matching the given XPath 2.0 expression. """
        try:
            return [
                self.__node(node_id) for node_id in self.__run_js(
                    Utils.qt_js_prepare('Qt.findXpath("{0}")'.format(
                        Utils.normalize_quotes(xpath)))).split(",") if node_id
            ]
        except AttributeError:
            return None

    def wait_until_css(self, selector, timeout=30):
        node = self.find_by_css(selector)
        elapsed = 0
        while not node:
            if elapsed > timeout:
                return None
            Utils.wait(1000)
            elapsed += 1
            node = self.find_by_css(selector)
        return node

    def wait_until_xpath(self, xpath, timeout=30):
        node = self.find_by_xpath(xpath)
        elapsed = 0
        while not node:
            if elapsed > timeout:
                return None
            Utils.wait(1000)
            elapsed += 1
            node = self.find_by_xpath(xpath)
        return node

    def find_by_following_sibling(self, tag, sibling):
        """ Return first sibling node after the current node """
        return self.find_by_xpath("//%s/following-sibling::%s" %
                                  (tag, sibling))

    def find_all_by_following_sibling(self, tag, sibling):
        """ Return all sibling nodes after the current node """
        return self.find_all_by_xpath("//%s/following-sibling::%s" %
                                      (tag, sibling))

    def find_by_preceding_sibling(self, tag, sibling):
        """ Return first sibling node before the current node """
        return self.find_by_xpath("//%s/preceding-sibling::%s" %
                                  (tag, sibling))

    def find_all_by_preceding_sibling(self, tag, sibling):
        """ Return all sibling nodes before the current node """
        return self.find_all_by_xpath("//%s/preceding-sibling::%s" %
                                      (tag, sibling))

    def find_element_has_attribute(self, tag, attr):
        """ Return the first node has attr in its attribute or none """
        return self.find_by_xpath("//%s[@%s]" % (tag, attr))

    def find_elements_has_attribute(self, tag, attr):
        """ Return all nodes has attr in their attribute or none """
        return self.find_all_by_xpath("//%s[@%s]" % (tag, attr))

    def find_elements_has_any_attribute(self, tag):
        """ Return all nodes that has any attribute or none"""
        return self.find_by_xpath("//%s[@*]" % tag)

    def find_elements_has_not_attribute(self, tag):
        """ Return all nodes that has not any attribute or none"""
        return self.find_by_xpath("//%s[not(@*)]" % tag)

    def find_by_attribute_value(self, tag, attr, value, normalize_space=True):
        """ Return first node has attr in its attribute and the value of attr is equal to value."""
        if normalize_space:
            return self.find_by_xpath("//%s[normalize-space(@%s = %s)]" %
                                      (tag, attr, value))
        else:
            return self.find_by_xpath("//%s[@%s = %s]" % (tag, attr, value))

    def find_all_by_attribute_value(self,
                                    tag,
                                    attr,
                                    value,
                                    normalize_space=True):
        """ Return all nodes has attr in their attribute and the value of attr is equal to value."""
        if normalize_space:
            return self.find_all_by_xpath("//%s[normalize-space(@%s = %s)]" %
                                          (tag, attr, value))
        else:
            return self.find_all_by_xpath("//%s[@%s = %s]" %
                                          (tag, attr, value))

    def find_by_children_number(self, tag, children_number):
        """ Return first node that number of its children is equal to children_number  """
        return self.find_all_by_xpath("//*[count(%s)= %s]" %
                                      (tag, children_number))

    def find_all_by_children_number(self, children_number):
        """ Return all nodes that number of their children is equal to children_number  """
        return self.find_all_by_xpath("//*[count(*)= %s]" % children_number)

    def find_by_name(self, tag_name):
        """ Return node that name of it is equal to tag_name """
        return self.find_all_by_xpath("//*[name()=%s]" % tag_name)

    def find_by_name_starts_with(self, letter):
        """ Return node that name of it starts with to letter """
        return self.find_all_by_xpath("//*[starts-with(name(), %s)]" % letter)

    def find_by_name_contains(self, letter):
        """ Return node that name of it contains letter """
        return self.find_all_by_xpath("//*[contains(name(),%s)]" % letter)

    # this finds excludes any descendants and  attribute nodes and namespace nodes.
    def find_by_following(self, node):
        """ Return nodes that exist in following of node """
        return self.find_all_by_xpath("//%s/following::*" % node)

    # this finds excludes any descendants and  attribute nodes and namespace nodes.
    def find_by_preceding(self, node):
        """ Return nodes that exist in preceding of node """
        return self.find_all_by_xpath("//%s/preceding::*" % node)

    def find_element_descendant(self, tag, child_tag='*'):
        return self.find_by_xpath("%s/descendant::%s" % (tag, child_tag))

    def find_elements_descendant(self, tag, child_tag='*'):
        return self.find_all_by_xpath("%s/descendant::%s" % (tag, child_tag))

    def find_all_elements_descendant(self, tag):
        return self.find_all_by_xpath("//%s/descendant::*" % tag)

    def find_by_contain_text(self, tag, text):
        """ Return node that contains text in their text value"""
        return self.find_by_xpath("//%s[contains(text(), '%s')]" % (tag, text))

    def find_all_by_contain_text(self, tag, text):
        """ Return all nodes that contains text in their text value"""
        return self.find_all_by_xpath("//%s[contains(text(), '%s')]" %
                                      (tag, text))
Esempio n. 8
0
class ViewQt5WebEngine(View, QObject):
    _emit_js_signal = pyqtSignal(str, QVariant);

    def __init__(self, name="MyLensApp", width=640, height=480, inspector=False, start_maximized=False, *args, **kwargs):
        View.__init__(self, name=name, width=width,height=height, *args, **kwargs)
        QObject.__init__(self)

        self._app = QApplication([])

        # prepare Qt DBus mainloop
        try:
            DBusQtMainLoop(set_as_default=True)

        except NameError:
            # TODO: validate DBus failed to import (windows)
            pass

        self._app_loaded = False

        self._manager = ThreadManagerQt5(app=self._app)

        self._inspector = inspector
        self._start_maximized = start_maximized
        self._build_app()


    def _build_app(self):
        if self._inspector:
            os.environ.setdefault('QTWEBENGINE_REMOTE_DEBUGGING', '8001')

        # build webengine container
        self._lensview = lv = _QWebView(inspector=self._inspector)
        self._page = p = _QWebPage()
        lv.setPage(self._page)

        # connect to Qt signals
        lv.loadFinished.connect(self._loaded_cb)
        self._app.lastWindowClosed.connect(self._last_window_closed_cb)

        # build webchannel script and inject
        qwebchannel_js = QFile(':/qtwebchannel/qwebchannel.js')

        if not qwebchannel_js.open(QIODevice.ReadOnly):
            raise SystemExit('Failed to load qwebchannel.js with error: %s' % qwebchannel_js.errorString())

        qwebchannel_js = bytes(qwebchannel_js.readAll()).decode('utf-8')

        script = QWebEngineScript()
        script.setSourceCode(qwebchannel_js + '''
                window.lens = window.lens || {};
                window.lens._channel = new QWebChannel(qt.webChannelTransport, function(channel) {
                    window.lens.emit = function() {
                        var args = Array.prototype.slice.call(arguments);
                        if (args.length > 0) {
                            channel.objects.bridge._from_bridge(args);
                        }
                    };

                    channel.objects.bridge._emit_js_signal.connect(function(name, args) {
                        window.lens.__broadcast(name, args);
                    });
                });
            ''')
        script.setName('lens-bridge')
        script.setWorldId(QWebEngineScript.MainWorld)
        script.setInjectionPoint(QWebEngineScript.DocumentCreation)
        script.setRunsOnSubFrames(True)

        p.profile().scripts().insert(script)

        self._channel = QWebChannel(p)
        p.setWebChannel(self._channel)
        self._channel.registerObject('bridge', self)

        # set up scheme handlers for app:// and lens://
        self._app_scheme_handler = AppSchemeHandler()
        self._lens_scheme_handler = LensSchemeHandler()

        self._interceptor = RequestInterceptor()

        self._profile = QWebEngineProfile().defaultProfile()
        self._profile.installUrlSchemeHandler('app'.encode(), self._app_scheme_handler)
        self._profile.installUrlSchemeHandler('lens'.encode(), self._lens_scheme_handler)

        self._profile.setRequestInterceptor(self._interceptor)

        # connect to Lens signals
        self.on('__close_app', self._close_cb)

        # center on screen
        _frame_geometry = lv.frameGeometry()
        _active_screen = self._app.desktop().screenNumber(self._app.desktop().cursor().pos())
        _center = self._app.desktop().screenGeometry(_active_screen).center()
        _frame_geometry.moveCenter(_center)
        lv.move(_frame_geometry.topLeft())

        self.set_title(self._app_name)
        self.set_size(self._app_width, self._app_height)

    def _close_cb(self):
        self.emit('app.close')
        self._app.exit()

    @pyqtSlot(QVariant)
    def _from_bridge(self, name_args):
        # emit our python/js bridge signal
        self.emit(name_args[0], *name_args[1:])

    def _last_window_closed_cb(self, *args):
        self.emit('__close_app', *args)

    def _loaded_cb(self, success):
        # show window once some page has loaded
        self._lensview.show()
        if self._start_maximized:
            self.toggle_window_maximize()

        if not self._app_loaded:
            self._app_loaded = True
            self.emit('app.loaded')

    def _run(self):
        signal.signal(signal.SIGINT, signal.SIG_DFL)
        self._app.exec_()

    def emit_js(self, name, *args):
        self._emit_js_signal.emit(name, list(args))

    def load_string(self, data):
        index_uri = pathlib.Path(self._app_scheme_handler._uri_app_base).as_uri()
        self._lensview.setHtml(data, QUrl(index_uri))

    def load_uri(self, uri):
        uri_base = os.path.dirname(uri) + '/'
        self.set_uri_app_base(uri_base)
        path = uri_base + 'app.html'

        stream = QFile(path)
        if stream.open(QFile.ReadOnly):
            data = str(stream.readAll(), 'utf-8')
            index_uri = pathlib.Path(uri_base).as_uri() + os.sep
            logger.debug('Using {0} as index URI'.format(index_uri))
            self._lensview.setHtml(data, QUrl(index_uri))

    def set_inspector(self, state):
        self._lensview.set_inspector(state)

    def set_size(self, width, height):
        logger.debug('Setting app size: {0}x{1}'.format(width, height))
        self._lensview.setMinimumSize(width, height)
        self._lensview.resize(width, height)

    def set_title(self, title):
        self._lensview.setWindowTitle(QString(title))

    def set_uri_app_base(self, uri):
        self._app_scheme_handler._uri_app_base = pathlib.Path(uri).as_uri() + "/"

    def set_uri_lens_base(self, uri):
        self._lens_scheme_handler._uri_lens_base = pathlib.Path(uri).as_uri() + "/"

    def timer(self, interval, callback, once=False):
        q = QTimer(parent=self._lensview)

        q.timeout.connect(callback)
        q.start(interval)

        return q.timerId

    def toggle_window_maximize(self):
        if self._lensview.windowState() & Qt.WindowMaximized:
            self._lensview.setWindowState(self._lensview.windowState() ^ Qt.WindowMaximized)
            self.emit_js('window-unmaximized')
        else:
            self._lensview.setWindowState(self._lensview.windowState() | Qt.WindowMaximized)
            self.emit_js('window-maximized')

    def toggle_window_fullscreen(self):
        if self._lensview.windowState() & Qt.WindowFullScreen:
            self._lensview.setWindowState(self._lensview.windowState() ^ Qt.WindowFullScreen)
            self.emit_js('window-unfullscreen')
        else:
            self._lensview.setWindowState(self._lensview.windowState() | Qt.WindowFullScreen)
            self.emit_js('window-fullscreen')