CURA-5137 Add filtering for materials and plugins and change the

behavior of switching tabs.
This commit is contained in:
Diego Prado Gesto 2018-04-03 17:07:33 +02:00
parent 1ad34495b4
commit b621b5ef6b
7 changed files with 85 additions and 51 deletions

View file

@ -1,6 +1,7 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import re
from typing import Dict from typing import Dict
from PyQt5.QtCore import Qt, pyqtProperty, pyqtSignal from PyQt5.QtCore import Qt, pyqtProperty, pyqtSignal
@ -33,7 +34,7 @@ class CuraPackageModel(ListModel):
self.addRoleName(CuraPackageModel.ImageURLsRole, "image_urls") self.addRoleName(CuraPackageModel.ImageURLsRole, "image_urls")
# List of filters for queries. The result is the union of the each list of results. # List of filters for queries. The result is the union of the each list of results.
self._filter = None # type: Dict[str,str] self._filter = {} # type: Dict[str,str]
def setPackagesMetaData(self, data): def setPackagesMetaData(self, data):
self._packages_metadata = data self._packages_metadata = data
@ -54,18 +55,46 @@ class CuraPackageModel(ListModel):
"image_urls": package["image_urls"] "image_urls": package["image_urls"]
}) })
items.sort(key = lambda k: k["name"]) # Filter on all the key-word arguments.
self.setItems(items) 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)
filterChanged = pyqtSignal() # 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. ## Set the filter of this model based on a string.
# \param filter_dict \type{Dict} Dictionary to do the filtering by. # \param filter_dict \type{Dict} Dictionary to do the filtering by.
def setFilter(self, filter_dict: Dict[str, str]) -> None: def setFilter(self, filter_dict: Dict[str, str]) -> None:
if filter_dict != self._filter: if filter_dict != self._filter:
self._filter = filter_dict self._filter = filter_dict
self.filterChanged.emit() self._update()
@pyqtProperty("QVariantMap", fset = setFilter, notify = filterChanged) @pyqtProperty("QVariantMap", fset = setFilter, constant = True)
def filter(self) -> Dict[str, str]: def filter(self) -> Dict[str, str]:
return self._filter 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

@ -43,12 +43,12 @@ class Toolbox(QObject, Extension):
self._plugin_registry = Application.getInstance().getPluginRegistry() self._plugin_registry = Application.getInstance().getPluginRegistry()
self._packages_version_number = self._plugin_registry.APIVersion self._packages_version_number = self._plugin_registry.APIVersion
self._packages_metadata = [] self._packages_metadata = [] # Stores the remote information of the packages
self._packages_model = None self._packages_model = None # Model that list the remote available packages
# Can be 'installed' or 'available' # Nowadays can be 'plugins', 'materials' or 'installed'
self._view = "available" self._current_view = "plugins"
self._detail_view = "" self._detail_view = False
self._restart_required = False self._restart_required = False
@ -91,6 +91,7 @@ class Toolbox(QObject, Extension):
restartRequiredChanged = pyqtSignal() restartRequiredChanged = pyqtSignal()
viewChanged = pyqtSignal() viewChanged = pyqtSignal()
detailViewChanged = pyqtSignal() detailViewChanged = pyqtSignal()
filterChanged = pyqtSignal()
@pyqtSlot(result = str) @pyqtSlot(result = str)
def getLicenseDialogPluginName(self): def getLicenseDialogPluginName(self):
@ -282,28 +283,31 @@ class Toolbox(QObject, Extension):
self.setIsDownloading(False) self.setIsDownloading(False)
@pyqtSlot(str) @pyqtSlot(str)
def setView(self, view = "available"): def filterPackagesByType(self, type):
self._view = view if not self._packages_model:
return
self._packages_model.setFilter({"type": type})
self.filterChanged.emit()
def setCurrentView(self, view = "plugins"):
self._current_view = view
self.viewChanged.emit() self.viewChanged.emit()
self.packagesMetadataChanged.emit()
@pyqtProperty(str, notify = viewChanged) @pyqtProperty(str, fset = setCurrentView, notify = viewChanged)
def viewing(self): def currentView(self):
return self._view return self._current_view
@pyqtSlot(str) def setDetailView(self, item = False):
def setDetailView(self, item = ""):
self._detail_view = item self._detail_view = item
self.detailViewChanged.emit() self.detailViewChanged.emit()
self.packagesMetadataChanged.emit()
@pyqtProperty(str, notify = detailViewChanged) @pyqtProperty(bool, fset = setDetailView, notify = detailViewChanged)
def detailView(self): def detailView(self):
return self._detail_view return self._detail_view
@pyqtProperty(QObject, notify = packagesMetadataChanged) @pyqtProperty(QObject, notify = packagesMetadataChanged)
def pluginsModel(self): def pluginsModel(self):
self._plugins_model = PluginsModel(None, self._view) self._plugins_model = PluginsModel(None, self._current_view)
# self._plugins_model.update() # self._plugins_model.update()
# Check each plugin the registry for matching plugin from server # Check each plugin the registry for matching plugin from server
@ -383,10 +387,10 @@ class Toolbox(QObject, Extension):
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._packages_metadata = json_data self._packages_metadata = json_data["data"]
if not self._packages_model: if not self._packages_model:
self._packages_model = CuraPackageModel() self._packages_model = CuraPackageModel()
self._packages_model.setPackagesMetaData(self._packages_metadata["data"]) self._packages_model.setPackagesMetaData(self._packages_metadata)
# self._plugin_registry.addExternalPlugins(self._packages_metadata) # self._plugin_registry.addExternalPlugins(self._packages_metadata)
self.packagesMetadataChanged.emit() self.packagesMetadataChanged.emit()
except json.decoder.JSONDecodeError: except json.decoder.JSONDecodeError:

View file

@ -14,7 +14,8 @@ import UM 1.1 as UM
Window Window
{ {
id: base id: base
title: catalog.i18nc("@title:tab", "Plugins"); title: catalog.i18nc("@title:tab", "Toolbox");
modality: Qt.ApplicationModal
width: 800 * screenScaleFactor width: 800 * screenScaleFactor
height: 640 * screenScaleFactor height: 640 * screenScaleFactor
minimumWidth: 800 * screenScaleFactor minimumWidth: 800 * screenScaleFactor
@ -42,18 +43,17 @@ Window
ToolboxViewDownloads ToolboxViewDownloads
{ {
id: viewDownloads id: viewDownloads
visible: manager.viewing == "available" && manager.detailView == "" ? true : false visible: manager.currentView != "installed" && !manager.detailView
} }
ToolboxViewDetail ToolboxViewDetail
{ {
id: viewDetail id: viewDetail
visible: manager.viewing == "available" && manager.detailView != "" ? true : false visible: manager.currentView != "installed" && manager.detailView
} }
ToolboxViewInstalled ToolboxViewInstalled
{ {
id: installedPluginList id: installedPluginList
visible: manager.viewing == "installed" ? true : false visible: manager.currentView == "installed"
} }
} }
SectionShadow SectionShadow

View file

@ -39,13 +39,10 @@ Rectangle
columnSpacing: UM.Theme.getSize("base_unit").width columnSpacing: UM.Theme.getSize("base_unit").width
rowSpacing: UM.Theme.getSize("base_unit").height rowSpacing: UM.Theme.getSize("base_unit").height
ToolboxGridTile {} Repeater
ToolboxGridTile {} {
ToolboxGridTile {} model: manager.packagesModel
ToolboxGridTile {} delegate: ToolboxGridTile {}
ToolboxGridTile {} }
ToolboxGridTile {}
ToolboxGridTile {}
ToolboxGridTile {}
} }
} }

View file

@ -33,7 +33,7 @@ Item
Label Label
{ {
id: name id: name
text: "Auto Orientation" text: model.name
width: parent.width width: parent.width
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
height: UM.Theme.getSize("base_unit").height * 2 height: UM.Theme.getSize("base_unit").height * 2
@ -44,7 +44,7 @@ Item
Label Label
{ {
id: info id: info
text: "Automatically orientate your model." text: model.description
width: parent.width width: parent.width
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
color: UM.Theme.getColor("text_medium") color: UM.Theme.getColor("text_medium")
@ -55,8 +55,6 @@ Item
MouseArea MouseArea
{ {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: manager.detailView = true
manager.setDetailView("thingy")
}
} }
} }

View file

@ -32,7 +32,7 @@ Rectangle {
implicitWidth: 96 implicitWidth: 96
implicitHeight: 48 implicitHeight: 48
Rectangle { Rectangle {
visible: manager.viewing == "available" ? true : false visible: manager.currentView == "plugins"
color: UM.Theme.getColor("primary") color: UM.Theme.getColor("primary")
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: parent.width width: parent.width
@ -49,7 +49,11 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
} }
onClicked: manager.setView("available") onClicked:
{
manager.filterPackagesByType("plugin")
manager.currentView = "plugins"
}
} }
Button { Button {
@ -60,7 +64,7 @@ Rectangle {
implicitWidth: 96 implicitWidth: 96
implicitHeight: 48 implicitHeight: 48
Rectangle { Rectangle {
visible: manager.viewing == "available" ? true : false visible: manager.currentView == "materials"
color: UM.Theme.getColor("primary") color: UM.Theme.getColor("primary")
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: parent.width width: parent.width
@ -77,7 +81,11 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
} }
onClicked: manager.setView("available") onClicked:
{
manager.filterPackagesByType("material")
manager.currentView = "materials"
}
} }
} }
@ -91,7 +99,7 @@ Rectangle {
implicitWidth: 96 implicitWidth: 96
implicitHeight: 48 implicitHeight: 48
Rectangle { Rectangle {
visible: manager.viewing == "installed" ? true : false visible: manager.currentView == "installed"
color: UM.Theme.getColor("primary") color: UM.Theme.getColor("primary")
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: parent.width width: parent.width
@ -108,6 +116,6 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
} }
onClicked: manager.setView("installed") onClicked: manager.currentView = "installed"
} }
} }

View file

@ -29,9 +29,7 @@ Item
Button Button
{ {
text: "Back" text: "Back"
onClicked: { onClicked: manager.detailView = false
manager.setDetailView("")
}
} }
} }
ScrollView ScrollView