Browse Source

Merge pull request #1481 from Ultimaker/feature_override_profile

Feature override profile
jack 8 years ago
parent
commit
fee73c352c

+ 17 - 1
cura/CuraApplication.py

@@ -55,7 +55,7 @@ from . import MachineActionManager
 
 from cura.Settings.MachineManager import MachineManager
 from cura.Settings.ExtruderManager import ExtruderManager
-from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
+from cura.Settings.UserChangesModel import UserChangesModel
 from cura.Settings.ExtrudersModel import ExtrudersModel
 from cura.Settings.ContainerSettingsModel import ContainerSettingsModel
 from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
@@ -325,11 +325,26 @@ class CuraApplication(QtApplication):
     ## A reusable dialogbox
     #
     showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"])
+
     def messageBox(self, title, text, informativeText = "", detailedText = "", buttons = QMessageBox.Ok, icon = QMessageBox.NoIcon, callback = None, callback_arguments = []):
         self._message_box_callback = callback
         self._message_box_callback_arguments = callback_arguments
         self.showMessageBox.emit(title, text, informativeText, detailedText, buttons, icon)
 
+    showDiscardOrKeepProfileChanges = pyqtSignal()
+
+    def discardOrKeepProfileChanges(self):
+        self.showDiscardOrKeepProfileChanges.emit()
+
+    @pyqtSlot(str)
+    def discardOrKeepProfileChangesClosed(self, option):
+        if option == "discard":
+            global_stack = self.getGlobalContainerStack()
+            for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
+                extruder.getTop().clear()
+
+            global_stack.getTop().clear()
+
     @pyqtSlot(int)
     def messageBoxClosed(self, button):
         if self._message_box_callback:
@@ -655,6 +670,7 @@ class CuraApplication(QtApplication):
         qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
         qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
         qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
+        qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel")
 
         qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
 

+ 1 - 42
cura/Settings/MachineManager.py

@@ -939,48 +939,7 @@ class MachineManager(QObject):
         container.nameChanged.connect(self._onQualityNameChanged)
 
     def _askUserToKeepOrClearCurrentSettings(self):
-        # Ask the user if the user profile should be cleared or not (discarding the current settings)
-        # In Simple Mode we assume the user always wants to keep the (limited) current settings
-        details_text = catalog.i18nc("@label", "You made changes to the following setting(s)/override(s):")
-
-        # user changes in global stack
-        details_list = [setting.definition.label for setting in self._global_container_stack.getTop().findInstances(**{})]
-
-        # user changes in extruder stacks
-        stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
-        for stack in stacks:
-            details_list.extend([
-                "%s (%s)" % (setting.definition.label, stack.getName())
-                for setting in stack.getTop().findInstances(**{})])
-
-        # Format to output string
-        details = "\n    ".join([details_text, ] + details_list)
-
-        num_changed_settings = len(details_list)
-        Application.getInstance().messageBox(
-            catalog.i18nc("@window:title", "Switched profiles"),
-            catalog.i18nc(
-                "@label",
-                "Do you want to transfer your %d changed setting(s)/override(s) to this profile?") % num_changed_settings,
-            catalog.i18nc(
-                "@label",
-                "If you transfer your settings they will override settings in the profile. If you don't transfer these settings, they will be lost."),
-            details,
-            buttons=QMessageBox.Yes + QMessageBox.No,
-            icon=QMessageBox.Question,
-            callback=self._keepUserSettingsDialogCallback)
-
-    def _keepUserSettingsDialogCallback(self, button):
-        if button == QMessageBox.Yes:
-            # Yes, keep the settings in the user profile with this profile
-            pass
-        elif button == QMessageBox.No:
-            # No, discard the settings in the user profile
-            global_stack = Application.getInstance().getGlobalContainerStack()
-            for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
-                extruder.getTop().clear()
-
-            global_stack.getTop().clear()
+        Application.getInstance().discardOrKeepProfileChanges()
 
     @pyqtProperty(str, notify = activeVariantChanged)
     def activeVariantName(self):

+ 112 - 0
cura/Settings/UserChangesModel.py

