Merge branch 'master' of github.com:Ultimaker/Cura

This commit is contained in:
Jack Ha 2017-12-13 13:39:22 +01:00
commit bae2193bfb
4 changed files with 214 additions and 165 deletions

View File

@ -59,7 +59,7 @@ class CrashHandler:
self.data = dict() self.data = dict()
self.data["time_stamp"] = time.time() self.data["time_stamp"] = time.time()
Logger.log("c", "An uncaught exception has occurred!") Logger.log("c", "An uncaught error has occurred!")
for line in traceback.format_exception(exception_type, value, tb): for line in traceback.format_exception(exception_type, value, tb):
for part in line.rstrip("\n").split("\n"): for part in line.rstrip("\n").split("\n"):
Logger.log("c", part) Logger.log("c", part)
@ -90,7 +90,7 @@ class CrashHandler:
def _messageWidget(self): def _messageWidget(self):
label = QLabel() label = QLabel()
label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal exception has occurred. Please send us this Crash Report to fix the problem</p></b> label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal error has occurred. Please send us this Crash Report to fix the problem</p></b>
<p>Please use the "Send report" button to post a bug report automatically to our servers</p> <p>Please use the "Send report" button to post a bug report automatically to our servers</p>
""")) """))
@ -143,7 +143,7 @@ class CrashHandler:
def _exceptionInfoWidget(self): def _exceptionInfoWidget(self):
group = QGroupBox() group = QGroupBox()
group.setTitle(catalog.i18nc("@title:groupbox", "Exception traceback")) group.setTitle(catalog.i18nc("@title:groupbox", "Error traceback"))
layout = QVBoxLayout() layout = QVBoxLayout()
text_area = QTextEdit() text_area = QTextEdit()

View File

@ -508,7 +508,7 @@ class CuraContainerStack(ContainerStack):
def findDefaultQuality(self) -> Optional[ContainerInterface]: def findDefaultQuality(self) -> Optional[ContainerInterface]:
definition = self._getMachineDefinition() definition = self._getMachineDefinition()
registry = ContainerRegistry.getInstance() registry = ContainerRegistry.getInstance()
material_container = self.material if self.material != self._empty_instance_container else None material_container = self.material if self.material.getId() not in (self._empty_material.getId(), self._empty_instance_container.getId()) else None
search_criteria = {"type": "quality"} search_criteria = {"type": "quality"}
@ -552,7 +552,7 @@ class CuraContainerStack(ContainerStack):
material_search_criteria = {"type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"} material_search_criteria = {"type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"}
if definition.getMetaDataEntry("has_machine_quality"): if definition.getMetaDataEntry("has_machine_quality"):
if self.material != self._empty_instance_container: if self.material != self._empty_instance_container:
material_search_criteria["definition"] = material_container.getDefinition().id material_search_criteria["definition"] = material_container.getMetaDataEntry("definition")
if definition.getMetaDataEntry("has_variants"): if definition.getMetaDataEntry("has_variants"):
material_search_criteria["variant"] = material_container.getMetaDataEntry("variant") material_search_criteria["variant"] = material_container.getMetaDataEntry("variant")

View File

@ -131,12 +131,21 @@ class StartSliceJob(Job):
Logger.log("w", "No objects suitable for one at a time found, or no correct order found") Logger.log("w", "No objects suitable for one at a time found, or no correct order found")
else: else:
temp_list = [] temp_list = []
is_non_printing_mesh = False
for node in DepthFirstIterator(self._scene.getRoot()): for node in DepthFirstIterator(self._scene.getRoot()):
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None: if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
if not getattr(node, "_outside_buildarea", False) or getattr(node, "_non_printing_mesh", False): _non_printing_mesh = getattr(node, "_non_printing_mesh", False)
if not getattr(node, "_outside_buildarea", False) or _non_printing_mesh:
temp_list.append(node) temp_list.append(node)
if _non_printing_mesh:
is_non_printing_mesh = True
Job.yieldThread() Job.yieldThread()
#If list has one node and it has non printing settings then remove it from list
# otherwise CuraEngine will crash
if len(temp_list) == 1 and is_non_printing_mesh:
temp_list.clear()
if temp_list: if temp_list:
object_groups.append(temp_list) object_groups.append(temp_list)

