CURA-5035 Added already installed plugins

This commit is contained in:
Ian Paschal 2018-04-12 17:22:50 +02:00
parent 0f966115e6
commit 5d395f549a
10 changed files with 51 additions and 206 deletions

View file

@ -118,8 +118,8 @@ class CuraPackageManager(QObject):
package_type = package_info["package_type"] package_type = package_info["package_type"]
if package_type not in installed_packages_dict: if package_type not in installed_packages_dict:
installed_packages_dict[package_type] = {} installed_packages_dict[package_type] = []
installed_packages_dict[package_type][package_id] = package_info installed_packages_dict[package_type].append( package_info )
# We also need to get information from the plugin registry such as if a plugin is active # We also need to get information from the plugin registry such as if a plugin is active
package_info["is_active"] = self._plugin_registry.isActivePlugin(package_id) package_info["is_active"] = self._plugin_registry.isActivePlugin(package_id)
@ -137,8 +137,8 @@ class CuraPackageManager(QObject):
plugin_package_info["is_active"] = self._plugin_registry.isActivePlugin(package_id) plugin_package_info["is_active"] = self._plugin_registry.isActivePlugin(package_id)
package_type = "plugin" package_type = "plugin"
if package_type not in installed_packages_dict: if package_type not in installed_packages_dict:
installed_packages_dict[package_type] = {} installed_packages_dict[package_type] = []
installed_packages_dict[package_type][package_id] = plugin_package_info installed_packages_dict[package_type].append( plugin_package_info )
return installed_packages_dict return installed_packages_dict

View file

@ -42,8 +42,8 @@ Item
onClicked: onClicked:
{ {
toolbox.viewPage = "overview" toolbox.viewPage = "overview"
toolbox.filterPackages("type", toolbox.viewCategory) toolbox.filterModelByProp("packages", "type", toolbox.viewCategory)
toolbox.filterAuthors("type", toolbox.viewCategory) toolbox.filterModelByProp("authors", "type", toolbox.viewCategory)
} }
style: ButtonStyle style: ButtonStyle
{ {

View file

@ -92,15 +92,15 @@ Item
{ {
toolbox.viewSelection = model.name toolbox.viewSelection = model.name
toolbox.viewPage = "author" toolbox.viewPage = "author"
toolbox.filterAuthors("name", model.name) toolbox.filterModelByProp("authors", "name", model.name)
toolbox.filterPackages("author_name", model.name) toolbox.filterModelByProp("packages", "author_name", model.name)
} }
else else
{ {
toolbox.viewSelection = model.id toolbox.viewSelection = model.id
toolbox.viewPage = "detail" toolbox.viewPage = "detail"
toolbox.filterAuthors("name", model.author_name) toolbox.filterModelByProp("authors", "name", model.author_name)
toolbox.filterPackages("id", model.id) toolbox.filterModelByProp("packages", "id", model.id)
} }
} }
} }

View file

@ -56,14 +56,14 @@ Item
case "material": case "material":
toolbox.viewSelection = model.name toolbox.viewSelection = model.name
toolbox.viewPage = "author" toolbox.viewPage = "author"
toolbox.filterAuthors("name", model.name) toolbox.filterModelByProp("authors", "name", model.name)
toolbox.filterPackages("author_name", model.name) toolbox.filterModelByProp("packages", "author_name", model.name)
break break
default: default:
toolbox.viewSelection = model.id toolbox.viewSelection = model.id
toolbox.viewPage = "detail" toolbox.viewPage = "detail"
toolbox.filterAuthors("name", model.author_name) toolbox.filterModelByProp("authors", "name", model.author_name)
toolbox.filterPackages("id", model.id) toolbox.filterModelByProp("packages", "id", model.id)
break break
} }
} }

View file

