wizard no longer crashes if selection menu reloaded

wizard now caches icons so no duplication of requests
enforcement of dependencies partially implemented
allowed redirection of all network requests
This commit is contained in:
Brennen Raimer
2019-04-30 12:55:41 -04:00
parent 1f426ea6ae
commit 2571e097e2

View File

@@ -34,6 +34,7 @@ class InstallerWizard(QtWidgets.QWizard):
self.selection_page.initializePage = self._load_tools self.selection_page.initializePage = self._load_tools
self.intro.anchorClicked.connect(self._link_clicked) self.intro.anchorClicked.connect(self._link_clicked)
self.license.anchorClicked.connect(self._link_clicked) self.license.anchorClicked.connect(self._link_clicked)
self.selection_menu.itemClicked.connect(self._enforce_dependencies)
self.install_location.setValidator(Location_Validator(parent=self)) self.install_location.setValidator(Location_Validator(parent=self))
self.location_page.registerField("Location*", self.install_location) self.location_page.registerField("Location*", self.install_location)
self.browse_button.clicked.connect(self._select_location) self.browse_button.clicked.connect(self._select_location)
@@ -95,6 +96,7 @@ class InstallerWizard(QtWidgets.QWizard):
if self._network_manager.networkAccessible(): if self._network_manager.networkAccessible():
request = QtNetwork.QNetworkRequest(QtCore.QUrl("https://www.gnu.org/licenses/gpl-3.0-standalone.html")) request = QtNetwork.QNetworkRequest(QtCore.QUrl("https://www.gnu.org/licenses/gpl-3.0-standalone.html"))
request.setAttribute(QtNetwork.QNetworkRequest.CacheLoadControlAttribute, QtNetwork.QNetworkRequest.AlwaysNetwork) request.setAttribute(QtNetwork.QNetworkRequest.CacheLoadControlAttribute, QtNetwork.QNetworkRequest.AlwaysNetwork)
request.setAttribute(QtNetwork.QNetworkRequest.FollowRedirectsAttribute, True)
reply = self._network_manager.get(request) reply = self._network_manager.get(request)
reply.downloadProgress.connect(lambda received, total: process_dialog.setMaximum(total)) reply.downloadProgress.connect(lambda received, total: process_dialog.setMaximum(total))
reply.downloadProgress.connect(lambda received, total: process_dialog.setValue(received)) reply.downloadProgress.connect(lambda received, total: process_dialog.setValue(received))
@@ -147,8 +149,15 @@ class InstallerWizard(QtWidgets.QWizard):
process_dialog.setAutoClose(True) process_dialog.setAutoClose(True)
process_dialog.setAutoReset(True) process_dialog.setAutoReset(True)
process_dialog.setCancelButton(None) process_dialog.setCancelButton(None)
try: #clear data from this page before reloading
self.__tools__ = None
self._icon_cache = {item.text(0):item.icon(0) for item in list(MenuIterator(self.selection_menu, QtWidgets.QTreeWidgetItemIterator.NoChildren))}
self.selection_menu.clear()
except NameError:
pass
request = QtNetwork.QNetworkRequest(QtCore.QUrl("https://raw.githubusercontent.com/norweeg/portable-computing-toolkit-installer/initial_dev/portable_computing_toolkit_installer/resources/supported_tools.json")) request = QtNetwork.QNetworkRequest(QtCore.QUrl("https://raw.githubusercontent.com/norweeg/portable-computing-toolkit-installer/initial_dev/portable_computing_toolkit_installer/resources/supported_tools.json"))
request.setAttribute(QtNetwork.QNetworkRequest.CacheLoadControlAttribute, QtNetwork.QNetworkRequest.AlwaysNetwork) request.setAttribute(QtNetwork.QNetworkRequest.CacheLoadControlAttribute, QtNetwork.QNetworkRequest.AlwaysNetwork)
request.setAttribute(QtNetwork.QNetworkRequest.FollowRedirectsAttribute, True)
reply = self._network_manager.get(request) reply = self._network_manager.get(request)
reply.downloadProgress.connect(lambda received, total: process_dialog.setMaximum(total)) reply.downloadProgress.connect(lambda received, total: process_dialog.setMaximum(total))
reply.downloadProgress.connect(lambda received, total: process_dialog.setValue(received)) reply.downloadProgress.connect(lambda received, total: process_dialog.setValue(received))
@@ -163,7 +172,6 @@ class InstallerWizard(QtWidgets.QWizard):
self._display_error(f"Unable to decode {request.url.toString()}", e).accepted.connect(self.back) self._display_error(f"Unable to decode {request.url.toString()}", e).accepted.connect(self.back)
else: else:
self._populate_menu() self._populate_menu()
self.selection_menu.itemSelectionChanged.connect(self._enforce_dependencies)
else: else:
self._display_error(f"Encountered an error while loading supported tools from {request.url().toString()}", reply.errorString()).finished.connect(lambda x: self.back()) self._display_error(f"Encountered an error while loading supported tools from {request.url().toString()}", reply.errorString()).finished.connect(lambda x: self.back())
@@ -202,9 +210,12 @@ class InstallerWizard(QtWidgets.QWizard):
new_item.setData(1, QtCore.Qt.DecorationRole, QtGui.QIcon(str(Path(__file__).parent.parent/"resources/icons/internet-web-browser-4.png"))) new_item.setData(1, QtCore.Qt.DecorationRole, QtGui.QIcon(str(Path(__file__).parent.parent/"resources/icons/internet-web-browser-4.png")))
new_item.setData(1, QtCore.Qt.ToolTipRole, tool["homepage"]) new_item.setData(1, QtCore.Qt.ToolTipRole, tool["homepage"])
try: try:
self._get_icon(new_item, tool["icon url"]) new_item.setIcon(0, self._icon_cache[new_item.text(0)])
except KeyError: except (AttributeError, KeyError):
self._get_icon(new_item) try:
self._get_icon(new_item, tool["icon url"])
except KeyError:
self._get_icon(new_item)
try: try:
if tool["depends on"] == current_level: #tool depends on itself makes it mandatory if tool["depends on"] == current_level: #tool depends on itself makes it mandatory
new_item.setFlags(new_item.flags()^QtCore.Qt.ItemIsUserCheckable) new_item.setFlags(new_item.flags()^QtCore.Qt.ItemIsUserCheckable)
@@ -244,20 +255,24 @@ class InstallerWizard(QtWidgets.QWizard):
""" """
if not icon_url: if not icon_url:
icon_url = QtCore.QUrl(f"http://www.google.com/s2/favicons?domain={QtCore.QUrl(tree_item.data(1, QtCore.Qt.ToolTipRole)).toString()}") icon_url = QtCore.QUrl(f"http://www.google.com/s2/favicons?domain={QtCore.QUrl(tree_item.data(1, QtCore.Qt.ToolTipRole)).toString()}")
icon_request = self._network_manager.get(QtNetwork.QNetworkRequest(QtCore.QUrl(icon_url))) icon_request = QtNetwork.QNetworkRequest(QtCore.QUrl(icon_url))
icon_request.setAttribute(QtNetwork.QNetworkRequest.CacheLoadControlAttribute, QtNetwork.QNetworkRequest.AlwaysNetwork)
icon_request.setAttribute(QtNetwork.QNetworkRequest.FollowRedirectsAttribute, True)
icon_reply = self._network_manager.get(icon_request)
#when download is complete, validates request returned without error and sets icon #when download is complete, validates request returned without error and sets icon
icon_request.finished.connect(partial(self._set_icon, tree_item, icon_request)) icon_reply.finished.connect(partial(self._set_icon, tree_item, icon_reply))
icon_reply.error.connect(lambda error: self._display_error(QtCore.QMetaEnum.valueToKey(error)))
def _set_icon(self, tree_item, request): def _set_icon(self, tree_item, reply):
"""Validates a network request and sets its result as the icon of a QTreeWidgetItem. """Validates a network request and sets its result as the icon of a QTreeWidgetItem.
Arguments: Arguments:
tree_item {QTreeWidgetItem} -- A tree widget item to set the icon of tree_item {QTreeWidgetItem} -- A tree widget item to set the icon of
request {QNetworkReply} -- The results of the HTTP GET request whose data will be used as the icon for tree_item request {QNetworkReply} -- The results of the HTTP GET request whose data will be used as the icon for tree_item
""" """
if not request.error(): if not reply.error():
pixmap = QtGui.QPixmap() pixmap = QtGui.QPixmap()
pixmap.loadFromData(request.readAll()) pixmap.loadFromData(reply.readAll())
tree_item.setIcon(0, QtGui.QIcon(pixmap)) tree_item.setIcon(0, QtGui.QIcon(pixmap))
def _get_selections(self): def _get_selections(self):
@@ -265,15 +280,17 @@ class InstallerWizard(QtWidgets.QWizard):
""" """
return list(MenuIterator(self.selection_menu, QtWidgets.QTreeWidgetItemIterator.Checked|QtWidgets.QTreeWidgetItemIterator.NoChildren)) return list(MenuIterator(self.selection_menu, QtWidgets.QTreeWidgetItemIterator.Checked|QtWidgets.QTreeWidgetItemIterator.NoChildren))
@QtCore.pyqtSlot() @QtCore.pyqtSlot("QTreeWidgetItem*","int")
def _enforce_dependencies(self): def _enforce_dependencies(self, item, column):
for tool in self._get_selections(): #if item is checked, look for dependent items and check them too
if item.checkState(0) == QtCore.Qt.Checked:
tools_by_name = {tool["name"]:tool for tool in self.__tools__}
try: try:
dependencies = tool["depends on"].split(",") dependencies = tools_by_name[item.text(0)]["depends on"].split(",")
except KeyError: except KeyError:
continue pass
else: else:
for dependency in [self.selection_menu.findItems(item, QtCore.Qt.MatchFixedString|QtCore.Qt.MatchCaseSensitive|QtCore.Qt.MatchRecursive) for item in dependencies]: for dependency in dependencies:
dependency.setSelected(True) for dependant_item in self.selection_menu.findItems(dependency, QtCore.Qt.MatchFixedString|QtCore.Qt.MatchCaseSensitive|QtCore.Qt.MatchRecursive):
dependency.setHidden(False) dependant_item.setCheckState(0, QtCore.Qt.Checked)