Exemple #1
0
    def __guessUrlFromPath(self, path):
        """
        Private method to guess an URL given a path string.
        
        @param path path string to guess an URL for (string)
        @return guessed URL (QUrl)
        """
        manager = self.__mainWindow.openSearchManager()
        path = Utilities.fromNativeSeparators(path)
        url = manager.convertKeywordSearchToUrl(path)
        if url.isValid():
            return url

        try:
            url = QUrl.fromUserInput(path)
        except AttributeError:
            url = QUrl(path)

        if url.scheme() == "about" and \
           url.path() == "home":
            url = QUrl("eric:home")

        if url.scheme() in ["s", "search"]:
            url = manager.currentEngine().searchUrl(url.path().strip())

        if url.scheme() != "" and \
           (url.host() != "" or url.path() != ""):
            return url

        urlString = Preferences.getHelp("DefaultScheme") + path.strip()
        url = QUrl.fromEncoded(urlString.encode("utf-8"), QUrl.TolerantMode)

        return url
Exemple #2
0
def same_domain(url1: QUrl, url2: QUrl) -> bool:
    """Check if url1 and url2 belong to the same website.

    This will use a "public suffix list" to determine what a "top level domain"
    is. All further domains are ignored.

    For example example.com and www.example.com are considered the same. but
    example.co.uk and test.co.uk are not.

    If the URL's schemes or ports are different, they are always treated as not equal.

    Return:
        True if the domains are the same, False otherwise.
    """
    ensure_valid(url1)
    ensure_valid(url2)

    if url1.scheme() != url2.scheme():
        return False
    if url1.port() != url2.port():
        return False

    suffix1 = url1.topLevelDomain()
    suffix2 = url2.topLevelDomain()
    if not suffix1:
        return url1.host() == url2.host()

    if suffix1 != suffix2:
        return False

    domain1 = url1.host()[:-len(suffix1)].split('.')[-1]
    domain2 = url2.host()[:-len(suffix2)].split('.')[-1]
    return domain1 == domain2
Exemple #3
0
 def __guessUrlFromPath(self, path):
     """
     Private method to guess an URL given a path string.
     
     @param path path string to guess an URL for (string)
     @return guessed URL (QUrl)
     """
     manager = self.__mainWindow.openSearchManager()
     path = Utilities.fromNativeSeparators(path)
     url = manager.convertKeywordSearchToUrl(path)
     if url.isValid():
         return url
     
     try:
         url = QUrl.fromUserInput(path)
     except AttributeError:
         url = QUrl(path)
     
     if url.scheme() == "about" and \
        url.path() == "home":
         url = QUrl("eric:home")
     
     if url.scheme() in ["s", "search"]:
         url = manager.currentEngine().searchUrl(url.path().strip())
     
     if url.scheme() != "" and \
        (url.host() != "" or url.path() != ""):
         return url
     
     urlString = Preferences.getHelp("DefaultScheme") + path.strip()
     url = QUrl.fromEncoded(urlString.encode("utf-8"), QUrl.TolerantMode)
     
     return url
Exemple #4
0
 def acceptNavigationRequest(self, url: QUrl,
                             _type: QWebEnginePage.NavigationType,
                             isMainFrame: bool) -> bool:
     if url.scheme() == "qrc":
         return True
     QDesktopServices.openUrl(url)
     return False
Exemple #5
0
    def _parse_notify_args(self, appname, replaces_id, icon, title, body, actions,
                           hints, timeout) -> NotificationProperties:
        """Parse a Notify dbus reply.

        Checks all constant values and returns a NotificationProperties object for
        values being checked inside test cases.
        """
        assert appname == "qutebrowser"
        assert icon == ''  # using icon data
        assert actions == ['default', 'Activate']
        assert timeout == -1

        assert hints.keys() == {
            "x-qutebrowser-origin",
            "x-kde-origin-name",
            "desktop-entry",
            "image-data",
        }
        for key in 'x-qutebrowser-origin', 'x-kde-origin-name':
            value = hints[key]
            url = QUrl(value)
            assert url.isValid(), value
            assert url.scheme() == 'http', value
            assert url.host() == 'localhost', value

        assert hints['desktop-entry'] == 'org.qutebrowser.qutebrowser'

        img = self._parse_image(*hints["image-data"])

        if replaces_id != 0:
            assert replaces_id in self.messages

        return NotificationProperties(title=title, body=body, replaces_id=replaces_id,
                                      img_width=img.width(), img_height=img.height())
Exemple #6
0
 def acceptNavigationRequest(self, url: QUrl, _type, isMainFrame):
     """При запросе урла со схемой file возбуждает событие и запрещает загрузку этого урла"""
     if url.scheme() == 'file':
         QCoreApplication.sendEvent(self.parent(), MyEvent(url.path()))
         return False
     return super(WebEnginePage,
                  self).acceptNavigationRequest(url, _type, isMainFrame)
Exemple #7
0
def proxy_from_url(url: QUrl) -> Union[QNetworkProxy, pac.PACFetcher]:
    """Create a QNetworkProxy from QUrl and a proxy type.

    Args:
        url: URL of a proxy (possibly with credentials).

    Return:
        New QNetworkProxy.
    """
    ensure_valid(url)

    scheme = url.scheme()
    if scheme in ['pac+http', 'pac+https', 'pac+file']:
        fetcher = pac.PACFetcher(url)
        fetcher.fetch()
        return fetcher

    types = {
        'http': QNetworkProxy.HttpProxy,
        'socks': QNetworkProxy.Socks5Proxy,
        'socks5': QNetworkProxy.Socks5Proxy,
        'direct': QNetworkProxy.NoProxy,
    }
    if scheme not in types:
        raise InvalidProxyTypeError(scheme)

    proxy = QNetworkProxy(types[scheme], url.host())

    if url.port() != -1:
        proxy.setPort(url.port())
    if url.userName():
        proxy.setUser(url.userName())
    if url.password():
        proxy.setPassword(url.password())
    return proxy
Exemple #8
0
    def handle_starttag(self, tag, alist):
        if tag not in ['a', 'link']:
            return

        attrs = dict(alist)
        href = attrs.get('href')

        if not isinstance(href, str):
            return

        if len(href) > 1024:
            return

        href = unquote(href)

        url = QUrl(href)
        if not url.isValid():
            return

        if not url.scheme() or url.isRelative():
            # Relative URL
            p = self.base.child(href)
            if p and self.pathValid(p):
                self.links.append(p)

        elif isIpfsUrl(url):
            # Absolute URL
            p = IPFSPath(url.toString())
            if self.pathValid(p):
                self.links.append(p)
    def _goToAddress(self):
        q = QUrl(self._itAddress.text())
        if q.scheme() == "":
            q.setScheme("http")

        self._currentWeb.load(q)
        self._currentWeb.show()
Exemple #10
0
def test_client():
    q=QUrl("entry: abc")
    print(q.toString().split(":")[1].strip("/ "))
    print(q.scheme())
    print(q.host())
    print(q.path())
    print(q.fragment())
Exemple #11
0
async def urlHistoryRecord(url, title):
    from galacteek.browser.schemes import isIpfsUrl

    item = await urlHistoryGet(url)

    if not item:
        qUrl = QUrl(url)
        scheme = qUrl.scheme() if qUrl.isValid() else ''

        rootcid = ''
        rootcidv = 0

        if isIpfsUrl(qUrl):
            ipfsPath = IPFSPath(url)
            if ipfsPath.valid and ipfsPath.rootCid:
                rootcid = str(ipfsPath.rootCid)
                rootcidv = ipfsPath.rootCid.version

        item = URLHistoryItem(url=url,
                              rootcid=rootcid,
                              rootcidv=rootcidv,
                              scheme=scheme)
        await item.save()

    visit = URLHistoryVisit(historyitem=item, title=title)
    await visit.save()

    return item, visit
Exemple #12
0
def filename_from_url(url: QUrl, fallback: str = None) -> Optional[str]:
    """Get a suitable filename from a URL.

    Args:
        url: The URL to parse, as a QUrl.
        fallback: Value to use if no name can be determined.

    Return:
        The suggested filename as a string, or None.
    """
    if not url.isValid():
        return fallback

    if url.scheme().lower() == 'data':
        mimetype, _encoding = mimetypes.guess_type(url.toString())
        if not mimetype:
            return fallback

        ext = utils.mimetype_extension(mimetype) or ''
        return 'download' + ext

    pathname = posixpath.basename(url.path())
    if pathname:
        return pathname
    elif url.host():
        return url.host() + '.html'
    else:
        return fallback
Exemple #13
0
    def yank(self, url: QUrl, context: HintContext) -> None:
        """Yank an element to the clipboard or primary selection."""
        sel = (context.target == Target.yank_primary
               and utils.supports_selection())

        flags = QUrl.FullyEncoded | QUrl.RemovePassword
        if url.scheme() == 'mailto':
            flags |= QUrl.RemoveScheme
        urlstr = url.toString(flags)  # type: ignore[arg-type]

        new_content = urlstr

        # only second and consecutive yanks are to append to the clipboard
        if context.rapid and not context.first_run:
            try:
                old_content = utils.get_clipboard(selection=sel)
            except utils.ClipboardEmptyError:
                pass
            else:
                new_content = os.linesep.join([old_content, new_content])
        utils.set_clipboard(new_content, selection=sel)

        msg = "Yanked URL to {}: {}".format(
            "primary selection" if sel else "clipboard", urlstr)
        message.info(msg)
Exemple #14
0
 def navigate_to_url(self):
     # print(self.urlbar.text())
     q = QUrl(self.urlbar.text())
     # print(q.scheme())
     if q.scheme() == '':
         q.setScheme('http')
     self.browser.setUrl(q)
Exemple #15
0
    def navigate_to_url(self, url): #todo: fix naming (url is an id right now) ... after the demo
        final_url = "{}/cards/checkin/{}/".format(self.baseUrl, url)
        print("navigate_to_url: [{}]".format(final_url))
        q = QUrl(final_url)
        if q.scheme() == "":
            q.setScheme("http")

        self.browser.setUrl(q)
Exemple #16
0
 def __addFeed(self):
     """
     Private slot to add a RSS feed.
     """
     button = self.sender()
     urlString = button.feed[1]
     url = QUrl(urlString)
     if not url.host():
         if not urlString.startswith("/"):
             urlString = "/" + urlString
         urlString = self.__browser.url().host() + urlString
         tmpUrl = QUrl(urlString)
         if not tmpUrl.scheme():
             urlString = "http://" + urlString
         tmpUrl = QUrl(urlString)
         if not tmpUrl.scheme() or not tmpUrl.host():
             return
     if not url.isValid():
         return
     
     if button.feed[0]:
         title = button.feed[0]
     else:
         title = self.__browser.url().host()
     
     import Helpviewer.HelpWindow
     feedsManager = Helpviewer.HelpWindow.HelpWindow.feedsManager()
     if feedsManager.addFeed(urlString, title, self.__browser.icon()):
         if Helpviewer.HelpWindow.HelpWindow.notificationsEnabled():
             Helpviewer.HelpWindow.HelpWindow.showNotification(
                 UI.PixmapCache.getPixmap("rss48.png"),
                 self.tr("Add RSS Feed"),
                 self.tr("""The feed was added successfully."""))
         else:
             E5MessageBox.information(
                 self,
                 self.tr("Add RSS Feed"),
                 self.tr("""The feed was added successfully."""))
     else:
         E5MessageBox.warning(
             self,
             self.tr("Add RSS Feed"),
             self.tr("""The feed was already added before."""))
         
     self.close()
Exemple #17
0
 def __addFeed(self):
     """
     Private slot to add a RSS feed.
     """
     button = self.sender()
     urlString = button.feed[1]
     url = QUrl(urlString)
     if not url.host():
         if not urlString.startswith("/"):
             urlString = "/" + urlString
         urlString = self.__browser.url().host() + urlString
         tmpUrl = QUrl(urlString)
         if not tmpUrl.scheme():
             urlString = "http://" + urlString
         tmpUrl = QUrl(urlString)
         if not tmpUrl.scheme() or not tmpUrl.host():
             return
     if not url.isValid():
         return
     
     if button.feed[0]:
         title = button.feed[0]
     else:
         title = self.__browser.url().host()
     
     import Helpviewer.HelpWindow
     feedsManager = Helpviewer.HelpWindow.HelpWindow.feedsManager()
     if feedsManager.addFeed(urlString, title, self.__browser.icon()):
         if Helpviewer.HelpWindow.HelpWindow.notificationsEnabled():
             Helpviewer.HelpWindow.HelpWindow.showNotification(
                 UI.PixmapCache.getPixmap("rss48.png"),
                 self.tr("Add RSS Feed"),
                 self.tr("""The feed was added successfully."""))
         else:
             E5MessageBox.information(
                 self,
                 self.tr("Add RSS Feed"),
                 self.tr("""The feed was added successfully."""))
     else:
         E5MessageBox.warning(
             self,
             self.tr("Add RSS Feed"),
             self.tr("""The feed was already added before."""))
         
     self.close()
