Просмотр исходного кода

Merge branch 'main' into PP-441-Generic-PEKK-profile

Casper Lamboo 1 год назад
Родитель
Сommit
26d181c695

+ 1 - 1
conandata.yml

@@ -4,7 +4,7 @@ requirements:
   - "curaengine/(latest)@ultimaker/testing"
   - "cura_binary_data/(latest)@ultimaker/testing"
   - "fdm_materials/(latest)@ultimaker/testing"
-  - "curaengine_plugin_gradual_flow/0.1.0-beta.2"
+  - "curaengine_plugin_gradual_flow/0.1.0-beta.3"
   - "dulcificum/latest@ultimaker/testing"
   - "pysavitar/5.3.0"
   - "pynest2d/5.3.0"

+ 0 - 2
cura/CuraActions.py

@@ -1,6 +1,5 @@
 # Copyright (c) 2023 UltiMaker
 # Cura is released under the terms of the LGPLv3 or higher.
-
 from typing import List, cast
 
 from PyQt6.QtCore import QObject, QUrl, pyqtSignal, pyqtProperty
@@ -33,7 +32,6 @@ from cura.Operations.SetBuildPlateNumberOperation import SetBuildPlateNumberOper
 from UM.Logger import Logger
 from UM.Scene.SceneNode import SceneNode
 
-
 class CuraActions(QObject):
     def __init__(self, parent: QObject = None) -> None:
         super().__init__(parent)

+ 19 - 2
cura/CuraApplication.py

@@ -601,9 +601,7 @@ class CuraApplication(QtApplication):
         preferences.addPreference("mesh/scale_to_fit", False)
         preferences.addPreference("mesh/scale_tiny_meshes", True)
         preferences.addPreference("cura/dialog_on_project_save", True)
-        preferences.addPreference("cura/dialog_on_ucp_project_save", True)
         preferences.addPreference("cura/asked_dialog_on_project_save", False)
-        preferences.addPreference("cura/asked_dialog_on_ucp_project_save", False)
         preferences.addPreference("cura/choice_on_profile_override", "always_ask")
         preferences.addPreference("cura/choice_on_open_project", "always_ask")
         preferences.addPreference("cura/use_multi_build_plate", False)
@@ -1979,6 +1977,17 @@ class CuraApplication(QtApplication):
 
     openProjectFile = pyqtSignal(QUrl, bool, arguments = ["project_file", "add_to_recent_files"])  # Emitted when a project file is about to open.
 
+    @pyqtSlot(QUrl, bool)
+    def readLocalUcpFile(self, file: QUrl, add_to_recent_files: bool = True):
+
+        file_name = QUrl(file).toLocalFile()
+        workspace_reader = self.getWorkspaceFileHandler()
+        if workspace_reader is None:
+            Logger.warning(f"Workspace reader not found, cannot read file {file_name}.")
+            return
+
+        workspace_reader.readLocalFile(file, add_to_recent_files)
+
     @pyqtSlot(QUrl, str, bool)
     @pyqtSlot(QUrl, str)
     @pyqtSlot(QUrl)
@@ -2184,6 +2193,12 @@ class CuraApplication(QtApplication):
     def addNonSliceableExtension(self, extension):
         self._non_sliceable_extensions.append(extension)
 
+    @pyqtSlot(str, result = bool)
+    def isProjectUcp(self, file_url) -> bool:
+        file_path = QUrl(file_url).toLocalFile()
+        workspace_reader = self.getWorkspaceFileHandler().getReaderForFile(file_path)
+        return workspace_reader.getIsProjectUcp()
+
     @pyqtSlot(str, result=bool)
     def checkIsValidProjectFile(self, file_url):
         """Checks if the given file URL is a valid project file. """
@@ -2193,6 +2208,8 @@ class CuraApplication(QtApplication):
         if workspace_reader is None:
             return False  # non-project files won't get a reader
         try:
+            if workspace_reader.getPluginId() == "3MFReader":
+                workspace_reader.clearOpenAsUcp()
             result = workspace_reader.preRead(file_path, show_dialog=False)
             return result == WorkspaceReader.PreReadResult.accepted
         except:

+ 8 - 3
cura/Machines/Models/MachineListModel.py

@@ -5,7 +5,7 @@
 # online cloud connected printers are represented within this ListModel. Additional information such as the number of
 # connected printers for each printer type is gathered.
 
-from typing import Optional, List, cast
+from typing import Optional, List, cast, Dict, Any
 
 from PyQt6.QtCore import Qt, QTimer, QObject, pyqtSlot, pyqtProperty, pyqtSignal
 
@@ -30,10 +30,10 @@ class MachineListModel(ListModel):
     ComponentTypeRole = Qt.ItemDataRole.UserRole + 8
     IsNetworkedMachineRole = Qt.ItemDataRole.UserRole + 9
 
-    def __init__(self, parent: Optional[QObject] = None, machines_filter: List[GlobalStack] = None, listenToChanges: bool = True) -> None:
+    def __init__(self, parent: Optional[QObject] = None, machines_filter: List[GlobalStack] = None, listenToChanges: bool = True, showCloudPrinters: bool = False) -> None:
         super().__init__(parent)
 
-        self._show_cloud_printers = False
+        self._show_cloud_printers = showCloudPrinters
         self._machines_filter = machines_filter
 
         self._catalog = i18nCatalog("cura")
@@ -159,3 +159,8 @@ class MachineListModel(ListModel):
             "machineCount": machine_count,
             "catergory": "connected" if is_online else "other",
         })
+
+    def getItems(self) -> Dict[str, Any]:
+        if self.count > 0:
+            return self.items
+        return {}

+ 9 - 1
plugins/3MFReader/SpecificSettingsModel.py

@@ -3,6 +3,7 @@
 
 from PyQt6.QtCore import Qt
 
+from UM.Logger import Logger
 from UM.Settings.SettingDefinition import SettingDefinition
 from UM.Qt.ListModel import ListModel
 
@@ -19,6 +20,8 @@ class SpecificSettingsModel(ListModel):
         self.addRoleName(self.ValueRole, "value")
 
         self._i18n_catalog = None
+        self._update()
+
 
     def addSettingsFromStack(self, stack, category, settings):
         for setting, value in settings.items():
@@ -27,7 +30,7 @@ class SpecificSettingsModel(ListModel):
             setting_type = stack.getProperty(setting, "type")
             if setting_type is not None:
                 # This is not very good looking, but will do for now
-                value = SettingDefinition.settingValueToString(setting_type, value) + " " + unit
+                value = str(SettingDefinition.settingValueToString(setting_type, value)) + " " + str(unit)
             else:
                 value = str(value)
 
@@ -36,3 +39,8 @@ class SpecificSettingsModel(ListModel):
                 "label": stack.getProperty(setting, "label"),
                 "value": value
             })
+
+    def _update(self):
+        Logger.debug(f"Updating {self.__class__.__name__}")
+        self.setItems([])
+        return

+ 62 - 48
plugins/3MFReader/ThreeMFWorkspaceReader.py

@@ -117,6 +117,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         self._supported_extensions = [".3mf"]
         self._dialog = WorkspaceDialog()
         self._3mf_mesh_reader = None
+        self._is_ucp = None
         self._container_registry = ContainerRegistry.getInstance()
 
         # suffixes registered with the MimeTypes don't start with a dot '.'
@@ -143,16 +144,17 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         self._old_new_materials: Dict[str, str] = {}
         self._machine_info = None
 
-        self._load_profile = False
         self._user_settings: Dict[str, Dict[str, Any]] = {}
 
     def _clearState(self):
         self._id_mapping = {}
         self._old_new_materials = {}
         self._machine_info = None
-        self._load_profile = False
         self._user_settings = {}
 
+    def clearOpenAsUcp(self):
+        self._is_ucp =  None
+
     def getNewId(self, old_id: str):
         """Get a unique name based on the old_id. This is different from directly calling the registry in that it caches results.
 
@@ -207,6 +209,16 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
 
         return global_stack_file_list[0], extruder_stack_file_list
 
+    def _isProjectUcp(self, file_name) -> bool:
+        if self._is_ucp == None:
+            archive = zipfile.ZipFile(file_name, "r")
+            cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")]
+            self._is_ucp =True if USER_SETTINGS_PATH in cura_file_names else False
+
+    def getIsProjectUcp(self) -> bool:
+        return self._is_ucp
+
+
     def preRead(self, file_name, show_dialog=True, *args, **kwargs):
         """Read some info so we can make decisions
 