View File

@ -212,11 +212,12 @@ class XmlMaterialProfile(InstanceContainer):
for definition_id, container in machine_container_map.items(): for definition_id, container in machine_container_map.items():
definition = container.getDefinition() definition = container.getDefinition()
try:
product = UM.Dictionary.findKey(product_id_map, definition_id) product = definition_id
except ValueError: for product_name, product_id_list in product_id_map.items():
# An unknown product id; export it anyway if definition_id in product_id_list:
product = definition_id product = product_name
break
builder.start("machine") builder.start("machine")
builder.start("machine_identifier", { builder.start("machine_identifier", {
@ -530,106 +531,112 @@ class XmlMaterialProfile(InstanceContainer):
identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces) identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces)
for identifier in identifiers: for identifier in identifiers:
machine_id = product_id_map.get(identifier.get("product"), None) machine_id_list = product_id_map.get(identifier.get("product"), [])
if machine_id is None: if not machine_id_list:
# Lets try again with some naive heuristics. machine_id_list = self.getPossibleDefinitionIDsFromName(identifier.get("product"))
machine_id = identifier.get("product").replace(" ", "").lower()
definitions = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id) for machine_id in machine_id_list:
if not definitions: definitions = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
Logger.log("w", "No definition found for machine ID %s", machine_id) if not definitions:
continue Logger.log("w", "No definition found for machine ID %s", machine_id)
definition = definitions[0]
machine_manufacturer = identifier.get("manufacturer", definition.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
if machine_compatibility:
new_material_id = self.getId() + "_" + machine_id
# The child or derived material container may already exist. This can happen when a material in a
# project file and the a material in Cura have the same ID.
# In the case if a derived material already exists, override that material container because if
# the data in the parent material has been changed, the derived ones should be updated too.
if ContainerRegistry.getInstance().isLoaded(new_material_id):
new_material = ContainerRegistry.getInstance().findContainers(id = new_material_id)[0]
is_new_material = False
else:
new_material = XmlMaterialProfile(new_material_id)
is_new_material = True
new_material.setMetaData(copy.deepcopy(self.getMetaData()))
new_material.getMetaData()["id"] = new_material_id
new_material.getMetaData()["name"] = self.getName()
new_material.setDefinition(machine_id)
# Don't use setMetadata, as that overrides it for all materials with same base file
new_material.getMetaData()["compatible"] = machine_compatibility
new_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
new_material.getMetaData()["definition"] = machine_id
new_material.setCachedValues(cached_machine_setting_properties)
new_material._dirty = False
if is_new_material:
containers_to_add.append(new_material)
hotends = machine.iterfind("./um:hotend", self.__namespaces)
for hotend in hotends:
hotend_id = hotend.get("id")
if hotend_id is None:
continue continue
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id) Logger.log("d", "Found definition for machine ID %s", machine_id)
if not variant_containers: definition = definitions[0]
# It is not really properly defined what "ID" is so also search for variants by name.
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = definition["id"], name = hotend_id)
if not variant_containers: machine_manufacturer = identifier.get("manufacturer", definition.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
continue
hotend_compatibility = machine_compatibility if machine_compatibility:
hotend_setting_values = {} new_material_id = self.getId() + "_" + machine_id
settings = hotend.iterfind("./um:setting", self.__namespaces)
for entry in settings: # The child or derived material container may already exist. This can happen when a material in a
key = entry.get("key") # project file and the a material in Cura have the same ID.
if key in self.__material_settings_setting_map: # In the case if a derived material already exists, override that material container because if
hotend_setting_values[self.__material_settings_setting_map[key]] = entry.text # the data in the parent material has been changed, the derived ones should be updated too.
elif key in self.__unmapped_settings: if ContainerRegistry.getInstance().isLoaded(new_material_id):
if key == "hardware compatible": new_material = ContainerRegistry.getInstance().findContainers(id = new_material_id)[0]
hotend_compatibility = self._parseCompatibleValue(entry.text) is_new_material = False
else: else:
Logger.log("d", "Unsupported material setting %s", key) new_material = XmlMaterialProfile(new_material_id)
is_new_material = True
new_hotend_id = self.getId() + "_" + machine_id + "_" + hotend_id.replace(" ", "_") new_material.setMetaData(copy.deepcopy(self.getMetaData()))
new_material.getMetaData()["id"] = new_material_id
new_material.getMetaData()["name"] = self.getName()
new_material.setDefinition(machine_id)
# Don't use setMetadata, as that overrides it for all materials with same base file
new_material.getMetaData()["compatible"] = machine_compatibility
new_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
new_material.getMetaData()["definition"] = machine_id
# Same as machine compatibility, keep the derived material containers consistent with the parent new_material.setCachedValues(cached_machine_setting_properties)
# material
if ContainerRegistry.getInstance().isLoaded(new_hotend_id):
new_hotend_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_id)[0]
is_new_material = False
else:
new_hotend_material = XmlMaterialProfile(new_hotend_id)
is_new_material = True
new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData())) new_material._dirty = False
new_hotend_material.getMetaData()["id"] = new_hotend_id
new_hotend_material.getMetaData()["name"] = self.getName()
new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"]
# Don't use setMetadata, as that overrides it for all materials with same base file
new_hotend_material.getMetaData()["compatible"] = hotend_compatibility
new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
new_hotend_material.getMetaData()["definition"] = machine_id
cached_hotend_setting_properties = cached_machine_setting_properties.copy() if is_new_material:
cached_hotend_setting_properties.update(hotend_setting_values) containers_to_add.append(new_material)
new_hotend_material.setCachedValues(cached_hotend_setting_properties) hotends = machine.iterfind("./um:hotend", self.__namespaces)
for hotend in hotends:
hotend_id = hotend.get("id")
if hotend_id is None:
continue
new_hotend_material._dirty = False variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id)
if not variant_containers:
# It is not really properly defined what "ID" is so also search for variants by name.
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = hotend_id)
if is_new_material: if not variant_containers:
containers_to_add.append(new_hotend_material) continue
hotend_compatibility = machine_compatibility
hotend_setting_values = {}
settings = hotend.iterfind("./um:setting", self.__namespaces)
for entry in settings:
key = entry.get("key")
if key in self.__material_settings_setting_map:
hotend_setting_values[self.__material_settings_setting_map[key]] = entry.text
elif key in self.__unmapped_settings:
if key == "hardware compatible":
hotend_compatibility = self._parseCompatibleValue(entry.text)
else:
Logger.log("d", "Unsupported material setting %s", key)
new_hotend_id = self.getId() + "_" + machine_id + "_" + hotend_id.replace(" ", "_")
# Same as machine compatibility, keep the derived material containers consistent with the parent
# material
if ContainerRegistry.getInstance().isLoaded(new_hotend_id):
new_hotend_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_id)[0]
is_new_material = False
else:
new_hotend_material = XmlMaterialProfile(new_hotend_id)
is_new_material = True
new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData()))
new_hotend_material.getMetaData()["id"] = new_hotend_id
new_hotend_material.getMetaData()["name"] = self.getName()
new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"]
new_hotend_material.setDefinition(machine_id)
# Don't use setMetadata, as that overrides it for all materials with same base file
new_hotend_material.getMetaData()["compatible"] = hotend_compatibility
new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
new_hotend_material.getMetaData()["definition"] = machine_id
cached_hotend_setting_properties = cached_machine_setting_properties.copy()
cached_hotend_setting_properties.update(hotend_setting_values)
new_hotend_material.setCachedValues(cached_hotend_setting_properties)
new_hotend_material._dirty = False
if is_new_material:
containers_to_add.append(new_hotend_material)
# there is only one ID for a machine. Once we have reached here, it means we have already found
# a workable ID for that machine, so there is no need to continue
break
for container_to_add in containers_to_add: for container_to_add in containers_to_add:
ContainerRegistry.getInstance().addContainer(container_to_add) ContainerRegistry.getInstance().addContainer(container_to_add)
@ -720,79 +727,86 @@ class XmlMaterialProfile(InstanceContainer):
machine_compatibility = cls._parseCompatibleValue(entry.text) machine_compatibility = cls._parseCompatibleValue(entry.text)
for identifier in machine.iterfind("./um:machine_identifier", cls.__namespaces): for identifier in machine.iterfind("./um:machine_identifier", cls.__namespaces):
machine_id = product_id_map.get(identifier.get("product"), None) machine_id_list = product_id_map.get(identifier.get("product"), [])
if machine_id is None: if not machine_id_list:
# Lets try again with some naive heuristics. machine_id_list = cls.getPossibleDefinitionIDsFromName(identifier.get("product"))
machine_id = identifier.get("product").replace(" ", "").lower()
definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
if not definition_metadata:
Logger.log("w", "No definition found for machine ID %s", machine_id)
continue
definition_metadata = definition_metadata[0]
machine_manufacturer = identifier.get("manufacturer", definition_metadata.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition. for machine_id in machine_id_list:
definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
if machine_compatibility: if not definition_metadata:
new_material_id = container_id + "_" + machine_id Logger.log("w", "No definition found for machine ID %s", machine_id)
# The child or derived material container may already exist. This can happen when a material in a
# project file and the a material in Cura have the same ID.
# In the case if a derived material already exists, override that material container because if
# the data in the parent material has been changed, the derived ones should be updated too.
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_material_id)
if found_materials:
new_material_metadata = found_materials[0]
else:
new_material_metadata = {}
new_material_metadata.update(base_metadata)
new_material_metadata["id"] = new_material_id
new_material_metadata["compatible"] = machine_compatibility
new_material_metadata["machine_manufacturer"] = machine_manufacturer
new_material_metadata["definition"] = machine_id
if len(found_materials) == 0: #This is a new material.
result_metadata.append(new_material_metadata)
for hotend in machine.iterfind("./um:hotend", cls.__namespaces):
hotend_id = hotend.get("id")
if hotend_id is None:
continue continue
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id) Logger.log("d", "========= Found def for machine [%s]", machine_id)
if not variant_containers: definition_metadata = definition_metadata[0]
# It is not really properly defined what "ID" is so also search for variants by name.
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = hotend_id)
hotend_compatibility = machine_compatibility machine_manufacturer = identifier.get("manufacturer", definition_metadata.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
for entry in hotend.iterfind("./um:setting", cls.__namespaces):
key = entry.get("key")
if key == "hardware compatible":
hotend_compatibility = cls._parseCompatibleValue(entry.text)
new_hotend_id = container_id + "_" + machine_id + "_" + hotend_id.replace(" ", "_") if machine_compatibility:
new_material_id = container_id + "_" + machine_id
# Same as machine compatibility, keep the derived material containers consistent with the parent # The child or derived material container may already exist. This can happen when a material in a
# material # project file and the a material in Cura have the same ID.
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_id) # In the case if a derived material already exists, override that material container because if
if found_materials: # the data in the parent material has been changed, the derived ones should be updated too.
new_hotend_material_metadata = found_materials[0] found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_material_id)
else: if found_materials:
new_hotend_material_metadata = {} new_material_metadata = found_materials[0]
else:
new_material_metadata = {}
new_hotend_material_metadata.update(base_metadata) new_material_metadata.update(base_metadata)
if variant_containers: new_material_metadata["id"] = new_material_id
new_hotend_material_metadata["variant"] = variant_containers[0]["id"] new_material_metadata["compatible"] = machine_compatibility
else: new_material_metadata["machine_manufacturer"] = machine_manufacturer
new_hotend_material_metadata["variant"] = hotend_id new_material_metadata["definition"] = machine_id
_with_missing_variants.append(new_hotend_material_metadata)
new_hotend_material_metadata["compatible"] = hotend_compatibility
new_hotend_material_metadata["machine_manufacturer"] = machine_manufacturer
new_hotend_material_metadata["id"] = new_hotend_id
new_hotend_material_metadata["definition"] = machine_id
if len(found_materials) == 0: if len(found_materials) == 0: #This is a new material.
result_metadata.append(new_hotend_material_metadata) result_metadata.append(new_material_metadata)
for hotend in machine.iterfind("./um:hotend", cls.__namespaces):
hotend_id = hotend.get("id")
if hotend_id is None:
continue
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id)
if not variant_containers:
# It is not really properly defined what "ID" is so also search for variants by name.
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = hotend_id)
hotend_compatibility = machine_compatibility
for entry in hotend.iterfind("./um:setting", cls.__namespaces):
key = entry.get("key")
if key == "hardware compatible":
hotend_compatibility = cls._parseCompatibleValue(entry.text)
new_hotend_id = container_id + "_" + machine_id + "_" + hotend_id.replace(" ", "_")
# Same as machine compatibility, keep the derived material containers consistent with the parent
# material
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_id)
if found_materials:
new_hotend_material_metadata = found_materials[0]
else:
new_hotend_material_metadata = {}
new_hotend_material_metadata.update(base_metadata)
if variant_containers:
new_hotend_material_metadata["variant"] = variant_containers[0]["id"]
else:
new_hotend_material_metadata["variant"] = hotend_id
_with_missing_variants.append(new_hotend_material_metadata)
new_hotend_material_metadata["compatible"] = hotend_compatibility
new_hotend_material_metadata["machine_manufacturer"] = machine_manufacturer
new_hotend_material_metadata["id"] = new_hotend_id
new_hotend_material_metadata["definition"] = machine_id
if len(found_materials) == 0:
result_metadata.append(new_hotend_material_metadata)
# there is only one ID for a machine. Once we have reached here, it means we have already found
# a workable ID for that machine, so there is no need to continue
break
return result_metadata return result_metadata
@ -813,15 +827,41 @@ class XmlMaterialProfile(InstanceContainer):
else: else:
return material_name return material_name
@classmethod
def getPossibleDefinitionIDsFromName(cls, name):
name_parts = name.lower().split(" ")
merged_name_parts = []
for part in name_parts:
if len(part) == 0:
continue
if len(merged_name_parts) == 0:
merged_name_parts.append(part)
continue
if part.isdigit():
# for names with digit(s) such as Ultimaker 3 Extended, we generate an ID like
# "ultimaker3_extended", ignoring the space between "Ultimaker" and "3".
merged_name_parts[-1] = merged_name_parts[-1] + part
else:
merged_name_parts.append(part)
id_list = [name.lower().replace(" ", ""), # simply removing all spaces
name.lower().replace(" ", "_"), # simply replacing all spaces with underscores
"_".join(merged_name_parts),
]
return id_list
## Gets a mapping from product names in the XML files to their definition ## Gets a mapping from product names in the XML files to their definition
# IDs. # IDs.
# #
# This loads the mapping from a file. # This loads the mapping from a file.
@classmethod @classmethod
def getProductIdMap(cls) -> Dict[str, str]: def getProductIdMap(cls) -> Dict[str, List[str]]:
product_to_id_file = os.path.join(os.path.dirname(sys.modules[cls.__module__].__file__), "product_to_id.json") product_to_id_file = os.path.join(os.path.dirname(sys.modules[cls.__module__].__file__), "product_to_id.json")
with open(product_to_id_file) as f: with open(product_to_id_file) as f:
return json.load(f) product_to_id_map = json.load(f)
product_to_id_map = {key: [value] for key, value in product_to_id_map.items()}
return product_to_id_map
## Parse the value of the "material compatible" property. ## Parse the value of the "material compatible" property.
@classmethod @classmethod