Exemple #18
0
    def matches(self, qurl: QUrl) -> bool:
        """Check if the pattern matches the given QUrl."""
        qtutils.ensure_valid(qurl)

        if self._match_all:
            return True

        if not self._matches_scheme(qurl.scheme()):
            return False
        # FIXME ignore for file:// like Chromium?
        if not self._matches_host(qurl.host()):
            return False
        if not self._matches_port(qurl.scheme(), qurl.port()):
            return False
        if not self._matches_path(qurl.path()):
            return False

        return True
Exemple #19
0
    def __init__(self, parent):
        """
        Copies the properties from the parent (WebEngineRenderer) object,
        creates the required instances of QWebPage, QWebView and QMainWindow
        and registers some Slots.
        """
        QObject.__init__(self)

        # Copy properties from parent
        for key, value in parent.__dict__.items():
            setattr(self, key, value)

        # Determine Proxy settings
        proxy = QNetworkProxy(QNetworkProxy.NoProxy)
        if 'http_proxy' in os.environ:
            proxy_url = QUrl(os.environ['http_proxy'])
            if proxy_url.scheme().startswith('http'):
                protocol = QNetworkProxy.HttpProxy
            else:
                protocol = QNetworkProxy.Socks5Proxy

            proxy = QNetworkProxy(protocol, proxy_url.host(), proxy_url.port(),
                                  proxy_url.userName(), proxy_url.password())

        # Create and connect required PyQt5 objects
        self._page = CustomWebPage(logger=self.logger,
                                   ignore_alert=self.ignoreAlert,
                                   ignore_confirm=self.ignoreConfirm,
                                   ignore_prompt=self.ignorePrompt,
                                   interrupt_js=self.interruptJavaScript)
        self._qt_proxy = QNetworkProxy()
        self._qt_proxy.setApplicationProxy(proxy)
        self._view = QWebEngineView()
        self._view.setPage(self._page)
        _window_flags = Qt.WindowFlags()
        self._window = QMainWindow(flags=_window_flags)
        self._window.setCentralWidget(self._view)
        self._qt_network_access_manager = QNetworkAccessManager()

        # Import QWebSettings
        for key, value in self.qWebSettings.items():
            self._page.settings().setAttribute(key, value)

        # Connect required event listeners
        # assert False, "Not finish"
        self._page.loadFinished.connect(self._on_load_finished)
        self._page.loadStarted.connect(self._on_load_started)
        self._qt_network_access_manager.sslErrors.connect(self._on_ssl_errors)
        self._qt_network_access_manager.finished.connect(self._on_each_reply)

        # The way we will use this, it seems to be unnecessary to have Scrollbars enabled
        self._scroll_area = QAbstractScrollArea()
        self._scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        # Show this widget
        self._window.show()
Exemple #20
0
    def _handle_errorpage(self, info, errpage):
        """Display an error page if needed.

        Loosly based on Helpviewer/HelpBrowserWV.py from eric5
        (line 260 @ 5d937eb378dd)

        Args:
            info: The QWebPage.ErrorPageExtensionOption instance.
            errpage: The QWebPage.ErrorPageExtensionReturn instance, where the
                     error page will get written to.

        Return:
            False if no error page should be displayed, True otherwise.
        """
        ignored_errors = [
            (QWebPage.QtNetwork, QNetworkReply.OperationCanceledError),
            (QWebPage.WebKit, 203),  # "Loading is handled by the media engine"
        ]
        errpage.baseUrl = info.url
        urlstr = info.url.toDisplayString()
        if (info.domain, info.error) == (QWebPage.QtNetwork,
                                         QNetworkReply.ProtocolUnknownError):
            # For some reason, we get a segfault when we use
            # QDesktopServices::openUrl with info.url directly - however it
            # works when we construct a copy of it.
            url = QUrl(info.url)
            msg = "Open external application for {}-link?\nURL: {}".format(
                url.scheme(), url.toDisplayString())
            message.confirm_async(
                self._win_id, msg,
                functools.partial(QDesktopServices.openUrl, url))
            return True
        elif (info.domain, info.error) in ignored_errors:
            log.webview.debug("Ignored error on {}: {} (error domain: {}, "
                              "error code: {})".format(
                                  urlstr, info.errorString, info.domain,
                                  info.error))
            return False
        else:
            error_str = info.errorString
            if error_str == networkmanager.HOSTBLOCK_ERROR_STRING:
                error_str = "Request blocked by host blocker."
                # we don't set error_occured in this case.
            else:
                self._ignore_load_started = True
                self.error_occured = True
            log.webview.error("Error while loading {}: {}".format(
                urlstr, error_str))
            log.webview.debug("Error domain: {}, error code: {}".format(
                info.domain, info.error))
            title = "Error loading page: {}".format(urlstr)
            template = jinja.env.get_template('error.html')
            html = template.render(  # pylint: disable=maybe-no-member
                title=title, url=urlstr, error=error_str, icon='')
            errpage.content = html.encode('utf-8')
            errpage.encoding = 'utf-8'
            return True
Exemple #21
0
def is_special_url(url: QUrl) -> bool:
    """Return True if url is an about:... or other special URL.

    Args:
        url: The URL as QUrl.
    """
    if not url.isValid():
        return False
    special_schemes = ('about', 'qute', 'file')
    return url.scheme() in special_schemes
Exemple #22
0
    def acceptNavigationRequest(self, url: QUrl,
                                type: QWebEnginePage.NavigationType,
                                isMainFrame: bool, **kwargs):
        if type == QWebEnginePage.NavigationTypeLinkClicked:
            if url.scheme() == 'entry':
                try:
                    _, item = url.toString().split(":")
                except:
                    return False
                ProgressDialog.show_progress(self.parent(), "Loading...")
                item = item.strip("/ ")
                dict_name = CurrentState.get_cur_dict()
                self.lookupThread.word = item
                self.lookupThread.dicts = [dict_name]
                self.lookupThread.start()
                #dict_name=CurrentState.get_cur_dict()
                #try:
                #result_obj: dict = SocketClient.lookup(item,[dict_name])
                #raw_html = pretty_dict_result(dict_name,result_obj.get(dict_name,"No entry found"))
                #except Exception as e:
                #    print(f"Lookup {item} error = {e}")
                #    return False
                #print(self.url())
                #self.setHtml(raw_html,self.url())
                #CurrentState.add_history(item)

            elif url.scheme() == 'sound':
                item = url.toString().split("://")[1]
                name = CurrentState.get_cur_dict()
                try:
                    httpPlaySound(item, name)
                except Exception as e:
                    self.play_sound_error_sig.emit(str(e))
                    print(f"play sound error = {e}")

                #command=[SOUND_PLAYER, str(Path(data_folder).joinpath(item))]
                #os.system(SOUND_PLAYER+" "+str(Path(data_folder).joinpath(item)))
                #subprocess.Popen(command)

            return False

        return True
Exemple #23
0
    def _handle_errorpage(self, info, errpage):
        """Display an error page if needed.

        Loosly based on Helpviewer/HelpBrowserWV.py from eric5
        (line 260 @ 5d937eb378dd)

        Args:
            info: The QWebPage.ErrorPageExtensionOption instance.
            errpage: The QWebPage.ErrorPageExtensionReturn instance, where the
                     error page will get written to.

        Return:
            False if no error page should be displayed, True otherwise.
        """
        ignored_errors = [
            (QWebPage.QtNetwork, QNetworkReply.OperationCanceledError),
            (QWebPage.WebKit, 203),  # "Loading is handled by the media engine"
        ]
        errpage.baseUrl = info.url
        urlstr = info.url.toDisplayString()
        if (info.domain, info.error) == (QWebPage.QtNetwork,
                                         QNetworkReply.ProtocolUnknownError):
            # For some reason, we get a segfault when we use
            # QDesktopServices::openUrl with info.url directly - however it
            # works when we construct a copy of it.
            url = QUrl(info.url)
            msg = "Open external application for {}-link?\nURL: {}".format(
                url.scheme(), url.toDisplayString())
            message.confirm_async(
                self._win_id, msg,
                functools.partial(QDesktopServices.openUrl, url))
            return True
        elif (info.domain, info.error) in ignored_errors:
            log.webview.debug("Ignored error on {}: {} (error domain: {}, "
                              "error code: {})".format(urlstr,
                                                       info.errorString,
                                                       info.domain,
                                                       info.error))
            return False
        else:
            log.webview.error("Error while loading {}: {}".format(
                urlstr, info.errorString))
            log.webview.debug("Error domain: {}, error code: {}".format(
                info.domain, info.error))
            title = "Error loading page: {}".format(urlstr)
            template = jinja.env.get_template('error.html')
            html = template.render(  # pylint: disable=maybe-no-member
                title=title,
                url=urlstr,
                error=info.errorString,
                icon='')
            errpage.content = html.encode('utf-8')
            errpage.encoding = 'utf-8'
            return True
Exemple #24
0
def _has_explicit_scheme(url: QUrl):
    """Check if a url has an explicit scheme given.

    Args:
        url: The URL as QUrl.
    """
    # Note that generic URI syntax actually would allow a second colon
    # after the scheme delimiter. Since we don't know of any URIs
    # using this and want to support e.g. searching for scoped C++
    # symbols, we treat this as not a URI anyways.
    return (url.isValid() and url.scheme() and (url.host() or url.path())
            and " " not in url.path() and not url.path().startswith(":"))
    def on_imagesTree_currentItemChanged(self, current, previous):
        """
        Private slot to show a preview of the selected image.
        
        @param current current image entry (QTreeWidgetItem)
        @param previous old current entry (QTreeWidgetItem)
        """
        if current is None:
            return

        imageUrl = QUrl(current.text(1))
        if imageUrl.isRelative():
            imageUrl = self.__baseUrl.resolved(imageUrl)

        pixmap = QPixmap()
        loading = False

        if imageUrl.scheme() == "data":
            encodedUrl = current.text(1).encode("utf-8")
            imageData = encodedUrl[encodedUrl.find(b",") + 1:]
            pixmap = WebBrowserTools.pixmapFromByteArray(imageData)
        elif imageUrl.scheme() == "file":
            pixmap = QPixmap(imageUrl.toLocalFile())
        elif imageUrl.scheme() == "qrc":
            pixmap = QPixmap(imageUrl.toString()[3:])
        else:
            if self.__imageReply is not None:
                self.__imageReply.deleteLater()
                self.__imageReply = None

            from WebBrowser.WebBrowserWindow import WebBrowserWindow
            self.__imageReply = WebBrowserWindow.networkManager().get(
                QNetworkRequest(imageUrl))
            self.__imageReply.finished.connect(self.__imageReplyFinished)
            loading = True
            self.__showLoadingText()

        if not loading:
            self.__showPixmap(pixmap)
Exemple #26
0
    def onAnchorClicked(self, url: QUrl):
        from notes.ui.MainWindow import MainWindow
        import webbrowser

        host = url.host()
        print(url.scheme())
        scheme = url.scheme()

        if scheme == "http" or scheme == "https":
            webbrowser.open(url.toString())
        elif scheme == "notesmanager":
            url.setScheme("file")

            local_path = url.toLocalFile()
            query = QUrlQuery(url)
            uuid = query.queryItemValue("uuid")

            if local_path == self.notebook.attachment_base.filename:
                self.noteViewManager.openNote(self.noteViewManager.notebook.get_note_by_uuid(uuid))
            else:
                spawn = MainWindow(None, local_path, uuid)
                spawn.show()
Exemple #27
0
    def __init__(self, connections=None, parent=None):
        """
        Constructor
        
        @param connections list of database connections to add
            (list of strings)
        @param parent reference to the parent widget (QWidget)
        """
        super(SqlBrowser, self).__init__(parent)
        self.setObjectName("SqlBrowser")

        if connections is None:
            connections = []

        self.setWindowTitle(self.tr("SQL Browser"))
        self.setWindowIcon(UI.PixmapCache.getIcon("eric.png"))

        self.setStyle(Preferences.getUI("Style"),
                      Preferences.getUI("StyleSheet"))

        from .SqlBrowserWidget import SqlBrowserWidget
        self.__browser = SqlBrowserWidget(self)
        self.setCentralWidget(self.__browser)

        self.__browser.statusMessage.connect(self.statusBar().showMessage)

        self.__initActions()
        self.__initMenus()
        self.__initToolbars()

        self.resize(self.__browser.size())

        self.__warnings = []

        for connection in connections:
            url = QUrl(connection, QUrl.TolerantMode)
            if not url.isValid():
                self.__warnings.append(
                    self.tr("Invalid URL: {0}").format(connection))
                continue

            err = self.__browser.addConnection(url.scheme(), url.path(),
                                               url.userName(), url.password(),
                                               url.host(), url.port(-1))
            if err.type() != QSqlError.NoError:
                self.__warnings.append(
                    self.tr("Unable to open connection: {0}".format(
                        err.text())))

        QTimer.singleShot(0, self.__uiStartUp)
