Merge branch 'master' into feature-backup-manager

This commit is contained in:
ChrisTerBeke 2018-05-15 12:56:19 +02:00
commit 82a1c95d98
13 changed files with 240 additions and 131 deletions

View file

@ -153,7 +153,6 @@ class CuraApplication(QtApplication):
if not hasattr(sys, "frozen"): if not hasattr(sys, "frozen"):
resource_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources") resource_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources")
Resources.addSearchPath(resource_path) Resources.addSearchPath(resource_path)
Resources.setBundledResourcesPath(resource_path)
self._use_gui = True self._use_gui = True
self._open_file_queue = [] # Files to open when plug-ins are loaded. self._open_file_queue = [] # Files to open when plug-ins are loaded.

View file

@ -28,15 +28,18 @@ class CuraPackageManager(QObject):
self._container_registry = self._application.getContainerRegistry() self._container_registry = self._application.getContainerRegistry()
self._plugin_registry = self._application.getPluginRegistry() self._plugin_registry = self._application.getPluginRegistry()
# JSON file that keeps track of all installed packages. #JSON files that keep track of all installed packages.
self._bundled_package_management_file_path = os.path.join( self._user_package_management_file_path = None
os.path.abspath(Resources.getBundledResourcesPath()), self._bundled_package_management_file_path = None
"packages.json" for search_path in Resources.getSearchPaths():
) candidate_bundled_path = os.path.join(search_path, "bundled_packages.json")
self._user_package_management_file_path = os.path.join( if os.path.exists(candidate_bundled_path):
os.path.abspath(Resources.getDataStoragePath()), self._bundled_package_management_file_path = candidate_bundled_path
"packages.json" candidate_user_path = os.path.join(search_path, "packages.json")
) if os.path.exists(candidate_user_path):
self._user_package_management_file_path = candidate_user_path
if self._user_package_management_file_path is None: #Doesn't exist yet.
self._user_package_management_file_path = os.path.join(Resources.getDataStoragePath(), "packages.json")
self._bundled_package_dict = {} # A dict of all bundled packages self._bundled_package_dict = {} # A dict of all bundled packages
self._installed_package_dict = {} # A dict of all installed packages self._installed_package_dict = {} # A dict of all installed packages
@ -136,14 +139,14 @@ class CuraPackageManager(QObject):
all_installed_ids = all_installed_ids.union(set(self._bundled_package_dict.keys())) all_installed_ids = all_installed_ids.union(set(self._bundled_package_dict.keys()))
if self._installed_package_dict.keys(): if self._installed_package_dict.keys():
all_installed_ids = all_installed_ids.union(set(self._installed_package_dict.keys())) all_installed_ids = all_installed_ids.union(set(self._installed_package_dict.keys()))
all_installed_ids = all_installed_ids.difference(self._to_remove_package_set)
# If it's going to be installed and to be removed, then the package is being updated and it should be listed.
if self._to_install_package_dict.keys(): if self._to_install_package_dict.keys():
all_installed_ids = all_installed_ids.union(set(self._to_install_package_dict.keys())) all_installed_ids = all_installed_ids.union(set(self._to_install_package_dict.keys()))
all_installed_ids = all_installed_ids.difference(self._to_remove_package_set)
# map of <package_type> -> <package_id> -> <package_info> # map of <package_type> -> <package_id> -> <package_info>
installed_packages_dict = {} installed_packages_dict = {}
for package_id in all_installed_ids: for package_id in all_installed_ids:
# Skip required plugins as they should not be tampered with # Skip required plugins as they should not be tampered with
if package_id in Application.getInstance().getRequiredPlugins(): if package_id in Application.getInstance().getRequiredPlugins():
continue continue
@ -194,11 +197,6 @@ class CuraPackageManager(QObject):
return return
package_id = package_info["package_id"] package_id = package_info["package_id"]
# Check the delayed installation and removal lists first
if package_id in self._to_remove_package_set:
self._to_remove_package_set.remove(package_id)
has_changes = True
# Check if it is installed # Check if it is installed
installed_package_info = self.getInstalledPackageInfo(package_info["package_id"]) installed_package_info = self.getInstalledPackageInfo(package_info["package_id"])
to_install_package = installed_package_info is None # Install if the package has not been installed to_install_package = installed_package_info is None # Install if the package has not been installed
@ -235,19 +233,27 @@ class CuraPackageManager(QObject):
self.installedPackagesChanged.emit() self.installedPackagesChanged.emit()
# Schedules the given package to be removed upon the next start. # Schedules the given package to be removed upon the next start.
# \param package_id id of the package
# \param force_add is used when updating. In that case you actually want to uninstall & install
@pyqtSlot(str) @pyqtSlot(str)
def removePackage(self, package_id: str) -> None: def removePackage(self, package_id: str, force_add: bool = False) -> None:
# Check the delayed installation and removal lists first # Check the delayed installation and removal lists first
if not self.isPackageInstalled(package_id): if not self.isPackageInstalled(package_id):
Logger.log("i", "Attempt to remove package [%s] that is not installed, do nothing.", package_id) Logger.log("i", "Attempt to remove package [%s] that is not installed, do nothing.", package_id)
return return
# Remove from the delayed installation list if present # Temp hack
if package_id in self._to_install_package_dict: if package_id not in self._installed_package_dict and package_id in self._bundled_package_dict:
del self._to_install_package_dict[package_id] Logger.log("i", "Not uninstalling [%s] because it is a bundled package.")
return
if package_id not in self._to_install_package_dict or force_add:
# Schedule for a delayed removal: # Schedule for a delayed removal:
self._to_remove_package_set.add(package_id) self._to_remove_package_set.add(package_id)
else:
if package_id in self._to_install_package_dict:
# Remove from the delayed installation list if present
del self._to_install_package_dict[package_id]
self._saveManagementData() self._saveManagementData()
self.installedPackagesChanged.emit() self.installedPackagesChanged.emit()

