CURA-5137 Create the Cura Packages Model for the Toolbox.

Fetch the data from the new server and create the model for show in the
toolbox.
This commit is contained in:
Diego Prado Gesto 2018-04-03 11:21:15 +02:00
parent 89c27ae7f4
commit 3d452d334b
2 changed files with 101 additions and 23 deletions

View file

@ -0,0 +1,71 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Dict
from PyQt5.QtCore import Qt, pyqtProperty, pyqtSignal
from UM.Qt.ListModel import ListModel
## Model that holds cura packages. By setting the filter property the instances held by this model can be changed.
class CuraPackageModel(ListModel):
IdRole = Qt.UserRole + 1
TypeRole = Qt.UserRole + 2
NameRole = Qt.UserRole + 3
VersionRole = Qt.UserRole + 4
AuthorRole = Qt.UserRole + 5
DescriptionRole = Qt.UserRole + 6
IconURLRole = Qt.UserRole + 7
ImageURLsRole = Qt.UserRole + 8
def __init__(self, parent = None):
super().__init__(parent)
self._packages_metadata = None
self.addRoleName(CuraPackageModel.IdRole, "id")
self.addRoleName(CuraPackageModel.TypeRole, "type")
self.addRoleName(CuraPackageModel.NameRole, "name")
self.addRoleName(CuraPackageModel.VersionRole, "version")
self.addRoleName(CuraPackageModel.AuthorRole, "author")
self.addRoleName(CuraPackageModel.DescriptionRole, "description")
self.addRoleName(CuraPackageModel.IconURLRole, "icon_url")
self.addRoleName(CuraPackageModel.ImageURLsRole, "image_urls")
# List of filters for queries. The result is the union of the each list of results.
self._filter = None # type: Dict[str,str]
def setPackagesMetaData(self, data):
self._packages_metadata = data
self._update()
def _update(self):
items = []
for package in self._packages_metadata:
items.append({
"id": package["package_id"],
"type": package["package_type"],
"name": package["display_name"],
"version": package["package_version"],
"author": package["author"],
"description": package["description"],
"icon_url": package["icon_url"] if "icon_url" in package else None,
"image_urls": package["image_urls"]
})
items.sort(key = lambda k: k["name"])
self.setItems(items)
filterChanged = pyqtSignal()
## Set the filter of this model based on a string.
# \param filter_dict \type{Dict} Dictionary to do the filtering by.
def setFilter(self, filter_dict: Dict[str, str]) -> None:
if filter_dict != self._filter:
self._filter = filter_dict
self.filterChanged.emit()
@pyqtProperty("QVariantMap", fset = setFilter, notify = filterChanged)
def filter(self) -> Dict[str, str]:
return self._filter

View file