Exemple #28
0
 def validate(self, value):
     self._basic_validation(value)
     if not value:
         return
     elif value in self.valid_values:
         return
     url = QUrl(value)
     if not url.isValid():
         raise configexc.ValidationError(value, "invalid url, {}".format(
             url.errorString()))
     elif url.scheme() not in self.PROXY_TYPES:
         raise configexc.ValidationError(value, "must be a proxy URL "
                                         "(http://... or socks://...) or "
                                         "system/none!")
Exemple #29
0
    def start_load(self, url):
        '''Create a Poppler.Document from the given URL, QUrl or filename.
           Return, then asynchronously call self.load_cb.
        '''

        # If it's not a local file, we'll need to load it.
        # http://doc.qt.io/qt-5/qnetworkaccessmanager.html
        qurl = QUrl(url)
        if not qurl.scheme():
            qurl = QUrl.fromLocalFile(url)
        if not self.network_manager:
            self.network_manager = QNetworkAccessManager();
        self.network_manager.finished.connect(self.download_finished)
        self.network_manager.get(QNetworkRequest(qurl))
Exemple #30
0
    def start_load(self, url):
        """Create a Poppler.Document from the given URL, QUrl or filename.
           Return, then asynchronously call self.load_cb.
        """

        # If it's not a local file, we'll need to load it.
        # http://doc.qt.io/qt-5/qnetworkaccessmanager.html
        qurl = QUrl(url)
        if not qurl.scheme():
            qurl = QUrl.fromLocalFile(url)
        if not self.network_manager:
            self.network_manager = QNetworkAccessManager()
        self.network_manager.finished.connect(self.download_finished)
        self.network_manager.get(QNetworkRequest(qurl))
Exemple #31
0
    def acceptNavigationRequest(self, url: QUrl,
                                type: QWebEnginePage.NavigationType,
                                isMainFrame: bool, **kwargs):
        if type == QWebEnginePage.NavigationTypeLinkClicked:
            if url.scheme() == 'entry':
                _, item = url.toString().split(":")
                item = item.strip("/ ")
                dict_name, data_folder = CurrentState.get_cur_dict_info()
                result_obj: dict = SocketClient.lookup(item, [dict_name])
                raw_html = pretty_dict_result(dict_name, result_obj[dict_name])
                #print(self.url())
                self.setHtml(raw_html, self.url())
                CurrentState.add_history(item)
            elif url.scheme() == 'sound':
                item = url.toString().split("://")[1].lower()
                _, data_folder = CurrentState.get_cur_dict_info()
                command = [SOUND_PLAYER, str(Path(data_folder).joinpath(item))]
                #os.system(SOUND_PLAYER+" "+str(Path(data_folder).joinpath(item)))
                subprocess.Popen(command)

            return False

        return True
 def validate(self, value):
     if not value:
         if self._none_ok:
             return
         else:
             raise ValidationError(value, "may not be empty!")
     if value in self.valid_values:
         return
     url = QUrl(value)
     if not url.isValid():
         raise ValidationError(value, "invalid url, {}".format(
             url.errorString()))
     elif url.scheme() not in self.PROXY_TYPES:
         raise ValidationError(value, "must be a proxy URL (http://... or "
                                      "socks://...) or system/none!")
Exemple #33
0
 def validate(self, value):
     if not value:
         if self._none_ok:
             return
         else:
             raise ValidationError(value, "may not be empty!")
     if value in self.valid_values:
         return
     url = QUrl(value)
     if not url.isValid():
         raise ValidationError(value, "invalid url, {}".format(
             url.errorString()))
     elif url.scheme() not in self.PROXY_TYPES:
         raise ValidationError(value, "must be a proxy URL (http://... or "
                                      "socks://...) or system/none!")
Exemple #34
0
 def _linkClicked(self, url: QUrl) -> None:
     scheme = url.scheme()
     if scheme == 'file':
         # Open the file in an external application.
         utilities.openFile(url.path())
     elif scheme == 'http' or scheme == 'https':
         # Open the web page in the default browser.
         webbrowser.open_new_tab(url.toString())
     elif scheme == 'item':
         # Clear the search and select the item (if present in the tree).
         self._searchEdit.clear()
         self._model.searchText = ''
         index = self._model.findItemById(url.path())
         if index.isValid():
             self._treeView.setCurrentIndex(index)
Exemple #35
0
 def addHistoryEntry(self, url):
     """
     Public method to add a history entry.
     
     @param url URL to be added (string)
     """
     cleanurl = QUrl(url)
     if cleanurl.scheme() not in ["eric", "about"]:
         if cleanurl.password():
             # don't save the password in the history
             cleanurl.setPassword("")
         if cleanurl.host():
             cleanurl.setHost(cleanurl.host().lower())
         itm = HistoryEntry(cleanurl.toString(), QDateTime.currentDateTime())
         self._addHistoryEntry(itm)
def test_resource_url():
    """Test resource_url() which can be used from templates."""
    data = jinja.render('test2.html')
    print(data)
    url = QUrl(data)
    assert url.isValid()
    assert url.scheme() == 'file'

    path = url.path()

    if os.name == "nt":
        path = path.lstrip('/')
        path = path.replace('/', os.sep)

    with open(path, 'r', encoding='utf-8') as f:
        assert f.read().splitlines()[0] == "Hello World!"
Exemple #37
0
def test_resource_url():
    """Test resource_url() which can be used from templates."""
    data = jinja.render('resource_url.html')
    print(data)
    url = QUrl(data)
    assert url.isValid()
    assert url.scheme() == 'file'

    path = url.path()

    if os.name == "nt":
        path = path.lstrip('/')
        path = path.replace('/', os.sep)

    with open(path, 'r', encoding='utf-8') as f:
        assert f.read().splitlines()[0] == "Hello World!"
Exemple #38
0
 def __setOkButton(self):
     """
     Private slot to enable or disable the OK button.
     """
     enable = True
     
     enable = enable and bool(self.titleEdit.text())
     
     urlString = self.urlEdit.text()
     enable = enable and bool(urlString)
     if urlString:
         url = QUrl(urlString)
         enable = enable and bool(url.scheme())
         enable = enable and bool(url.host())
     
     self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable)
Exemple #39
0
 def __init__(self, connections=[], parent=None):
     """
     Constructor
     
     @param connections list of database connections to add
         (list of strings)
     @param parent reference to the parent widget (QWidget)
     """
     super(SqlBrowser, self).__init__(parent)
     self.setObjectName("SqlBrowser")
     
     self.setWindowTitle(self.tr("SQL Browser"))
     self.setWindowIcon(UI.PixmapCache.getIcon("eric.png"))
     
     self.setStyle(Preferences.getUI("Style"),
                   Preferences.getUI("StyleSheet"))
     
     from .SqlBrowserWidget import SqlBrowserWidget
     self.__browser = SqlBrowserWidget(self)
     self.setCentralWidget(self.__browser)
     
     self.__browser.statusMessage.connect(self.statusBar().showMessage)
     
     self.__initActions()
     self.__initMenus()
     self.__initToolbars()
     
     self.resize(self.__browser.size())
     
     self.__warnings = []
     
     for connection in connections:
         url = QUrl(connection, QUrl.TolerantMode)
         if not url.isValid():
             self.__warnings.append(
                 self.tr("Invalid URL: {0}").format(connection))
             continue
         
         err = self.__browser.addConnection(url.scheme(), url.path(),
                                            url.userName(), url.password(),
                                            url.host(), url.port(-1))
         if err.type() != QSqlError.NoError:
             self.__warnings.append(
                 self.tr("Unable to open connection: {0}".format(
                     err.text())))
     
     QTimer.singleShot(0, self.__uiStartUp)
Exemple #40
0
def test_resource_url():
    """Test resource_url() which can be used from templates."""
    template = jinja.env.get_template("test2.html")
    data = template.render()  # pylint: disable=no-member
    print(data)
    url = QUrl(data)
    assert url.isValid()
    assert url.scheme() == "file"

    path = url.path()

    if os.name == "nt":
        path = path.lstrip("/")
        path = path.replace("/", os.sep)

    with open(path, "r", encoding="utf-8") as f:
        assert f.read().splitlines()[0] == "Hello World!"
Exemple #41
0
 def transform(self, value):
     if not value:
         return None
     elif value == 'system':
         return SYSTEM_PROXY
     elif value == 'none':
         return QNetworkProxy(QNetworkProxy.NoProxy)
     url = QUrl(value)
     typ = self.PROXY_TYPES[url.scheme()]
     proxy = QNetworkProxy(typ, url.host())
     if url.port() != -1:
         proxy.setPort(url.port())
     if url.userName():
         proxy.setUser(url.userName())
     if url.password():
         proxy.setPassword(url.password())
     return proxy
Exemple #42
0
 def updateHistoryEntry(self, url, title):
     """
     Public method to update a history entry.
     
     @param url URL of the entry to update (string)
     @param title title of the entry to update (string)
     """
     cleanurl = QUrl(url)
     if cleanurl.scheme() not in ["eric", "about"]:
         for index in range(len(self.__history)):
             if url == self.__history[index].url:
                 self.__history[index].title = title
                 self.__saveTimer.changeOccurred()
                 if not self.__lastSavedUrl:
                     self.__lastSavedUrl = self.__history[index].url
                 self.entryUpdated.emit(index)
                 break
Exemple #43
0
    def load_url(self, url, tab=None):
        '''Load the given URL in the specified tab, or current tab if tab=None.
           url is a str, not a QUrl.
           PDF URLs will be loaded in a new tab, because there doesn't
           seem to be a way of replacing the BrowserView with a BrowserPDFView.
        '''

        # If there are newlines, remove newlines plus all adjacent whitespace.
        if '\n' in url:
            lines = url.split('\n')
            url = ''.join([ l.strip() for l in lines ])

        # Note that tab=0 is a valid argument here.
        # When testing whether tab is set, be sure to test for None.

        if is_pdf(url):
            self.new_tab(url)
            return

        qurl = QUrl(url)

        if not qurl.scheme():
            if os.path.exists(url):
                qurl.setScheme('file')
                if not os.path.isabs(url):
                    # Is it better to use posixpath.join or os.path.join?
                    # Both work on Linux.
                    qurl.setPath(os.path.normpath(os.path.join(os.getcwd(),
                                                               url)))
            else:
                qurl.setScheme('http')

        if len(self.browserviews) == 0:
            self.new_tab()
            tab = 0
        elif tab == None:
            tab = self.active_tab

        self.set_tab_text(url[:self.init_tab_name_len],
                          self.browserviews[tab])
        if tab == self.active_tab:
            self.urlbar.setText(url)

        self.browserviews[tab].load(qurl)
Exemple #44
0
 def __stripUrl(self, url):
     """
     Private method to strip off all unneeded parts of a URL.
     
     @param url URL to be stripped (QUrl)
     @return stripped URL (QUrl)
     """
     cleanUrl = QUrl(url)
     if qVersion() >= "5.0.0":
         cleanUrl.setQuery("")
     else:
         cleanUrl.setQueryItems([])
     cleanUrl.setUserInfo("")
     
     authority = cleanUrl.authority()
     if authority.startswith("@"):
         authority = authority[1:]
     cleanUrl = QUrl("{0}://{1}{2}".format(
         cleanUrl.scheme(), authority, cleanUrl.path()))
     cleanUrl.setFragment("")
     return cleanUrl