@@ -215,7 +227,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
                             we don't want to show a dialog.
         """
         self._clearState()
-
+        self._isProjectUcp(file_name)
         self._3mf_mesh_reader = Application.getInstance().getMeshFileHandler().getReaderForFile(file_name)
         if self._3mf_mesh_reader and self._3mf_mesh_reader.preRead(file_name) == WorkspaceReader.PreReadResult.accepted:
             pass
@@ -242,7 +254,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         # Read definition containers
         #
         machine_definition_id = None
-        updatable_machines = None if is_ucp else []
+        updatable_machines = None if self._is_ucp else []
         machine_definition_container_count = 0
         extruder_definition_container_count = 0
         definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)]
@@ -609,11 +621,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
 
         # Load the user specifically exported settings
         self._dialog.exportedSettingModel.clear()
-        if is_ucp:
+        self._dialog.setCurrentMachineName("")
+        if self._is_ucp:
             try:
                 self._user_settings = json.loads(archive.open("Cura/user-settings.json").read().decode("utf-8"))
                 any_extruder_stack = ExtruderManager.getInstance().getExtruderStack(0)
                 actual_global_stack = CuraApplication.getInstance().getGlobalContainerStack()
+                self._dialog.setCurrentMachineName(actual_global_stack.id)
 
                 for stack_name, settings in self._user_settings.items():
                     if stack_name == 'global':
@@ -658,15 +672,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         self._dialog.setVariantType(variant_type_name)
         self._dialog.setHasObjectsOnPlate(Application.getInstance().platformActivity)
         self._dialog.setMissingPackagesMetadata(missing_package_metadata)
-        self._dialog.setHasVisibleSelectSameProfileChanged(is_ucp)
-        self._dialog.setAllowCreatemachine(not is_ucp)
+        self._dialog.setAllowCreatemachine(not self._is_ucp)
+        self._dialog.setIsUcp(self._is_ucp)
         self._dialog.show()
 
 
         # Choosing the initially selected printer in MachineSelector
         is_networked_machine = False
         is_abstract_machine = False
-        if global_stack and isinstance(global_stack, GlobalStack):
+        if global_stack and isinstance(global_stack, GlobalStack) and not self._is_ucp:
             # The machine included in the project file exists locally already, no need to change selected printers.
             is_networked_machine = global_stack.hasNetworkedConnection()
             is_abstract_machine = parseBool(existing_global_stack.getMetaDataEntry("is_abstract_machine", False))
@@ -675,7 +689,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         elif self._dialog.updatableMachinesModel.count > 0:
             # The machine included in the project file does not exist. There is another machine of the same type.
             # This will always default to an abstract machine first.
-            machine = self._dialog.updatableMachinesModel.getItem(0)
+            machine = self._dialog.updatableMachinesModel.getItem(self._dialog.currentMachinePositionIndex)
             machine_name = machine["name"]
             is_networked_machine = machine["isNetworked"]
             is_abstract_machine = machine["isAbstractMachine"]
@@ -693,7 +707,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         self._dialog.setIsAbstractMachine(is_abstract_machine)
         self._dialog.setMachineName(machine_name)
         self._dialog.updateCompatibleMachine()
-        self._dialog.setSelectSameProfileChecked(self._dialog.isCompatibleMachine)
 
         # Block until the dialog is closed.
         self._dialog.waitForClose()
@@ -701,8 +714,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         if self._dialog.getResult() == {}:
             return WorkspaceReader.PreReadResult.cancelled
 
-        self._load_profile = not is_ucp or (self._dialog.selectSameProfileChecked and self._dialog.isCompatibleMachine)
-
         self._resolve_strategies = self._dialog.getResult()
         #
         # There can be 3 resolve strategies coming from the dialog:
@@ -717,7 +728,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
             if key not in containers_found_dict or strategy is not None:
                 continue
             self._resolve_strategies[key] = "override" if containers_found_dict[key] else "new"
-
         return WorkspaceReader.PreReadResult.accepted
 
     @call_on_qt_thread
@@ -825,7 +835,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
             for stack in extruder_stacks:
                 stack.setNextStack(global_stack, connect_signals = False)
 
-        if self._load_profile:
+        if not self._is_ucp:
             Logger.log("d", "Workspace loading is checking definitions...")
             # Get all the definition files & check if they exist. If not, add them.
             definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)]
@@ -899,7 +909,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
                     QCoreApplication.processEvents()  # Ensure that the GUI does not freeze.
 
         if global_stack:
-            if self._load_profile:
+            if not self._is_ucp:
                 # Handle quality changes if any
                 self._processQualityChanges(global_stack)
 
@@ -907,7 +917,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
                 self._applyChangesToMachine(global_stack, extruder_stack_dict)
             else:
                 # Just clear the settings now, so that we can change the active machine without conflicts
-                self._clearMachineSettings(global_stack, extruder_stack_dict)
+                self._clearMachineSettings(global_stack, {})
+
 
             Logger.log("d", "Workspace loading is notifying rest of the code of changes...")
             # Actually change the active machine.
@@ -917,9 +928,10 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
             # function is running on the main thread (Qt thread), although those "changed" signals have been emitted, but
             # they won't take effect until this function is done.
             # To solve this, we schedule _updateActiveMachine() for later so it will have the latest data.
+
             self._updateActiveMachine(global_stack)
 
-            if not self._load_profile:
+            if self._is_ucp:
                 # Now we have switched, apply the user settings
                 self._applyUserSettings(global_stack, extruder_stack_dict, self._user_settings)
 
@@ -931,6 +943,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         base_file_name = os.path.basename(file_name)
         self.setWorkspaceName(base_file_name)
 
+        self._is_ucp = None
         return nodes, self._loadMetadata(file_name)
 
     @staticmethod
@@ -1309,39 +1322,40 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         machine_manager.setActiveMachine(global_stack.getId())
 
         # Set metadata fields that are missing from the global stack
-        for key, value in self._machine_info.metadata_dict.items():
-            if key not in global_stack.getMetaData() and key not in _ignored_machine_network_metadata:
-                global_stack.setMetaDataEntry(key, value)
-
-        if self._quality_changes_to_apply:
-            quality_changes_group_list = container_tree.getCurrentQualityChangesGroups()
-            quality_changes_group = next((qcg for qcg in quality_changes_group_list if qcg.name == self._quality_changes_to_apply), None)
-            if not quality_changes_group:
-                Logger.log("e", "Could not find quality_changes [%s]", self._quality_changes_to_apply)
-                return
-            machine_manager.setQualityChangesGroup(quality_changes_group, no_dialog = True)
-        else:
-            self._quality_type_to_apply = self._quality_type_to_apply.lower() if self._quality_type_to_apply else None
-            quality_group_dict = container_tree.getCurrentQualityGroups()
-            if self._quality_type_to_apply in quality_group_dict:
-                quality_group = quality_group_dict[self._quality_type_to_apply]
+        if not self._is_ucp:
+            for key, value in self._machine_info.metadata_dict.items():
+                if key not in global_stack.getMetaData() and key not in _ignored_machine_network_metadata:
+                    global_stack.setMetaDataEntry(key, value)
+
+            if self._quality_changes_to_apply !=None:
+                quality_changes_group_list = container_tree.getCurrentQualityChangesGroups()
+                quality_changes_group = next((qcg for qcg in quality_changes_group_list if qcg.name == self._quality_changes_to_apply), None)
+                if not quality_changes_group:
+                    Logger.log("e", "Could not find quality_changes [%s]", self._quality_changes_to_apply)
+                    return
+                machine_manager.setQualityChangesGroup(quality_changes_group, no_dialog = True)
             else:
-                Logger.log("i", "Could not find quality type [%s], switch to default", self._quality_type_to_apply)
-                preferred_quality_type = global_stack.getMetaDataEntry("preferred_quality_type")
-                quality_group = quality_group_dict.get(preferred_quality_type)
-                if quality_group is None:
-                    Logger.log("e", "Could not get preferred quality type [%s]", preferred_quality_type)
-
-            if quality_group is not None:
-                machine_manager.setQualityGroup(quality_group, no_dialog = True)
-
-                # Also apply intent if available
-                available_intent_category_list = IntentManager.getInstance().currentAvailableIntentCategories()
-                if self._intent_category_to_apply is not None and self._intent_category_to_apply in available_intent_category_list:
-                    machine_manager.setIntentByCategory(self._intent_category_to_apply)
+                self._quality_type_to_apply = self._quality_type_to_apply.lower() if self._quality_type_to_apply else None
+                quality_group_dict = container_tree.getCurrentQualityGroups()
+                if self._quality_type_to_apply in quality_group_dict:
+                    quality_group = quality_group_dict[self._quality_type_to_apply]
                 else:
-                    # if no intent is provided, reset to the default (balanced) intent
-                    machine_manager.resetIntents()
+                    Logger.log("i", "Could not find quality type [%s], switch to default", self._quality_type_to_apply)
+                    preferred_quality_type = global_stack.getMetaDataEntry("preferred_quality_type")
+                    quality_group = quality_group_dict.get(preferred_quality_type)
+                    if quality_group is None:
+                        Logger.log("e", "Could not get preferred quality type [%s]", preferred_quality_type)
+
+                if quality_group is not None:
+                    machine_manager.setQualityGroup(quality_group, no_dialog = True)
+
+                    # Also apply intent if available
+                    available_intent_category_list = IntentManager.getInstance().currentAvailableIntentCategories()
+                    if self._intent_category_to_apply is not None and self._intent_category_to_apply in available_intent_category_list:
+                        machine_manager.setIntentByCategory(self._intent_category_to_apply)
+                    else:
+                        # if no intent is provided, reset to the default (balanced) intent
+                        machine_manager.resetIntents()
         # Notify everything/one that is to notify about changes.
         global_stack.containersChanged.emit(global_stack.getTop())
 

+ 35 - 22
plugins/3MFReader/WorkspaceDialog.py

@@ -63,21 +63,22 @@ class WorkspaceDialog(QObject):
         self._machine_name = ""
         self._machine_type = ""
         self._variant_type = ""
+        self._current_machine_name = ""
         self._material_labels = []
         self._extruders = []
         self._objects_on_plate = False
         self._is_printer_group = False
-        self._updatable_machines_model = MachineListModel(self, listenToChanges=False)
+        self._updatable_machines_model = MachineListModel(self, listenToChanges = False, showCloudPrinters = True)
         self._missing_package_metadata: List[Dict[str, str]] = []
         self._plugin_registry: PluginRegistry = CuraApplication.getInstance().getPluginRegistry()
         self._install_missing_package_dialog: Optional[QObject] = None
         self._is_abstract_machine = False
         self._is_networked_machine = False
         self._is_compatible_machine = False
-        self._has_visible_select_same_profile = False
-        self._select_same_profile_checked = True
         self._allow_create_machine = True
         self._exported_settings_model = SpecificSettingsModel()
+        self._current_machine_pos_index = 0
+        self._is_ucp = False
 
     machineConflictChanged = pyqtSignal()
     qualityChangesConflictChanged = pyqtSignal()
@@ -102,8 +103,7 @@ class WorkspaceDialog(QObject):
     isPrinterGroupChanged = pyqtSignal()
     missingPackagesChanged = pyqtSignal()
     isCompatibleMachineChanged = pyqtSignal()
-    hasVisibleSelectSameProfileChanged = pyqtSignal()
-    selectSameProfileCheckedChanged = pyqtSignal()
+    isUcpChanged = pyqtSignal()
 
     @pyqtProperty(bool, notify = isPrinterGroupChanged)
     def isPrinterGroup(self) -> bool:
@@ -176,8 +176,30 @@ class WorkspaceDialog(QObject):
             self._machine_name = machine_name
             self.machineNameChanged.emit()
 
+    def setCurrentMachineName(self, machine: str) -> None:
+        self._current_machine_name = machine
+
+    @pyqtProperty(str, notify = machineNameChanged)
+    def currentMachineName(self) -> str:
+        return self._current_machine_name
+
+    @staticmethod
+    def getIndexOfCurrentMachine(list_of_dicts, key, value, defaultIndex):
+        for i, d in enumerate(list_of_dicts):
+            if d.get(key) == value:  # found the dictionary
+                return i
+        return defaultIndex
+
+    @pyqtProperty(int, notify = machineNameChanged)
+    def currentMachinePositionIndex(self):
+        return self._current_machine_pos_index
+
     @pyqtProperty(QObject, notify = updatableMachinesChanged)
     def updatableMachinesModel(self) -> MachineListModel:
+        if self._current_machine_name != "":
+            self._current_machine_pos_index = self.getIndexOfCurrentMachine(self._updatable_machines_model.getItems(), "id", self._current_machine_name, defaultIndex = 0)
+        else:
+            self._current_machine_pos_index = 0
         return cast(MachineListModel, self._updatable_machines_model)
 
     def setUpdatableMachines(self, updatable_machines: List[GlobalStack]) -> None:
@@ -318,23 +340,14 @@ class WorkspaceDialog(QObject):
     def isCompatibleMachine(self) -> bool:
         return self._is_compatible_machine
 
-    def setHasVisibleSelectSameProfileChanged(self, has_visible_select_same_profile):
-        if has_visible_select_same_profile != self._has_visible_select_same_profile:
-            self._has_visible_select_same_profile = has_visible_select_same_profile
-            self.hasVisibleSelectSameProfileChanged.emit()
-
-    @pyqtProperty(bool, notify = hasVisibleSelectSameProfileChanged)
-    def hasVisibleSelectSameProfile(self):
-        return self._has_visible_select_same_profile
-
-    def setSelectSameProfileChecked(self, select_same_profile_checked):
-        if select_same_profile_checked != self._select_same_profile_checked:
-            self._select_same_profile_checked = select_same_profile_checked
-            self.selectSameProfileCheckedChanged.emit()
+    def setIsUcp(self, isUcp: bool) -> None:
+        if isUcp != self._is_ucp:
+            self._is_ucp = isUcp
+            self.isUcpChanged.emit()
 
-    @pyqtProperty(bool, notify = selectSameProfileCheckedChanged, fset = setSelectSameProfileChecked)
-    def selectSameProfileChecked(self):
-        return self._select_same_profile_checked
+    @pyqtProperty(bool, notify=isUcpChanged)
+    def isUcp(self):
+        return self._is_ucp
 
     def setAllowCreatemachine(self, allow_create_machine):
         self._allow_create_machine = allow_create_machine
@@ -343,7 +356,7 @@ class WorkspaceDialog(QObject):
     def allowCreateMachine(self):
         return self._allow_create_machine
 
-    @pyqtProperty(QObject, constant = True)
+    @pyqtProperty(QObject)
     def exportedSettingModel(self):
         return self._exported_settings_model
 

+ 33 - 23
plugins/3MFReader/WorkspaceDialog.qml

@@ -12,7 +12,7 @@ import Cura 1.1 as Cura
 UM.Dialog
 {
     id: workspaceDialog
-    title: catalog.i18nc("@title:window", "Open Project")
+    title: manager.isUcp? catalog.i18nc("@title:window", "Open Universal Cura Project (UCP)"): catalog.i18nc("@title:window", "Open Project")
 
     margin: UM.Theme.getSize("default_margin").width
     minimumWidth: UM.Theme.getSize("modal_window_minimum").width
@@ -28,7 +28,7 @@ UM.Dialog
         UM.Label
         {
             id: titleLabel
-            text: catalog.i18nc("@action:title", "Summary - Cura Project")
+            text: manager.isUcp? catalog.i18nc("@action:title", "Summary - Open Universal Cura Project (UCP)"): catalog.i18nc("@action:title", "Summary - Cura Project")
             font: UM.Theme.getFont("large")
             anchors.top: parent.top
             anchors.left: parent.left
@@ -96,7 +96,7 @@ UM.Dialog
                         WorkspaceRow
                         {
                             leftLabelText: catalog.i18nc("@action:label", manager.isPrinterGroup ? "Printer Group" : "Printer Name")
-                            rightLabelText: manager.machineName == catalog.i18nc("@button", "Create new") ? "" : manager.machineName
+                            rightLabelText: manager.isUcp? manager.machineType: manager.machineName == catalog.i18nc("@button", "Create new") ? "" : manager.machineName
                         }
                     }
 
@@ -159,7 +159,7 @@ UM.Dialog
                 WorkspaceSection
                 {
                     id: profileSection
-                    title: catalog.i18nc("@action:label", "Profile settings")
+                    title: manager.isUcp? catalog.i18nc("@action:label", "Suggested Profile settings"):catalog.i18nc("@action:label", "Profile settings")
                     iconSource: UM.Theme.getIcon("Sliders")
                     content: Column
                     {
@@ -185,32 +185,44 @@ UM.Dialog
                         {
                             leftLabelText: catalog.i18nc("@action:label", "Not in profile")
                             rightLabelText: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", manager.numUserSettings).arg(manager.numUserSettings)
-                            visible: manager.numUserSettings != 0 && manager.selectSameProfileChecked && manager.isCompatibleMachine
+                            visible: manager.numUserSettings != 0 && manager.isCompatibleMachine
                         }
 
                         WorkspaceRow
                         {
                             leftLabelText: catalog.i18nc("@action:label", "Derivative from")
                             rightLabelText: catalog.i18ncp("@action:label", "%1, %2 override", "%1, %2 overrides", manager.numSettingsOverridenByQualityChanges).arg(manager.qualityType).arg(manager.numSettingsOverridenByQualityChanges)
-                            visible: manager.numSettingsOverridenByQualityChanges != 0 && manager.selectSameProfileChecked && manager.isCompatibleMachine
+                            visible: manager.numSettingsOverridenByQualityChanges != 0 && manager.isCompatibleMachine
                         }
+                    }
+                }
+                WorkspaceSection
+                {
+                    id: ucpProfileSection
+                    visible: manager.isUcp
+                    title: catalog.i18nc("@action:label", "Settings Loaded from UCP file")
+                    iconSource: UM.Theme.getIcon("Settings")
+
+                    content: Column
+                    {
+                        id: ucpProfileSettingsValuesTable
+                        spacing: UM.Theme.getSize("default_margin").height
+                        leftPadding: UM.Theme.getSize("medium_button_icon").width + UM.Theme.getSize("default_margin").width
 
                         WorkspaceRow
                         {
-                            leftLabelText: catalog.i18nc("@action:label", "Specific settings")
+                            leftLabelText: catalog.i18nc("@action:label", "Settings Loaded from UCP file")
                             rightLabelText: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", manager.exportedSettingModel.rowCount()).arg(manager.exportedSettingModel.rowCount())
                             buttonText: tableViewSpecificSettings.shouldBeVisible ? catalog.i18nc("@action:button", "Hide settings") : catalog.i18nc("@action:button", "Show settings")
-                            visible: !manager.selectSameProfileChecked || !manager.isCompatibleMachine
                             onButtonClicked: tableViewSpecificSettings.shouldBeVisible = !tableViewSpecificSettings.shouldBeVisible
                         }
-
                         Cura.TableView
                         {
                             id: tableViewSpecificSettings
                             width: parent.width - parent.leftPadding - UM.Theme.getSize("default_margin").width
                             height: UM.Theme.getSize("card").height
-                            visible: shouldBeVisible && (!manager.selectSameProfileChecked || !manager.isCompatibleMachine)
-                            property bool shouldBeVisible: false
+                            visible: shouldBeVisible && manager.isUcp
+                            property bool shouldBeVisible: true
 
                             columnHeaders:
                             [
@@ -227,15 +239,11 @@ UM.Dialog
                             }
                         }
 
-                        UM.CheckBox
+                        property var modelRows: manager.exportedSettingModel.items
+                        onModelRowsChanged:
                         {
-                            text: catalog.i18nc("@action:checkbox", "Select the same profile")
-                            onEnabledChanged: manager.selectSameProfileChecked = enabled
-                            tooltip: enabled ? "" : catalog.i18nc("@tooltip", "You can use the same profile only if you have the same printer as the project was published with")
-                            visible: manager.hasVisibleSelectSameProfile && manager.isCompatibleMachine
-
-                            checked: manager.selectSameProfileChecked
-                            onCheckedChanged: manager.selectSameProfileChecked = checked
+                            tableModel.clear()
+                            tableModel.rows = modelRows
                         }
                     }
 
@@ -245,7 +253,7 @@ UM.Dialog
                         id: qualityChangesResolveComboBox
                         model: resolveStrategiesModel
                         textRole: "label"
-                        visible: manager.qualityChangesConflict
+                        visible: manager.qualityChangesConflict && !manager.isUcp
                         contentLeftPadding: UM.Theme.getSize("default_margin").width + UM.Theme.getSize("narrow_margin").width
                         textFont: UM.Theme.getFont("medium")
 
@@ -274,7 +282,7 @@ UM.Dialog
                 WorkspaceSection
                 {
                     id: materialSection
-                    title: catalog.i18nc("@action:label", "Material settings")
+                    title: manager.isUcp? catalog.i18nc("@action:label", "Suggested Material settings"): catalog.i18nc("@action:label", "Material settings")
                     iconSource: UM.Theme.getIcon("Spool")
                     content: Column
                     {
@@ -299,7 +307,7 @@ UM.Dialog
                         id: materialResolveComboBox
                         model: resolveStrategiesModel
                         textRole: "label"
-                        visible: manager.materialConflict
+                        visible: manager.materialConflict && !manager.isUcp
                         contentLeftPadding: UM.Theme.getSize("default_margin").width + UM.Theme.getSize("narrow_margin").width
                         textFont: UM.Theme.getFont("medium")
 
@@ -330,6 +338,7 @@ UM.Dialog
                     id: visibilitySection
                     title: catalog.i18nc("@action:label", "Setting visibility")
                     iconSource: UM.Theme.getIcon("Eye")
+                    visible : !manager.isUcp
                     content: Column
                     {
                         spacing: UM.Theme.getSize("default_margin").height
@@ -467,12 +476,13 @@ UM.Dialog
     {
         if (visible)
         {
-            // Force relead the comboboxes
+            // Force reload the comboboxes
             // Since this dialog is only created once the first time you open it, these comboxes need to be reloaded
             // each time it is shown after the first time so that the indexes will update correctly.
             materialSection.reloadValues()
             profileSection.reloadValues()
             printerSection.reloadValues()
+            ucpProfileSection.reloadValues()
         }
     }
 }

+ 2 - 1
plugins/3MFReader/WorkspaceSection.qml

@@ -84,7 +84,8 @@ Item
         {
             anchors.right: parent.right
             anchors.verticalCenter: comboboxLabel.verticalCenter
-
+            color: UM.Theme.getColor("small_button_text")
+            icon: UM.Theme.getIcon("Information")
             text: comboboxTooltipText
             visible: comboboxTooltipText != ""
         }

+ 4 - 3
plugins/3MFWriter/SettingSelection.qml

@@ -19,7 +19,7 @@ RowLayout
         Layout.preferredWidth: UM.Theme.getSize("setting").width
         checked: modelData.selected
         onClicked: modelData.selected = checked
-        enabled: modelData.selectable
+        tooltip: modelData.selectable ? "" :catalog.i18nc("@tooltip", "This setting may not perform well while exporting to UCP. Users are asked to add it at their own risk.")
     }
 
     UM.Label
@@ -30,9 +30,10 @@ RowLayout
     UM.HelpIcon
     {
         UM.I18nCatalog { id: catalog; name: "cura" }
-
         text: catalog.i18nc("@tooltip",
-                            "This setting can't be exported because it depends on the used printer capacities")
+                            "This setting may not perform well while exporting to UCP, Users are asked to add it at their own risk.")
         visible: !modelData.selectable
     }
+
+
 }

Некоторые файлы не были показаны из-за большого количества измененных файлов