@@ -0,0 +1,112 @@
+from UM.Qt.ListModel import ListModel
+
+from PyQt5.QtCore import pyqtSlot, Qt
+from UM.Application import Application
+from cura.Settings.ExtruderManager import ExtruderManager
+from UM.Settings.ContainerRegistry import ContainerRegistry
+from UM.i18n import i18nCatalog
+from UM.Settings.SettingFunction import SettingFunction
+
+import os
+
+class UserChangesModel(ListModel):
+    KeyRole = Qt.UserRole + 1
+    LabelRole = Qt.UserRole + 2
+    ExtruderRole = Qt.UserRole +3
+    OriginalValueRole = Qt.UserRole + 4
+    UserValueRole = Qt.UserRole + 6
+    CategoryRole = Qt.UserRole + 7
+
+    def __init__(self, parent = None):
+        super().__init__(parent = parent)
+        self.addRoleName(self.KeyRole, "key")
+        self.addRoleName(self.LabelRole, "label")
+        self.addRoleName(self.ExtruderRole, "extruder")
+        self.addRoleName(self.OriginalValueRole, "original_value")
+        self.addRoleName(self.UserValueRole, "user_value")
+        self.addRoleName(self.CategoryRole, "category")
+
+        self._i18n_catalog = None
+
+        self._update()
+
+    @pyqtSlot()
+    def forceUpdate(self):
+        self._update()
+
+    def _update(self):
+        items = []
+        global_stack = Application.getInstance().getGlobalContainerStack()
+        stacks = ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks()
+
+        # Check if the definition container has a translation file and ensure it's loaded.
+        definition = global_stack.getBottom()
+
+        definition_suffix = ContainerRegistry.getMimeTypeForContainer(type(definition)).preferredSuffix
+        catalog = i18nCatalog(os.path.basename(definition.getId() + "." + definition_suffix))
+
+        if catalog.hasTranslationLoaded():
+            self._i18n_catalog = catalog
+
+        for file_name in definition.getInheritedFiles():
+            catalog = i18nCatalog(os.path.basename(file_name))
+            if catalog.hasTranslationLoaded():
+                self._i18n_catalog = catalog
+
+        for stack in stacks:
+            # Make a list of all containers in the stack.
+            containers = []
+            latest_stack = stack
+            while latest_stack:
+                containers.extend(latest_stack.getContainers())
+                latest_stack = latest_stack.getNextStack()
+
+            # Drop the user container.
+            user_changes = containers.pop(0)
+
+            for setting_key in user_changes.getAllKeys():
+                original_value = None
+
+                # Find the category of the instance by moving up until we find a category.
+                category = user_changes.getInstance(setting_key).definition
+                while category.type != "category":
+                    category = category.parent
+
+                # Handle translation (and fallback if we weren't able to find any translation files.
+                if self._i18n_catalog:
+                    category_label = self._i18n_catalog.i18nc(category.key + " label", category.label)
+                else:
+                    category_label = category.label
+
+                if self._i18n_catalog:
+                    label = self._i18n_catalog.i18nc(setting_key + " label", stack.getProperty(setting_key, "label"))
+                else:
+                    label = stack.getProperty(setting_key, "label")
+
+                for container in containers:
+                    if stack == global_stack:
+                        resolve = global_stack.getProperty(setting_key, "resolve")
+                        if resolve is not None:
+                            original_value = resolve
+                            break
+
+                    original_value = container.getProperty(setting_key, "value")
+                    if original_value is not None:
+                        break
+
+                    # If a value is a function, ensure it's called with the stack it's in.
+                    if isinstance(original_value, SettingFunction):
+                        original_value = original_value(stack)
+
+                item_to_add = {"key": setting_key,
+                               "label": label,
+                               "user_value": str(user_changes.getProperty(setting_key, "value")),
+                               "original_value": str(original_value),
+                               "extruder": "",
+                               "category": category_label}
+
+                if stack != global_stack:
+                    item_to_add["extruder"] = stack.getName()
+
+                items.append(item_to_add)
+        self.setItems(items)

+ 15 - 0
resources/qml/Cura.qml

@@ -882,6 +882,21 @@ UM.MainWindow
         }
     }
 
+    DiscardOrKeepProfileChangesDialog
+    {
+        id: discardOrKeepProfileChangesDialog
+    }
+
+    Connections
+    {
+        target: Printer
+        onShowDiscardOrKeepProfileChanges:
+        {
+            discardOrKeepProfileChangesDialog.show()
+        }
+
+    }
+
     Connections
     {
         target: Cura.Actions.addMachine

+ 157 - 0
resources/qml/DiscardOrKeepProfileChangesDialog.qml

@@ -0,0 +1,157 @@
+// Copyright (c) 2017 Ultimaker B.V.
+// Cura is released under the terms of the AGPLv3 or higher.
+
+import QtQuick 2.1
+import QtQuick.Controls 1.1
+import QtQuick.Dialogs 1.2
+
+import UM 1.2 as UM
+import Cura 1.1 as Cura
+
+UM.Dialog
+{
+    id: base
+    title: catalog.i18nc("@title:window", "Discard or Keep changes")
+
+    width: 500
+    height: 300
+    property var changesModel: Cura.UserChangesModel{ id: userChangesModel}
+    onVisibilityChanged:
+    {
+        if(visible)
+        {
+            changesModel.forceUpdate()
+        }
+    }
+
+    Column
+    {
+        anchors.fill: parent
+        spacing: UM.Theme.getSize("default_margin").width
+
+        UM.I18nCatalog
+        {
+            id: catalog;
+            name:"cura"
+        }
+
+        Row
+        {
+            height: childrenRect.height
+            anchors.margins: UM.Theme.getSize("default_margin").width
+            anchors.left: parent.left
+            anchors.right: parent.right
+            spacing: UM.Theme.getSize("default_margin").width
+            UM.RecolorImage
+            {
+                source: UM.Theme.getIcon("star")
+                width : 30
+                height: width
+                color: UM.Theme.getColor("setting_control_button")
+            }
+
+            Label
+            {
+                text: "You have customized some profile settings.\nWould you like to keep or discard those settings?"
+                anchors.margins: UM.Theme.getSize("default_margin").width
+                font: UM.Theme.getFont("default_bold")
+                wrapMode: Text.WordWrap
+            }
+        }
+
+        TableView
+        {
+            anchors.margins: UM.Theme.getSize("default_margin").width
+            anchors.left: parent.left
+            anchors.right: parent.right
+            height: 200
+            id: tableView
+            Component
+            {
+                id: labelDelegate
+                Label
+                {
+                    property var extruder_name: userChangesModel.getItem(styleData.row).extruder
+                    anchors.left: parent.left
+                    anchors.leftMargin: UM.Theme.getSize("default_margin").width
+                    font: UM.Theme.getFont("default")
+                    text:
+                    {
+                        var result = styleData.value
+                        if (extruder_name!= "")
+                        {
+                            result += " (" + extruder_name + ")"
+                        }
+                        return result
+                    }
+                }
+            }
+
+            Component
+            {
+                id: defaultDelegate
+                Label
+                {
+                    text: styleData.value
+                    font: UM.Theme.getFont("default")
+                    color: UM.Theme.getColor("setting_control_disabled_text")
+                }
+            }
+
+            TableViewColumn
+            {
+                role: "label"
+                title: catalog.i18nc("@title:column", "Settings")
+                delegate: labelDelegate
+                width: tableView.width * 0.5
+            }
+
+            TableViewColumn
+            {
+                role: "original_value"
+                title: "Profile"
+                width: tableView.width * 0.25
+                delegate: defaultDelegate
+            }
+            TableViewColumn
+            {
+                role: "user_value"
+                title: catalog.i18nc("@title:column", "Customized")
+                width: tableView.width * 0.25 - 1
+            }
+            section.property: "category"
+            section.delegate: Label
+            {
+                text: section
+                font.bold: true
+            }
+
+            model: base.changesModel
+        }
+
+        Row
+        {
+            anchors.right: parent.right
+            anchors.rightMargin: UM.Theme.getSize("default_margin").width
+            spacing: UM.Theme.getSize("default_margin").width
+            Button
+            {
+                text: catalog.i18nc("@action:button", "Keep");
+                onClicked:
+                {
+                    Printer.discardOrKeepProfileChangesClosed("keep")
+                    base.hide()
+                }
+            }
+            Button
+            {
+                text: catalog.i18nc("@action:button", "Discard");
+                onClicked:
+                {
+                    Printer.discardOrKeepProfileChangesClosed("discard")
+                    base.hide()
+                }
+            }
+        }
+    }
+}