Exemple #45
0
    def _parse_entry(self, line):
        """Parse a history line like '12345 http://example.com title'."""
        if not line or line.startswith('#'):
            return None
        data = line.split(maxsplit=2)
        if len(data) == 2:
            atime, url = data
            title = ""
        elif len(data) == 3:
            atime, url, title = data
        else:
            raise ValueError("2 or 3 fields expected")

        # http://xn--pple-43d.com/ with
        # https://bugreports.qt.io/browse/QTBUG-60364
        if url in ['http://.com/', 'https://.com/',
                   'http://www..com/', 'https://www..com/']:
            return None

        url = QUrl(url)
        if not url.isValid():
            raise ValueError("Invalid URL: {}".format(url.errorString()))

        # https://github.com/qutebrowser/qutebrowser/issues/2646
        if url.scheme() == 'data':
            return None

        # https://github.com/qutebrowser/qutebrowser/issues/670
        atime = atime.lstrip('\0')

        if '-' in atime:
            atime, flags = atime.split('-')
        else:
            flags = ''

        if not set(flags).issubset('r'):
            raise ValueError("Invalid flags {!r}".format(flags))

        redirect = 'r' in flags
        return (url, title, int(atime), redirect)
Exemple #46
0
 def __convertFromOldBookmarks(self):
     """
     Private method to convert the old bookmarks into the new ones.
     """
     bmNames = Preferences.Prefs.settings.value('Bookmarks/Names')
     bmFiles = Preferences.Prefs.settings.value('Bookmarks/Files')
     
     if bmNames is not None and bmFiles is not None:
         if len(bmNames) == len(bmFiles):
             convertedRootNode = BookmarkNode(BookmarkNode.Folder)
             convertedRootNode.title = self.tr("Converted {0}")\
                 .format(QDate.currentDate().toString(
                     Qt.SystemLocaleShortDate))
             for i in range(len(bmNames)):
                 node = BookmarkNode(BookmarkNode.Bookmark,
                                     convertedRootNode)
                 node.title = bmNames[i]
                 url = QUrl(bmFiles[i])
                 if not url.scheme():
                     url.setScheme("file")
                 node.url = url.toString()
             self.addBookmark(self.menu(), convertedRootNode)
             
             Preferences.Prefs.settings.remove('Bookmarks')
