diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 5ac0f03b2e..d3ea3f134c 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -261,7 +261,7 @@ class CuraApplication(QtApplication): "TranslateTool", "FileLogger", "XmlMaterialProfile", - "PluginBrowser", + "Toolbox", "PrepareStage", "MonitorStage" ]) diff --git a/plugins/PluginBrowser/__init__.py b/plugins/PluginBrowser/__init__.py deleted file mode 100644 index d414c36a99..0000000000 --- a/plugins/PluginBrowser/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2017 Ultimaker B.V. -# PluginBrowser is released under the terms of the LGPLv3 or higher. - -from . import PluginBrowser - - -def getMetaData(): - return {} - - -def register(app): - return {"extension": PluginBrowser.PluginBrowser()} diff --git a/plugins/PluginBrowser/plugin.json b/plugins/PluginBrowser/plugin.json deleted file mode 100644 index 491e21f506..0000000000 --- a/plugins/PluginBrowser/plugin.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Plugin Browser", - "author": "Ultimaker B.V.", - "version": "1.0.0", - "api": 4, - "description": "Find, manage and install new plugins." -} \ No newline at end of file diff --git a/plugins/Toolbox/Toolbox/CuraPackageModel.py b/plugins/Toolbox/Toolbox/CuraPackageModel.py new file mode 100644 index 0000000000..facf21cc6f --- /dev/null +++ b/plugins/Toolbox/Toolbox/CuraPackageModel.py @@ -0,0 +1,100 @@ +# 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 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 = {} # 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"] + }) + + # 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() diff --git a/plugins/PluginBrowser/PluginBrowser.py b/plugins/Toolbox/Toolbox/Toolbox.py similarity index 82% rename from plugins/PluginBrowser/PluginBrowser.py rename to plugins/Toolbox/Toolbox/Toolbox.py index 917502efa0..b799754cbf 100644 --- a/plugins/PluginBrowser/PluginBrowser.py +++ b/plugins/Toolbox/Toolbox/Toolbox.py @@ -1,5 +1,6 @@ -# Copyright (c) 2017 Ultimaker B.V. -# PluginBrowser is released under the terms of the LGPLv3 or higher. +# Copyright (c) 2018 Ultimaker B.V. +# 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.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply @@ -21,30 +22,33 @@ import platform import zipfile from cura.CuraApplication import CuraApplication +from .CuraPackageModel import CuraPackageModel i18n_catalog = i18nCatalog("cura") -class PluginBrowser(QObject, Extension): +## The Toolbox class is responsible of communicating with the server through the API +class Toolbox(QObject, Extension): def __init__(self, parent=None): super().__init__(parent) - self._api_version = 4 - self._api_url = "http://software.ultimaker.com/cura/v%s/" % self._api_version + self._api_version = 1 + 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_reply = None self._network_manager = None self._plugin_registry = Application.getInstance().getPluginRegistry() + self._packages_version_number = self._plugin_registry.APIVersion - self._plugins_metadata = [] - self._plugins_model = None + self._packages_metadata = [] # Stores the remote information of the packages + self._packages_model = None # Model that list the remote available packages - # Can be 'installed' or 'available' - self._view = "available" - self._detail_view = "" + # Nowadays can be 'plugins', 'materials' or 'installed' + self._current_view = "plugins" + self._detail_view = False self._restart_required = False @@ -81,12 +85,13 @@ class PluginBrowser(QObject, Extension): showLicenseDialog = pyqtSignal() showRestartDialog = pyqtSignal() - pluginsMetadataChanged = pyqtSignal() + packagesMetadataChanged = pyqtSignal() onDownloadProgressChanged = pyqtSignal() onIsDownloadingChanged = pyqtSignal() restartRequiredChanged = pyqtSignal() viewChanged = pyqtSignal() detailViewChanged = pyqtSignal() + filterChanged = pyqtSignal() @pyqtSlot(result = str) def getLicenseDialogPluginName(self): @@ -119,21 +124,20 @@ class PluginBrowser(QObject, Extension): return self._is_downloading @pyqtSlot() - def browsePlugins(self): + def browsePackages(self): self._createNetworkManager() - self.requestPluginList() + self.requestPackageList() if not self._dialog: self._dialog = self._createDialog("PluginBrowser.qml") self._dialog.show() - @pyqtSlot() - def requestPluginList(self): - Logger.log("i", "Requesting plugin list") - url = QUrl(self._api_url + "plugins") - self._plugin_list_request = QNetworkRequest(url) - self._plugin_list_request.setRawHeader(*self._request_header) - self._network_manager.get(self._plugin_list_request) + def requestPackageList(self): + Logger.log("i", "Requesting package list") + url = QUrl("{base_url}packages?cura_version={version}".format(base_url = self._api_url, version = self._packages_version_number)) + self._package_list_request = QNetworkRequest(url) + self._package_list_request.setRawHeader(*self._request_header) + self._network_manager.get(self._package_list_request) def _createDialog(self, qml_name): Logger.log("d", "Creating dialog [%s]", qml_name) @@ -217,19 +221,18 @@ class PluginBrowser(QObject, Extension): result = PluginRegistry.getInstance().installPlugin("file://" + location) self._newly_installed_plugin_ids.append(result["id"]) - self.pluginsMetadataChanged.emit() + self.packagesMetadataChanged.emit() self.openRestartDialog(result["message"]) self._restart_required = True self.restartRequiredChanged.emit() - # Application.getInstance().messageBox(i18n_catalog.i18nc("@window:title", "Plugin browser"), result["message"]) @pyqtSlot(str) def removePlugin(self, plugin_id): result = PluginRegistry.getInstance().uninstallPlugin(plugin_id) self._newly_uninstalled_plugin_ids.append(result["id"]) - self.pluginsMetadataChanged.emit() + self.packagesMetadataChanged.emit() self._restart_required = True self.restartRequiredChanged.emit() @@ -239,13 +242,13 @@ class PluginBrowser(QObject, Extension): @pyqtSlot(str) def enablePlugin(self, plugin_id): self._plugin_registry.enablePlugin(plugin_id) - self.pluginsMetadataChanged.emit() + self.packagesMetadataChanged.emit() Logger.log("i", "%s was set as 'active'", id) @pyqtSlot(str) def disablePlugin(self, plugin_id): self._plugin_registry.disablePlugin(plugin_id) - self.pluginsMetadataChanged.emit() + self.packagesMetadataChanged.emit() Logger.log("i", "%s was set as 'deactive'", id) @pyqtProperty(int, notify = onDownloadProgressChanged) @@ -280,28 +283,32 @@ class PluginBrowser(QObject, Extension): self.setIsDownloading(False) @pyqtSlot(str) - def setView(self, view = "available"): - self._view = view + def filterPackagesByType(self, type): + 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._detail_view = False self.viewChanged.emit() - self.pluginsMetadataChanged.emit() - @pyqtProperty(str, notify = viewChanged) - def viewing(self): - return self._view + @pyqtProperty(str, fset = setCurrentView, notify = viewChanged) + def currentView(self): + return self._current_view - @pyqtSlot(str) - def setDetailView(self, item = ""): + def setDetailView(self, item = False): self._detail_view = item self.detailViewChanged.emit() - self.pluginsMetadataChanged.emit() - @pyqtProperty(str, notify = detailViewChanged) + @pyqtProperty(bool, fset = setDetailView, notify = detailViewChanged) def detailView(self): return self._detail_view - @pyqtProperty(QObject, notify = pluginsMetadataChanged) + @pyqtProperty(QObject, notify = packagesMetadataChanged) def pluginsModel(self): - self._plugins_model = PluginsModel(None, self._view) + self._plugins_model = PluginsModel(None, self._current_view) # self._plugins_model.update() # Check each plugin the registry for matching plugin from server @@ -311,20 +318,22 @@ class PluginBrowser(QObject, Extension): if self._checkCanUpgrade(plugin["id"], plugin["version"]): plugin["can_upgrade"] = True - for item in self._plugins_metadata: + for item in self._packages_metadata: if item["id"] == plugin["id"]: plugin["update_url"] = item["file_location"] return self._plugins_model - + @pyqtProperty(QObject, notify = packagesMetadataChanged) + def packagesModel(self): + return self._packages_model def _checkCanUpgrade(self, id, version): # TODO: This could maybe be done more efficiently using a dictionary... # 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"]: reg_version = Version(version) new_version = Version(plugin["version"]) @@ -374,14 +383,17 @@ class PluginBrowser(QObject, Extension): return 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: json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) # Add metadata to the manager: - self._plugins_metadata = json_data - self._plugin_registry.addExternalPlugins(self._plugins_metadata) - self.pluginsMetadataChanged.emit() + self._packages_metadata = json_data["data"] + if not self._packages_model: + self._packages_model = CuraPackageModel() + self._packages_model.setPackagesMetaData(self._packages_metadata) + # self._plugin_registry.addExternalPlugins(self._packages_metadata) + self.packagesMetadataChanged.emit() except json.decoder.JSONDecodeError: Logger.log("w", "Received an invalid print job state message: Not valid JSON.") return diff --git a/plugins/Toolbox/Toolbox/__init__.py b/plugins/Toolbox/Toolbox/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/Toolbox/__init__.py b/plugins/Toolbox/__init__.py new file mode 100644 index 0000000000..dc2d6c9c23 --- /dev/null +++ b/plugins/Toolbox/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Toolbox is released under the terms of the LGPLv3 or higher. + +from .Toolbox import Toolbox + + +def getMetaData(): + return {} + + +def register(app): + return {"extension": Toolbox.Toolbox()} diff --git a/plugins/Toolbox/plugin.json b/plugins/Toolbox/plugin.json new file mode 100644 index 0000000000..7c85851df7 --- /dev/null +++ b/plugins/Toolbox/plugin.json @@ -0,0 +1,7 @@ +{ + "name": "Toolbox", + "author": "Ultimaker B.V.", + "version": "1.0.0", + "api": 4, + "description": "Find, manage and install new cura packages." +} \ No newline at end of file diff --git a/plugins/PluginBrowser/resources/qml/PluginBrowser.qml b/plugins/Toolbox/resources/qml/PluginBrowser.qml similarity index 88% rename from plugins/PluginBrowser/resources/qml/PluginBrowser.qml rename to plugins/Toolbox/resources/qml/PluginBrowser.qml index d0e150eaf5..c2ce4975f4 100644 --- a/plugins/PluginBrowser/resources/qml/PluginBrowser.qml +++ b/plugins/Toolbox/resources/qml/PluginBrowser.qml @@ -12,9 +12,10 @@ import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM Window - { +{ id: base - title: catalog.i18nc("@title:tab", "Plugins"); + title: catalog.i18nc("@title:tab", "Toolbox"); + modality: Qt.ApplicationModal width: 800 * screenScaleFactor height: 640 * screenScaleFactor minimumWidth: 800 * screenScaleFactor @@ -42,18 +43,17 @@ Window ToolboxViewDownloads { id: viewDownloads - visible: manager.viewing == "available" && manager.detailView == "" ? true : false + visible: manager.currentView != "installed" && !manager.detailView } - ToolboxViewDetail { id: viewDetail - visible: manager.viewing == "available" && manager.detailView != "" ? true : false + visible: manager.currentView != "installed" && manager.detailView } ToolboxViewInstalled { id: installedPluginList - visible: manager.viewing == "installed" ? true : false + visible: manager.currentView == "installed" } } SectionShadow @@ -75,9 +75,6 @@ Window } } - - - UM.I18nCatalog { id: catalog; name: "cura" } Connections diff --git a/plugins/PluginBrowser/resources/qml/PluginEntry.qml b/plugins/Toolbox/resources/qml/PluginEntry.qml similarity index 100% rename from plugins/PluginBrowser/resources/qml/PluginEntry.qml rename to plugins/Toolbox/resources/qml/PluginEntry.qml diff --git a/plugins/PluginBrowser/resources/qml/SectionShadow.qml b/plugins/Toolbox/resources/qml/SectionShadow.qml similarity index 100% rename from plugins/PluginBrowser/resources/qml/SectionShadow.qml rename to plugins/Toolbox/resources/qml/SectionShadow.qml diff --git a/plugins/PluginBrowser/resources/qml/ToolboxDetailTile.qml b/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml similarity index 100% rename from plugins/PluginBrowser/resources/qml/ToolboxDetailTile.qml rename to plugins/Toolbox/resources/qml/ToolboxDetailTile.qml diff --git a/plugins/PluginBrowser/resources/qml/ToolboxFooter.qml b/plugins/Toolbox/resources/qml/ToolboxFooter.qml similarity index 100% rename from plugins/PluginBrowser/resources/qml/ToolboxFooter.qml rename to plugins/Toolbox/resources/qml/ToolboxFooter.qml diff --git a/plugins/PluginBrowser/resources/qml/ToolboxGrid.qml b/plugins/Toolbox/resources/qml/ToolboxGrid.qml similarity index 59% rename from plugins/PluginBrowser/resources/qml/ToolboxGrid.qml rename to plugins/Toolbox/resources/qml/ToolboxGrid.qml index 53c4443493..115638bd71 100644 --- a/plugins/PluginBrowser/resources/qml/ToolboxGrid.qml +++ b/plugins/Toolbox/resources/qml/ToolboxGrid.qml @@ -11,41 +11,34 @@ import UM 1.1 as UM // TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles -Rectangle +Column { id: base - width: parent.width - height: childrenRect.height + UM.Theme.getSize("double_margin").height * 8 - color: "transparent" + height: childrenRect.height + spacing: UM.Theme.getSize("base_unit").height Label { id: heading text: "Community Plugins" width: parent.width - height: UM.Theme.getSize("base_unit").width * 4 - verticalAlignment: Text.AlignVCenter color: UM.Theme.getColor("text_medium") font: UM.Theme.getFont("medium") } GridLayout { id: grid - width: base.width - anchors - { - top: heading.bottom - } + width: parent.width columns: 3 columnSpacing: UM.Theme.getSize("base_unit").width rowSpacing: UM.Theme.getSize("base_unit").height - ToolboxGridTile {} - ToolboxGridTile {} - ToolboxGridTile {} - ToolboxGridTile {} - ToolboxGridTile {} - ToolboxGridTile {} - ToolboxGridTile {} - ToolboxGridTile {} + Repeater + { + model: manager.packagesModel + delegate: ToolboxGridTile + { + Layout.preferredWidth: (grid.width - (grid.columns - 1) * grid.columnSpacing) / grid.columns + } + } } } diff --git a/plugins/PluginBrowser/resources/qml/ToolboxGridTile.qml b/plugins/Toolbox/resources/qml/ToolboxGridTile.qml similarity index 71% rename from plugins/PluginBrowser/resources/qml/ToolboxGridTile.qml rename to plugins/Toolbox/resources/qml/ToolboxGridTile.qml index 160e59bf15..67c04a4cc7 100644 --- a/plugins/PluginBrowser/resources/qml/ToolboxGridTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxGridTile.qml @@ -13,7 +13,7 @@ Item { id: base height: childrenRect.height - Layout.fillWidth: true + Layout.alignment: Qt.AlignTop | Qt.AlignLeft Row { width: parent.width @@ -29,22 +29,28 @@ Item } Column { - width: UM.Theme.getSize("base_unit").width * 12 + width: parent.width - thumbnail.width - parent.spacing + spacing: Math.floor(UM.Theme.getSize("base_unit").width / 2) Label { id: name - text: "Auto Orientation" + text: model.name width: parent.width wrapMode: Text.WordWrap - height: UM.Theme.getSize("base_unit").height * 2 - verticalAlignment: Text.AlignVCenter color: UM.Theme.getColor("text") font: UM.Theme.getFont("default_bold") } Label { id: info - text: "Automatically orientate your model." + text: + { + if (model.description.length > 50) + { + return model.description.substring(0, 50) + "..." + } + return model.description + } width: parent.width wrapMode: Text.WordWrap color: UM.Theme.getColor("text_medium") @@ -55,8 +61,6 @@ Item MouseArea { anchors.fill: parent - onClicked: { - manager.setDetailView("thingy") - } + onClicked: manager.detailView = true } } diff --git a/plugins/PluginBrowser/resources/qml/ToolboxHeader.qml b/plugins/Toolbox/resources/qml/ToolboxHeader.qml similarity index 85% rename from plugins/PluginBrowser/resources/qml/ToolboxHeader.qml rename to plugins/Toolbox/resources/qml/ToolboxHeader.qml index cce078035d..106b988e9e 100644 --- a/plugins/PluginBrowser/resources/qml/ToolboxHeader.qml +++ b/plugins/Toolbox/resources/qml/ToolboxHeader.qml @@ -32,7 +32,7 @@ Rectangle { implicitWidth: 96 implicitHeight: 48 Rectangle { - visible: manager.viewing == "available" ? true : false + visible: manager.currentView == "plugins" color: UM.Theme.getColor("primary") anchors.bottom: parent.bottom width: parent.width @@ -49,7 +49,11 @@ Rectangle { horizontalAlignment: Text.AlignHCenter } } - onClicked: manager.setView("available") + onClicked: + { + manager.filterPackagesByType("plugin") + manager.currentView = "plugins" + } } Button { @@ -60,7 +64,7 @@ Rectangle { implicitWidth: 96 implicitHeight: 48 Rectangle { - visible: manager.viewing == "available" ? true : false + visible: manager.currentView == "materials" color: UM.Theme.getColor("primary") anchors.bottom: parent.bottom width: parent.width @@ -77,7 +81,11 @@ Rectangle { horizontalAlignment: Text.AlignHCenter } } - onClicked: manager.setView("available") + onClicked: + { + manager.filterPackagesByType("material") + manager.currentView = "materials" + } } } @@ -91,7 +99,7 @@ Rectangle { implicitWidth: 96 implicitHeight: 48 Rectangle { - visible: manager.viewing == "installed" ? true : false + visible: manager.currentView == "installed" color: UM.Theme.getColor("primary") anchors.bottom: parent.bottom width: parent.width @@ -108,6 +116,6 @@ Rectangle { horizontalAlignment: Text.AlignHCenter } } - onClicked: manager.setView("installed") + onClicked: manager.currentView = "installed" } } diff --git a/plugins/PluginBrowser/resources/qml/ToolboxLicenseDialog.qml b/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml similarity index 100% rename from plugins/PluginBrowser/resources/qml/ToolboxLicenseDialog.qml rename to plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml diff --git a/plugins/PluginBrowser/resources/qml/ToolboxRestartDialog.qml b/plugins/Toolbox/resources/qml/ToolboxRestartDialog.qml similarity index 100% rename from plugins/PluginBrowser/resources/qml/ToolboxRestartDialog.qml rename to plugins/Toolbox/resources/qml/ToolboxRestartDialog.qml diff --git a/plugins/PluginBrowser/resources/qml/ToolboxShowcase.qml b/plugins/Toolbox/resources/qml/ToolboxShowcase.qml similarity index 65% rename from plugins/PluginBrowser/resources/qml/ToolboxShowcase.qml rename to plugins/Toolbox/resources/qml/ToolboxShowcase.qml index f5aec67e09..5abf14cecc 100644 --- a/plugins/PluginBrowser/resources/qml/ToolboxShowcase.qml +++ b/plugins/Toolbox/resources/qml/ToolboxShowcase.qml @@ -10,45 +10,30 @@ import UM 1.1 as UM // TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles -Rectangle +Column { id: base - width: parent.width height: childrenRect.height - color: "transparent" + spacing: UM.Theme.getSize("base_unit").height Label { id: heading text: "Top Downloads" width: parent.width - height: UM.Theme.getSize("base_unit").width * 4 - verticalAlignment: Text.AlignVCenter color: UM.Theme.getColor("text_medium") font: UM.Theme.getFont("medium") } Row { height: childrenRect.height - width: childrenRect.width spacing: UM.Theme.getSize("base_unit").width * 2 anchors { horizontalCenter: parent.horizontalCenter - top: heading.bottom } ToolboxShowcaseTile {} ToolboxShowcaseTile {} ToolboxShowcaseTile {} } - Rectangle - { - color: UM.Theme.getColor("text_medium") - width: parent.width - height: UM.Theme.getSize("base_unit").height / 6 - anchors - { - bottom: parent.bottom - } - } } diff --git a/plugins/PluginBrowser/resources/qml/ToolboxShowcaseTile.qml b/plugins/Toolbox/resources/qml/ToolboxShowcaseTile.qml similarity index 100% rename from plugins/PluginBrowser/resources/qml/ToolboxShowcaseTile.qml rename to plugins/Toolbox/resources/qml/ToolboxShowcaseTile.qml diff --git a/plugins/PluginBrowser/resources/qml/ToolboxViewDetail.qml b/plugins/Toolbox/resources/qml/ToolboxViewDetail.qml similarity index 98% rename from plugins/PluginBrowser/resources/qml/ToolboxViewDetail.qml rename to plugins/Toolbox/resources/qml/ToolboxViewDetail.qml index 84175b118c..dec4ddc1e6 100644 --- a/plugins/PluginBrowser/resources/qml/ToolboxViewDetail.qml +++ b/plugins/Toolbox/resources/qml/ToolboxViewDetail.qml @@ -44,10 +44,7 @@ Item } width: UM.Theme.getSize("base_unit").width * 4 height: UM.Theme.getSize("base_unit").height * 2 - onClicked: - { - manager.setDetailView("") - } + onClicked: manager.detailView = false style: ButtonStyle { background: Rectangle diff --git a/plugins/PluginBrowser/resources/qml/ToolboxViewDownloads.qml b/plugins/Toolbox/resources/qml/ToolboxViewDownloads.qml similarity index 55% rename from plugins/PluginBrowser/resources/qml/ToolboxViewDownloads.qml rename to plugins/Toolbox/resources/qml/ToolboxViewDownloads.qml index 55e3650488..4141685787 100644 --- a/plugins/PluginBrowser/resources/qml/ToolboxViewDownloads.qml +++ b/plugins/Toolbox/resources/qml/ToolboxViewDownloads.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // PluginBrowser is released under the terms of the LGPLv3 or higher. -import QtQuick 2.2 +import QtQuick 2.7 import QtQuick.Dialogs 1.1 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 @@ -12,29 +12,31 @@ import UM 1.1 as UM ScrollView { id: base - frameVisible: false - anchors.fill: parent + frameVisible: true + width: parent.width + height: parent.height style: UM.Theme.styles.scrollview Column { width: base.width spacing: UM.Theme.getSize("base_unit").height - height: childrenRect.height - anchors - { - fill: parent - topMargin: UM.Theme.getSize("base_unit").height - bottomMargin: UM.Theme.getSize("base_unit").height - leftMargin: UM.Theme.getSize("base_unit").width * 2 - rightMargin: UM.Theme.getSize("base_unit").width * 2 - } + padding: UM.Theme.getSize("base_unit").height * 2 + height: childrenRect.height + 2 * padding ToolboxShowcase { id: showcase + width: parent.width - 2 * parent.padding + } + Rectangle + { + color: UM.Theme.getColor("text_medium") + width: parent.width - 2 * parent.padding + height: UM.Theme.getSize("base_unit").height / 6 } ToolboxGrid { id: allPlugins + width: parent.width - 2 * parent.padding } } } diff --git a/plugins/PluginBrowser/resources/qml/ToolboxViewInstalled.qml b/plugins/Toolbox/resources/qml/ToolboxViewInstalled.qml similarity index 100% rename from plugins/PluginBrowser/resources/qml/ToolboxViewInstalled.qml rename to plugins/Toolbox/resources/qml/ToolboxViewInstalled.qml diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 7002711614..21e6eebf58 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -68,7 +68,7 @@ Item property alias configureSettingVisibility: configureSettingVisibilityAction - property alias browsePlugins: browsePluginsAction + property alias browsePackages: browsePackagesAction UM.I18nCatalog{id: catalog; name:"cura"} @@ -429,8 +429,8 @@ Item Action { - id: browsePluginsAction - text: catalog.i18nc("@action:menu", "Browse plugins...") + id: browsePackagesAction + text: catalog.i18nc("@action:menu", "Browse packages...") iconName: "plugins_browse" } diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index c4ebb790e8..e20a29fe16 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -270,9 +270,9 @@ UM.MainWindow Menu { id: plugin_menu - title: catalog.i18nc("@title:menu menubar:toplevel", "P&lugins") + title: catalog.i18nc("@title:menu menubar:toplevel", "&Toolbox") - MenuItem { action: Cura.Actions.browsePlugins } + MenuItem { action: Cura.Actions.browsePackages } } Menu @@ -668,9 +668,9 @@ UM.MainWindow // show the plugin browser dialog Connections { - target: Cura.Actions.browsePlugins + target: Cura.Actions.browsePackages onTriggered: { - curaExtensions.callExtensionMethod("Plugin Browser", "browsePlugins") + curaExtensions.callExtensionMethod("Toolbox", "browsePackages") } }