mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-12 20:29:05 +08:00
Merge pull request #1481 from Ultimaker/feature_override_profile
Feature override profile
This commit is contained in:
commit
fee73c352c
@ -55,7 +55,7 @@ from . import MachineActionManager
|
|||||||
|
|
||||||
from cura.Settings.MachineManager import MachineManager
|
from cura.Settings.MachineManager import MachineManager
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
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.ExtrudersModel import ExtrudersModel
|
||||||
from cura.Settings.ContainerSettingsModel import ContainerSettingsModel
|
from cura.Settings.ContainerSettingsModel import ContainerSettingsModel
|
||||||
from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
|
from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
|
||||||
@ -325,11 +325,26 @@ class CuraApplication(QtApplication):
|
|||||||
## A reusable dialogbox
|
## A reusable dialogbox
|
||||||
#
|
#
|
||||||
showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"])
|
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 = []):
|
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 = callback
|
||||||
self._message_box_callback_arguments = callback_arguments
|
self._message_box_callback_arguments = callback_arguments
|
||||||
self.showMessageBox.emit(title, text, informativeText, detailedText, buttons, icon)
|
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)
|
@pyqtSlot(int)
|
||||||
def messageBoxClosed(self, button):
|
def messageBoxClosed(self, button):
|
||||||
if self._message_box_callback:
|
if self._message_box_callback:
|
||||||
@ -655,6 +670,7 @@ class CuraApplication(QtApplication):
|
|||||||
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
|
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
|
||||||
qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
|
qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
|
||||||
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
|
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
|
||||||
|
qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel")
|
||||||
|
|
||||||
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
|
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
|
||||||
|
|
||||||
|
@ -939,48 +939,7 @@ class MachineManager(QObject):
|
|||||||
container.nameChanged.connect(self._onQualityNameChanged)
|
container.nameChanged.connect(self._onQualityNameChanged)
|
||||||
|
|
||||||
def _askUserToKeepOrClearCurrentSettings(self):
|
def _askUserToKeepOrClearCurrentSettings(self):
|
||||||
# Ask the user if the user profile should be cleared or not (discarding the current settings)
|
Application.getInstance().discardOrKeepProfileChanges()
|
||||||
# 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()
|
|
||||||
|
|
||||||
@pyqtProperty(str, notify = activeVariantChanged)
|
@pyqtProperty(str, notify = activeVariantChanged)
|
||||||
def activeVariantName(self):
|
def activeVariantName(self):
|
||||||
|
112
cura/Settings/UserChangesModel.py
Normal file
112
cura/Settings/UserChangesModel.py
Normal file
@ -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)
|
@ -882,6 +882,21 @@ UM.MainWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiscardOrKeepProfileChangesDialog
|
||||||
|
{
|
||||||
|
id: discardOrKeepProfileChangesDialog
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: Printer
|
||||||
|
onShowDiscardOrKeepProfileChanges:
|
||||||
|
{
|
||||||
|
discardOrKeepProfileChangesDialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Connections
|
Connections
|
||||||
{
|
{
|
||||||
target: Cura.Actions.addMachine
|
target: Cura.Actions.addMachine
|
||||||
|
157
resources/qml/DiscardOrKeepProfileChangesDialog.qml
Normal file
157
resources/qml/DiscardOrKeepProfileChangesDialog.qml
Normal file
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user