Exemple #47
0
class WebView(QWebView):

    """One browser tab in TabbedBrowser.

    Our own subclass of a QWebView with some added bells and whistles.

    Attributes:
        hintmanager: The HintManager instance for this view.
        progress: loading progress of this page.
        scroll_pos: The current scroll position as (x%, y%) tuple.
        statusbar_message: The current javascript statusbar message.
        inspector: The QWebInspector used for this webview.
        load_status: loading status of this page (index into LoadStatus)
        viewing_source: Whether the webview is currently displaying source
                        code.
        keep_icon: Whether the (e.g. cloned) icon should not be cleared on page
                   load.
        registry: The ObjectRegistry associated with this tab.
        tab_id: The tab ID of the view.
        win_id: The window ID of the view.
        search_text: The text of the last search.
        search_flags: The search flags of the last search.
        _has_ssl_errors: Whether SSL errors occurred during loading.
        _zoom: A NeighborList with the zoom levels.
        _old_scroll_pos: The old scroll position.
        _check_insertmode: If True, in mouseReleaseEvent we should check if we
                           need to enter/leave insert mode.
        _default_zoom_changed: Whether the zoom was changed from the default.
        _ignore_wheel_event: Ignore the next wheel event.
                             See https://github.com/The-Compiler/qutebrowser/issues/395

    Signals:
        scroll_pos_changed: Scroll percentage of current tab changed.
                            arg 1: x-position in %.
                            arg 2: y-position in %.
        linkHovered: QWebPages linkHovered signal exposed.
        load_status_changed: The loading status changed
        url_text_changed: Current URL string changed.
        shutting_down: Emitted when the view is shutting down.
    """

    scroll_pos_changed = pyqtSignal(int, int)
    linkHovered = pyqtSignal(str, str, str)
    load_status_changed = pyqtSignal(str)
    url_text_changed = pyqtSignal(str)
    shutting_down = pyqtSignal()

    def __init__(self, win_id, parent=None):
        super().__init__(parent)
        if sys.platform == 'darwin' and qtutils.version_check('5.4'):
            # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-42948
            # See https://github.com/The-Compiler/qutebrowser/issues/462
            self.setStyle(QStyleFactory.create('Fusion'))
        self.win_id = win_id
        self.load_status = LoadStatus.none
        self._check_insertmode = False
        self.inspector = None
        self.scroll_pos = (-1, -1)
        self.statusbar_message = ''
        self._old_scroll_pos = (-1, -1)
        self._zoom = None
        self._has_ssl_errors = False
        self._ignore_wheel_event = False
        self.keep_icon = False
        self.search_text = None
        self.search_flags = 0
        self.selection_enabled = False
        self.init_neighborlist()
        self._set_bg_color()
        cfg = objreg.get('config')
        cfg.changed.connect(self.init_neighborlist)
        # For some reason, this signal doesn't get disconnected automatically
        # when the WebView is destroyed on older PyQt versions.
        # See https://github.com/The-Compiler/qutebrowser/issues/390
        self.destroyed.connect(functools.partial(
            cfg.changed.disconnect, self.init_neighborlist))
        self.cur_url = QUrl()
        self.progress = 0
        self.registry = objreg.ObjectRegistry()
        self.tab_id = next(tab_id_gen)
        tab_registry = objreg.get('tab-registry', scope='window',
                                  window=win_id)
        tab_registry[self.tab_id] = self
        objreg.register('webview', self, registry=self.registry)
        page = self._init_page()
        hintmanager = hints.HintManager(win_id, self.tab_id, self)
        hintmanager.mouse_event.connect(self.on_mouse_event)
        hintmanager.start_hinting.connect(page.on_start_hinting)
        hintmanager.stop_hinting.connect(page.on_stop_hinting)
        objreg.register('hintmanager', hintmanager, registry=self.registry)
        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=win_id)
        mode_manager.entered.connect(self.on_mode_entered)
        mode_manager.left.connect(self.on_mode_left)
        self.viewing_source = False
        self.setZoomFactor(float(config.get('ui', 'default-zoom')) / 100)
        self._default_zoom_changed = False
        if config.get('input', 'rocker-gestures'):
            self.setContextMenuPolicy(Qt.PreventContextMenu)
        self.urlChanged.connect(self.on_url_changed)
        self.loadProgress.connect(lambda p: setattr(self, 'progress', p))
        objreg.get('config').changed.connect(self.on_config_changed)

    def _init_page(self):
        """Initialize the QWebPage used by this view."""
        page = webpage.BrowserPage(self.win_id, self.tab_id, self)
        self.setPage(page)
        page.linkHovered.connect(self.linkHovered)
        page.mainFrame().loadStarted.connect(self.on_load_started)
        page.mainFrame().loadFinished.connect(self.on_load_finished)
        page.statusBarMessage.connect(
            lambda msg: setattr(self, 'statusbar_message', msg))
        page.networkAccessManager().sslErrors.connect(
            lambda *args: setattr(self, '_has_ssl_errors', True))
        return page

    def __repr__(self):
        url = utils.elide(self.url().toDisplayString(QUrl.EncodeUnicode), 100)
        return utils.get_repr(self, tab_id=self.tab_id, url=url)

    def __del__(self):
        # Explicitly releasing the page here seems to prevent some segfaults
        # when quitting.
        # Copied from:
        # https://code.google.com/p/webscraping/source/browse/webkit.py#325
        try:
            self.setPage(None)
        except RuntimeError:
            # It seems sometimes Qt has already deleted the QWebView and we
            # get: RuntimeError: wrapped C/C++ object of type WebView has been
            # deleted
            pass

    def _set_load_status(self, val):
        """Setter for load_status."""
        if not isinstance(val, LoadStatus):
            raise TypeError("Type {} is no LoadStatus member!".format(val))
        log.webview.debug("load status for {}: {}".format(repr(self), val))
        self.load_status = val
        self.load_status_changed.emit(val.name)

    def _set_bg_color(self):
        """Set the webpage background color as configured."""
        col = config.get('colors', 'webpage.bg')
        palette = self.palette()
        if col is None:
            col = self.style().standardPalette().color(QPalette.Base)
        palette.setColor(QPalette.Base, col)
        self.setPalette(palette)

    @pyqtSlot(str, str)
    def on_config_changed(self, section, option):
        """Reinitialize the zoom neighborlist if related config changed."""
        if section == 'ui' and option in ('zoom-levels', 'default-zoom'):
            if not self._default_zoom_changed:
                self.setZoomFactor(float(config.get('ui', 'default-zoom')) /
                                   100)
            self._default_zoom_changed = False
            self.init_neighborlist()
        elif section == 'input' and option == 'rocker-gestures':
            if config.get('input', 'rocker-gestures'):
                self.setContextMenuPolicy(Qt.PreventContextMenu)
            else:
                self.setContextMenuPolicy(Qt.DefaultContextMenu)
        elif section == 'colors' and option == 'webpage.bg':
            self._set_bg_color()

    def init_neighborlist(self):
        """Initialize the _zoom neighborlist."""
        levels = config.get('ui', 'zoom-levels')
        self._zoom = usertypes.NeighborList(
            levels, mode=usertypes.NeighborList.Modes.block)
        self._zoom.fuzzyval = config.get('ui', 'default-zoom')

    def _mousepress_backforward(self, e):
        """Handle back/forward mouse button presses.

        Args:
            e: The QMouseEvent.
        """
        if e.button() in (Qt.XButton1, Qt.LeftButton):
            # Back button on mice which have it, or rocker gesture
            if self.page().history().canGoBack():
                self.back()
            else:
                message.error(self.win_id, "At beginning of history.",
                              immediately=True)
        elif e.button() in (Qt.XButton2, Qt.RightButton):
            # Forward button on mice which have it, or rocker gesture
            if self.page().history().canGoForward():
                self.forward()
            else:
                message.error(self.win_id, "At end of history.",
                              immediately=True)

    def _mousepress_insertmode(self, e):
        """Switch to insert mode when an editable element was clicked.

        Args:
            e: The QMouseEvent.
        """
        pos = e.pos()
        frame = self.page().frameAt(pos)
        if frame is None:
            # This happens when we click inside the webview, but not actually
            # on the QWebPage - for example when clicking the scrollbar
            # sometimes.
            log.mouse.debug("Clicked at {} but frame is None!".format(pos))
            return
        # You'd think we have to subtract frame.geometry().topLeft() from the
        # position, but it seems QWebFrame::hitTestContent wants a position
        # relative to the QWebView, not to the frame. This makes no sense to
        # me, but it works this way.
        hitresult = frame.hitTestContent(pos)
        if hitresult.isNull():
            # For some reason, the whole hit result can be null sometimes (e.g.
            # on doodle menu links). If this is the case, we schedule a check
            # later (in mouseReleaseEvent) which uses webelem.focus_elem.
            log.mouse.debug("Hitresult is null!")
            self._check_insertmode = True
            return
        try:
            elem = webelem.WebElementWrapper(hitresult.element())
        except webelem.IsNullError:
            # For some reason, the hit result element can be a null element
            # sometimes (e.g. when clicking the timetable fields on
            # http://www.sbb.ch/ ). If this is the case, we schedule a check
            # later (in mouseReleaseEvent) which uses webelem.focus_elem.
            log.mouse.debug("Hitresult element is null!")
            self._check_insertmode = True
            return
        if ((hitresult.isContentEditable() and elem.is_writable()) or
                elem.is_editable()):
            log.mouse.debug("Clicked editable element!")
            modeman.enter(self.win_id, usertypes.KeyMode.insert, 'click',
                          only_if_normal=True)
        else:
            log.mouse.debug("Clicked non-editable element!")
            if config.get('input', 'auto-leave-insert-mode'):
                modeman.maybe_leave(self.win_id, usertypes.KeyMode.insert,
                                    'click')

    def mouserelease_insertmode(self):
        """If we have an insertmode check scheduled, handle it."""
        if not self._check_insertmode:
            return
        self._check_insertmode = False
        try:
            elem = webelem.focus_elem(self.page().currentFrame())
        except (webelem.IsNullError, RuntimeError):
            log.mouse.debug("Element/page vanished!")
            return
        if elem.is_editable():
            log.mouse.debug("Clicked editable element (delayed)!")
            modeman.enter(self.win_id, usertypes.KeyMode.insert,
                          'click-delayed', only_if_normal=True)
        else:
            log.mouse.debug("Clicked non-editable element (delayed)!")
            if config.get('input', 'auto-leave-insert-mode'):
                modeman.maybe_leave(self.win_id, usertypes.KeyMode.insert,
                                    'click-delayed')

    def _mousepress_opentarget(self, e):
        """Set the open target when something was clicked.

        Args:
            e: The QMouseEvent.
        """
        if e.button() == Qt.MidButton or e.modifiers() & Qt.ControlModifier:
            background_tabs = config.get('tabs', 'background-tabs')
            if e.modifiers() & Qt.ShiftModifier:
                background_tabs = not background_tabs
            if background_tabs:
                target = usertypes.ClickTarget.tab_bg
            else:
                target = usertypes.ClickTarget.tab
            self.page().open_target = target
            log.mouse.debug("Middle click, setting target: {}".format(target))
        else:
            self.page().open_target = usertypes.ClickTarget.normal
            log.mouse.debug("Normal click, setting normal target")

    def shutdown(self):
        """Shut down the webview."""
        self.shutting_down.emit()
        # We disable javascript because that prevents some segfaults when
        # quitting it seems.
        log.destroy.debug("Shutting down {!r}.".format(self))
        settings = self.settings()
        settings.setAttribute(QWebSettings.JavascriptEnabled, False)
        self.stop()
        self.page().shutdown()

    def openurl(self, url):
        """Open a URL in the browser.

        Args:
            url: The URL to load as QUrl
        """
        qtutils.ensure_valid(url)
        urlstr = url.toDisplayString()
        log.webview.debug("New title: {}".format(urlstr))
        self.titleChanged.emit(urlstr)
        self.cur_url = url
        self.url_text_changed.emit(url.toDisplayString())
        self.load(url)
        if url.scheme() == 'qute':
            frame = self.page().mainFrame()
            frame.javaScriptWindowObjectCleared.connect(self.add_js_bridge)

    @pyqtSlot()
    def add_js_bridge(self):
        """Add the javascript bridge for qute:... pages."""
        frame = self.sender()
        if not isinstance(frame, QWebFrame):
            log.webview.error("Got non-QWebFrame in add_js_bridge")
            return

        if frame.url().scheme() == 'qute':
            bridge = objreg.get('js-bridge')
            frame.addToJavaScriptWindowObject('qute', bridge)

    def zoom_perc(self, perc, fuzzyval=True):
        """Zoom to a given zoom percentage.

        Args:
            perc: The zoom percentage as int.
            fuzzyval: Whether to set the NeighborLists fuzzyval.
        """
        if fuzzyval:
            self._zoom.fuzzyval = int(perc)
        if perc < 0:
            raise ValueError("Can't zoom {}%!".format(perc))
        self.setZoomFactor(float(perc) / 100)
        self._default_zoom_changed = True

    def zoom(self, offset):
        """Increase/Decrease the zoom level.

        Args:
            offset: The offset in the zoom level list.

        Return:
            The new zoom percentage.
        """
        level = self._zoom.getitem(offset)
        self.zoom_perc(level, fuzzyval=False)
        return level

    @pyqtSlot('QUrl')
    def on_url_changed(self, url):
        """Update cur_url when URL has changed.

        If the URL is invalid, we just ignore it here.
        """
        if url.isValid():
            self.cur_url = url
            self.url_text_changed.emit(url.toDisplayString())
            if not self.title():
                self.titleChanged.emit(self.url().toDisplayString())

    @pyqtSlot('QMouseEvent')
    def on_mouse_event(self, evt):
        """Post a new mouse event from a hintmanager."""
        log.modes.debug("Hint triggered, focusing {!r}".format(self))
        self.setFocus()
        QApplication.postEvent(self, evt)

    @pyqtSlot()
    def on_load_started(self):
        """Leave insert/hint mode and set vars when a new page is loading."""
        self.progress = 0
        self.viewing_source = False
        self._has_ssl_errors = False
        self._set_load_status(LoadStatus.loading)

    @pyqtSlot()
    def on_load_finished(self):
        """Handle a finished page load.

        We don't take loadFinished's ok argument here as it always seems to be
        true when the QWebPage has an ErrorPageExtension implemented.
        See https://github.com/The-Compiler/qutebrowser/issues/84
        """
        ok = not self.page().error_occurred
        if ok and not self._has_ssl_errors:
            if self.cur_url.scheme() == 'https':
                self._set_load_status(LoadStatus.success_https)
            else:
                self._set_load_status(LoadStatus.success)

        elif ok:
            self._set_load_status(LoadStatus.warn)
        else:
            self._set_load_status(LoadStatus.error)
        if not self.title():
            self.titleChanged.emit(self.url().toDisplayString())
        self._handle_auto_insert_mode(ok)

    def _handle_auto_insert_mode(self, ok):
        """Handle auto-insert-mode after loading finished."""
        if not config.get('input', 'auto-insert-mode'):
            return
        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self.win_id)
        cur_mode = mode_manager.mode
        if cur_mode == usertypes.KeyMode.insert or not ok:
            return
        frame = self.page().currentFrame()
        try:
            elem = webelem.WebElementWrapper(frame.findFirstElement(':focus'))
        except webelem.IsNullError:
            log.webview.debug("Focused element is null!")
            return
        log.modes.debug("focus element: {}".format(repr(elem)))
        if elem.is_editable():
            modeman.enter(self.win_id, usertypes.KeyMode.insert,
                          'load finished', only_if_normal=True)

    @pyqtSlot(usertypes.KeyMode)
    def on_mode_entered(self, mode):
        """Ignore attempts to focus the widget if in any status-input mode."""
        if mode in (usertypes.KeyMode.command, usertypes.KeyMode.prompt,
                    usertypes.KeyMode.yesno):
            log.webview.debug("Ignoring focus because mode {} was "
                              "entered.".format(mode))
            self.setFocusPolicy(Qt.NoFocus)
        elif mode == usertypes.KeyMode.caret:
            settings = self.settings()
            settings.setAttribute(QWebSettings.CaretBrowsingEnabled, True)
            self.selection_enabled = bool(self.page().selectedText())

            if self.isVisible():
                # Sometimes the caret isn't immediately visible, but unfocusing
                # and refocusing it fixes that.
                self.clearFocus()
                self.setFocus(Qt.OtherFocusReason)

                # Move the caret to the first element in the viewport if there
                # isn't any text which is already selected.
                #
                # Note: We can't use hasSelection() here, as that's always
                # true in caret mode.
                if not self.page().selectedText():
                    self.page().currentFrame().evaluateJavaScript(
                        utils.read_file('javascript/position_caret.js'))

    @pyqtSlot(usertypes.KeyMode)
    def on_mode_left(self, mode):
        """Restore focus policy if status-input modes were left."""
        if mode in (usertypes.KeyMode.command, usertypes.KeyMode.prompt,
                    usertypes.KeyMode.yesno):
            log.webview.debug("Restoring focus policy because mode {} was "
                              "left.".format(mode))
        elif mode == usertypes.KeyMode.caret:
            settings = self.settings()
            if settings.testAttribute(QWebSettings.CaretBrowsingEnabled):
                if self.selection_enabled and self.hasSelection():
                    # Remove selection if it exists
                    self.triggerPageAction(QWebPage.MoveToNextChar)
                settings.setAttribute(QWebSettings.CaretBrowsingEnabled, False)
                self.selection_enabled = False

        self.setFocusPolicy(Qt.WheelFocus)

    def search(self, text, flags):
        """Search for text in the current page.

        Args:
            text: The text to search for.
            flags: The QWebPage::FindFlags.
        """
        log.webview.debug("Searching with text '{}' and flags "
                          "0x{:04x}.".format(text, int(flags)))
        old_scroll_pos = self.scroll_pos
        flags = QWebPage.FindFlags(flags)
        found = self.findText(text, flags)
        backward = flags & QWebPage.FindBackward

        if not found and not flags & QWebPage.HighlightAllOccurrences and text:
            # User disabled wrapping; but findText() just returns False. If we
            # have a selection, we know there's a match *somewhere* on the page
            if (not flags & QWebPage.FindWrapsAroundDocument and
                    self.hasSelection()):
                if not backward:
                    message.warning(self.win_id, "Search hit BOTTOM without "
                                    "match for: {}".format(text),
                                    immediately=True)
                else:
                    message.warning(self.win_id, "Search hit TOP without "
                                    "match for: {}".format(text),
                                    immediately=True)
            else:
                message.warning(self.win_id, "Text '{}' not found on "
                                "page!".format(text), immediately=True)
        else:
            def check_scroll_pos():
                """Check if the scroll position got smaller and show info."""
                if not backward and self.scroll_pos < old_scroll_pos:
                    message.info(self.win_id, "Search hit BOTTOM, continuing "
                                 "at TOP", immediately=True)
                elif backward and self.scroll_pos > old_scroll_pos:
                    message.info(self.win_id, "Search hit TOP, continuing at "
                                 "BOTTOM", immediately=True)
            # We first want QWebPage to refresh.
            QTimer.singleShot(0, check_scroll_pos)

    def createWindow(self, wintype):
        """Called by Qt when a page wants to create a new window.

        This function is called from the createWindow() method of the
        associated QWebPage, each time the page wants to create a new window of
        the given type. This might be the result, for example, of a JavaScript
        request to open a document in a new window.

        Args:
            wintype: This enum describes the types of window that can be
                     created by the createWindow() function.

                     QWebPage::WebBrowserWindow: The window is a regular web
                                                 browser window.
                     QWebPage::WebModalDialog: The window acts as modal dialog.

        Return:
            The new QWebView object.
        """
        if wintype == QWebPage.WebModalDialog:
            log.webview.warning("WebModalDialog requested, but we don't "
                                "support that!")
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self.win_id)
        return tabbed_browser.tabopen(background=False)

    def paintEvent(self, e):
        """Extend paintEvent to emit a signal if the scroll position changed.

        This is a bit of a hack: We listen to repaint requests here, in the
        hope a repaint will always be requested when scrolling, and if the
        scroll position actually changed, we emit a signal.

        Args:
            e: The QPaintEvent.

        Return:
            The superclass event return value.
        """
        frame = self.page().mainFrame()
        new_pos = (frame.scrollBarValue(Qt.Horizontal),
                   frame.scrollBarValue(Qt.Vertical))
        if self._old_scroll_pos != new_pos:
            self._old_scroll_pos = new_pos
            m = (frame.scrollBarMaximum(Qt.Horizontal),
                 frame.scrollBarMaximum(Qt.Vertical))
            perc = (round(100 * new_pos[0] / m[0]) if m[0] != 0 else 0,
                    round(100 * new_pos[1] / m[1]) if m[1] != 0 else 0)
            self.scroll_pos = perc
            self.scroll_pos_changed.emit(*perc)
        # Let superclass handle the event
        super().paintEvent(e)

    def mousePressEvent(self, e):
        """Extend QWidget::mousePressEvent().

        This does the following things:
            - Check if a link was clicked with the middle button or Ctrl and
              set the page's open_target attribute accordingly.
            - Emit the editable_elem_selected signal if an editable element was
              clicked.

        Args:
            e: The arrived event.

        Return:
            The superclass return value.
        """
        is_rocker_gesture = (config.get('input', 'rocker-gestures') and
                             e.buttons() == Qt.LeftButton | Qt.RightButton)

        if e.button() in (Qt.XButton1, Qt.XButton2) or is_rocker_gesture:
            self._mousepress_backforward(e)
            super().mousePressEvent(e)
            return
        self._mousepress_insertmode(e)
        self._mousepress_opentarget(e)
        self._ignore_wheel_event = True
        super().mousePressEvent(e)

    def mouseReleaseEvent(self, e):
        """Extend mouseReleaseEvent to enter insert mode if needed."""
        super().mouseReleaseEvent(e)
        # We want to make sure we check the focus element after the WebView is
        # updated completely.
        QTimer.singleShot(0, self.mouserelease_insertmode)

    def contextMenuEvent(self, e):
        """Save a reference to the context menu so we can close it."""
        menu = self.page().createStandardContextMenu()
        self.shutting_down.connect(menu.close)
        modeman.instance(self.win_id).entered.connect(menu.close)
        menu.exec_(e.globalPos())

    def wheelEvent(self, e):
        """Zoom on Ctrl-Mousewheel.

        Args:
            e: The QWheelEvent.
        """
        if self._ignore_wheel_event:
            self._ignore_wheel_event = False
            # See https://github.com/The-Compiler/qutebrowser/issues/395
            return
        if e.modifiers() & Qt.ControlModifier:
            e.accept()
            divider = config.get('input', 'mouse-zoom-divider')
            factor = self.zoomFactor() + e.angleDelta().y() / divider
            if factor < 0:
                return
            perc = int(100 * factor)
            message.info(self.win_id, "Zoom level: {}%".format(perc))
            self._zoom.fuzzyval = perc
            self.setZoomFactor(factor)
            self._default_zoom_changed = True
        else:
            super().wheelEvent(e)