View file

@ -346,7 +346,7 @@ class PrintInformation(QObject):
Logger.log("w", "Unsupported Mime Type Database file extension") Logger.log("w", "Unsupported Mime Type Database file extension")
if data is not None and check_name is not None: if data is not None and check_name is not None:
self._base_name = check_name self._base_name = data
else: else:
self._base_name = '' self._base_name = ''

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

View file

@ -0,0 +1 @@
<svg width="200px" height="200px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-rolling" style="animation-play-state: running; animation-delay: 0s; background-image: none; background-position: initial initial; background-repeat: initial initial;"><circle cx="50" cy="50" fill="none" ng-attr-stroke="{{config.color}}" ng-attr-stroke-width="{{config.width}}" ng-attr-r="{{config.radius}}" ng-attr-stroke-dasharray="{{config.dasharray}}" stroke="#0CA9E3" stroke-width="13" r="43" stroke-dasharray="202.63272615654165 69.54424205218055" style="animation-play-state: running; animation-delay: 0s;"><animateTransform attributeName="transform" type="rotate" calcMode="linear" values="0 50 50;360 50 50" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animateTransform></circle></svg>

After

Width:  |  Height:  |  Size: 903 B

View file

@ -20,7 +20,7 @@ Item
{ {
left: parent.left left: parent.left
right: controls.left right: controls.left
rightMargin: UM.Theme.getSize("default_margin").width rightMargin: UM.Theme.getSize("default_margin").width * 2 + UM.Theme.getSize("toolbox_loader").width
top: parent.top top: parent.top
} }
Label Label
@ -53,60 +53,25 @@ Item
anchors.top: tile.top anchors.top: tile.top
width: childrenRect.width width: childrenRect.width
height: childrenRect.height height: childrenRect.height
Button
ToolboxProgressButton
{ {
id: installButton id: installButton
text: active: toolbox.isDownloading && toolbox.activePackage == model
{ complete: tile.installed
if (installed) readyAction: function() {
{ toolbox.activePackage = model
return catalog.i18nc("@action:button", "Installed") toolbox.startDownload(model.download_url)
} }
else activeAction: function() {
{ toolbox.cancelDownload()
if (toolbox.isDownloading && toolbox.activePackage == model)
{
return catalog.i18nc("@action:button", "Cancel")
} }
else completeAction: function() {
{
return catalog.i18nc("@action:button", "Install")
}
}
}
enabled: installed || !(toolbox.isDownloading && toolbox.activePackage != model) //Don't allow installing while another download is running.
opacity: enabled ? 1.0 : 0.5
property alias installed: tile.installed
style: UM.Theme.styles.toolbox_action_button
onClicked:
{
if (installed)
{
toolbox.viewCategory = "installed" toolbox.viewCategory = "installed"
} }
else // Don't allow installing while another download is running
{ enabled: installed || !(toolbox.isDownloading && toolbox.activePackage != model)
// if ( toolbox.isDownloading && toolbox.activePackage == model ) opacity: enabled ? 1.0 : 0.5
if ( toolbox.isDownloading )
{
toolbox.cancelDownload();
}
else
{
toolbox.activePackage = model
// toolbox.activePackage = model;
if ( model.can_upgrade )
{
// toolbox.downloadAndInstallPlugin( model.update_url );
}
else
{
toolbox.startDownload( model.download_url );
}
}
}
}
} }
} }

View file

@ -11,56 +11,26 @@ Column
width: UM.Theme.getSize("toolbox_action_button").width width: UM.Theme.getSize("toolbox_action_button").width
spacing: UM.Theme.getSize("narrow_margin").height spacing: UM.Theme.getSize("narrow_margin").height
Item ToolboxProgressButton
{
width: parent.width
height: childrenRect.height
visible: canUpdate
Button
{ {
id: updateButton id: updateButton
text: catalog.i18nc("@action:button", "Update") active: toolbox.isDownloading && toolbox.activePackage == model
style: ButtonStyle readyLabel: catalog.i18nc("@action:button", "Update")
{ activeLabel: catalog.i18nc("@action:button", "Updating")
background: Rectangle completeLabel: catalog.i18nc("@action:button", "Updated")
{ readyAction: function() {
implicitWidth: UM.Theme.getSize("toolbox_action_button").width toolbox.activePackage = model
implicitHeight: UM.Theme.getSize("toolbox_action_button").height toolbox.update(model.id)
color: control.hovered ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary")
}
label: Label
{
text: control.text
color: control.hovered ? UM.Theme.getColor("button_text") : UM.Theme.getColor("button_text_hover")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font: UM.Theme.getFont("default_bold")
}
}
onClicked: toolbox.update(model.id)
}
ProgressBar
{
id: progressbar
width: parent.width
value: toolbox.isDownloading ? toolbox.downloadProgress : 0
visible: toolbox.isDownloading
style: ProgressBarStyle
{
background: Rectangle
{
color: "transparent"
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
}
progress: Rectangle
{
// TODO Define a good color that fits the purpuse
color: "blue"
opacity: 0.5
}
} }
activeAction: function() {
toolbox.cancelDownload()
} }
// Don't allow installing while another download is running
enabled: !(toolbox.isDownloading && toolbox.activePackage != model)
opacity: enabled ? 1.0 : 0.5
visible: canUpdate
} }
Button Button
{ {
id: removeButton id: removeButton

View file

@ -0,0 +1,125 @@
// Copyright (c) 2018 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM
Item
{
id: base
property var active: false
property var complete: false
property var readyLabel: "Install"
property var activeLabel: "Installing"
property var completeLabel: "Installed"
property var readyAction: null // Action when button is ready and clicked (likely install)
property var activeAction: null // Action when button is active and clicked (likely cancel)
property var completeAction: null // Action when button is complete and clicked (likely go to installed)
width: UM.Theme.getSize("toolbox_action_button").width
height: UM.Theme.getSize("toolbox_action_button").height
Button
{
id: button
text:
{
if (complete)
{
return catalog.i18nc("@action:button", "Installed")
}
else if (active)
{
return catalog.i18nc("@action:button", "Cancel")
}
else
{
return catalog.i18nc("@action:button", "Install")
}
}
onClicked:
{
if (complete)
{
return completeAction()
}
else if (active)
{
return activeAction()
}
else
{
return readyAction()
}
}
style: ButtonStyle
{
background: Rectangle
{
implicitWidth: UM.Theme.getSize("toolbox_action_button").width
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
color:
{
if (base.complete)
{
return UM.Theme.getColor("action_button_disabled")
}
else
{
if (control.hovered)
{
return UM.Theme.getColor("primary_hover")
}
else
{
return UM.Theme.getColor("primary")
}
}
}
}
label: Label
{
text: control.text
color:
{
if (base.complete)
{
return UM.Theme.getColor("action_button_disabled_text")
}
else
{
if (control.hovered)
{
return UM.Theme.getColor("button_text_hover")
}
else
{
return UM.Theme.getColor("button_text")
}
}
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font: UM.Theme.getFont("default_bold")
}
}
}
AnimatedImage
{
id: loader
visible: active
source: "../images/loading.gif"
width: UM.Theme.getSize("toolbox_loader").width
height: UM.Theme.getSize("toolbox_loader").height
anchors.right: button.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: button.verticalCenter
}
}

View file

@ -70,6 +70,7 @@ class Toolbox(QObject, Extension):
"plugins_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)), "plugins_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)),
"materials_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)) "materials_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url))
} }
self._to_update = [] # Package_ids that are waiting to be updated
# Data: # Data:
self._metadata = { self._metadata = {
@ -234,13 +235,35 @@ class Toolbox(QObject, Extension):
@pyqtSlot(str) @pyqtSlot(str)
def uninstall(self, plugin_id: str) -> None: def uninstall(self, plugin_id: str) -> None:
self._package_manager.removePackage(plugin_id) self._package_manager.removePackage(plugin_id, force_add = True)
self.installChanged.emit() self.installChanged.emit()
self._updateInstalledModels() self._updateInstalledModels()
self.metadataChanged.emit() self.metadataChanged.emit()
self._restart_required = True self._restart_required = True
self.restartRequiredChanged.emit() self.restartRequiredChanged.emit()
## Actual update packages that are in self._to_update
def _update(self) -> None:
if self._to_update:
plugin_id = self._to_update.pop(0)
remote_package = self.getRemotePackage(plugin_id)
if remote_package:
download_url = remote_package["download_url"]
Logger.log("d", "Updating package [%s]..." % plugin_id)
self.uninstall(plugin_id)
self.startDownload(download_url)
else:
Logger.log("e", "Could not update package [%s] because there is no remote package info available.", plugin_id)
if self._to_update:
self._application.callLater(self._update)
## Update a plugin by plugin_id
@pyqtSlot(str)
def update(self, plugin_id: str) -> None:
self._to_update.append(plugin_id)
self._application.callLater(self._update)
@pyqtSlot(str) @pyqtSlot(str)
def enable(self, plugin_id: str) -> None: def enable(self, plugin_id: str) -> None:
self._plugin_registry.enablePlugin(plugin_id) self._plugin_registry.enablePlugin(plugin_id)
@ -269,6 +292,15 @@ class Toolbox(QObject, Extension):
def restart(self): def restart(self):
CuraApplication.getInstance().windowClosed() CuraApplication.getInstance().windowClosed()
def getRemotePackage(self, package_id: str) -> Optional[Dict]:
# TODO: make the lookup in a dict, not a loop. canUpdate is called for every item.
remote_package = None
for package in self._metadata["packages"]:
if package["package_id"] == package_id:
remote_package = package
break
return remote_package
# Checks # Checks
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
@pyqtSlot(str, result = bool) @pyqtSlot(str, result = bool)
@ -277,10 +309,7 @@ class Toolbox(QObject, Extension):
if local_package is None: if local_package is None:
return False return False
remote_package = None remote_package = self.getRemotePackage(package_id)
for package in self._metadata["packages"]:
if package["package_id"] == package_id:
remote_package = package
if remote_package is None: if remote_package is None:
return False return False
@ -339,8 +368,8 @@ class Toolbox(QObject, Extension):
def resetDownload(self) -> None: def resetDownload(self) -> None:
if self._download_reply: if self._download_reply:
self._download_reply.abort()
self._download_reply.downloadProgress.disconnect(self._onDownloadProgress) self._download_reply.downloadProgress.disconnect(self._onDownloadProgress)
self._download_reply.abort()
self._download_reply = None self._download_reply = None
self._download_request = None self._download_request = None
self.setDownloadProgress(0) self.setDownloadProgress(0)

View file

@ -458,6 +458,7 @@
"toolbox_header": [1.0, 4.0], "toolbox_header": [1.0, 4.0],
"toolbox_progress_bar": [8.0, 0.5], "toolbox_progress_bar": [8.0, 0.5],
"toolbox_chart_row": [1.0, 2.0], "toolbox_chart_row": [1.0, 2.0],
"toolbox_action_button": [8.0, 2.5] "toolbox_action_button": [8.0, 2.5],
"toolbox_loader": [2.0, 2.0]
} }
} }

View file

@ -0,0 +1,13 @@
[general]
name = Aluminum
version = 4
definition = ultimaker_s5
[metadata]
setting_version = 4
type = variant
hardware_type = buildplate
[values]
material_bed_temperature = =default_material_bed_temperature + 10
machine_buildplate_type = aluminum