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
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
def acceptNavigationRequest(self, url: QUrl, _type: QWebEnginePage.NavigationType, isMainFrame: bool) -> bool: if url.scheme() == "qrc": return True QDesktopServices.openUrl(url) return False
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())
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)
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
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()
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())
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
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
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)
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)
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)
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()
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
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()
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
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
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
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
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)
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()
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)
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!")
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))
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))
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!")
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)
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!"
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!"
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)
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)
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!"
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
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
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)
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
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)
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')
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)
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
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)
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
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)]