Exemple #48
0
 def importedBookmarks(self):
     """
     Public method to get the imported bookmarks.
     
     @return imported bookmarks (BookmarkNode)
     """
     from ..BookmarkNode import BookmarkNode
     importRootNode = BookmarkNode(BookmarkNode.Root)
     
     # step 1: build the hierarchy of bookmark folders
     folders = {}
     
     try:
         cursor = self.__db.cursor()
         cursor.execute(
             "SELECT id, parent, title FROM moz_bookmarks "
             "WHERE type = 2 and title !=''")
         for row in cursor:
             id_ = row[0]
             parent = row[1]
             title = row[2]
             if parent in folders:
                 folder = BookmarkNode(BookmarkNode.Folder, folders[parent])
             else:
                 folder = BookmarkNode(BookmarkNode.Folder, importRootNode)
             folder.title = title.replace("&", "&&")
             folders[id_] = folder
     except sqlite3.DatabaseError as err:
         self._error = True
         self._errorString = self.tr(
             "Unable to open database.\nReason: {0}").format(str(err))
         return None
     
     try:
         cursor = self.__db.cursor()
         cursor.execute(
             "SELECT parent, title, fk, position FROM moz_bookmarks"
             " WHERE type = 1 and title != '' ORDER BY position")
         for row in cursor:
             parent = row[0]
             title = row[1]
             placesId = row[2]
             
             cursor2 = self.__db.cursor()
             cursor2.execute(
                 "SELECT url FROM moz_places WHERE id = {0}"
                 .format(placesId))
             row2 = cursor2.fetchone()
             if row2:
                 url = QUrl(row2[0])
                 if not title or url.isEmpty() or \
                         url.scheme() in ["place", "about"]:
                     continue
                 
                 if parent in folders:
                     bookmark = BookmarkNode(BookmarkNode.Bookmark,
                                             folders[parent])
                 else:
                     bookmark = BookmarkNode(BookmarkNode.Bookmark,
                                             importRootNode)
                 bookmark.url = url.toString()
                 bookmark.title = title.replace("&", "&&")
     except sqlite3.DatabaseError as err:
         self._error = True
         self._errorString = self.tr(
             "Unable to open database.\nReason: {0}").format(str(err))
         return None
     
     importRootNode.setType(BookmarkNode.Folder)
     if self._id == "firefox":
         importRootNode.title = self.tr("Mozilla Firefox Import")
     else:
         importRootNode.title = self.tr("Imported {0}")\
             .format(QDate.currentDate().toString(Qt.SystemLocaleShortDate))
     return importRootNode
Exemple #49
0
class CoverArtImage:

    # Indicate if types are provided by the source, ie. CAA or certain file
    # formats may have types associated with cover art, but some other sources
    # don't provide such information
    support_types = False
    # Indicates that the source supports multiple types per image.
    support_multi_types = False
    # `is_front` has to be explicitly set, it is used to handle CAA is_front
    # indicator
    is_front = None
    sourceprefix = "URL"

    def __init__(self, url=None, types=None, comment='', data=None, support_types=None, support_multi_types=None):
        if types is None:
            self.types = []
        else:
            self.types = types
        if url is not None:
            self.parse_url(url)
        else:
            self.url = None
        self.comment = comment
        self.datahash = None
        # thumbnail is used to link to another CoverArtImage, ie. for PDFs
        self.thumbnail = None
        self.can_be_saved_to_tags = True
        self.can_be_saved_to_disk = True
        self.can_be_saved_to_metadata = True
        if support_types is not None:
            self.support_types = support_types
        if support_multi_types is not None:
            self.support_multi_types = support_multi_types
        if data is not None:
            self.set_data(data)

    def parse_url(self, url):
        self.url = QUrl(url)
        self.host = self.url.host()
        self.port = self.url.port(443 if self.url.scheme() == 'https' else 80)
        self.path = self.url.path(QUrl.FullyEncoded)
        if self.url.hasQuery():
            self.path += '?' + self.url.query(QUrl.FullyEncoded)

    @property
    def source(self):
        if self.url is not None:
            return "%s: %s" % (self.sourceprefix, self.url.toString())
        else:
            return "%s" % self.sourceprefix

    def is_front_image(self):
        """Indicates if image is considered as a 'front' image.
        It depends on few things:
            - if `is_front` was set, it is used over anything else
            - if `types` was set, search for 'front' in it
            - if `support_types` is False, default to True for any image
            - if `support_types` is True, default to False for any image
        """
        if not self.can_be_saved_to_metadata:
            # ignore thumbnails
            return False
        if self.is_front is not None:
            return self.is_front
        if 'front' in self.types:
            return True
        return (self.support_types is False)

    def imageinfo_as_string(self):
        if self.datahash is None:
            return ""
        return "w=%d h=%d mime=%s ext=%s datalen=%d file=%s" % (self.width,
                                                                self.height,
                                                                self.mimetype,
                                                                self.extension,
                                                                self.datalength,
                                                                self.tempfile_filename)

    def __repr__(self):
        p = []
        if self.url is not None:
            p.append("url=%r" % self.url.toString())
        if self.types:
            p.append("types=%r" % self.types)
        p.append('support_types=%r' % self.support_types)
        p.append('support_multi_types=%r' % self.support_types)
        if self.is_front is not None:
            p.append("is_front=%r" % self.is_front)
        if self.comment:
            p.append("comment=%r" % self.comment)
        return "%s(%s)" % (self.__class__.__name__, ", ".join(p))

    def __str__(self):
        p = ['Image']
        if self.url is not None:
            p.append("from %s" % self.url.toString())
        if self.types:
            p.append("of type %s" % ','.join(self.types))
        if self.comment:
            p.append("and comment '%s'" % self.comment)
        return ' '.join(p)

    def __eq__(self, other):
        if self and other:
            if self.support_types and other.support_types:
                if self.support_multi_types and other.support_multi_types:
                    return (self.datahash, self.types) == (other.datahash, other.types)
                else:
                    return (self.datahash, self.maintype) == (other.datahash, other.maintype)
            else:
                return self.datahash == other.datahash
        elif not self and not other:
            return True
        else:
            return False

    def __hash__(self):
        if self.datahash is None:
            return 0
        return hash(self.datahash.hash())

    def set_data(self, data):
        """Store image data in a file, if data already exists in such file
           it will be re-used and no file write occurs
        """
        if self.datahash:
            self.datahash.delete_file()
            self.datahash = None

        try:
            (self.width, self.height, self.mimetype, self.extension,
             self.datalength) = imageinfo.identify(data)
        except imageinfo.IdentificationError as e:
            raise CoverArtImageIdentificationError(e)

        try:
            self.datahash = DataHash(data, suffix=self.extension)
        except (OSError, IOError) as e:
            raise CoverArtImageIOError(e)

    @property
    def maintype(self):
        """Returns one type only, even for images having more than one type set.
        This is mostly used when saving cover art to tags because most formats
        don't support multiple types for one image.
        Images coming from CAA can have multiple types (ie. 'front, booklet').
        """
        if self.is_front_image() or not self.types or 'front' in self.types:
            return 'front'
        # TODO: do something better than randomly using the first in the list
        return self.types[0]

    def _make_image_filename(self, filename, dirname, _metadata):
        metadata = Metadata()
        metadata.copy(_metadata)
        metadata["coverart_maintype"] = self.maintype
        metadata["coverart_comment"] = self.comment
        if self.is_front:
            metadata.add_unique("coverart_types", "front")
        for cover_type in self.types:
            metadata.add_unique("coverart_types", cover_type)
        filename = script_to_filename(filename, metadata)
        if not filename:
            filename = "cover"
        if not os.path.isabs(filename):
            filename = os.path.join(dirname, filename)
        return encode_filename(filename)

    def save(self, dirname, metadata, counters):
        """Saves this image.

        :dirname: The name of the directory that contains the audio file
        :metadata: A metadata object
        :counters: A dictionary mapping filenames to the amount of how many
                    images with that filename were already saved in `dirname`.
        """
        if not self.can_be_saved_to_disk:
            return
        if (config.setting["caa_image_type_as_filename"]
            and not self.is_front_image()):
            filename = self.maintype
            log.debug("Make cover filename from types: %r -> %r",
                      self.types, filename)
        else:
            filename = config.setting["cover_image_filename"]
            log.debug("Using default cover image filename %r", filename)
        filename = self._make_image_filename(filename, dirname, metadata)

        overwrite = config.setting["save_images_overwrite"]
        ext = encode_filename(self.extension)
        image_filename = self._next_filename(filename, counters)
        while os.path.exists(image_filename + ext) and not overwrite:
            if not self._is_write_needed(image_filename + ext):
                break
            image_filename = self._next_filename(filename, counters)
        else:
            new_filename = image_filename + ext
            # Even if overwrite is enabled we don't need to write the same
            # image multiple times
            if not self._is_write_needed(new_filename):
                return
            log.debug("Saving cover image to %r", new_filename)
            try:
                new_dirname = os.path.dirname(new_filename)
                if not os.path.isdir(new_dirname):
                    os.makedirs(new_dirname)
                shutil.copyfile(self.tempfile_filename, new_filename)
            except (OSError, IOError) as e:
                raise CoverArtImageIOError(e)

    def _next_filename(self, filename, counters):
        if counters[filename]:
            new_filename = "%s (%d)" % (decode_filename(filename), counters[filename])
        else:
            new_filename = filename
        counters[filename] += 1
        return encode_filename(new_filename)

    def _is_write_needed(self, filename):
        if (os.path.exists(filename)
                and os.path.getsize(filename) == self.datalength):
            log.debug("Identical file size, not saving %r", filename)
            return False
        return True

    @property
    def data(self):
        """Reads the data from the temporary file created for this image.
        May raise CoverArtImageIOError
        """
        try:
            return self.datahash.data
        except (OSError, IOError) as e:
            raise CoverArtImageIOError(e)

    @property
    def tempfile_filename(self):
        return self.datahash.filename

    def normalized_types(self):
        if self.types:
            types = sorted(set(self.types))
        elif self.is_front_image():
            types = ['front']
        else:
            types = ['-']
        return types

    def types_as_string(self, translate=True, separator=', '):
        types = self.normalized_types()
        if translate:
            types = [translate_caa_type(type) for type in types]
        return separator.join(types)
Exemple #50
0
    def _handle_errorpage(self, info, errpage):
        """Display an error page if needed.

        Loosely based on Helpviewer/HelpBrowserWV.py from eric5
        (line 260 @ 5d937eb378dd)

        Args:
            info: The QWebPage.ErrorPageExtensionOption instance.
            errpage: The QWebPage.ErrorPageExtensionReturn instance, where the
                     error page will get written to.

        Return:
            False if no error page should be displayed, True otherwise.
        """
        ignored_errors = [
            (QWebPage.QtNetwork, QNetworkReply.OperationCanceledError),
            # "Loading is handled by the media engine"
            (QWebPage.WebKit, 203),
            # "Frame load interrupted by policy change"
            (QWebPage.WebKit, 102),
        ]
        errpage.baseUrl = info.url
        urlstr = info.url.toDisplayString()
        if (info.domain, info.error) == (QWebPage.QtNetwork,
                                         QNetworkReply.ProtocolUnknownError):
            # For some reason, we get a segfault when we use
            # QDesktopServices::openUrl with info.url directly - however it
            # works when we construct a copy of it.
            url = QUrl(info.url)
            msg = "Open external application for {}-link?\nURL: {}".format(
                url.scheme(), url.toDisplayString())
            message.confirm_async(
                self._win_id, msg,
                functools.partial(QDesktopServices.openUrl, url))
            return True
        elif (info.domain, info.error) in ignored_errors:
            log.webview.debug("Ignored error on {}: {} (error domain: {}, "
                              "error code: {})".format(
                                  urlstr, info.errorString, info.domain,
                                  info.error))
            return False
        else:
            error_str = info.errorString
            if error_str == networkmanager.HOSTBLOCK_ERROR_STRING:
                # We don't set error_occurred in this case.
                error_str = "Request blocked by host blocker."
                main_frame = info.frame.page().mainFrame()
                if info.frame != main_frame:
                    # Content in an iframe -> Hide the frame so it doesn't use
                    # any space. We can't hide the frame's documentElement
                    # directly though.
                    for elem in main_frame.documentElement().findAll('iframe'):
                        if QUrl(elem.attribute('src')) == info.url:
                            elem.setAttribute('style', 'display: none')
                    return False
            else:
                self._ignore_load_started = True
                self.error_occurred = True
            log.webview.error("Error while loading {}: {}".format(
                urlstr, error_str))
            log.webview.debug("Error domain: {}, error code: {}".format(
                info.domain, info.error))
            title = "Error loading page: {}".format(urlstr)
            html = jinja.render(
                'error.html',
                title=title, url=urlstr, error=error_str, icon='')
            errpage.content = html.encode('utf-8')
            errpage.encoding = 'utf-8'
            return True