@ -6,9 +6,6 @@ import QtQuick.Dialogs 1.1
import QtQuick.Window 2.2 import QtQuick.Window 2.2
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
// TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles
import UM 1.1 as UM import UM 1.1 as UM
Rectangle { Rectangle {
@ -55,8 +52,8 @@ Rectangle {
} }
onClicked: onClicked:
{ {
toolbox.filterPackages("type", "plugin") toolbox.filterModelByProp("packages", "type", "plugin")
toolbox.filterAuthors("type", "plugin") toolbox.filterModelByProp("authors", "type", "plugin")
toolbox.viewCategory = "plugin" toolbox.viewCategory = "plugin"
toolbox.viewPage = "overview" toolbox.viewPage = "overview"
} }
@ -92,8 +89,8 @@ Rectangle {
} }
onClicked: onClicked:
{ {
toolbox.filterPackages("type", "material") toolbox.filterModelByProp("packages", "type", "material")
toolbox.filterAuthors("type", "material") toolbox.filterModelByProp("authors", "type", "material")
toolbox.viewCategory = "material" toolbox.viewCategory = "material"
toolbox.viewPage = "overview" toolbox.viewPage = "overview"
} }

View file

@ -58,7 +58,7 @@ ScrollView
Repeater Repeater
{ {
id: materialList id: materialList
model: toolbox.packagesModel model: toolbox.pluginsInstalledModel
delegate: ToolboxInstalledTile {} delegate: ToolboxInstalledTile {}
} }
} }
@ -93,7 +93,7 @@ ScrollView
Repeater Repeater
{ {
id: pluginList id: pluginList
model: toolbox.packagesModel model: toolbox.materialsInstalledModel
delegate: ToolboxInstalledTile {} delegate: ToolboxInstalledTile {}
} }
} }

View file

@ -103,7 +103,7 @@ Item
Button { Button {
id: removeButton id: removeButton
text: "Uninstall" text: "Uninstall"
visible: model.can_uninstall && model.status == "installed" // visible: model.can_uninstall && model.status == "installed"
enabled: !toolbox.isDownloading enabled: !toolbox.isDownloading
style: ButtonStyle style: ButtonStyle
{ {
@ -131,7 +131,7 @@ Item
Button { Button {
id: updateButton id: updateButton
text: "Update" text: "Update"
enabled: model.can_update // enabled: model.can_update
style: ButtonStyle style: ButtonStyle
{ {
background: Rectangle background: Rectangle
@ -157,9 +157,9 @@ Item
ProgressBar ProgressBar
{ {
id: progressbar id: progressbar
anchors.left: installButton.left anchors.left: updateButton.left
anchors.right: installButton.right anchors.right: updateButton.right
anchors.top: installButton.bottom anchors.top: updateButton.bottom
anchors.topMargin: 4 anchors.topMargin: 4
value: toolbox.isDownloading ? toolbox.downloadProgress : 0 value: toolbox.isDownloading ? toolbox.downloadProgress : 0
visible: toolbox.isDownloading visible: toolbox.isDownloading

View file

@ -52,7 +52,6 @@ class PackagesModel(ListModel):
items = [] items = []
for package in self._metadata: for package in self._metadata:
print(package)
items.append({ items.append({
"id": package["package_id"], "id": package["package_id"],
"type": package["package_type"], "type": package["package_type"],
@ -62,9 +61,9 @@ class PackagesModel(ListModel):
"author_email": package["author"]["email"], "author_email": package["author"]["email"],
"description": package["description"], "description": package["description"],
"icon_url": package["icon_url"] if "icon_url" in package else None, "icon_url": package["icon_url"] if "icon_url" in package else None,
"image_urls": package["image_urls"], "image_urls": package["image_urls"] if "image_urls" in package else None,
"download_url": package["download_url"], "download_url": package["download_url"] if "download_url" in package else None,
"last_updated": package["last_updated"] "last_updated": package["last_updated"] if "last_updated" in package else None
}) })
# Filter on all the key-word arguments. # Filter on all the key-word arguments.

View file

@ -1,110 +0,0 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import re
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 ShowcaseModel(ListModel):
IdRole = Qt.UserRole + 1
TypeRole = Qt.UserRole + 2
NameRole = Qt.UserRole + 3
VersionRole = Qt.UserRole + 4
AuthorNameRole = Qt.UserRole + 5
AuthorEmailRole = Qt.UserRole + 6
DescriptionRole = Qt.UserRole + 7
IconURLRole = Qt.UserRole + 8
ImageURLsRole = Qt.UserRole + 9
DownloadURLRole = Qt.UserRole + 10
LastUpdatedRole = Qt.UserRole + 11
def __init__(self, parent = None):
super().__init__(parent)
self._metadata = None
self.addRoleName(ShowcaseModel.IdRole, "id")
self.addRoleName(ShowcaseModel.TypeRole, "type")
self.addRoleName(ShowcaseModel.NameRole, "name")
self.addRoleName(ShowcaseModel.VersionRole, "version")
self.addRoleName(ShowcaseModel.AuthorNameRole, "author_name")
self.addRoleName(ShowcaseModel.AuthorEmailRole, "author_email")
self.addRoleName(ShowcaseModel.DescriptionRole, "description")
self.addRoleName(ShowcaseModel.IconURLRole, "icon_url")
self.addRoleName(ShowcaseModel.ImageURLsRole, "image_urls")
self.addRoleName(ShowcaseModel.DownloadURLRole, "download_url")
self.addRoleName(ShowcaseModel.LastUpdatedRole, "last_updated")
# List of filters for queries. The result is the union of the each list of results.
self._filter = {} # type: Dict[str,str]
def setMetadata(self, data):
self._metadata = data
self._update()
def _update(self):
items = []
for package in self._metadata:
print(package)
items.append({
"id": package["id"],
"type": package["type"],
"name": package["name"],
"version": package["package_version"],
"author_name": package["author"]["name"],
"author_email": package["author"]["email"],
"description": package["description"],
"icon_url": package["icon_url"] if "icon_url" in package else None,
"image_urls": package["image_urls"],
"download_url": package["download_url"],
"last_updated": package["last_updated"]
})
# Filter on all the key-word arguments.
for key, value in self._filter.items():
if "*" in value:
key_filter = lambda candidate, key = key, value = value: self._matchRegExp(candidate, key, value)
else:
key_filter = lambda candidate, key = key, value = value: self._matchString(candidate, key, value)
items = filter(key_filter, items)
# Execute all filters.
filtered_items = list(items)
filtered_items.sort(key = lambda k: k["name"])
self.setItems(filtered_items)
## 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._update()
@pyqtProperty("QVariantMap", fset = setFilter, constant = True)
def filter(self) -> Dict[str, str]:
return self._filter
# Check to see if a container matches with a regular expression
def _matchRegExp(self, metadata, property_name, value):
if property_name not in metadata:
return False
value = re.escape(value) #Escape for regex patterns.
value = "^" + value.replace("\\*", ".*") + "$" #Instead of (now escaped) asterisks, match on any string. Also add anchors for a complete match.
if self._ignore_case:
value_pattern = re.compile(value, re.IGNORECASE)
else:
value_pattern = re.compile(value)
return value_pattern.match(str(metadata[property_name]))
# Check to see if a container matches with a string
def _matchString(self, metadata, property_name, value):
if property_name not in metadata:
return False
return value.lower() == str(metadata[property_name]).lower()

View file

@ -21,7 +21,6 @@ from cura.Utils.VersionTools import compareSemanticVersions
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from .AuthorsModel import AuthorsModel from .AuthorsModel import AuthorsModel
from .PackagesModel import PackagesModel from .PackagesModel import PackagesModel
from .ShowcaseModel import ShowcaseModel
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
@ -68,6 +67,8 @@ class Toolbox(QObject, Extension):
"authors": [], "authors": [],
"packages": [], "packages": [],
"plugins_showcase": [], "plugins_showcase": [],
"plugins_installed": [],
# TODO: Replace this with a proper API call:
"materials_showcase": [ "materials_showcase": [
{ {
"name": "DSM", "name": "DSM",
@ -81,7 +82,8 @@ class Toolbox(QObject, Extension):
"website": "www.basf.de", "website": "www.basf.de",
"type": "material" "type": "material"
} }
] ],
"materials_installed": []
} }
# Models: # Models:
@ -185,8 +187,20 @@ class Toolbox(QObject, Extension):
self._network_manager.finished.connect(self._onRequestFinished) self._network_manager.finished.connect(self._onRequestFinished)
self._network_manager.networkAccessibleChanged.connect(self._onNetworkAccesibleChanged) self._network_manager.networkAccessibleChanged.connect(self._onNetworkAccesibleChanged)
self.makeRequestByType("packages") # Make remote requests:
self.makeRequestByType("plugins_showcase") self._makeRequestByType("packages")
self._makeRequestByType("plugins_showcase")
# Gather installed packages:
all_packages = self._package_manager.getAllInstalledPackagesInfo()
if "plugin" in all_packages:
self._metadata["plugins_installed"] = all_packages["plugin"]
self._models["plugins_installed"].setMetadata(self._metadata["plugins_installed"])
self.metadataChanged.emit()
if "material" in all_packages:
self._metadata["materials_installed"] = all_packages["material"]
self._models["materials_installed"].setMetadata(self._metadata["materials_installed"])
self.metadataChanged.emit()
if not self._dialog: if not self._dialog:
self._dialog = self._createDialog("Toolbox.qml") self._dialog = self._createDialog("Toolbox.qml")
@ -248,7 +262,6 @@ class Toolbox(QObject, Extension):
installed_plugin_data = self._package_manager.getInstalledPackageInfo(package_id) installed_plugin_data = self._package_manager.getInstalledPackageInfo(package_id)
if installed_plugin_data is None: if installed_plugin_data is None:
return False return False
installed_version = installed_plugin_data["package_version"] installed_version = installed_plugin_data["package_version"]
return compareSemanticVersions(version, installed_version) > 0 return compareSemanticVersions(version, installed_version) > 0
@ -260,36 +273,15 @@ class Toolbox(QObject, Extension):
return True return True
return False return False
def _createNetworkManager(self):
if self._network_manager:
self._network_manager.finished.disconnect(self._onRequestFinished)
self._network_manager.networkAccessibleChanged.disconnect(self._onNetworkAccesibleChanged)
self._network_manager = QNetworkAccessManager()
self._network_manager.finished.connect(self._onRequestFinished)
self._network_manager.networkAccessibleChanged.connect(self._onNetworkAccesibleChanged)
# Make API Calls # Make API Calls
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
def makeRequestByType(self, type): def _makeRequestByType(self, type):
Logger.log("i", "Toolbox: Requesting %s metadata from server.", type) Logger.log("i", "Toolbox: Requesting %s metadata from server.", type)
request = QNetworkRequest(self._request_urls[type]) request = QNetworkRequest(self._request_urls[type])
request.setRawHeader(*self._request_header) request.setRawHeader(*self._request_header)
self._network_manager.get(request) self._network_manager.get(request)
def _requestPackages(self):
Logger.log("i", "Toolbox: Requesting package list from server.")
self._get_packages_request = QNetworkRequest(self._request_urls["packages"])
self._get_packages_request.setRawHeader(*self._request_header)
self._network_manager.get(self._get_packages_request)
def _requestShowcase(self):
Logger.log("i", "Toolbox: Requesting showcase list from server.")
self._get_showcase_request = QNetworkRequest(self._request_urls["plugins_showcase"])
self._get_showcase_request.setRawHeader(*self._request_header)
self._network_manager.get(self._get_showcase_request)
# TODO: Request authors and request material showcase # TODO: Request authors and request material showcase
@pyqtSlot(str) @pyqtSlot(str)
@ -327,7 +319,6 @@ class Toolbox(QObject, Extension):
self._download_reply.abort() self._download_reply.abort()
self._download_reply = None self._download_reply = None
# TODO: This function is sooooo ugly. Needs a rework:
def _onRequestFinished(self, reply): def _onRequestFinished(self, reply):
if reply.error() == QNetworkReply.TimeoutError: if reply.error() == QNetworkReply.TimeoutError:
@ -340,15 +331,16 @@ class Toolbox(QObject, Extension):
self._download_plugin_reply.abort() self._download_plugin_reply.abort()
self._download_plugin_reply = None self._download_plugin_reply = None
return return
elif reply.error() == QNetworkReply.HostNotFoundError:
if reply.error() == QNetworkReply.HostNotFoundError:
Logger.log("w", "Unable to reach server.") Logger.log("w", "Unable to reach server.")
return return
if reply.operation() == QNetworkAccessManager.GetOperation: if reply.operation() == QNetworkAccessManager.GetOperation:
# TODO: In the future use the following to build any model from any # TODO: In the future use the following to build any model from any
# request. Right now this doesn't work though as the packages # request. Right now this doesn't work because the packages request
# request is also responsible for populating other models. # is also responsible for populating other models.
# for type, url in self._request_urls.items(): # for type, url in self._request_urls.items():
# if reply.url() == url: # if reply.url() == url:
# try: # try:
@ -368,7 +360,6 @@ class Toolbox(QObject, Extension):
if reply.url() == self._request_urls["packages"]: if reply.url() == self._request_urls["packages"]:
try: try:
json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) json_data = json.loads(bytes(reply.readAll()).decode("utf-8"))
print(json_data)
# Create packages model with all packages: # Create packages model with all packages:
if not self._models["packages"]: if not self._models["packages"]:
self._models["packages"] = PackagesModel(self) self._models["packages"] = PackagesModel(self)
@ -408,8 +399,6 @@ class Toolbox(QObject, Extension):
self._models["plugins_showcase"] = PackagesModel() self._models["plugins_showcase"] = PackagesModel()
self._metadata["plugins_showcase"] = json_data["data"] self._metadata["plugins_showcase"] = json_data["data"]
self._models["plugins_showcase"].setMetadata(self._metadata["plugins_showcase"]) self._models["plugins_showcase"].setMetadata(self._metadata["plugins_showcase"])
for package in self._models["plugins_showcase"].items:
print(package)
self.metadataChanged.emit() self.metadataChanged.emit()
self.setViewPage("overview") self.setViewPage("overview")
@ -440,7 +429,6 @@ class Toolbox(QObject, Extension):
def _onDownloadComplete(self, file_path): def _onDownloadComplete(self, file_path):
Logger.log("i", "Toolbox: Download complete.") Logger.log("i", "Toolbox: Download complete.")
print(file_path)
try: try:
package_info = self._package_manager.getPackageInfo(file_path) package_info = self._package_manager.getPackageInfo(file_path)
except: except:
@ -551,32 +539,3 @@ class Toolbox(QObject, Extension):
return return
self._models[modelType].setFilter({}) self._models[modelType].setFilter({})
self.filterChanged.emit() self.filterChanged.emit()
# TODO: Eventually dump everything below here:
@pyqtSlot(str, str)
def filterPackages(self, filterType, parameter):
if not self._models["packages"]:
return
self._models["packages"].setFilter({ filterType: parameter })
self.filterChanged.emit()
@pyqtSlot()
def unfilterPackages(self):
if not self._models["packages"]:
return
self._models["packages"].setFilter({})
self.filterChanged.emit()
@pyqtSlot(str, str)
def filterAuthors(self, filterType, parameter):
if not self._models["authors"]:
return
self._models["authors"].setFilter({ filterType: parameter })
self.filterChanged.emit()
@pyqtSlot()
def unfilterAuthors(self):
if not self._models["authors"]:
return
self._models["authors"].setFilter({})
self.filterChanged.emit()