@ -1,5 +1,6 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Toolbox is released under the terms of the LGPLv3 or higher. # Toolbox is released under the terms of the LGPLv3 or higher.
from typing import Dict
from PyQt5.QtCore import QUrl, QObject, pyqtProperty, pyqtSignal, pyqtSlot from PyQt5.QtCore import QUrl, QObject, pyqtProperty, pyqtSignal, pyqtSlot
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
@ -21,6 +22,7 @@ import platform
import zipfile import zipfile
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from .CuraPackageModel import CuraPackageModel
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
@ -32,16 +34,17 @@ class Toolbox(QObject, Extension):
self._api_version = 1 self._api_version = 1
self._api_url = "https://api-staging.ultimaker.com/cura-packages/v%s/" % self._api_version self._api_url = "https://api-staging.ultimaker.com/cura-packages/v%s/" % self._api_version
self._plugin_list_request = None self._package_list_request = None
self._download_plugin_request = None self._download_plugin_request = None
self._download_plugin_reply = None self._download_plugin_reply = None
self._network_manager = None self._network_manager = None
self._plugin_registry = Application.getInstance().getPluginRegistry() self._plugin_registry = Application.getInstance().getPluginRegistry()
self._packages_version_number = self._plugin_registry.APIVersion
self._plugins_metadata = [] self._packages_metadata = []
self._plugins_model = None self._packages_model = None
# Can be 'installed' or 'available' # Can be 'installed' or 'available'
self._view = "available" self._view = "available"
@ -82,7 +85,7 @@ class Toolbox(QObject, Extension):
showLicenseDialog = pyqtSignal() showLicenseDialog = pyqtSignal()
showRestartDialog = pyqtSignal() showRestartDialog = pyqtSignal()
pluginsMetadataChanged = pyqtSignal() packagesMetadataChanged = pyqtSignal()
onDownloadProgressChanged = pyqtSignal() onDownloadProgressChanged = pyqtSignal()
onIsDownloadingChanged = pyqtSignal() onIsDownloadingChanged = pyqtSignal()
restartRequiredChanged = pyqtSignal() restartRequiredChanged = pyqtSignal()
@ -129,12 +132,11 @@ class Toolbox(QObject, Extension):
self._dialog.show() self._dialog.show()
def requestPackageList(self): def requestPackageList(self):
cura_version = 4
Logger.log("i", "Requesting package list") Logger.log("i", "Requesting package list")
url = QUrl(self._api_url + "packages?cura_version={version}".format(version = cura_version)) url = QUrl("{base_url}packages?cura_version={version}".format(base_url = self._api_url, version = self._packages_version_number))
self._plugin_list_request = QNetworkRequest(url) self._package_list_request = QNetworkRequest(url)
self._plugin_list_request.setRawHeader(*self._request_header) self._package_list_request.setRawHeader(*self._request_header)
self._network_manager.get(self._plugin_list_request) self._network_manager.get(self._package_list_request)
def _createDialog(self, qml_name): def _createDialog(self, qml_name):
Logger.log("d", "Creating dialog [%s]", qml_name) Logger.log("d", "Creating dialog [%s]", qml_name)
@ -218,7 +220,7 @@ class Toolbox(QObject, Extension):
result = PluginRegistry.getInstance().installPlugin("file://" + location) result = PluginRegistry.getInstance().installPlugin("file://" + location)
self._newly_installed_plugin_ids.append(result["id"]) self._newly_installed_plugin_ids.append(result["id"])
self.pluginsMetadataChanged.emit() self.packagesMetadataChanged.emit()
self.openRestartDialog(result["message"]) self.openRestartDialog(result["message"])
self._restart_required = True self._restart_required = True
@ -229,7 +231,7 @@ class Toolbox(QObject, Extension):
result = PluginRegistry.getInstance().uninstallPlugin(plugin_id) result = PluginRegistry.getInstance().uninstallPlugin(plugin_id)
self._newly_uninstalled_plugin_ids.append(result["id"]) self._newly_uninstalled_plugin_ids.append(result["id"])
self.pluginsMetadataChanged.emit() self.packagesMetadataChanged.emit()
self._restart_required = True self._restart_required = True
self.restartRequiredChanged.emit() self.restartRequiredChanged.emit()
@ -239,13 +241,13 @@ class Toolbox(QObject, Extension):
@pyqtSlot(str) @pyqtSlot(str)
def enablePlugin(self, plugin_id): def enablePlugin(self, plugin_id):
self._plugin_registry.enablePlugin(plugin_id) self._plugin_registry.enablePlugin(plugin_id)
self.pluginsMetadataChanged.emit() self.packagesMetadataChanged.emit()
Logger.log("i", "%s was set as 'active'", id) Logger.log("i", "%s was set as 'active'", id)
@pyqtSlot(str) @pyqtSlot(str)
def disablePlugin(self, plugin_id): def disablePlugin(self, plugin_id):
self._plugin_registry.disablePlugin(plugin_id) self._plugin_registry.disablePlugin(plugin_id)
self.pluginsMetadataChanged.emit() self.packagesMetadataChanged.emit()
Logger.log("i", "%s was set as 'deactive'", id) Logger.log("i", "%s was set as 'deactive'", id)
@pyqtProperty(int, notify = onDownloadProgressChanged) @pyqtProperty(int, notify = onDownloadProgressChanged)
@ -283,7 +285,7 @@ class Toolbox(QObject, Extension):
def setView(self, view = "available"): def setView(self, view = "available"):
self._view = view self._view = view
self.viewChanged.emit() self.viewChanged.emit()
self.pluginsMetadataChanged.emit() self.packagesMetadataChanged.emit()
@pyqtProperty(str, notify = viewChanged) @pyqtProperty(str, notify = viewChanged)
def viewing(self): def viewing(self):
@ -293,13 +295,13 @@ class Toolbox(QObject, Extension):
def setDetailView(self, item = ""): def setDetailView(self, item = ""):
self._detail_view = item self._detail_view = item
self.detailViewChanged.emit() self.detailViewChanged.emit()
self.pluginsMetadataChanged.emit() self.packagesMetadataChanged.emit()
@pyqtProperty(str, notify = detailViewChanged) @pyqtProperty(str, notify = detailViewChanged)
def detailView(self): def detailView(self):
return self._detail_view return self._detail_view
@pyqtProperty(QObject, notify = pluginsMetadataChanged) @pyqtProperty(QObject, notify = packagesMetadataChanged)
def pluginsModel(self): def pluginsModel(self):
self._plugins_model = PluginsModel(None, self._view) self._plugins_model = PluginsModel(None, self._view)
# self._plugins_model.update() # self._plugins_model.update()
@ -311,20 +313,22 @@ class Toolbox(QObject, Extension):
if self._checkCanUpgrade(plugin["id"], plugin["version"]): if self._checkCanUpgrade(plugin["id"], plugin["version"]):
plugin["can_upgrade"] = True plugin["can_upgrade"] = True
for item in self._plugins_metadata: for item in self._packages_metadata:
if item["id"] == plugin["id"]: if item["id"] == plugin["id"]:
plugin["update_url"] = item["file_location"] plugin["update_url"] = item["file_location"]
return self._plugins_model return self._plugins_model
@pyqtProperty(QObject, notify = packagesMetadataChanged)
def packagesModel(self):
return self._packages_model
def _checkCanUpgrade(self, id, version): def _checkCanUpgrade(self, id, version):
# TODO: This could maybe be done more efficiently using a dictionary... # TODO: This could maybe be done more efficiently using a dictionary...
# Scan plugin server data for plugin with the given id: # Scan plugin server data for plugin with the given id:
for plugin in self._plugins_metadata: for plugin in self._packages_metadata:
if id == plugin["id"]: if id == plugin["id"]:
reg_version = Version(version) reg_version = Version(version)
new_version = Version(plugin["version"]) new_version = Version(plugin["version"])
@ -374,14 +378,17 @@ class Toolbox(QObject, Extension):
return return
if reply.operation() == QNetworkAccessManager.GetOperation: if reply.operation() == QNetworkAccessManager.GetOperation:
if reply_url == self._api_url + "plugins": if reply_url == "{base_url}packages?cura_version={version}".format(base_url = self._api_url, version = self._packages_version_number):
try: try:
json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) json_data = json.loads(bytes(reply.readAll()).decode("utf-8"))
# Add metadata to the manager: # Add metadata to the manager:
self._plugins_metadata = json_data self._packages_metadata = json_data
self._plugin_registry.addExternalPlugins(self._plugins_metadata) if not self._packages_model:
self.pluginsMetadataChanged.emit() self._packages_model = CuraPackageModel()
self._packages_model.setPackagesMetaData(self._packages_metadata["data"])
# self._plugin_registry.addExternalPlugins(self._packages_metadata)
self.packagesMetadataChanged.emit()
except json.decoder.JSONDecodeError: except json.decoder.JSONDecodeError:
Logger.log("w", "Received an invalid print job state message: Not valid JSON.") Logger.log("w", "Received an invalid print job state message: Not valid JSON.")
return return