Exemple #51
0
class DownloadItem(QWidget, Ui_DownloadItem):
    """
    Class implementing a widget controlling a download.
    
    @signal statusChanged() emitted upon a status change of a download
    @signal downloadFinished() emitted when a download finished
    @signal progress(int, int) emitted to signal the download progress
    """
    statusChanged = pyqtSignal()
    downloadFinished = pyqtSignal()
    progress = pyqtSignal(int, int)
    
    Downloading = 0
    DownloadSuccessful = 1
    DownloadCancelled = 2
    
    def __init__(self, reply=None, requestFilename=False, webPage=None,
                 download=False, parent=None, mainWindow=None):
        """
        Constructor
        
        @keyparam reply reference to the network reply object (QNetworkReply)
        @keyparam requestFilename flag indicating to ask the user for a
            filename (boolean)
        @keyparam webPage reference to the web page object the download
            originated from (QWebPage)
        @keyparam download flag indicating a download operation (boolean)
        @keyparam parent reference to the parent widget (QWidget)
        @keyparam mainWindow reference to the main window (HelpWindow)
        """
        super(DownloadItem, self).__init__(parent)
        self.setupUi(self)
        
        p = self.infoLabel.palette()
        p.setColor(QPalette.Text, Qt.darkGray)
        self.infoLabel.setPalette(p)
        
        self.progressBar.setMaximum(0)
        
        self.__isFtpDownload = reply is not None and \
            reply.url().scheme() == "ftp"
        
        self.tryAgainButton.setIcon(UI.PixmapCache.getIcon("restart.png"))
        self.tryAgainButton.setEnabled(False)
        self.tryAgainButton.setVisible(False)
        self.stopButton.setIcon(UI.PixmapCache.getIcon("stopLoading.png"))
        self.pauseButton.setIcon(UI.PixmapCache.getIcon("pause.png"))
        self.openButton.setIcon(UI.PixmapCache.getIcon("open.png"))
        self.openButton.setEnabled(False)
        self.openButton.setVisible(False)
        if self.__isFtpDownload:
            self.stopButton.setEnabled(False)
            self.stopButton.setVisible(False)
            self.pauseButton.setEnabled(False)
            self.pauseButton.setVisible(False)
        
        self.__state = DownloadItem.Downloading
        
        icon = self.style().standardIcon(QStyle.SP_FileIcon)
        self.fileIcon.setPixmap(icon.pixmap(48, 48))
        
        self.__mainWindow = mainWindow
        self.__reply = reply
        self.__requestFilename = requestFilename
        self.__page = webPage
        self.__pageUrl = webPage and webPage.mainFrame().url() or QUrl()
        self.__toDownload = download
        self.__bytesReceived = 0
        self.__bytesTotal = -1
        self.__downloadTime = QTime()
        self.__output = QFile()
        self.__fileName = ""
        self.__originalFileName = ""
        self.__startedSaving = False
        self.__finishedDownloading = False
        self.__gettingFileName = False
        self.__canceledFileSelect = False
        self.__autoOpen = False
        
        self.__sha1Hash = QCryptographicHash(QCryptographicHash.Sha1)
        self.__md5Hash = QCryptographicHash(QCryptographicHash.Md5)
        
        if not requestFilename:
            self.__requestFilename = \
                Preferences.getUI("RequestDownloadFilename")
        
        self.__initialize()
    
    def __initialize(self, tryAgain=False):
        """
        Private method to (re)initialize the widget.
        
        @param tryAgain flag indicating a retry (boolean)
        """
        if self.__reply is None:
            return
        
        self.__startedSaving = False
        self.__finishedDownloading = False
        self.__bytesReceived = 0
        self.__bytesTotal = -1
        
        self.__sha1Hash.reset()
        self.__md5Hash.reset()
        
        # start timer for the download estimation
        self.__downloadTime.start()
        
        # attach to the reply object
        self.__url = self.__reply.url()
        self.__reply.setParent(self)
        self.__reply.setReadBufferSize(16 * 1024 * 1024)
        self.__reply.readyRead.connect(self.__readyRead)
        self.__reply.error.connect(self.__networkError)
        self.__reply.downloadProgress.connect(self.__downloadProgress)
        self.__reply.metaDataChanged.connect(self.__metaDataChanged)
        self.__reply.finished.connect(self.__finished)
        
        # reset info
        self.infoLabel.clear()
        self.progressBar.setValue(0)
        self.__getFileName()
        
        if self.__reply.error() != QNetworkReply.NoError:
            self.__networkError()
            self.__finished()
    
    def __getFileName(self):
        """
        Private method to get the file name to save to from the user.
        """
        if self.__gettingFileName:
            return
        
        import Helpviewer.HelpWindow
        downloadDirectory = Helpviewer.HelpWindow.HelpWindow\
            .downloadManager().downloadDirectory()
        
        if self.__fileName:
            fileName = self.__fileName
            originalFileName = self.__originalFileName
            self.__toDownload = True
            ask = False
        else:
            defaultFileName, originalFileName = \
                self.__saveFileName(downloadDirectory)
            fileName = defaultFileName
            self.__originalFileName = originalFileName
            ask = True
        self.__autoOpen = False
        if not self.__toDownload:
            from .DownloadAskActionDialog import DownloadAskActionDialog
            url = self.__reply.url()
            dlg = DownloadAskActionDialog(
                QFileInfo(originalFileName).fileName(),
                self.__reply.header(QNetworkRequest.ContentTypeHeader),
                "{0}://{1}".format(url.scheme(), url.authority()),
                self)
            if dlg.exec_() == QDialog.Rejected or dlg.getAction() == "cancel":
                self.progressBar.setVisible(False)
                self.__reply.close()
                self.on_stopButton_clicked()
                self.filenameLabel.setText(
                    self.tr("Download canceled: {0}").format(
                        QFileInfo(defaultFileName).fileName()))
                self.__canceledFileSelect = True
                return
            
            if dlg.getAction() == "scan":
                self.__mainWindow.requestVirusTotalScan(url)
                
                self.progressBar.setVisible(False)
                self.__reply.close()
                self.on_stopButton_clicked()
                self.filenameLabel.setText(
                    self.tr("VirusTotal scan scheduled: {0}").format(
                        QFileInfo(defaultFileName).fileName()))
                self.__canceledFileSelect = True
                return
            
            self.__autoOpen = dlg.getAction() == "open"
            if PYQT_VERSION_STR >= "5.0.0":
                from PyQt5.QtCore import QStandardPaths
                tempLocation = QStandardPaths.standardLocations(
                    QStandardPaths.TempLocation)[0]
            else:
                from PyQt5.QtGui import QDesktopServices
                tempLocation = QDesktopServices.storageLocation(
                    QDesktopServices.TempLocation)
            fileName = tempLocation + '/' + \
                QFileInfo(fileName).completeBaseName()
        
        if ask and not self.__autoOpen and self.__requestFilename:
            self.__gettingFileName = True
            fileName = E5FileDialog.getSaveFileName(
                None,
                self.tr("Save File"),
                defaultFileName,
                "")
            self.__gettingFileName = False
            if not fileName:
                self.progressBar.setVisible(False)
                self.__reply.close()
                self.on_stopButton_clicked()
                self.filenameLabel.setText(
                    self.tr("Download canceled: {0}")
                        .format(QFileInfo(defaultFileName).fileName()))
                self.__canceledFileSelect = True
                return
        
        fileInfo = QFileInfo(fileName)
        Helpviewer.HelpWindow.HelpWindow.downloadManager()\
            .setDownloadDirectory(fileInfo.absoluteDir().absolutePath())
        self.filenameLabel.setText(fileInfo.fileName())
        
        self.__output.setFileName(fileName + ".part")
        self.__fileName = fileName
        
        # check file path for saving
        saveDirPath = QFileInfo(self.__fileName).dir()
        if not saveDirPath.exists():
            if not saveDirPath.mkpath(saveDirPath.absolutePath()):
                self.progressBar.setVisible(False)
                self.on_stopButton_clicked()
                self.infoLabel.setText(self.tr(
                    "Download directory ({0}) couldn't be created.")
                    .format(saveDirPath.absolutePath()))
                return
        
        self.filenameLabel.setText(QFileInfo(self.__fileName).fileName())
        if self.__requestFilename:
            self.__readyRead()
    
    def __saveFileName(self, directory):
        """
        Private method to calculate a name for the file to download.
        
        @param directory name of the directory to store the file into (string)
        @return proposed filename and original filename (string, string)
        """
        path = parseContentDisposition(self.__reply)
        info = QFileInfo(path)
        baseName = info.completeBaseName()
        endName = info.suffix()
        
        origName = baseName
        if endName:
            origName += '.' + endName
        
        name = directory + baseName
        if endName:
            name += '.' + endName
            if not self.__requestFilename:
                # do not overwrite, if the user is not being asked
                i = 1
                while QFile.exists(name):
                    # file exists already, don't overwrite
                    name = directory + baseName + ('-{0:d}'.format(i))
                    if endName:
                        name += '.' + endName
                    i += 1
        return name, origName
    
    def __open(self):
        """
        Private slot to open the downloaded file.
        """
        info = QFileInfo(self.__output)
        url = QUrl.fromLocalFile(info.absoluteFilePath())
        QDesktopServices.openUrl(url)
    
    @pyqtSlot()
    def on_tryAgainButton_clicked(self):
        """
        Private slot to retry the download.
        """
        self.retry()
    
    def retry(self):
        """
        Public slot to retry the download.
        """
        if not self.tryAgainButton.isEnabled():
            return
        
        self.tryAgainButton.setEnabled(False)
        self.tryAgainButton.setVisible(False)
        self.openButton.setEnabled(False)
        self.openButton.setVisible(False)
        if not self.__isFtpDownload:
            self.stopButton.setEnabled(True)
            self.stopButton.setVisible(True)
            self.pauseButton.setEnabled(True)
            self.pauseButton.setVisible(True)
        self.progressBar.setVisible(True)
        
        if self.__page:
            nam = self.__page.networkAccessManager()
        else:
            import Helpviewer.HelpWindow
            nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager()
        reply = nam.get(QNetworkRequest(self.__url))
        if self.__output.exists():
            self.__output.remove()
        self.__output = QFile()
        self.__reply = reply
        self.__initialize(tryAgain=True)
        self.__state = DownloadItem.Downloading
        self.statusChanged.emit()
    
    @pyqtSlot(bool)
    def on_pauseButton_clicked(self, checked):
        """
        Private slot to pause the download.
        
        @param checked flag indicating the state of the button (boolean)
        """
        if checked:
            self.__reply.readyRead.disconnect(self.__readyRead)
            self.__reply.setReadBufferSize(16 * 1024)
        else:
            self.__reply.readyRead.connect(self.__readyRead)
            self.__reply.setReadBufferSize(16 * 1024 * 1024)
            self.__readyRead()
    
    @pyqtSlot()
    def on_stopButton_clicked(self):
        """
        Private slot to stop the download.
        """
        self.cancelDownload()
    
    def cancelDownload(self):
        """
        Public slot to stop the download.
        """
        self.setUpdatesEnabled(False)
        if not self.__isFtpDownload:
            self.stopButton.setEnabled(False)
            self.stopButton.setVisible(False)
            self.pauseButton.setEnabled(False)
            self.pauseButton.setVisible(False)
        self.tryAgainButton.setEnabled(True)
        self.tryAgainButton.setVisible(True)
        self.openButton.setEnabled(False)
        self.openButton.setVisible(False)
        self.setUpdatesEnabled(True)
        self.__state = DownloadItem.DownloadCancelled
        self.__reply.abort()
        self.downloadFinished.emit()
    
    @pyqtSlot()
    def on_openButton_clicked(self):
        """
        Private slot to open the downloaded file.
        """
        self.openFile()
    
    def openFile(self):
        """
        Public slot to open the downloaded file.
        """
        info = QFileInfo(self.__fileName)
        url = QUrl.fromLocalFile(info.absoluteFilePath())
        QDesktopServices.openUrl(url)
    
    def openFolder(self):
        """
        Public slot to open the folder containing the downloaded file.
        """
        info = QFileInfo(self.__fileName)
        url = QUrl.fromLocalFile(info.absolutePath())
        QDesktopServices.openUrl(url)
    
    def __readyRead(self):
        """
        Private slot to read the available data.
        """
        if self.__requestFilename and not self.__output.fileName():
            return
        
        if not self.__output.isOpen():
            # in case someone else has already put a file there
            if not self.__requestFilename:
                self.__getFileName()
            if not self.__output.open(QIODevice.WriteOnly):
                self.infoLabel.setText(
                    self.tr("Error opening save file: {0}")
                    .format(self.__output.errorString()))
                self.on_stopButton_clicked()
                self.statusChanged.emit()
                return
            self.statusChanged.emit()
        
        buffer = self.__reply.readAll()
        self.__sha1Hash.addData(buffer)
        self.__md5Hash.addData(buffer)
        bytesWritten = self.__output.write(buffer)
        if bytesWritten == -1:
            self.infoLabel.setText(
                self.tr("Error saving: {0}")
                    .format(self.__output.errorString()))
            self.on_stopButton_clicked()
        else:
            self.__startedSaving = True
            if self.__finishedDownloading:
                self.__finished()
    
    def __networkError(self):
        """
        Private slot to handle a network error.
        """
        self.infoLabel.setText(
            self.tr("Network Error: {0}")
                .format(self.__reply.errorString()))
        self.tryAgainButton.setEnabled(True)
        self.tryAgainButton.setVisible(True)
        self.downloadFinished.emit()
    
    def __metaDataChanged(self):
        """
        Private slot to handle a change of the meta data.
        """
        locationHeader = self.__reply.header(QNetworkRequest.LocationHeader)
        if locationHeader and locationHeader.isValid():
            self.__url = QUrl(locationHeader)
            import Helpviewer.HelpWindow
            self.__reply = Helpviewer.HelpWindow.HelpWindow\
                .networkAccessManager().get(QNetworkRequest(self.__url))
            self.__initialize()
    
    def __downloadProgress(self, bytesReceived, bytesTotal):
        """
        Private method to show the download progress.
        
        @param bytesReceived number of bytes received (integer)
        @param bytesTotal number of total bytes (integer)
        """
        self.__bytesReceived = bytesReceived
        self.__bytesTotal = bytesTotal
        currentValue = 0
        totalValue = 0
        if bytesTotal > 0:
            currentValue = bytesReceived * 100 / bytesTotal
            totalValue = 100
        self.progressBar.setValue(currentValue)
        self.progressBar.setMaximum(totalValue)
        
        self.progress.emit(currentValue, totalValue)
        self.__updateInfoLabel()
    
    def bytesTotal(self):
        """
        Public method to get the total number of bytes of the download.
        
        @return total number of bytes (integer)
        """
        if self.__bytesTotal == -1:
            self.__bytesTotal = self.__reply.header(
                QNetworkRequest.ContentLengthHeader)
            if self.__bytesTotal is None:
                self.__bytesTotal = -1
        return self.__bytesTotal
    
    def bytesReceived(self):
        """
        Public method to get the number of bytes received.
        
        @return number of bytes received (integer)
        """
        return self.__bytesReceived
    
    def remainingTime(self):
        """
        Public method to get an estimation for the remaining time.
        
        @return estimation for the remaining time (float)
        """
        if not self.downloading():
            return -1.0
        
        if self.bytesTotal() == -1:
            return -1.0
        
        cSpeed = self.currentSpeed()
        if cSpeed != 0:
            timeRemaining = (self.bytesTotal() - self.bytesReceived()) / cSpeed
        else:
            timeRemaining = 1
        
        # ETA should never be 0
        if timeRemaining == 0:
            timeRemaining = 1
        
        return timeRemaining
    
    def currentSpeed(self):
        """
        Public method to get an estimation for the download speed.
        
        @return estimation for the download speed (float)
        """
        if not self.downloading():
            return -1.0
        
        return self.__bytesReceived * 1000.0 / self.__downloadTime.elapsed()
    
    def __updateInfoLabel(self):
        """
        Private method to update the info label.
        """
        if self.__reply.error() != QNetworkReply.NoError:
            return
        
        bytesTotal = self.bytesTotal()
        running = not self.downloadedSuccessfully()
        
        speed = self.currentSpeed()
        timeRemaining = self.remainingTime()
        
        info = ""
        if running:
            remaining = ""
            
            if bytesTotal > 0:
                remaining = timeString(timeRemaining)
            
            info = self.tr("{0} of {1} ({2}/sec)\n{3}")\
                .format(
                    dataString(self.__bytesReceived),
                    bytesTotal == -1 and self.tr("?")
                    or dataString(bytesTotal),
                    dataString(int(speed)),
                    remaining)
        else:
            if self.__bytesReceived == bytesTotal or bytesTotal == -1:
                info = self.tr("{0} downloaded\nSHA1: {1}\nMD5: {2}")\
                    .format(dataString(self.__output.size()),
                            str(self.__sha1Hash.result().toHex(),
                                encoding="ascii"),
                            str(self.__md5Hash.result().toHex(),
                                encoding="ascii")
                            )
            else:
                info = self.tr("{0} of {1} - Stopped")\
                    .format(dataString(self.__bytesReceived),
                            dataString(bytesTotal))
        self.infoLabel.setText(info)
    
    def downloading(self):
        """
        Public method to determine, if a download is in progress.
        
        @return flag indicating a download is in progress (boolean)
        """
        return self.__state == DownloadItem.Downloading
    
    def downloadedSuccessfully(self):
        """
        Public method to check for a successful download.
        
        @return flag indicating a successful download (boolean)
        """
        return self.__state == DownloadItem.DownloadSuccessful
    
    def downloadCanceled(self):
        """
        Public method to check, if the download was cancelled.
        
        @return flag indicating a canceled download (boolean)
        """
        return self.__state == DownloadItem.DownloadCancelled
    
    def __finished(self):
        """
        Private slot to handle the download finished.
        """
        self.__finishedDownloading = True
        if not self.__startedSaving:
            return
        
        noError = self.__reply.error() == QNetworkReply.NoError
        
        self.progressBar.setVisible(False)
        if not self.__isFtpDownload:
            self.stopButton.setEnabled(False)
            self.stopButton.setVisible(False)
            self.pauseButton.setEnabled(False)
            self.pauseButton.setVisible(False)
        self.openButton.setEnabled(noError)
        self.openButton.setVisible(noError)
        self.__output.close()
        if QFile.exists(self.__fileName):
            QFile.remove(self.__fileName)
        self.__output.rename(self.__fileName)
        self.__updateInfoLabel()
        self.__state = DownloadItem.DownloadSuccessful
        self.statusChanged.emit()
        self.downloadFinished.emit()
        
        if self.__autoOpen:
            self.__open()
    
    def canceledFileSelect(self):
        """
        Public method to check, if the user canceled the file selection.
        
        @return flag indicating cancellation (boolean)
        """
        return self.__canceledFileSelect
    
    def setIcon(self, icon):
        """
        Public method to set the download icon.
        
        @param icon reference to the icon to be set (QIcon)
        """
        self.fileIcon.setPixmap(icon.pixmap(48, 48))
    
    def fileName(self):
        """
        Public method to get the name of the output file.
        
        @return name of the output file (string)
        """
        return self.__fileName
    
    def absoluteFilePath(self):
        """
        Public method to get the absolute path of the output file.
        
        @return absolute path of the output file (string)
        """
        return QFileInfo(self.__fileName).absoluteFilePath()
    
    def getData(self):
        """
        Public method to get the relevant download data.
        
        @return tuple of URL, save location, flag and the
            URL of the related web page (QUrl, string, boolean,QUrl)
        """
        return (self.__url, QFileInfo(self.__fileName).filePath(),
                self.downloadedSuccessfully(), self.__pageUrl)
    
    def setData(self, data):
        """
        Public method to set the relevant download data.
        
        @param data tuple of URL, save location, flag and the
            URL of the related web page (QUrl, string, boolean, QUrl)
        """
        self.__url = data[0]
        self.__fileName = data[1]
        self.__pageUrl = data[3]
        self.__isFtpDownload = self.__url.scheme() == "ftp"
        
        self.filenameLabel.setText(QFileInfo(self.__fileName).fileName())
        self.infoLabel.setText(self.__fileName)
        
        self.stopButton.setEnabled(False)
        self.stopButton.setVisible(False)
        self.pauseButton.setEnabled(False)
        self.pauseButton.setVisible(False)
        self.openButton.setEnabled(data[2])
        self.openButton.setVisible(data[2])
        self.tryAgainButton.setEnabled(not data[2])
        self.tryAgainButton.setVisible(not data[2])
        if data[2]:
            self.__state = DownloadItem.DownloadSuccessful
        else:
            self.__state = DownloadItem.DownloadCancelled
        self.progressBar.setVisible(False)
    
    def getInfoData(self):
        """
        Public method to get the text of the info label.
        
        @return text of the info label (string)
        """
        return self.infoLabel.text()
    
    def getPageUrl(self):
        """
        Public method to get the URL of the download page.
        
        @return URL of the download page (QUrl)
        """
        return self.__pageUrl
    def queryProxy(self, query):
        """
        Public method to determine a proxy for a given query.
        
        @param query reference to the query object (QNetworkProxyQuery)
        @return list of proxies in order of preference (list of QNetworkProxy)
        """
        if query.queryType() == QNetworkProxyQuery.UrlRequest and query.protocolTag() in ["http", "https", "ftp"]:
            # use proxy at all ?
            if not Preferences.getUI("UseProxy"):
                return [QNetworkProxy(QNetworkProxy.NoProxy)]

            # test for exceptions
            exceptions = Preferences.getUI("ProxyExceptions")
            if exceptions != self.__exceptions:
                self.__setExceptions(exceptions)
            urlHost = query.url().host()
            for matcher in self.__hostnameMatchers:
                if matcher.match(urlHost):
                    return [QNetworkProxy(QNetworkProxy.NoProxy)]

            # determine proxy
            if Preferences.getUI("UseSystemProxy"):
                proxyList = QNetworkProxyFactory.systemProxyForQuery(query)
                if (
                    not Globals.isWindowsPlatform()
                    and len(proxyList) == 1
                    and proxyList[0].type() == QNetworkProxy.NoProxy
                ):
                    # try it the Python way
                    # scan the environment for variables named <scheme>_proxy
                    # scan over whole environment to make this case insensitive
                    for name, value in os.environ.items():
                        name = name.lower()
                        if value and name[-6:] == "_proxy" and name[:-6] == query.protocolTag().lower():
                            url = QUrl(value)
                            if url.scheme() == "http":
                                proxyType = QNetworkProxy.HttpProxy
                            elif url.scheme() == "https":
                                proxyType = QNetworkProxy.HttpCachingProxy
                            elif url.scheme() == "ftp":
                                proxyType = QNetworkProxy.FtpCachingProxy
                            else:
                                proxyType = QNetworkProxy.HttpProxy
                            proxy = QNetworkProxy(proxyType, url.host(), url.port(), url.userName(), url.password())
                            proxyList = [proxy]
                            break
                if proxyList:
                    scheme = schemeFromProxyType(proxyList[0].type())
                    if scheme == "":
                        scheme = "Http"
                    if scheme != "NoProxy":
                        proxyList[0].setUser(Preferences.getUI("ProxyUser/{0}".format(scheme)))
                        proxyList[0].setPassword(Preferences.getUI("ProxyPassword/{0}".format(scheme)))
                    return proxyList
                else:
                    return [QNetworkProxy(QNetworkProxy.NoProxy)]
            else:
                if Preferences.getUI("UseHttpProxyForAll"):
                    protocolKey = "Http"
                else:
                    protocolKey = query.protocolTag().capitalize()
                host = Preferences.getUI("ProxyHost/{0}".format(protocolKey))
                if not host:
                    E5MessageBox.critical(
                        None,
                        QCoreApplication.translate("E5NetworkProxyFactory", "Proxy Configuration Error"),
                        QCoreApplication.translate(
                            "E5NetworkProxyFactory",
                            """Proxy usage was activated"""
                            """ but no proxy host for protocol"""
                            """ '{0}' configured.""",
                        ).format(protocolKey),
                    )
                    return [QNetworkProxy(QNetworkProxy.DefaultProxy)]
                else:
                    if protocolKey in ["Http", "Https", "Ftp"]:
                        if query.protocolTag() == "ftp":
                            proxyType = QNetworkProxy.FtpCachingProxy
                        elif query.protocolTag() == "https":
                            proxyType = QNetworkProxy.HttpCachingProxy
                        else:
                            proxyType = QNetworkProxy.HttpProxy
                        proxy = QNetworkProxy(
                            proxyType,
                            host,
                            Preferences.getUI("ProxyPort/" + protocolKey),
                            Preferences.getUI("ProxyUser/" + protocolKey),
                            Preferences.getUI("ProxyPassword/" + protocolKey),
                        )
                    else:
                        proxy = QNetworkProxy(QNetworkProxy.DefaultProxy)
                    return [proxy, QNetworkProxy(QNetworkProxy.DefaultProxy)]
        else:
            return [QNetworkProxy(QNetworkProxy.NoProxy)]