mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 10:45:54 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
2e0489c509
13
.github/no-response.yml
vendored
Normal file
13
.github/no-response.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Configuration for probot-no-response - https://github.com/probot/no-response
|
||||||
|
|
||||||
|
# Number of days of inactivity before an Issue is closed for lack of response
|
||||||
|
daysUntilClose: 14
|
||||||
|
# Label requiring a response
|
||||||
|
responseRequiredLabel: 'Status: Needs Info'
|
||||||
|
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
|
||||||
|
closeComment: >
|
||||||
|
This issue has been automatically closed because there has been no response
|
||||||
|
to our request for more information from the original author. With only the
|
||||||
|
information that is currently in the issue, we don't have enough information
|
||||||
|
to take action. Please reach out if you have or find the answers we need so
|
||||||
|
that we can investigate further.
|
@ -80,8 +80,11 @@ class Arrange:
|
|||||||
# After scaling (like up to 0.1 mm) the node might not have points
|
# After scaling (like up to 0.1 mm) the node might not have points
|
||||||
if not points.size:
|
if not points.size:
|
||||||
continue
|
continue
|
||||||
|
try:
|
||||||
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
||||||
|
except ValueError:
|
||||||
|
Logger.logException("w", "Unable to create polygon")
|
||||||
|
continue
|
||||||
arranger.place(0, 0, shape_arr)
|
arranger.place(0, 0, shape_arr)
|
||||||
|
|
||||||
# If a build volume was set, add the disallowed areas
|
# If a build volume was set, add the disallowed areas
|
||||||
|
@ -31,7 +31,6 @@ class AutoSave:
|
|||||||
self._change_timer.timeout.connect(self._onTimeout)
|
self._change_timer.timeout.connect(self._onTimeout)
|
||||||
self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||||
self._onGlobalStackChanged()
|
self._onGlobalStackChanged()
|
||||||
self._triggerTimer()
|
|
||||||
|
|
||||||
def _triggerTimer(self, *args: Any) -> None:
|
def _triggerTimer(self, *args: Any) -> None:
|
||||||
if not self._saving:
|
if not self._saving:
|
||||||
|
@ -215,6 +215,16 @@ class CrashHandler:
|
|||||||
locale.getdefaultlocale()[0]
|
locale.getdefaultlocale()[0]
|
||||||
self.data["locale_cura"] = self.cura_locale
|
self.data["locale_cura"] = self.cura_locale
|
||||||
|
|
||||||
|
try:
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
plugins = CuraApplication.getInstance().getPluginRegistry()
|
||||||
|
self.data["plugins"] = {
|
||||||
|
plugin_id: plugins.getMetaData(plugin_id)["plugin"]["version"]
|
||||||
|
for plugin_id in plugins.getInstalledPlugins() if not plugins.isBundledPlugin(plugin_id)
|
||||||
|
}
|
||||||
|
except:
|
||||||
|
self.data["plugins"] = {"[FAILED]": "0.0.0"}
|
||||||
|
|
||||||
crash_info = "<b>" + catalog.i18nc("@label Cura version number", "Cura version") + ":</b> " + str(self.cura_version) + "<br/>"
|
crash_info = "<b>" + catalog.i18nc("@label Cura version number", "Cura version") + ":</b> " + str(self.cura_version) + "<br/>"
|
||||||
crash_info += "<b>" + catalog.i18nc("@label", "Cura language") + ":</b> " + str(self.cura_locale) + "<br/>"
|
crash_info += "<b>" + catalog.i18nc("@label", "Cura language") + ":</b> " + str(self.cura_locale) + "<br/>"
|
||||||
crash_info += "<b>" + catalog.i18nc("@label", "OS language") + ":</b> " + str(self.data["locale_os"]) + "<br/>"
|
crash_info += "<b>" + catalog.i18nc("@label", "OS language") + ":</b> " + str(self.data["locale_os"]) + "<br/>"
|
||||||
@ -238,6 +248,8 @@ class CrashHandler:
|
|||||||
scope.set_tag("locale_cura", self.cura_locale)
|
scope.set_tag("locale_cura", self.cura_locale)
|
||||||
scope.set_tag("is_enterprise", ApplicationMetadata.IsEnterpriseVersion)
|
scope.set_tag("is_enterprise", ApplicationMetadata.IsEnterpriseVersion)
|
||||||
|
|
||||||
|
scope.set_context("plugins", self.data["plugins"])
|
||||||
|
|
||||||
scope.set_user({"id": str(uuid.getnode())})
|
scope.set_user({"id": str(uuid.getnode())})
|
||||||
|
|
||||||
return group
|
return group
|
||||||
|
@ -756,7 +756,6 @@ class CuraApplication(QtApplication):
|
|||||||
if not hasattr(sys, "frozen"):
|
if not hasattr(sys, "frozen"):
|
||||||
self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins"))
|
self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins"))
|
||||||
self._plugin_registry.loadPlugin("ConsoleLogger")
|
self._plugin_registry.loadPlugin("ConsoleLogger")
|
||||||
self._plugin_registry.loadPlugin("CuraEngineBackend")
|
|
||||||
|
|
||||||
self._plugin_registry.loadPlugins()
|
self._plugin_registry.loadPlugins()
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2019 Ultimaker B.V.
|
# Copyright (c) 2020 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.
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
@ -119,9 +119,9 @@ class CuraSceneNode(SceneNode):
|
|||||||
self._aabb = None
|
self._aabb = None
|
||||||
if self._mesh_data:
|
if self._mesh_data:
|
||||||
self._aabb = self._mesh_data.getExtents(self.getWorldTransformation())
|
self._aabb = self._mesh_data.getExtents(self.getWorldTransformation())
|
||||||
else: # If there is no mesh_data, use a boundingbox that encompasses the local (0,0,0)
|
else: # If there is no mesh_data, use a bounding box that encompasses the local (0,0,0)
|
||||||
position = self.getWorldPosition()
|
position = self.getWorldPosition()
|
||||||
self._aabb = AxisAlignedBox(minimum=position, maximum=position)
|
self._aabb = AxisAlignedBox(minimum = position, maximum = position)
|
||||||
|
|
||||||
for child in self.getAllChildren():
|
for child in self.getAllChildren():
|
||||||
if child.callDecoration("isNonPrintingMesh"):
|
if child.callDecoration("isNonPrintingMesh"):
|
||||||
|
@ -60,6 +60,8 @@ class CuraContainerStack(ContainerStack):
|
|||||||
import cura.CuraApplication #Here to prevent circular imports.
|
import cura.CuraApplication #Here to prevent circular imports.
|
||||||
self.setMetaDataEntry("setting_version", cura.CuraApplication.CuraApplication.SettingVersion)
|
self.setMetaDataEntry("setting_version", cura.CuraApplication.CuraApplication.SettingVersion)
|
||||||
|
|
||||||
|
self.setDirty(False)
|
||||||
|
|
||||||
# This is emitted whenever the containersChanged signal from the ContainerStack base class is emitted.
|
# This is emitted whenever the containersChanged signal from the ContainerStack base class is emitted.
|
||||||
pyqtContainersChanged = pyqtSignal()
|
pyqtContainersChanged = pyqtSignal()
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ class ExtruderStack(CuraContainerStack):
|
|||||||
|
|
||||||
self.propertiesChanged.connect(self._onPropertiesChanged)
|
self.propertiesChanged.connect(self._onPropertiesChanged)
|
||||||
|
|
||||||
|
self.setDirty(False)
|
||||||
|
|
||||||
enabledChanged = pyqtSignal()
|
enabledChanged = pyqtSignal()
|
||||||
|
|
||||||
@override(ContainerStack)
|
@override(ContainerStack)
|
||||||
|
@ -55,6 +55,8 @@ class GlobalStack(CuraContainerStack):
|
|||||||
# properties. So we need to tie them together like this.
|
# properties. So we need to tie them together like this.
|
||||||
self.metaDataChanged.connect(self.configuredConnectionTypesChanged)
|
self.metaDataChanged.connect(self.configuredConnectionTypesChanged)
|
||||||
|
|
||||||
|
self.setDirty(False)
|
||||||
|
|
||||||
extrudersChanged = pyqtSignal()
|
extrudersChanged = pyqtSignal()
|
||||||
configuredConnectionTypesChanged = pyqtSignal()
|
configuredConnectionTypesChanged = pyqtSignal()
|
||||||
|
|
||||||
|
@ -738,14 +738,15 @@ class MachineManager(QObject):
|
|||||||
containers = CuraContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id)
|
containers = CuraContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id)
|
||||||
for container in containers:
|
for container in containers:
|
||||||
CuraContainerRegistry.getInstance().removeContainer(container["id"])
|
CuraContainerRegistry.getInstance().removeContainer(container["id"])
|
||||||
machine_stack = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", name = machine_id)[0]
|
machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", name = machine_id)
|
||||||
CuraContainerRegistry.getInstance().removeContainer(machine_stack.definitionChanges.getId())
|
if machine_stacks:
|
||||||
|
CuraContainerRegistry.getInstance().removeContainer(machine_stacks[0].definitionChanges.getId())
|
||||||
CuraContainerRegistry.getInstance().removeContainer(machine_id)
|
CuraContainerRegistry.getInstance().removeContainer(machine_id)
|
||||||
|
|
||||||
# If the printer that is being removed is a network printer, the hidden printers have to be also removed
|
# If the printer that is being removed is a network printer, the hidden printers have to be also removed
|
||||||
group_id = metadata.get("group_id", None)
|
group_id = metadata.get("group_id", None)
|
||||||
if group_id:
|
if group_id:
|
||||||
metadata_filter = {"group_id": group_id}
|
metadata_filter = {"group_id": group_id, "hidden": True}
|
||||||
hidden_containers = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter)
|
hidden_containers = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter)
|
||||||
if hidden_containers:
|
if hidden_containers:
|
||||||
# This reuses the method and remove all printers recursively
|
# This reuses the method and remove all printers recursively
|
||||||
@ -1368,7 +1369,6 @@ class MachineManager(QObject):
|
|||||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||||
self.switchPrinterType(configuration.printerType)
|
self.switchPrinterType(configuration.printerType)
|
||||||
|
|
||||||
disabled_used_extruder_position_set = set()
|
|
||||||
extruders_to_disable = set()
|
extruders_to_disable = set()
|
||||||
|
|
||||||
# If an extruder that's currently used to print a model gets disabled due to the syncing, we need to show
|
# If an extruder that's currently used to print a model gets disabled due to the syncing, we need to show
|
||||||
@ -1377,8 +1377,8 @@ class MachineManager(QObject):
|
|||||||
|
|
||||||
for extruder_configuration in configuration.extruderConfigurations:
|
for extruder_configuration in configuration.extruderConfigurations:
|
||||||
# We support "" or None, since the cloud uses None instead of empty strings
|
# We support "" or None, since the cloud uses None instead of empty strings
|
||||||
extruder_has_hotend = extruder_configuration.hotendID and extruder_configuration.hotendID != ""
|
extruder_has_hotend = extruder_configuration.hotendID not in ["", None]
|
||||||
extruder_has_material = extruder_configuration.material.guid and extruder_configuration.material.guid != ""
|
extruder_has_material = extruder_configuration.material.guid not in [None, "", "00000000-0000-0000-0000-000000000000"]
|
||||||
|
|
||||||
# If the machine doesn't have a hotend or material, disable this extruder
|
# If the machine doesn't have a hotend or material, disable this extruder
|
||||||
if not extruder_has_hotend or not extruder_has_material:
|
if not extruder_has_hotend or not extruder_has_material:
|
||||||
@ -1396,7 +1396,6 @@ class MachineManager(QObject):
|
|||||||
self._global_container_stack.extruderList[int(position)].setEnabled(False)
|
self._global_container_stack.extruderList[int(position)].setEnabled(False)
|
||||||
|
|
||||||
need_to_show_message = True
|
need_to_show_message = True
|
||||||
disabled_used_extruder_position_set.add(int(position))
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
machine_node = ContainerTree.getInstance().machines.get(self._global_container_stack.definition.getId())
|
machine_node = ContainerTree.getInstance().machines.get(self._global_container_stack.definition.getId())
|
||||||
@ -1427,7 +1426,7 @@ class MachineManager(QObject):
|
|||||||
|
|
||||||
# Show human-readable extruder names such as "Extruder Left", "Extruder Front" instead of "Extruder 1, 2, 3".
|
# Show human-readable extruder names such as "Extruder Left", "Extruder Front" instead of "Extruder 1, 2, 3".
|
||||||
extruder_names = []
|
extruder_names = []
|
||||||
for extruder_position in sorted(disabled_used_extruder_position_set):
|
for extruder_position in sorted(extruders_to_disable):
|
||||||
extruder_stack = self._global_container_stack.extruderList[int(extruder_position)]
|
extruder_stack = self._global_container_stack.extruderList[int(extruder_position)]
|
||||||
extruder_name = extruder_stack.definition.getName()
|
extruder_name = extruder_stack.definition.getName()
|
||||||
extruder_names.append(extruder_name)
|
extruder_names.append(extruder_name)
|
||||||
|
@ -67,4 +67,4 @@ cmake3 \
|
|||||||
-DBUILD_TESTS=ON \
|
-DBUILD_TESTS=ON \
|
||||||
..
|
..
|
||||||
make
|
make
|
||||||
ctest3 --output-on-failure -T Test
|
ctest3 -j4 --output-on-failure -T Test
|
||||||
|
@ -651,7 +651,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
self._container_registry.addContainer(global_stack)
|
self._container_registry.addContainer(global_stack)
|
||||||
else:
|
else:
|
||||||
# Find the machine
|
# Find the machine
|
||||||
global_stack = self._container_registry.findContainerStacks(name = self._machine_info.name, type = "machine")[0]
|
global_stacks = self._container_registry.findContainerStacks(name = self._machine_info.name, type = "machine")
|
||||||
|
if not global_stacks:
|
||||||
|
message = Message(i18n_catalog.i18nc("@info:error Don't translate the XML tag <filename>!", "Project file <filename>{0}</filename> is made using profiles that are unknown to this version of Ultimaker Cura.", file_name))
|
||||||
|
message.show()
|
||||||
|
self.setWorkspaceName("")
|
||||||
|
return [], {}
|
||||||
|
global_stack = global_stacks[0]
|
||||||
extruder_stacks = self._container_registry.findContainerStacks(machine = global_stack.getId(),
|
extruder_stacks = self._container_registry.findContainerStacks(machine = global_stack.getId(),
|
||||||
type = "extruder_train")
|
type = "extruder_train")
|
||||||
extruder_stack_dict = {stack.getMetaDataEntry("position"): stack for stack in extruder_stacks}
|
extruder_stack_dict = {stack.getMetaDataEntry("position"): stack for stack in extruder_stacks}
|
||||||
|
@ -204,10 +204,11 @@ class PauseAtHeight(Script):
|
|||||||
"""Get the X and Y values for a layer (will be used to get X and Y of the layer after the pause)."""
|
"""Get the X and Y values for a layer (will be used to get X and Y of the layer after the pause)."""
|
||||||
lines = layer.split("\n")
|
lines = layer.split("\n")
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if self.getValue(line, "X") is not None and self.getValue(line, "Y") is not None:
|
if line.startswith(("G0", "G1", "G2", "G3")):
|
||||||
x = self.getValue(line, "X")
|
if self.getValue(line, "X") is not None and self.getValue(line, "Y") is not None:
|
||||||
y = self.getValue(line, "Y")
|
x = self.getValue(line, "X")
|
||||||
return x, y
|
y = self.getValue(line, "Y")
|
||||||
|
return x, y
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
def execute(self, data: List[str]) -> List[str]:
|
def execute(self, data: List[str]) -> List[str]:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2019 Ultimaker B.V.
|
# Copyright (c) 2020 Ultimaker B.V.
|
||||||
# Toolbox is released under the terms of the LGPLv3 or higher.
|
# Toolbox is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@ -232,7 +232,7 @@ class Toolbox(QObject, Extension):
|
|||||||
"licenseModel": self._license_model
|
"licenseModel": self._license_model
|
||||||
})
|
})
|
||||||
if not dialog:
|
if not dialog:
|
||||||
raise Exception("Failed to create Marketplace dialog")
|
return None
|
||||||
return dialog
|
return dialog
|
||||||
|
|
||||||
def _convertPluginMetadata(self, plugin_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
def _convertPluginMetadata(self, plugin_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||||
|
@ -31,6 +31,7 @@ class CloudOutputDeviceManager:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
META_CLUSTER_ID = "um_cloud_cluster_id"
|
META_CLUSTER_ID = "um_cloud_cluster_id"
|
||||||
|
META_HOST_GUID = "host_guid"
|
||||||
META_NETWORK_KEY = "um_network_key"
|
META_NETWORK_KEY = "um_network_key"
|
||||||
|
|
||||||
SYNC_SERVICE_NAME = "CloudOutputDeviceManager"
|
SYNC_SERVICE_NAME = "CloudOutputDeviceManager"
|
||||||
@ -113,13 +114,18 @@ class CloudOutputDeviceManager:
|
|||||||
all_clusters = {c.cluster_id: c for c in clusters} # type: Dict[str, CloudClusterResponse]
|
all_clusters = {c.cluster_id: c for c in clusters} # type: Dict[str, CloudClusterResponse]
|
||||||
online_clusters = {c.cluster_id: c for c in clusters if c.is_online} # type: Dict[str, CloudClusterResponse]
|
online_clusters = {c.cluster_id: c for c in clusters if c.is_online} # type: Dict[str, CloudClusterResponse]
|
||||||
|
|
||||||
# Add the new printers in Cura. If a printer was previously added and is rediscovered, set its metadata to
|
# Add the new printers in Cura.
|
||||||
# reflect that and mark the printer not removed from the account
|
|
||||||
for device_id, cluster_data in all_clusters.items():
|
for device_id, cluster_data in all_clusters.items():
|
||||||
if device_id not in self._remote_clusters:
|
if device_id not in self._remote_clusters:
|
||||||
new_clusters.append(cluster_data)
|
new_clusters.append(cluster_data)
|
||||||
if device_id in self._um_cloud_printers and not parseBool(self._um_cloud_printers[device_id].getMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, "true")):
|
if device_id in self._um_cloud_printers:
|
||||||
self._um_cloud_printers[device_id].setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, True)
|
# Existing cloud printers may not have the host_guid meta-data entry. If that's the case, add it.
|
||||||
|
if not self._um_cloud_printers[device_id].getMetaDataEntry(self.META_HOST_GUID, None):
|
||||||
|
self._um_cloud_printers[device_id].setMetaDataEntry(self.META_HOST_GUID, cluster_data.host_guid)
|
||||||
|
# If a printer was previously not linked to the account and is rediscovered, mark the printer as linked
|
||||||
|
# to the current account
|
||||||
|
if not parseBool(self._um_cloud_printers[device_id].getMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, "true")):
|
||||||
|
self._um_cloud_printers[device_id].setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, True)
|
||||||
self._onDevicesDiscovered(new_clusters)
|
self._onDevicesDiscovered(new_clusters)
|
||||||
|
|
||||||
# Hide the current removed_printers_message, if there is any
|
# Hide the current removed_printers_message, if there is any
|
||||||
@ -161,11 +167,22 @@ class CloudOutputDeviceManager:
|
|||||||
"""
|
"""
|
||||||
new_devices = []
|
new_devices = []
|
||||||
remote_clusters_added = False
|
remote_clusters_added = False
|
||||||
|
host_guid_map = {machine.getMetaDataEntry(self.META_HOST_GUID): device_cluster_id
|
||||||
|
for device_cluster_id, machine in self._um_cloud_printers.items()
|
||||||
|
if machine.getMetaDataEntry(self.META_HOST_GUID)}
|
||||||
|
machine_manager = CuraApplication.getInstance().getMachineManager()
|
||||||
|
|
||||||
for cluster_data in clusters:
|
for cluster_data in clusters:
|
||||||
device = CloudOutputDevice(self._api, cluster_data)
|
device = CloudOutputDevice(self._api, cluster_data)
|
||||||
# Create a machine if we don't already have it. Do not make it the active machine.
|
# If the machine already existed before, it will be present in the host_guid_map
|
||||||
machine_manager = CuraApplication.getInstance().getMachineManager()
|
if cluster_data.host_guid in host_guid_map:
|
||||||
|
machine = machine_manager.getMachine(device.printerType, {self.META_HOST_GUID: cluster_data.host_guid})
|
||||||
|
if machine and machine.getMetaDataEntry(self.META_CLUSTER_ID) != device.key:
|
||||||
|
# If the retrieved device has a different cluster_id than the existing machine, bring the existing
|
||||||
|
# machine up-to-date.
|
||||||
|
self._updateOutdatedMachine(outdated_machine = machine, new_cloud_output_device = device)
|
||||||
|
|
||||||
|
# Create a machine if we don't already have it. Do not make it the active machine.
|
||||||
# We only need to add it if it wasn't already added by "local" network or by cloud.
|
# We only need to add it if it wasn't already added by "local" network or by cloud.
|
||||||
if machine_manager.getMachine(device.printerType, {self.META_CLUSTER_ID: device.key}) is None \
|
if machine_manager.getMachine(device.printerType, {self.META_CLUSTER_ID: device.key}) is None \
|
||||||
and machine_manager.getMachine(device.printerType, {self.META_NETWORK_KEY: cluster_data.host_name + "*"}) is None: # The host name is part of the network key.
|
and machine_manager.getMachine(device.printerType, {self.META_NETWORK_KEY: cluster_data.host_name + "*"}) is None: # The host name is part of the network key.
|
||||||
@ -239,17 +256,42 @@ class CloudOutputDeviceManager:
|
|||||||
num_hidden = len(new_devices) - max_disp_devices + 1
|
num_hidden = len(new_devices) - max_disp_devices + 1
|
||||||
device_name_list = ["<li>{} ({})</li>".format(device.name, device.printerTypeName) for device in new_devices[0:num_hidden]]
|
device_name_list = ["<li>{} ({})</li>".format(device.name, device.printerTypeName) for device in new_devices[0:num_hidden]]
|
||||||
device_name_list.append(self.I18N_CATALOG.i18nc("info:hidden list items", "<li>... and {} others</li>", num_hidden))
|
device_name_list.append(self.I18N_CATALOG.i18nc("info:hidden list items", "<li>... and {} others</li>", num_hidden))
|
||||||
device_names = "\n".join(device_name_list)
|
device_names = "".join(device_name_list)
|
||||||
else:
|
else:
|
||||||
device_names = "\n".join(["<li>{} ({})</li>".format(device.name, device.printerTypeName) for device in new_devices])
|
device_names = "".join(["<li>{} ({})</li>".format(device.name, device.printerTypeName) for device in new_devices])
|
||||||
|
|
||||||
message_text = self.I18N_CATALOG.i18nc(
|
message_text = self.I18N_CATALOG.i18nc(
|
||||||
"info:status",
|
"info:status",
|
||||||
"Cloud printers added from your account:\n<ul>{}</ul>",
|
"Cloud printers added from your account:<ul>{}</ul>",
|
||||||
device_names
|
device_names
|
||||||
)
|
)
|
||||||
message.setText(message_text)
|
message.setText(message_text)
|
||||||
|
|
||||||
|
def _updateOutdatedMachine(self, outdated_machine: GlobalStack, new_cloud_output_device: CloudOutputDevice) -> None:
|
||||||
|
"""
|
||||||
|
Update the cloud metadata of a pre-existing machine that is rediscovered (e.g. if the printer was removed and
|
||||||
|
re-added to the account) and delete the old CloudOutputDevice related to this machine.
|
||||||
|
|
||||||
|
:param outdated_machine: The cloud machine that needs to be brought up-to-date with the new data received from
|
||||||
|
the account
|
||||||
|
:param new_cloud_output_device: The new CloudOutputDevice that should be linked to the pre-existing machine
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
old_cluster_id = outdated_machine.getMetaDataEntry(self.META_CLUSTER_ID)
|
||||||
|
outdated_machine.setMetaDataEntry(self.META_CLUSTER_ID, new_cloud_output_device.key)
|
||||||
|
outdated_machine.setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, True)
|
||||||
|
# Cleanup the remainings of the old CloudOutputDevice(old_cluster_id)
|
||||||
|
self._um_cloud_printers[new_cloud_output_device.key] = self._um_cloud_printers.pop(old_cluster_id)
|
||||||
|
output_device_manager = CuraApplication.getInstance().getOutputDeviceManager()
|
||||||
|
if old_cluster_id in output_device_manager.getOutputDeviceIds():
|
||||||
|
output_device_manager.removeOutputDevice(old_cluster_id)
|
||||||
|
if old_cluster_id in self._remote_clusters:
|
||||||
|
# We need to close the device so that it stops checking for its status
|
||||||
|
self._remote_clusters[old_cluster_id].close()
|
||||||
|
del self._remote_clusters[old_cluster_id]
|
||||||
|
self._remote_clusters[new_cloud_output_device.key] = new_cloud_output_device
|
||||||
|
|
||||||
|
|
||||||
def _devicesRemovedFromAccount(self, removed_device_ids: Set[str]) -> None:
|
def _devicesRemovedFromAccount(self, removed_device_ids: Set[str]) -> None:
|
||||||
"""
|
"""
|
||||||
Removes the CloudOutputDevice from the received device ids and marks the specific printers as "removed from
|
Removes the CloudOutputDevice from the received device ids and marks the specific printers as "removed from
|
||||||
@ -378,6 +420,7 @@ class CloudOutputDeviceManager:
|
|||||||
def _setOutputDeviceMetadata(self, device: CloudOutputDevice, machine: GlobalStack):
|
def _setOutputDeviceMetadata(self, device: CloudOutputDevice, machine: GlobalStack):
|
||||||
machine.setName(device.name)
|
machine.setName(device.name)
|
||||||
machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key)
|
machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key)
|
||||||
|
machine.setMetaDataEntry(self.META_HOST_GUID, device.clusterData.host_guid)
|
||||||
machine.setMetaDataEntry("group_name", device.name)
|
machine.setMetaDataEntry("group_name", device.name)
|
||||||
machine.setMetaDataEntry("group_size", device.clusterSize)
|
machine.setMetaDataEntry("group_size", device.clusterSize)
|
||||||
machine.setMetaDataEntry("removal_warning", self.I18N_CATALOG.i18nc(
|
machine.setMetaDataEntry("removal_warning", self.I18N_CATALOG.i18nc(
|
||||||
|
@ -4474,6 +4474,19 @@
|
|||||||
"enabled": "support_enable or support_meshes_present",
|
"enabled": "support_enable or support_meshes_present",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
},
|
},
|
||||||
|
"support_bottom_stair_step_min_slope":
|
||||||
|
{
|
||||||
|
"label": "Support Stair Step Minimum Slope Angle",
|
||||||
|
"description": "The minimum slope of the area for stair-stepping to take effect. Low values should make support easier to remove on shallower slopes, but really low values may result in some very counter-intuitive results on other parts of the model.",
|
||||||
|
"unit": "°",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 10.0,
|
||||||
|
"limit_to_extruder": "support_bottom_extruder_nr if support_bottom_enable else support_infill_extruder_nr",
|
||||||
|
"minimum_value": "0.01",
|
||||||
|
"maximum_value": "89.99",
|
||||||
|
"enabled": "support_enable or support_meshes_present",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
"support_join_distance":
|
"support_join_distance":
|
||||||
{
|
{
|
||||||
"label": "Support Join Distance",
|
"label": "Support Join Distance",
|
||||||
|
@ -153,6 +153,9 @@ class MockContainer(ContainerInterface, UM.PluginObject.PluginObject):
|
|||||||
def isDirty(self):
|
def isDirty(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def setDirty(self, dirty):
|
||||||
|
pass
|
||||||
|
|
||||||
metaDataChanged = Signal()
|
metaDataChanged = Signal()
|
||||||
propertyChanged = Signal()
|
propertyChanged = Signal()
|
||||||
containersChanged = Signal()
|
containersChanged = Signal()
|
||||||
|
@ -12,7 +12,7 @@ from unittest.mock import patch, MagicMock
|
|||||||
import UM.Settings.ContainerRegistry #To create empty instance containers.
|
import UM.Settings.ContainerRegistry #To create empty instance containers.
|
||||||
import UM.Settings.ContainerStack #To set the container registry the container stacks use.
|
import UM.Settings.ContainerStack #To set the container registry the container stacks use.
|
||||||
from UM.Settings.DefinitionContainer import DefinitionContainer #To check against the class of DefinitionContainer.
|
from UM.Settings.DefinitionContainer import DefinitionContainer #To check against the class of DefinitionContainer.
|
||||||
|
from UM.VersionUpgradeManager import FilesDataUpdateResult
|
||||||
from UM.Resources import Resources
|
from UM.Resources import Resources
|
||||||
Resources.addSearchPath(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "resources")))
|
Resources.addSearchPath(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "resources")))
|
||||||
|
|
||||||
@ -36,6 +36,7 @@ def definition_container():
|
|||||||
assert result.getId() == uid
|
assert result.getId() == uid
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("file_path", definition_filepaths)
|
@pytest.mark.parametrize("file_path", definition_filepaths)
|
||||||
def test_definitionIds(file_path):
|
def test_definitionIds(file_path):
|
||||||
"""
|
"""
|
||||||
@ -45,6 +46,7 @@ def test_definitionIds(file_path):
|
|||||||
definition_id = os.path.basename(file_path).split(".")[0]
|
definition_id = os.path.basename(file_path).split(".")[0]
|
||||||
assert " " not in definition_id # Definition IDs are not allowed to have spaces.
|
assert " " not in definition_id # Definition IDs are not allowed to have spaces.
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("file_path", definition_filepaths)
|
@pytest.mark.parametrize("file_path", definition_filepaths)
|
||||||
def test_noCategory(file_path):
|
def test_noCategory(file_path):
|
||||||
"""
|
"""
|
||||||
@ -57,6 +59,7 @@ def test_noCategory(file_path):
|
|||||||
metadata = DefinitionContainer.deserializeMetadata(json, "test_container_id")
|
metadata = DefinitionContainer.deserializeMetadata(json, "test_container_id")
|
||||||
assert "category" not in metadata[0]
|
assert "category" not in metadata[0]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("file_path", machine_filepaths)
|
@pytest.mark.parametrize("file_path", machine_filepaths)
|
||||||
def test_validateMachineDefinitionContainer(file_path, definition_container):
|
def test_validateMachineDefinitionContainer(file_path, definition_container):
|
||||||
"""Tests all definition containers"""
|
"""Tests all definition containers"""
|
||||||
@ -65,13 +68,12 @@ def test_validateMachineDefinitionContainer(file_path, definition_container):
|
|||||||
if file_name == "fdmprinter.def.json" or file_name == "fdmextruder.def.json":
|
if file_name == "fdmprinter.def.json" or file_name == "fdmextruder.def.json":
|
||||||
return # Stop checking, these are root files.
|
return # Stop checking, these are root files.
|
||||||
|
|
||||||
from UM.VersionUpgradeManager import FilesDataUpdateResult
|
|
||||||
|
|
||||||
mocked_vum = MagicMock()
|
mocked_vum = MagicMock()
|
||||||
mocked_vum.updateFilesData = lambda ct, v, fdl, fnl: FilesDataUpdateResult(ct, v, fdl, fnl)
|
mocked_vum.updateFilesData = lambda ct, v, fdl, fnl: FilesDataUpdateResult(ct, v, fdl, fnl)
|
||||||
with patch("UM.VersionUpgradeManager.VersionUpgradeManager.getInstance", MagicMock(return_value = mocked_vum)):
|
with patch("UM.VersionUpgradeManager.VersionUpgradeManager.getInstance", MagicMock(return_value = mocked_vum)):
|
||||||
assertIsDefinitionValid(definition_container, file_path)
|
assertIsDefinitionValid(definition_container, file_path)
|
||||||
|
|
||||||
|
|
||||||
def assertIsDefinitionValid(definition_container, file_path):
|
def assertIsDefinitionValid(definition_container, file_path):
|
||||||
with open(file_path, encoding = "utf-8") as data:
|
with open(file_path, encoding = "utf-8") as data:
|
||||||
json = data.read()
|
json = data.read()
|
||||||
@ -86,6 +88,7 @@ def assertIsDefinitionValid(definition_container, file_path):
|
|||||||
if "platform_texture" in metadata[0]:
|
if "platform_texture" in metadata[0]:
|
||||||
assert metadata[0]["platform_texture"] in all_images
|
assert metadata[0]["platform_texture"] in all_images
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("file_path", definition_filepaths)
|
@pytest.mark.parametrize("file_path", definition_filepaths)
|
||||||
def test_validateOverridingDefaultValue(file_path: str):
|
def test_validateOverridingDefaultValue(file_path: str):
|
||||||
"""Tests whether setting values are not being hidden by parent containers.
|
"""Tests whether setting values are not being hidden by parent containers.
|
||||||
@ -189,7 +192,9 @@ def test_noId(file_path: str):
|
|||||||
|
|
||||||
@pytest.mark.parametrize("file_path", extruder_filepaths)
|
@pytest.mark.parametrize("file_path", extruder_filepaths)
|
||||||
def test_extruderMatch(file_path: str):
|
def test_extruderMatch(file_path: str):
|
||||||
"""Verifies that extruders say that they work on the same extruder_nr as what is listed in their machine definition."""
|
"""
|
||||||
|
Verifies that extruders say that they work on the same extruder_nr as what is listed in their machine definition.
|
||||||
|
"""
|
||||||
|
|
||||||
extruder_id = os.path.basename(file_path).split(".")[0]
|
extruder_id = os.path.basename(file_path).split(".")[0]
|
||||||
with open(file_path, encoding = "utf-8") as f:
|
with open(file_path, encoding = "utf-8") as f:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user