mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-10 15:25:09 -06:00
Merge branch 'master' into feature_local_container_server
This commit is contained in:
commit
1029d4509c
117 changed files with 15146 additions and 3512 deletions
|
@ -63,7 +63,18 @@ class ContainerManager(QObject):
|
|||
return ""
|
||||
|
||||
container = containers[0]
|
||||
new_container = self.duplicateContainerInstance(container)
|
||||
return new_container.getId()
|
||||
|
||||
## Create a duplicate of the given container instance
|
||||
#
|
||||
# This will create and add a duplicate of the container that was passed.
|
||||
#
|
||||
# \param container \type{ContainerInterface} The container to duplicate.
|
||||
#
|
||||
# \return The duplicated container, or None if duplication failed.
|
||||
def duplicateContainerInstance(self, container):
|
||||
new_container = None
|
||||
new_name = self._container_registry.uniqueName(container.getName())
|
||||
# Only InstanceContainer has a duplicate method at the moment.
|
||||
# So fall back to serialize/deserialize when no duplicate method exists.
|
||||
|
@ -74,10 +85,11 @@ class ContainerManager(QObject):
|
|||
new_container.deserialize(container.serialize())
|
||||
new_container.setName(new_name)
|
||||
|
||||
# TODO: we probably don't want to add it to the registry here!
|
||||
if new_container:
|
||||
self._container_registry.addContainer(new_container)
|
||||
|
||||
return new_container.getId()
|
||||
return new_container
|
||||
|
||||
## Change the name of a specified container to a new name.
|
||||
#
|
||||
|
|
|
@ -204,53 +204,57 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||
# Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None.
|
||||
Logger.log("e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name,profile_reader.getPluginId(), str(e))
|
||||
return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))}
|
||||
if profile_or_list: # Success!
|
||||
|
||||
if profile_or_list:
|
||||
name_seed = os.path.splitext(os.path.basename(file_name))[0]
|
||||
new_name = self.uniqueName(name_seed)
|
||||
|
||||
# Ensure it is always a list of profiles
|
||||
if type(profile_or_list) is not list:
|
||||
profile = profile_or_list
|
||||
profile_or_list = [profile_or_list]
|
||||
|
||||
result = self._configureProfile(profile, name_seed, new_name)
|
||||
if result is not None:
|
||||
return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result)}
|
||||
if len(profile_or_list) == 1:
|
||||
# If there is only 1 stack file it means we're loading a legacy (pre-3.1) .curaprofile.
|
||||
# In that case we find the per-extruder settings and put those in a new quality_changes container
|
||||
# so that it is compatible with the new stack setup.
|
||||
profile = profile_or_list[0]
|
||||
extruder_stack_quality_changes_container = ContainerManager.getInstance().duplicateContainerInstance(profile)
|
||||
extruder_stack_quality_changes_container.addMetaDataEntry("extruder", "fdmextruder")
|
||||
|
||||
return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName())}
|
||||
else:
|
||||
profile_index = -1
|
||||
global_profile = None
|
||||
|
||||
for profile in profile_or_list:
|
||||
if profile_index >= 0:
|
||||
if len(machine_extruders) > profile_index:
|
||||
extruder_id = Application.getInstance().getMachineManager().getQualityDefinitionId(machine_extruders[profile_index].getBottom())
|
||||
# Ensure the extruder profiles get non-conflicting names
|
||||
# NB: these are not user-facing
|
||||
if "extruder" in profile.getMetaData():
|
||||
profile.setMetaDataEntry("extruder", extruder_id)
|
||||
else:
|
||||
profile.addMetaDataEntry("extruder", extruder_id)
|
||||
profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_")
|
||||
elif profile_index == 0:
|
||||
# Importing a multiextrusion profile into a single extrusion machine; merge 1st extruder profile into global profile
|
||||
profile._id = self.uniqueName("temporary_profile")
|
||||
self.addContainer(profile)
|
||||
ContainerManager.getInstance().mergeContainers(global_profile.getId(), profile.getId())
|
||||
self.removeContainer(profile.getId())
|
||||
break
|
||||
else:
|
||||
# The imported composite profile has a profile for an extruder that this machine does not have. Ignore this extruder-profile
|
||||
break
|
||||
for quality_changes_setting_key in extruder_stack_quality_changes_container.getAllKeys():
|
||||
settable_per_extruder = extruder_stack_quality_changes_container.getProperty(quality_changes_setting_key, "settable_per_extruder")
|
||||
if settable_per_extruder:
|
||||
profile.removeInstance(quality_changes_setting_key, postpone_emit = True)
|
||||
else:
|
||||
global_profile = profile
|
||||
profile_id = (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")
|
||||
extruder_stack_quality_changes_container.removeInstance(quality_changes_setting_key, postpone_emit = True)
|
||||
|
||||
result = self._configureProfile(profile, profile_id, new_name)
|
||||
if result is not None:
|
||||
return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result)}
|
||||
# We add the new container to the profile list so things like extruder positions are taken care of
|
||||
# in the next code segment.
|
||||
profile_or_list.append(extruder_stack_quality_changes_container)
|
||||
|
||||
profile_index += 1
|
||||
# Import all profiles
|
||||
for profile_index, profile in enumerate(profile_or_list):
|
||||
if profile_index == 0:
|
||||
# This is assumed to be the global profile
|
||||
profile_id = (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")
|
||||
|
||||
return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}
|
||||
elif len(machine_extruders) > profile_index:
|
||||
# This is assumed to be an extruder profile
|
||||
extruder_id = Application.getInstance().getMachineManager().getQualityDefinitionId(machine_extruders[profile_index - 1].getBottom())
|
||||
if not profile.getMetaDataEntry("extruder"):
|
||||
profile.addMetaDataEntry("extruder", extruder_id)
|
||||
else:
|
||||
profile.setMetaDataEntry("extruder", extruder_id)
|
||||
profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_")
|
||||
|
||||
result = self._configureProfile(profile, profile_id, new_name)
|
||||
if result is not None:
|
||||
return {"status": "error", "message": catalog.i18nc(
|
||||
"@info:status Don't translate the XML tags <filename> or <message>!",
|
||||
"Failed to import profile from <filename>{0}</filename>: <message>{1}</message>",
|
||||
file_name, result)}
|
||||
|
||||
return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}
|
||||
|
||||
# If it hasn't returned by now, none of the plugins loaded the profile successfully.
|
||||
return {"status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name)}
|
||||
|
|
|
@ -356,14 +356,16 @@ class ExtruderManager(QObject):
|
|||
# \return \type{List[ContainerStack]} a list of
|
||||
def getActiveExtruderStacks(self) -> List["ExtruderStack"]:
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if not global_stack:
|
||||
return None
|
||||
|
||||
result = []
|
||||
machine_extruder_count = global_stack.getProperty("machine_extruder_count", "value")
|
||||
|
||||
if global_stack and global_stack.getId() in self._extruder_trains:
|
||||
if global_stack.getId() in self._extruder_trains:
|
||||
for extruder in sorted(self._extruder_trains[global_stack.getId()]):
|
||||
result.append(self._extruder_trains[global_stack.getId()][extruder])
|
||||
|
||||
machine_extruder_count = global_stack.getProperty("machine_extruder_count", "value")
|
||||
|
||||
return result[:machine_extruder_count]
|
||||
|
||||
def __globalContainerStackChanged(self) -> None:
|
||||
|
|
|
@ -8,8 +8,8 @@ from UM.i18n import i18nCatalog
|
|||
import UM.Qt.ListModel
|
||||
from UM.Application import Application
|
||||
import UM.FlameProfiler
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
from cura.Settings.ExtruderStack import ExtruderStack #To listen to changes on the extruders.
|
||||
|
||||
from cura.Settings.ExtruderStack import ExtruderStack # To listen to changes on the extruders.
|
||||
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
|
@ -68,7 +68,6 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
|||
self._update_extruder_timer.setSingleShot(True)
|
||||
self._update_extruder_timer.timeout.connect(self.__updateExtruders)
|
||||
|
||||
self._add_global = False
|
||||
self._simple_names = False
|
||||
|
||||
self._active_machine_extruders = [] # type: Iterable[ExtruderStack]
|
||||
|
@ -76,21 +75,10 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
|||
|
||||
# Listen to changes
|
||||
Application.getInstance().globalContainerStackChanged.connect(self._extrudersChanged) # When the machine is swapped we must update the active machine extruders
|
||||
ExtruderManager.getInstance().extrudersChanged.connect(self._extrudersChanged) # When the extruders change we must link to the stack-changed signal of the new extruder
|
||||
Application.getInstance().getExtruderManager().extrudersChanged.connect(self._extrudersChanged) # When the extruders change we must link to the stack-changed signal of the new extruder
|
||||
Application.getInstance().getContainerRegistry().containerMetaDataChanged.connect(self._onExtruderStackContainersChanged) # When meta data from a material container changes we must update
|
||||
self._extrudersChanged() # Also calls _updateExtruders
|
||||
|
||||
def setAddGlobal(self, add):
|
||||
if add != self._add_global:
|
||||
self._add_global = add
|
||||
self._updateExtruders()
|
||||
self.addGlobalChanged.emit()
|
||||
|
||||
addGlobalChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty(bool, fset = setAddGlobal, notify = addGlobalChanged)
|
||||
def addGlobal(self):
|
||||
return self._add_global
|
||||
|
||||
addOptionalExtruderChanged = pyqtSignal()
|
||||
|
||||
def setAddOptionalExtruder(self, add_optional_extruder):
|
||||
|
@ -140,7 +128,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
|||
|
||||
# Link to new extruders
|
||||
self._active_machine_extruders = []
|
||||
extruder_manager = ExtruderManager.getInstance()
|
||||
extruder_manager = Application.getInstance().getExtruderManager()
|
||||
for extruder in extruder_manager.getExtruderStacks():
|
||||
if extruder is None: #This extruder wasn't loaded yet. This happens asynchronously while this model is constructed from QML.
|
||||
continue
|
||||
|
@ -175,24 +163,10 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
|||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack:
|
||||
|
||||
# TODO: remove this - CURA-4482
|
||||
if self._add_global:
|
||||
material = global_container_stack.material
|
||||
color = material.getMetaDataEntry("color_code", default = self.defaultColors[0]) if material else self.defaultColors[0]
|
||||
item = {
|
||||
"id": global_container_stack.getId(),
|
||||
"name": catalog.i18nc("@menuitem", "Global"),
|
||||
"color": color,
|
||||
"index": -1,
|
||||
"definition": ""
|
||||
}
|
||||
items.append(item)
|
||||
extruders_changed = True
|
||||
|
||||
# get machine extruder count for verification
|
||||
machine_extruder_count = global_container_stack.getProperty("machine_extruder_count", "value")
|
||||
|
||||
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId()):
|
||||
for extruder in Application.getInstance().getExtruderManager().getMachineExtruders(global_container_stack.getId()):
|
||||
position = extruder.getMetaDataEntry("position", default = "0") # Get the position
|
||||
try:
|
||||
position = int(position)
|
||||
|
|
|
@ -502,6 +502,7 @@ class MachineManager(QObject):
|
|||
@pyqtProperty("QVariantList", notify=activeVariantChanged)
|
||||
def activeVariantNames(self) -> List[str]:
|
||||
result = []
|
||||
|
||||
active_stacks = ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks()
|
||||
if active_stacks is not None:
|
||||
for stack in active_stacks:
|
||||
|
@ -514,6 +515,7 @@ class MachineManager(QObject):
|
|||
@pyqtProperty("QVariantList", notify = activeMaterialChanged)
|
||||
def activeMaterialNames(self) -> List[str]:
|
||||
result = []
|
||||
|
||||
active_stacks = ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks()
|
||||
if active_stacks is not None:
|
||||
for stack in active_stacks:
|
||||
|
@ -534,6 +536,7 @@ class MachineManager(QObject):
|
|||
@pyqtProperty("QVariantMap", notify = activeVariantChanged)
|
||||
def allActiveVariantIds(self) -> Dict[str, str]:
|
||||
result = {}
|
||||
|
||||
active_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
|
||||
if active_stacks is not None: #If we have a global stack.
|
||||
for stack in active_stacks:
|
||||
|
@ -552,10 +555,8 @@ class MachineManager(QObject):
|
|||
@pyqtProperty("QVariantMap", notify = activeMaterialChanged)
|
||||
def allActiveMaterialIds(self) -> Dict[str, str]:
|
||||
result = {}
|
||||
|
||||
active_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
|
||||
|
||||
result[self._global_container_stack.getId()] = self._global_container_stack.material.getId()
|
||||
|
||||
if active_stacks is not None: # If we have extruder stacks
|
||||
for stack in active_stacks:
|
||||
material_container = stack.material
|
||||
|
@ -734,6 +735,9 @@ class MachineManager(QObject):
|
|||
|
||||
old_material = self._active_container_stack.material
|
||||
old_quality = self._active_container_stack.quality
|
||||
old_quality_type = None
|
||||
if old_quality and old_quality.getId() != self._empty_quality_container.getId():
|
||||
old_quality_type = old_quality.getMetaDataEntry("quality_type")
|
||||
old_quality_changes = self._active_container_stack.qualityChanges
|
||||
if not old_material:
|
||||
Logger.log("w", "While trying to set the active material, no material was found to replace it.")
|
||||
|
@ -774,13 +778,28 @@ class MachineManager(QObject):
|
|||
quality_manager.getWholeMachineDefinition(global_stack.definition),
|
||||
[material_container.getMetaData()])
|
||||
|
||||
if not candidate_quality or isinstance(candidate_quality, type(self._empty_quality_changes_container)):
|
||||
if not candidate_quality or candidate_quality.getId() == self._empty_quality_changes_container:
|
||||
Logger.log("d", "Attempting to find fallback quality")
|
||||
# Fall back to a quality (which must be compatible with all other extruders)
|
||||
new_qualities = quality_manager.findAllUsableQualitiesForMachineAndExtruders(
|
||||
self._global_container_stack, ExtruderManager.getInstance().getExtruderStacks())
|
||||
if new_qualities:
|
||||
new_quality_id = new_qualities[0].getId() # Just pick the first available one
|
||||
|
||||
quality_types = sorted([q.getMetaDataEntry("quality_type") for q in new_qualities], reverse = True)
|
||||
quality_type_to_use = None
|
||||
if quality_types:
|
||||
# try to use the same quality as before, otherwise the first one in the quality_types
|
||||
quality_type_to_use = quality_types[0]
|
||||
if old_quality_type is not None and old_quality_type in quality_type_to_use:
|
||||
quality_type_to_use = old_quality_type
|
||||
|
||||
new_quality = None
|
||||
for q in new_qualities:
|
||||
if quality_type_to_use is not None and q.getMetaDataEntry("quality_type") == quality_type_to_use:
|
||||
new_quality = q
|
||||
break
|
||||
|
||||
if new_quality is not None:
|
||||
new_quality_id = new_quality.getId() # Just pick the first available one
|
||||
else:
|
||||
Logger.log("w", "No quality profile found that matches the current machine and extruders.")
|
||||
else:
|
||||
|
|
|
@ -22,6 +22,14 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||
## Event indicating that the user selected a different extruder.
|
||||
activeExtruderChanged = Signal()
|
||||
|
||||
## Non-printing meshes
|
||||
#
|
||||
# If these settings are True for any mesh, the mesh does not need a convex hull,
|
||||
# and is sent to the slicer regardless of whether it fits inside the build volume.
|
||||
# Note that Support Mesh is not in here because it actually generates
|
||||
# g-code in the volume of the mesh.
|
||||
_non_printing_mesh_settings = {"anti_overhang_mesh", "infill_mesh", "cutting_mesh"}
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._stack = PerObjectContainerStack(stack_id = id(self))
|
||||
|
@ -78,6 +86,8 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||
Application.getInstance().getBackend().needsSlicing()
|
||||
Application.getInstance().getBackend().tickle()
|
||||
|
||||
self._node._non_printing_mesh = any(self._stack.getProperty(setting, "value") for setting in self._non_printing_mesh_settings)
|
||||
|
||||
## Makes sure that the stack upon which the container stack is placed is
|
||||
# kept up to date.
|
||||
def _updateNextStack(self):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue