Browse Source

Resolve merge conflicts with master - CURA-4482

Chris ter Beke 7 years ago
parent
commit
9806ec7374

+ 0 - 1
cura/CrashHandler.py

@@ -75,7 +75,6 @@ class CrashHandler:
 
     ##  Creates a modal dialog.
     def _createDialog(self):
-        self.dialog = QDialog()
         self.dialog.setMinimumWidth(640)
         self.dialog.setMinimumHeight(640)
         self.dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report"))

+ 14 - 2
cura/CuraApplication.py

@@ -105,7 +105,7 @@ class CuraApplication(QtApplication):
     # SettingVersion represents the set of settings available in the machine/extruder definitions.
     # You need to make sure that this version number needs to be increased if there is any non-backwards-compatible
     # changes of the settings.
-    SettingVersion = 3
+    SettingVersion = 4
 
     class ResourceTypes:
         QmlFiles = Resources.UserType + 1
@@ -216,6 +216,7 @@ class CuraApplication(QtApplication):
 
         self.setRequiredPlugins([
             "CuraEngineBackend",
+            "UserAgreement",
             "SolidView",
             "LayerView",
             "STLReader",
@@ -274,8 +275,9 @@ class CuraApplication(QtApplication):
         empty_quality_container = copy.deepcopy(empty_container)
         empty_quality_container._id = "empty_quality"
         empty_quality_container.setName("Not Supported")
-        empty_quality_container.addMetaDataEntry("quality_type", "normal")
+        empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
         empty_quality_container.addMetaDataEntry("type", "quality")
+        empty_quality_container.addMetaDataEntry("supported", False)
         ContainerRegistry.getInstance().addContainer(empty_quality_container)
 
         empty_quality_changes_container = copy.deepcopy(empty_container)
@@ -308,6 +310,8 @@ class CuraApplication(QtApplication):
 
         preferences.addPreference("view/invert_zoom", False)
 
+        self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement")
+
         for key in [
             "dialog_load_path",  # dialog_save_path is in LocalFileOutputDevicePlugin
             "dialog_profile_path",
@@ -380,6 +384,14 @@ class CuraApplication(QtApplication):
     def _onEngineCreated(self):
         self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
 
+    @pyqtProperty(bool)
+    def needToShowUserAgreement(self):
+        return self._need_to_show_user_agreement
+
+
+    def setNeedToShowUserAgreement(self, set_value = True):
+        self._need_to_show_user_agreement = set_value
+
     ## The "Quit" button click event handler.
     @pyqtSlot()
     def closeApplication(self):

+ 6 - 2
cura/PrintInformation.py

@@ -313,7 +313,12 @@ class PrintInformation(QObject):
             elif word.isdigit():
                 abbr_machine += word
             else:
-                abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0]
+                stripped_word = self._stripAccents(word.strip("()[]{}#").upper())
+                # - use only the first character if the word is too long (> 3 characters)
+                # - use the whole word if it's not too long (<= 3 characters)
+                if len(stripped_word) > 3:
+                    stripped_word = stripped_word[0]
+                abbr_machine += stripped_word
 
         self._abbr_machine = abbr_machine
 
@@ -339,4 +344,3 @@ class PrintInformation(QObject):
 
         temp_material_amounts = [0]
         self._onPrintDurationMessage(temp_message, temp_material_amounts)
-

+ 18 - 5
cura/QualityManager.py

@@ -87,7 +87,7 @@ class QualityManager:
         qualities = set(quality_type_dict.values())
         for material_container in material_containers[1:]:
             next_quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_container)
-            qualities.update(set(next_quality_type_dict.values()))
+            qualities.intersection_update(set(next_quality_type_dict.values()))
 
         return list(qualities)
 
@@ -178,12 +178,25 @@ class QualityManager:
     def findAllUsableQualitiesForMachineAndExtruders(self, global_container_stack: "GlobalStack", extruder_stacks: List["ExtruderStack"]) -> List[InstanceContainer]:
         global_machine_definition = global_container_stack.getBottom()
 
+        machine_manager = Application.getInstance().getMachineManager()
+        active_stack_id = machine_manager.activeStackId
+
+        materials = []
+
+        # TODO: fix this
         if extruder_stacks:
-            # Multi-extruder machine detected.
-            materials = [stack.material for stack in extruder_stacks]
+            # Multi-extruder machine detected
+            for stack in extruder_stacks:
+                if stack.getId() == active_stack_id and machine_manager.newMaterial:
+                    materials.append(machine_manager.newMaterial)
+                else:
+                    materials.append(stack.material)
         else:
-            # Machine with one extruder.
-            materials = [global_container_stack.material]
+            # Machine with one extruder
+            if global_container_stack.getId() == active_stack_id and machine_manager.newMaterial:
+                materials.append(machine_manager.newMaterial)
+            else:
+                materials.append(global_container_stack.material)
 
         quality_types = self.findAllQualityTypesForMachineAndMaterials(global_machine_definition, materials)
 

+ 3 - 0
cura/Settings/CuraContainerRegistry.py

@@ -306,6 +306,9 @@ class CuraContainerRegistry(ContainerRegistry):
         if "material" in quality_type_criteria:
             materials = ContainerRegistry.getInstance().findInstanceContainers(id = quality_type_criteria["material"])
             del quality_type_criteria["material"]
+        # Do not filter quality containers here with materials because we are trying to import a profile, so it should
+        # NOT be restricted by the active materials on the current machine.
+        materials = None
 
         # Check to make sure the imported profile actually makes sense in context of the current configuration.
         # This prevents issues where importing a "draft" profile for a machine without "draft" qualities would report as

+ 72 - 26
cura/Settings/MachineManager.py

@@ -50,6 +50,7 @@ class MachineManager(QObject):
         # Used to store the new containers until after confirming the dialog
         self._new_variant_container = None
         self._new_material_container = None
+        self._new_quality_containers = []
 
         self._error_check_timer = QTimer()
         self._error_check_timer.setInterval(250)
@@ -70,10 +71,10 @@ class MachineManager(QObject):
 
         self._stacks_have_errors = None
 
-        self._empty_variant_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
-        self._empty_material_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
-        self._empty_quality_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
-        self._empty_quality_changes_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
+        self._empty_variant_container = ContainerRegistry.getInstance().findContainers(id = "empty_variant")[0]
+        self._empty_material_container = ContainerRegistry.getInstance().findContainers(id = "empty_material")[0]
+        self._empty_quality_container = ContainerRegistry.getInstance().findContainers(id = "empty_quality")[0]
+        self._empty_quality_changes_container = ContainerRegistry.getInstance().findContainers(id = "empty_quality_changes")[0]
 
         self._onGlobalContainerChanged()
 
@@ -146,6 +147,14 @@ class MachineManager(QObject):
 
         self.outputDevicesChanged.emit()
 
+    @property
+    def newVariant(self):
+        return self._new_variant_container
+
+    @property
+    def newMaterial(self):
+        return self._new_material_container
+
     @pyqtProperty("QVariantList", notify = outputDevicesChanged)
     def printerOutputDevices(self):
         return self._printer_output_devices
@@ -838,8 +847,6 @@ class MachineManager(QObject):
             if not containers or not self._global_container_stack:
                 return
 
-            Logger.log("d", "Attempting to change the active quality to %s", quality_id)
-
             # Quality profile come in two flavours: type=quality and type=quality_changes
             # If we found a quality_changes profile then look up its parent quality profile.
             container_type = containers[0].getMetaDataEntry("type")
@@ -859,49 +866,73 @@ class MachineManager(QObject):
             if new_quality_settings_list is None:
                 return
 
-            name_changed_connect_stacks = []  # Connect these stacks to the name changed callback
+            # check if any of the stacks have a not supported profile
+            # if that is the case, all stacks should have a not supported state (otherwise it will show quality_type normal)
+            has_not_supported_quality = False
+
+            # check all stacks for not supported
+            for setting_info in new_quality_settings_list:
+                if setting_info["quality"].getMetaDataEntry("quality_type") == "not_supported":
+                    has_not_supported_quality = True
+                    break
+
+            # set all stacks to not supported if that's the case
+            if has_not_supported_quality:
+                for setting_info in new_quality_settings_list:
+                    setting_info["quality"] = self._empty_quality_container
+
+            self._new_quality_containers.clear()
+
+            # store the upcoming quality profile changes per stack for later execution
+            # this prevents re-slicing before the user has made a choice in the discard or keep dialog
+            # (see _executeDelayedActiveContainerStackChanges)
             for setting_info in new_quality_settings_list:
                 stack = setting_info["stack"]
                 stack_quality = setting_info["quality"]
                 stack_quality_changes = setting_info["quality_changes"]
 
-                name_changed_connect_stacks.append(stack_quality)
-                name_changed_connect_stacks.append(stack_quality_changes)
-                self._replaceQualityOrQualityChangesInStack(stack, stack_quality, postpone_emit=True)
-                self._replaceQualityOrQualityChangesInStack(stack, stack_quality_changes, postpone_emit=True)
-
-            # Connect to onQualityNameChanged
-            for stack in name_changed_connect_stacks:
-                stack.nameChanged.connect(self._onQualityNameChanged)
+                self._new_quality_containers.append({
+                    "stack": stack,
+                    "quality": stack_quality,
+                    "quality_changes": stack_quality_changes
+                })
 
             has_user_interaction = False
 
             if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
                 # Show the keep/discard user settings dialog
                 has_user_interaction = Application.getInstance().discardOrKeepProfileChanges()
-            else:
-                # If the user doesn't have any of adjusted settings then slicing will be triggered by emit()
-                # Send emits that are postponed in replaceContainer.
-                # Here the stacks are finished replacing and every value can be resolved based on the current state.
-                for setting_info in new_quality_settings_list:
-                    setting_info["stack"].sendPostponedEmits()
 
+            # If there is no interaction with the user (it means the dialog showing "keep" or "discard" was not shown)
+            # because either there are not user changes or because the used already decided to always keep or discard,
+            # then the quality instance container is replaced, in which case, the activeQualityChanged signal is emitted.
             if not has_user_interaction:
                 self._executeDelayedActiveContainerStackChanges()
-                self.activeQualityChanged.emit()
 
     ##  Used to update material and variant in the active container stack with a delay.
     #   This delay prevents the stack from triggering a lot of signals (eventually resulting in slicing)
     #   before the user decided to keep or discard any of their changes using the dialog.
     #   The Application.onDiscardOrKeepProfileChangesClosed signal triggers this method.
     def _executeDelayedActiveContainerStackChanges(self):
+        if self._new_variant_container is not None:
+            self._active_container_stack.variant = self._new_variant_container
+            self._new_variant_container = None
+
         if self._new_material_container is not None:
             self._active_container_stack.material = self._new_material_container
             self._new_material_container = None
 
-        if self._new_variant_container is not None:
-            self._active_container_stack.variant = self._new_variant_container
-            self._new_variant_container = None
+        # apply the new quality to all stacks
+        if self._new_quality_containers:
+            for new_quality in self._new_quality_containers:
+                self._replaceQualityOrQualityChangesInStack(new_quality["stack"], new_quality["quality"], postpone_emit = True)
+                self._replaceQualityOrQualityChangesInStack(new_quality["stack"], new_quality["quality_changes"], postpone_emit = True)
+
+            for new_quality in self._new_quality_containers:
+                new_quality["stack"].nameChanged.connect(self._onQualityNameChanged)
+                new_quality["stack"].sendPostponedEmits() # Send the signals that were postponed in _replaceQualityOrQualityChangesInStack
+
+            self._new_quality_containers.clear()
 
     ##  Cancel set changes for material and variant in the active container stack.
     #   Used for ignoring any changes when switching between printers (setActiveMachine)
@@ -931,8 +962,14 @@ class MachineManager(QObject):
 
         for stack in stacks:
             material = stack.material
+
+            # TODO: fix this
+            if self._new_material_container and stack.getId() == self._active_container_stack.getId():
+                material = self._new_material_container
+
             quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
-            if not quality: #No quality profile is found for this quality type.
+            if not quality:
+                # No quality profile is found for this quality type.
                 quality = self._empty_quality_container
             result.append({"stack": stack, "quality": quality, "quality_changes": empty_quality_changes})
 
@@ -970,6 +1007,11 @@ class MachineManager(QObject):
         material = global_container_stack.material
 
         # find a quality type that matches both machine and materials
+        if self._new_material_container and self._active_container_stack.getId() == global_container_stack.getId():
+            material = self._new_material_container
+
+        # For the global stack, find a quality which matches the quality_type in
+        # the quality changes profile and also satisfies any material constraints.
         quality_type = global_quality_changes.getMetaDataEntry("quality_type")
 
         extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
@@ -989,6 +1031,10 @@ class MachineManager(QObject):
                 quality_changes = self._empty_quality_changes_container
 
             material = extruder_stack.material
+
+            if self._new_material_container and self._active_container_stack.getId() == stack.getId():
+                material = self._new_material_container
+
             quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
 
             if not quality:

+ 20 - 2
cura/Settings/ProfilesModel.py

@@ -82,10 +82,18 @@ class ProfilesModel(InstanceContainersModel):
             if quality.getMetaDataEntry("quality_type") not in quality_type_set:
                 result.append(quality)
 
+        # if still profiles are found, add a single empty_quality ("Not supported") instance to the drop down list
+        if len(result) == 0:
+            # If not qualities are found we dynamically create a not supported container for this machine + material combination
+            not_supported_container = ContainerRegistry.getInstance().findContainers(id = "empty_quality")[0]
+            result.append(not_supported_container)
+
         return result
 
     ##  Re-computes the items in this model, and adds the layer height role.
     def _recomputeItems(self):
+
+        # Some globals that we can re-use.
         global_container_stack = Application.getInstance().getGlobalContainerStack()
         if global_container_stack is None:
             return
@@ -134,14 +142,24 @@ class ProfilesModel(InstanceContainersModel):
 
         # Now all the containers are set
         for item in containers:
-            profile = container_registry.findContainers(id=item["id"])
+            profile = container_registry.findContainers(id = item["id"])
+
+            # When for some reason there is no profile container in the registry
             if not profile:
-                self._setItemLayerHeight(item, "", unit)
+                self._setItemLayerHeight(item, "", "")
                 item["available"] = False
                 yield item
                 continue
 
             profile = profile[0]
+
+            # When there is a profile but it's an empty quality should. It's shown in the list (they are "Not Supported" profiles)
+            if profile.getId() == "empty_quality":
+                self._setItemLayerHeight(item, "", "")
+                item["available"] = True
+                yield item
+                continue
+
             item["available"] = profile in qualities
 
             # Easy case: This profile defines its own layer height.

+ 27 - 1
plugins/3MFReader/ThreeMFWorkspaceReader.py

@@ -21,6 +21,8 @@ from cura.Settings.CuraStackBuilder import CuraStackBuilder
 from cura.Settings.ExtruderManager import ExtruderManager
 from cura.Settings.ExtruderStack import ExtruderStack
 from cura.Settings.GlobalStack import GlobalStack
+from cura.Settings.CuraContainerStack import _ContainerIndexes
+from cura.QualityManager import QualityManager
 
 from configparser import ConfigParser
 import zipfile
@@ -757,13 +759,37 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
                 self._container_registry.removeContainer(container.getId())
             return
 
+        # Check quality profiles to make sure that if one stack has the "not supported" quality profile,
+        # all others should have the same.
+        #
+        # This block code tries to fix the following problems in Cura 3.0 and earlier:
+        #  1. The upgrade script can rename all "Not Supported" quality profiles to "empty_quality", but it cannot fix
+        #     the problem that the global stack the extruder stacks may have different quality profiles. The code
+        #     below loops over all stacks and make sure that if there is one stack with "Not Supported" profile, the
+        #     rest should also use the "Not Supported" profile.
+        #  2. In earlier versions (at least 2.7 and 3.0), a wrong quality profile could be assigned to a stack. For
+        #     example, a UM3 can have a BB 0.8 variant with "aa04_pla_fast" quality profile enabled. To fix this,
+        #     in the code below we also check the actual available quality profiles for the machine.
+        #
+        has_not_supported = False
+        for stack in [global_stack] + extruder_stacks:
+            if stack.quality.getId() == "empty_quality":
+                has_not_supported = True
+                break
+        if not has_not_supported:
+            available_quality = QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_stack, extruder_stacks)
+            has_not_supported = not available_quality
+        if has_not_supported:
+            empty_quality_container = self._container_registry.findInstanceContainers(id = "empty_quality")[0]
+            for stack in [global_stack] + extruder_stacks:
+                stack.replaceContainer(_ContainerIndexes.Quality, empty_quality_container)
+
         #
         # Replacing the old containers if resolve is "new".
         # When resolve is "new", some containers will get renamed, so all the other containers that reference to those
         # MUST get updated too.
         #
         if self._resolve_strategies["machine"] == "new":
-
             # A new machine was made, but it was serialized with the wrong user container. Fix that now.
             for container in user_instance_containers:
                 # replacing the container ID for user instance containers for the extruders

+ 0 - 1
plugins/ChangeLogPlugin/ChangeLog.py

@@ -8,7 +8,6 @@ from UM.Application import Application
 from UM.PluginRegistry import PluginRegistry
 from UM.Version import Version
 
-from PyQt5.QtQuick import QQuickView
 from PyQt5.QtQml import QQmlComponent, QQmlContext
 from PyQt5.QtCore import QUrl, pyqtSlot, QObject
 

+ 11 - 5
plugins/MachineSettingsAction/MachineSettingsAction.py

@@ -147,6 +147,7 @@ class MachineSettingsAction(MachineAction):
                 for setting_instance in extruder_user_container.findInstances():
                     setting_key = setting_instance.definition.key
                     settable_per_extruder = self._global_container_stack.getProperty(setting_key, "settable_per_extruder")
+
                     if settable_per_extruder:
                         limit_to_extruder = self._global_container_stack.getProperty(setting_key, "limit_to_extruder")
 
@@ -154,11 +155,16 @@ class MachineSettingsAction(MachineAction):
                             global_user_container.setProperty(setting_key, "value", extruder_user_container.getProperty(setting_key, "value"))
                             extruder_user_container.removeInstance(setting_key)
 
-        # Check to see if any features are set to print with an extruder that will no longer exist
-        for setting_key in ["adhesion_extruder_nr", "support_extruder_nr", "support_extruder_nr_layer_0", "support_infill_extruder_nr", "support_interface_extruder_nr"]:
-            if int(self._global_container_stack.getProperty(setting_key, "value")) > extruder_count - 1:
-                Logger.log("i", "Lowering %s setting to match number of extruders", setting_key)
-                self._global_container_stack.getTop().setProperty(setting_key, "value", extruder_count - 1)
+        # reset all extruder number settings whose value is no longer valid
+        for setting_instance in self._global_container_stack.userChanges.findInstances():
+            setting_key = setting_instance.definition.key
+            if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"):
+                continue
+
+            old_value = int(self._global_container_stack.userChanges.getProperty(setting_key, "value"))
+            if old_value >= extruder_count:
+                self._global_container_stack.userChanges.removeInstance(setting_key)
+                Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid ", setting_key, old_value)
 
         # Check to see if any objects are set to print with an extruder that will no longer exist
         root_node = Application.getInstance().getController().getScene().getRoot()

Some files were not shown because too many files changed in this diff