diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 4dc1f297f7..48ccf76b1a 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -207,6 +207,7 @@ class CuraApplication(QtApplication): UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions( { + ("quality", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"), ("quality_changes", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.QualityChangesInstanceContainer, "application/x-uranium-instancecontainer"), ("machine_stack", ContainerStack.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.MachineStack, "application/x-cura-globalstack"), ("extruder_train", ContainerStack.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.ExtruderStack, "application/x-cura-extruderstack"), diff --git a/cura/CuraPackageManager.py b/cura/CuraPackageManager.py index ec75174db4..322a9639cf 100644 --- a/cura/CuraPackageManager.py +++ b/cura/CuraPackageManager.py @@ -18,9 +18,6 @@ from UM.Version import Version class CuraPackageManager(QObject): Version = 1 - # The prefix that's added to all files for an installed package to avoid naming conflicts with user created files. - PREFIX_PLACE_HOLDER = "-CP;" - def __init__(self, parent = None): super().__init__(parent) @@ -171,7 +168,7 @@ class CuraPackageManager(QObject): package_info["is_active"] = self._plugin_registry.isActivePlugin(package_id) # If the package ID is in bundled, label it as such - package_info["is_bundled"] = package_info["package_id"] in self._bundled_package_dict.keys() + package_info["is_bundled"] = package_info["package_id"] in self._bundled_package_dict.keys() and not self.isUserInstalledPackage(package_info["package_id"]) # If there is not a section in the dict for this type, add it if package_info["package_type"] not in installed_packages_dict: @@ -182,7 +179,7 @@ class CuraPackageManager(QObject): return installed_packages_dict - # Checks if the given package is installed. + # Checks if the given package is installed (at all). def isPackageInstalled(self, package_id: str) -> bool: return self.getInstalledPackageInfo(package_id) is not None @@ -242,7 +239,7 @@ class CuraPackageManager(QObject): Logger.log("i", "Attempt to remove package [%s] that is not installed, do nothing.", package_id) return - # Temp hack + # Extra safety check if package_id not in self._installed_package_dict and package_id in self._bundled_package_dict: Logger.log("i", "Not uninstalling [%s] because it is a bundled package.") return @@ -258,6 +255,10 @@ class CuraPackageManager(QObject): self._saveManagementData() self.installedPackagesChanged.emit() + ## Is the package an user installed package? + def isUserInstalledPackage(self, package_id: str): + return package_id in self._installed_package_dict + # Removes everything associated with the given package ID. def _purgePackage(self, package_id: str) -> None: # Iterate through all directories in the data storage directory and look for sub-directories that belong to @@ -308,27 +309,15 @@ class CuraPackageManager(QObject): if not os.path.exists(src_dir_path): continue - - # Need to rename the container files so they don't get ID conflicts - to_rename_files = sub_dir_name not in ("plugins",) - self.__installPackageFiles(package_id, src_dir_path, dst_dir_path, need_to_rename_files= to_rename_files) + self.__installPackageFiles(package_id, src_dir_path, dst_dir_path) # Remove the file os.remove(filename) - def __installPackageFiles(self, package_id: str, src_dir: str, dst_dir: str, need_to_rename_files: bool = True) -> None: + def __installPackageFiles(self, package_id: str, src_dir: str, dst_dir: str) -> None: + Logger.log("i", "Moving package {package_id} from {src_dir} to {dst_dir}".format(package_id=package_id, src_dir=src_dir, dst_dir=dst_dir)) shutil.move(src_dir, dst_dir) - # Rename files if needed - if not need_to_rename_files: - return - for root, _, file_names in os.walk(dst_dir): - for filename in file_names: - new_filename = self.PREFIX_PLACE_HOLDER + package_id + "-" + filename - old_file_path = os.path.join(root, filename) - new_file_path = os.path.join(root, new_filename) - os.rename(old_file_path, new_file_path) - # Gets package information from the given file. def getPackageInfo(self, filename: str) -> Dict[str, Any]: with zipfile.ZipFile(filename) as archive: diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 719795ac45..ad3c7f165f 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -113,8 +113,6 @@ class MaterialManager(QObject): grouped_by_type_dict = dict() material_types_without_fallback = set() for root_material_id, material_node in self._material_group_map.items(): - if not self._container_registry.isReadOnly(root_material_id): - continue material_type = material_node.root_material_node.metadata["material"] if material_type not in grouped_by_type_dict: grouped_by_type_dict[material_type] = {"generic": None, @@ -127,9 +125,15 @@ class MaterialManager(QObject): diameter = material_node.root_material_node.metadata.get("approximate_diameter") if diameter != self._default_approximate_diameter_for_quality_search: to_add = False # don't add if it's not the default diameter + if to_add: - grouped_by_type_dict[material_type] = material_node.root_material_node.metadata - material_types_without_fallback.remove(material_type) + # Checking this first allow us to differentiate between not read only materials: + # - if it's in the list, it means that is a new material without fallback + # - if it is not, then it is a custom material with a fallback material (parent) + if material_type in material_types_without_fallback: + grouped_by_type_dict[material_type] = material_node.root_material_node.metadata + material_types_without_fallback.remove(material_type) + # Remove the materials that have no fallback materials for material_type in material_types_without_fallback: del grouped_by_type_dict[material_type] @@ -147,9 +151,6 @@ class MaterialManager(QObject): material_group_dict = dict() keys_to_fetch = ("name", "material", "brand", "color") for root_material_id, machine_node in self._material_group_map.items(): - if not self._container_registry.isReadOnly(root_material_id): - continue - root_material_metadata = machine_node.root_material_node.metadata key_data = [] @@ -157,8 +158,13 @@ class MaterialManager(QObject): key_data.append(root_material_metadata.get(key)) key_data = tuple(key_data) + # If the key_data doesn't exist, no matter if the material is read only... if key_data not in material_group_dict: material_group_dict[key_data] = dict() + else: + # ...but if key_data exists, we just overrite it if the material is read only, otherwise we skip it + if not machine_node.is_read_only: + continue approximate_diameter = root_material_metadata.get("approximate_diameter") material_group_dict[key_data][approximate_diameter] = root_material_metadata["id"] diff --git a/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml b/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml index d3aafae987..a977ef999b 100644 --- a/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml +++ b/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml @@ -14,9 +14,9 @@ Item property var active: false property var complete: false - property var readyLabel: "Install" - property var activeLabel: "Installing" - property var completeLabel: "Installed" + property var readyLabel: catalog.i18nc("@action:button", "Install") + property var activeLabel: catalog.i18nc("@action:button", "Cancel") + property var completeLabel: catalog.i18nc("@action:button", "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) @@ -32,15 +32,15 @@ Item { if (complete) { - return catalog.i18nc("@action:button", "Installed") + return completeLabel } else if (active) { - return catalog.i18nc("@action:button", "Cancel") + return activeLabel } else { - return catalog.i18nc("@action:button", "Install") + return readyLabel } } onClicked: diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index fb74fefdfa..13f631ebd3 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -250,7 +250,8 @@ class Toolbox(QObject, Extension): if remote_package: download_url = remote_package["download_url"] Logger.log("d", "Updating package [%s]..." % plugin_id) - self.uninstall(plugin_id) + if self._package_manager.isUserInstalledPackage(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) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 7e726c5c60..5d7eed5c6d 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -3703,6 +3703,20 @@ "settable_per_mesh": false, "settable_per_extruder": true }, + "support_wall_count": + { + "label": "Support Wall Line Count", + "description": "The number of walls with which to surround support infill. Adding a wall can make support print more reliably and can support overhangs better, but increases print time and material used.", + "default_value": 1, + "minimum_value": "0", + "minimum_value_warning": "1 if support_pattern == 'concentric' else 0", + "maximum_value_warning": "3", + "type": "int", + "value": "1 if (support_pattern == 'grid' or support_pattern == 'triangles' or support_pattern == 'concentric') else 0", + "enabled": "support_enable", + "limit_to_extruder": "support_infill_extruder_nr", + "settable_per_mesh": true + }, "zig_zaggify_support": { "label": "Connect Support Lines", diff --git a/resources/setting_visibility/expert.cfg b/resources/setting_visibility/expert.cfg index d6989f8b26..db271cc985 100644 --- a/resources/setting_visibility/expert.cfg +++ b/resources/setting_visibility/expert.cfg @@ -220,6 +220,7 @@ support_bottom_extruder_nr support_type support_angle support_pattern +support_wall_count zig_zaggify_support support_connect_zigzags support_infill_rate