mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-07-26 16:12:04 +08:00
Merge pull request #3618 from Ultimaker/feature_cura_package_api
Backend of the Toolbox
This commit is contained in:
commit
0cfcc8cd5f
@ -261,7 +261,7 @@ class CuraApplication(QtApplication):
|
|||||||
"TranslateTool",
|
"TranslateTool",
|
||||||
"FileLogger",
|
"FileLogger",
|
||||||
"XmlMaterialProfile",
|
"XmlMaterialProfile",
|
||||||
"PluginBrowser",
|
"Toolbox",
|
||||||
"PrepareStage",
|
"PrepareStage",
|
||||||
"MonitorStage"
|
"MonitorStage"
|
||||||
])
|
])
|
||||||
|
@ -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()}
|
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Plugin Browser",
|
|
||||||
"author": "Ultimaker B.V.",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"api": 4,
|
|
||||||
"description": "Find, manage and install new plugins."
|
|
||||||
}
|
|
100
plugins/Toolbox/Toolbox/CuraPackageModel.py
Normal file
100
plugins/Toolbox/Toolbox/CuraPackageModel.py
Normal file
@ -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()
|
@ -1,5 +1,6 @@
|
|||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# PluginBrowser 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,30 +22,33 @@ 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")
|
||||||
|
|
||||||
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):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
self._api_version = 4
|
self._api_version = 1
|
||||||
self._api_url = "http://software.ultimaker.com/cura/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 = [] # Stores the remote information of the packages
|
||||||
self._plugins_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
|
||||||
|
|
||||||
@ -81,12 +85,13 @@ class PluginBrowser(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()
|
||||||
viewChanged = pyqtSignal()
|
viewChanged = pyqtSignal()
|
||||||
detailViewChanged = pyqtSignal()
|
detailViewChanged = pyqtSignal()
|
||||||
|
filterChanged = pyqtSignal()
|
||||||
|
|
||||||
@pyqtSlot(result = str)
|
@pyqtSlot(result = str)
|
||||||
def getLicenseDialogPluginName(self):
|
def getLicenseDialogPluginName(self):
|
||||||
@ -119,21 +124,20 @@ class PluginBrowser(QObject, Extension):
|
|||||||
return self._is_downloading
|
return self._is_downloading
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def browsePlugins(self):
|
def browsePackages(self):
|
||||||
self._createNetworkManager()
|
self._createNetworkManager()
|
||||||
self.requestPluginList()
|
self.requestPackageList()
|
||||||
|
|
||||||
if not self._dialog:
|
if not self._dialog:
|
||||||
self._dialog = self._createDialog("PluginBrowser.qml")
|
self._dialog = self._createDialog("PluginBrowser.qml")
|
||||||
self._dialog.show()
|
self._dialog.show()
|
||||||
|
|
||||||
@pyqtSlot()
|
def requestPackageList(self):
|
||||||
def requestPluginList(self):
|
Logger.log("i", "Requesting package list")
|
||||||
Logger.log("i", "Requesting plugin list")
|
url = QUrl("{base_url}packages?cura_version={version}".format(base_url = self._api_url, version = self._packages_version_number))
|
||||||
url = QUrl(self._api_url + "plugins")
|
self._package_list_request = QNetworkRequest(url)
|
||||||
self._plugin_list_request = QNetworkRequest(url)
|
self._package_list_request.setRawHeader(*self._request_header)
|
||||||
self._plugin_list_request.setRawHeader(*self._request_header)
|
self._network_manager.get(self._package_list_request)
|
||||||
self._network_manager.get(self._plugin_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)
|
||||||
@ -217,19 +221,18 @@ class PluginBrowser(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
|
||||||
self.restartRequiredChanged.emit()
|
self.restartRequiredChanged.emit()
|
||||||
# Application.getInstance().messageBox(i18n_catalog.i18nc("@window:title", "Plugin browser"), result["message"])
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def removePlugin(self, plugin_id):
|
def removePlugin(self, plugin_id):
|
||||||
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 +242,13 @@ class PluginBrowser(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)
|
||||||
@ -280,28 +283,32 @@ class PluginBrowser(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._detail_view = False
|
||||||
self.viewChanged.emit()
|
self.viewChanged.emit()
|
||||||
self.pluginsMetadataChanged.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.pluginsMetadataChanged.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 = pluginsMetadataChanged)
|
@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
|
||||||
@ -311,20 +318,22 @@ class PluginBrowser(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 +383,17 @@ class PluginBrowser(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["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)
|
||||||
|
# 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
|
0
plugins/Toolbox/Toolbox/__init__.py
Normal file
0
plugins/Toolbox/Toolbox/__init__.py
Normal file
12
plugins/Toolbox/__init__.py
Normal file
12
plugins/Toolbox/__init__.py
Normal file
@ -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()}
|
7
plugins/Toolbox/plugin.json
Normal file
7
plugins/Toolbox/plugin.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Toolbox",
|
||||||
|
"author": "Ultimaker B.V.",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"api": 4,
|
||||||
|
"description": "Find, manage and install new cura packages."
|
||||||
|
}
|
@ -12,9 +12,10 @@ import QtQuick.Controls.Styles 1.4
|
|||||||
import UM 1.1 as UM
|
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
|
||||||
@ -75,9 +75,6 @@ Window
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UM.I18nCatalog { id: catalog; name: "cura" }
|
UM.I18nCatalog { id: catalog; name: "cura" }
|
||||||
|
|
||||||
Connections
|
Connections
|
@ -11,41 +11,34 @@ import UM 1.1 as UM
|
|||||||
|
|
||||||
// TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles
|
// TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles
|
||||||
|
|
||||||
Rectangle
|
Column
|
||||||
{
|
{
|
||||||
id: base
|
id: base
|
||||||
width: parent.width
|
height: childrenRect.height
|
||||||
height: childrenRect.height + UM.Theme.getSize("double_margin").height * 8
|
spacing: UM.Theme.getSize("base_unit").height
|
||||||
color: "transparent"
|
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: heading
|
id: heading
|
||||||
text: "Community Plugins"
|
text: "Community Plugins"
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: UM.Theme.getSize("base_unit").width * 4
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
color: UM.Theme.getColor("text_medium")
|
color: UM.Theme.getColor("text_medium")
|
||||||
font: UM.Theme.getFont("medium")
|
font: UM.Theme.getFont("medium")
|
||||||
}
|
}
|
||||||
GridLayout
|
GridLayout
|
||||||
{
|
{
|
||||||
id: grid
|
id: grid
|
||||||
width: base.width
|
width: parent.width
|
||||||
anchors
|
|
||||||
{
|
|
||||||
top: heading.bottom
|
|
||||||
}
|
|
||||||
columns: 3
|
columns: 3
|
||||||
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 {}
|
Layout.preferredWidth: (grid.width - (grid.columns - 1) * grid.columnSpacing) / grid.columns
|
||||||
ToolboxGridTile {}
|
}
|
||||||
ToolboxGridTile {}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ Item
|
|||||||
{
|
{
|
||||||
id: base
|
id: base
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
Layout.fillWidth: true
|
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||||
Row
|
Row
|
||||||
{
|
{
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@ -29,22 +29,28 @@ Item
|
|||||||
}
|
}
|
||||||
Column
|
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
|
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
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
color: UM.Theme.getColor("text")
|
color: UM.Theme.getColor("text")
|
||||||
font: UM.Theme.getFont("default_bold")
|
font: UM.Theme.getFont("default_bold")
|
||||||
}
|
}
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: info
|
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
|
width: parent.width
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
color: UM.Theme.getColor("text_medium")
|
color: UM.Theme.getColor("text_medium")
|
||||||
@ -55,8 +61,6 @@ Item
|
|||||||
MouseArea
|
MouseArea
|
||||||
{
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: manager.detailView = true
|
||||||
manager.setDetailView("thingy")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,45 +10,30 @@ import UM 1.1 as UM
|
|||||||
|
|
||||||
// TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles
|
// TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles
|
||||||
|
|
||||||
Rectangle
|
Column
|
||||||
{
|
{
|
||||||
id: base
|
id: base
|
||||||
width: parent.width
|
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
color: "transparent"
|
spacing: UM.Theme.getSize("base_unit").height
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: heading
|
id: heading
|
||||||
text: "Top Downloads"
|
text: "Top Downloads"
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: UM.Theme.getSize("base_unit").width * 4
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
color: UM.Theme.getColor("text_medium")
|
color: UM.Theme.getColor("text_medium")
|
||||||
font: UM.Theme.getFont("medium")
|
font: UM.Theme.getFont("medium")
|
||||||
}
|
}
|
||||||
Row
|
Row
|
||||||
{
|
{
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
width: childrenRect.width
|
|
||||||
spacing: UM.Theme.getSize("base_unit").width * 2
|
spacing: UM.Theme.getSize("base_unit").width * 2
|
||||||
anchors
|
anchors
|
||||||
{
|
{
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
top: heading.bottom
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolboxShowcaseTile {}
|
ToolboxShowcaseTile {}
|
||||||
ToolboxShowcaseTile {}
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -44,10 +44,7 @@ Item
|
|||||||
}
|
}
|
||||||
width: UM.Theme.getSize("base_unit").width * 4
|
width: UM.Theme.getSize("base_unit").width * 4
|
||||||
height: UM.Theme.getSize("base_unit").height * 2
|
height: UM.Theme.getSize("base_unit").height * 2
|
||||||
onClicked:
|
onClicked: manager.detailView = false
|
||||||
{
|
|
||||||
manager.setDetailView("")
|
|
||||||
}
|
|
||||||
style: ButtonStyle
|
style: ButtonStyle
|
||||||
{
|
{
|
||||||
background: Rectangle
|
background: Rectangle
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2018 Ultimaker B.V.
|
// Copyright (c) 2018 Ultimaker B.V.
|
||||||
// PluginBrowser is released under the terms of the LGPLv3 or higher.
|
// 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.Dialogs 1.1
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Controls.Styles 1.4
|
import QtQuick.Controls.Styles 1.4
|
||||||
@ -12,29 +12,31 @@ import UM 1.1 as UM
|
|||||||
ScrollView
|
ScrollView
|
||||||
{
|
{
|
||||||
id: base
|
id: base
|
||||||
frameVisible: false
|
frameVisible: true
|
||||||
anchors.fill: parent
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
style: UM.Theme.styles.scrollview
|
style: UM.Theme.styles.scrollview
|
||||||
Column
|
Column
|
||||||
{
|
{
|
||||||
width: base.width
|
width: base.width
|
||||||
spacing: UM.Theme.getSize("base_unit").height
|
spacing: UM.Theme.getSize("base_unit").height
|
||||||
height: childrenRect.height
|
padding: UM.Theme.getSize("base_unit").height * 2
|
||||||
anchors
|
height: childrenRect.height + 2 * padding
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
ToolboxShowcase
|
ToolboxShowcase
|
||||||
{
|
{
|
||||||
id: showcase
|
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
|
ToolboxGrid
|
||||||
{
|
{
|
||||||
id: allPlugins
|
id: allPlugins
|
||||||
|
width: parent.width - 2 * parent.padding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -68,7 +68,7 @@ Item
|
|||||||
|
|
||||||
property alias configureSettingVisibility: configureSettingVisibilityAction
|
property alias configureSettingVisibility: configureSettingVisibilityAction
|
||||||
|
|
||||||
property alias browsePlugins: browsePluginsAction
|
property alias browsePackages: browsePackagesAction
|
||||||
|
|
||||||
UM.I18nCatalog{id: catalog; name:"cura"}
|
UM.I18nCatalog{id: catalog; name:"cura"}
|
||||||
|
|
||||||
@ -429,8 +429,8 @@ Item
|
|||||||
|
|
||||||
Action
|
Action
|
||||||
{
|
{
|
||||||
id: browsePluginsAction
|
id: browsePackagesAction
|
||||||
text: catalog.i18nc("@action:menu", "Browse plugins...")
|
text: catalog.i18nc("@action:menu", "Browse packages...")
|
||||||
iconName: "plugins_browse"
|
iconName: "plugins_browse"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,9 +270,9 @@ UM.MainWindow
|
|||||||
Menu
|
Menu
|
||||||
{
|
{
|
||||||
id: plugin_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
|
Menu
|
||||||
@ -668,9 +668,9 @@ UM.MainWindow
|
|||||||
// show the plugin browser dialog
|
// show the plugin browser dialog
|
||||||
Connections
|
Connections
|
||||||
{
|
{
|
||||||
target: Cura.Actions.browsePlugins
|
target: Cura.Actions.browsePackages
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
curaExtensions.callExtensionMethod("Plugin Browser", "browsePlugins")
|
curaExtensions.callExtensionMethod("Toolbox", "browsePackages")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user