Merge branch 'master' into CURA-5536_installed_check

This commit is contained in:
Diego Prado Gesto 2018-07-13 14:43:29 +02:00
commit a8727d7b39
12 changed files with 241 additions and 192 deletions

View File

@ -5,6 +5,7 @@ import copy
import os import os
import sys import sys
import time import time
from typing import cast, TYPE_CHECKING, Optional
import numpy import numpy
@ -13,8 +14,6 @@ from PyQt5.QtGui import QColor, QIcon
from PyQt5.QtWidgets import QMessageBox from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
from typing import cast, TYPE_CHECKING
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from UM.Scene.Camera import Camera from UM.Scene.Camera import Camera
from UM.Math.Vector import Vector from UM.Math.Vector import Vector
@ -97,6 +96,8 @@ from . import CuraSplashScreen
from . import CameraImageProvider from . import CameraImageProvider
from . import MachineActionManager from . import MachineActionManager
from cura.TaskManagement.OnExitCallbackManager import OnExitCallbackManager
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.UserChangesModel import UserChangesModel from cura.Settings.UserChangesModel import UserChangesModel
@ -158,6 +159,8 @@ class CuraApplication(QtApplication):
self._boot_loading_time = time.time() self._boot_loading_time = time.time()
self._on_exit_callback_manager = OnExitCallbackManager(self)
# Variables set from CLI # Variables set from CLI
self._files_to_open = [] self._files_to_open = []
self._use_single_instance = False self._use_single_instance = False
@ -279,6 +282,8 @@ class CuraApplication(QtApplication):
self._machine_action_manager = MachineActionManager.MachineActionManager(self) self._machine_action_manager = MachineActionManager.MachineActionManager(self)
self._machine_action_manager.initialize() self._machine_action_manager.initialize()
self.change_log_url = "https://ultimaker.com/ultimaker-cura-latest-features"
def __sendCommandToSingleInstance(self): def __sendCommandToSingleInstance(self):
self._single_instance = SingleInstance(self, self._files_to_open) self._single_instance = SingleInstance(self, self._files_to_open)
@ -520,8 +525,8 @@ class CuraApplication(QtApplication):
def setNeedToShowUserAgreement(self, set_value = True): def setNeedToShowUserAgreement(self, set_value = True):
self._need_to_show_user_agreement = set_value self._need_to_show_user_agreement = set_value
## The "Quit" button click event handler. # DO NOT call this function to close the application, use checkAndExitApplication() instead which will perform
@pyqtSlot() # pre-exit checks such as checking for in-progress USB printing, etc.
def closeApplication(self): def closeApplication(self):
Logger.log("i", "Close application") Logger.log("i", "Close application")
main_window = self.getMainWindow() main_window = self.getMainWindow()
@ -530,6 +535,32 @@ class CuraApplication(QtApplication):
else: else:
self.exit(0) self.exit(0)
# This function first performs all upon-exit checks such as USB printing that is in progress.
# Use this to close the application.
@pyqtSlot()
def checkAndExitApplication(self) -> None:
self._on_exit_callback_manager.resetCurrentState()
self._on_exit_callback_manager.triggerNextCallback()
@pyqtSlot(result = bool)
def getIsAllChecksPassed(self) -> bool:
return self._on_exit_callback_manager.getIsAllChecksPassed()
def getOnExitCallbackManager(self) -> "OnExitCallbackManager":
return self._on_exit_callback_manager
def triggerNextExitCheck(self) -> None:
self._on_exit_callback_manager.triggerNextCallback()
showConfirmExitDialog = pyqtSignal(str, arguments = ["message"])
def setConfirmExitDialogCallback(self, callback):
self._confirm_exit_dialog_callback = callback
@pyqtSlot(bool)
def callConfirmExitDialogCallback(self, yes_or_no: bool):
self._confirm_exit_dialog_callback(yes_or_no)
## Signal to connect preferences action in QML ## Signal to connect preferences action in QML
showPreferencesWindow = pyqtSignal() showPreferencesWindow = pyqtSignal()
@ -1701,22 +1732,3 @@ class CuraApplication(QtApplication):
@pyqtSlot() @pyqtSlot()
def showMoreInformationDialogForAnonymousDataCollection(self): def showMoreInformationDialogForAnonymousDataCollection(self):
cast(SliceInfo, self._plugin_registry.getPluginObject("SliceInfoPlugin")).showMoreInfoDialog() cast(SliceInfo, self._plugin_registry.getPluginObject("SliceInfoPlugin")).showMoreInfoDialog()
## Signal to check whether the application can be closed or not
checkCuraCloseChange = pyqtSignal()
# This variable is necessary to ensure that all methods that were subscribed for the checkCuraCloseChange event
# have been passed checks
_isCuraCanBeClosed = True
def setCuraCanBeClosed(self, value: bool):
self._isCuraCanBeClosed = value
@pyqtSlot(result=bool)
def preCloseEventHandler(self)-> bool:
# If any of checks failed then then _isCuraCanBeClosed should be set to False and Cura will not be closed
# after clicking the quit button
self.checkCuraCloseChange.emit()
return self._isCuraCanBeClosed

View File

@ -46,19 +46,21 @@ class ContainerManager(QObject):
self._quality_manager = self._application.getQualityManager() self._quality_manager = self._application.getQualityManager()
self._container_name_filters = {} # type: Dict[str, Dict[str, Any]] self._container_name_filters = {} # type: Dict[str, Dict[str, Any]]
@pyqtSlot(str, str, str, result=str) @pyqtSlot(str, str, result=str)
def getContainerMetaDataEntry(self, container_id, entry_name, sub_entry: Optional[str] = None): def getContainerMetaDataEntry(self, container_id: str, entry_names: str) -> str:
metadatas = self._container_registry.findContainersMetadata(id = container_id) metadatas = self._container_registry.findContainersMetadata(id = container_id)
if not metadatas: if not metadatas:
Logger.log("w", "Could not get metadata of container %s because it was not found.", container_id) Logger.log("w", "Could not get metadata of container %s because it was not found.", container_id)
return "" return ""
sub_data = metadatas[0].get(entry_name, "") entries = entry_names.split("/")
result = str(sub_data) result = metadatas[0]
if sub_entry: while entries:
result = str(sub_data.get(sub_entry, "")) entry = entries.pop(0)
result = result.get(entry, {})
return result if not result:
return ""
return str(result)
## Set a metadata entry of the specified container. ## Set a metadata entry of the specified container.
# #
@ -73,6 +75,7 @@ class ContainerManager(QObject):
# #
# \return True if successful, False if not. # \return True if successful, False if not.
# TODO: This is ONLY used by MaterialView for material containers. Maybe refactor this. # TODO: This is ONLY used by MaterialView for material containers. Maybe refactor this.
# Update: In order for QML to use objects and sub objects, those (sub) objects must all be QObject. Is that what we want?
@pyqtSlot("QVariant", str, str) @pyqtSlot("QVariant", str, str)
def setContainerMetaDataEntry(self, container_node, entry_name, entry_value): def setContainerMetaDataEntry(self, container_node, entry_name, entry_value):
root_material_id = container_node.metadata["base_file"] root_material_id = container_node.metadata["base_file"]
@ -107,63 +110,6 @@ class ContainerManager(QObject):
if sub_item_changed: #If it was only a sub-item that has changed then the setMetaDataEntry won't correctly notice that something changed, and we must manually signal that the metadata changed. if sub_item_changed: #If it was only a sub-item that has changed then the setMetaDataEntry won't correctly notice that something changed, and we must manually signal that the metadata changed.
container.metaDataChanged.emit(container) container.metaDataChanged.emit(container)
## Set a setting property of the specified container.
#
# This will set the specified property of the specified setting of the container
# and all containers that share the same base_file (if any). The latter only
# happens for material containers.
#
# \param container_id \type{str} The ID of the container to change.
# \param setting_key \type{str} The key of the setting.
# \param property_name \type{str} The name of the property, eg "value".
# \param property_value \type{str} The new value of the property.
#
# \return True if successful, False if not.
@pyqtSlot(str, str, str, str, result = bool)
def setContainerProperty(self, container_id, setting_key, property_name, property_value):
if self._container_registry.isReadOnly(container_id):
Logger.log("w", "Cannot set properties of read-only container %s.", container_id)
return False
containers = self._container_registry.findContainers(id = container_id)
if not containers:
Logger.log("w", "Could not set properties of container %s because it was not found.", container_id)
return False
container = containers[0]
container.setProperty(setting_key, property_name, property_value)
basefile = container.getMetaDataEntry("base_file", container_id)
for sibbling_container in self._container_registry.findInstanceContainers(base_file = basefile):
if sibbling_container != container:
sibbling_container.setProperty(setting_key, property_name, property_value)
return True
## Get a setting property of the specified container.
#
# This will get the specified property of the specified setting of the
# specified container.
#
# \param container_id The ID of the container to get the setting property
# of.
# \param setting_key The key of the setting to get the property of.
# \param property_name The property to obtain.
# \return The value of the specified property. The type of this property
# value depends on the type of the property. For instance, the "value"
# property of an integer setting will be a Python int, but the "value"
# property of an enum setting will be a Python str.
@pyqtSlot(str, str, str, result = QVariant)
def getContainerProperty(self, container_id: str, setting_key: str, property_name: str):
containers = self._container_registry.findContainers(id = container_id)
if not containers:
Logger.log("w", "Could not get properties of container %s because it was not found.", container_id)
return ""
container = containers[0]
return container.getProperty(setting_key, property_name)
@pyqtSlot(str, result = str) @pyqtSlot(str, result = str)
def makeUniqueName(self, original_name): def makeUniqueName(self, original_name):
return self._container_registry.uniqueName(original_name) return self._container_registry.uniqueName(original_name)

View File

@ -0,0 +1,69 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import TYPE_CHECKING, Callable, List
from UM.Logger import Logger
if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication
#
# This class manages a all registered upon-exit checks that need to be perform when the application tries to exit.
# For example, to show a confirmation dialog when there is USB printing in progress, etc. All callbacks will be called
# in the order of when they got registered. If all callbacks "passes", that is, for example, if the user clicks "yes"
# on the exit confirmation dialog or nothing that's blocking the exit, then the application will quit after that.
#
class OnExitCallbackManager:
def __init__(self, application: "CuraApplication") -> None:
self._application = application
self._on_exit_callback_list = list() # type: List[Callable]
self._current_callback_idx = 0
self._is_all_checks_passed = False
def addCallback(self, callback: Callable) -> None:
self._on_exit_callback_list.append(callback)
Logger.log("d", "on-app-exit callback [%s] added.", callback)
# Reset the current state so the next time it will call all the callbacks again.
def resetCurrentState(self) -> None:
self._current_callback_idx = 0
self._is_all_checks_passed = False
def getIsAllChecksPassed(self) -> bool:
return self._is_all_checks_passed
# Trigger the next callback if available. If not, it means that all callbacks have "passed", which means we should
# not block the application to quit, and it will call the application to actually quit.
def triggerNextCallback(self) -> None:
# Get the next callback and schedule that if
this_callback = None
if self._current_callback_idx < len(self._on_exit_callback_list):
this_callback = self._on_exit_callback_list[self._current_callback_idx]
self._current_callback_idx += 1
if this_callback is not None:
Logger.log("d", "Scheduled the next on-app-exit callback [%s]", this_callback)
self._application.callLater(this_callback)
else:
Logger.log("d", "No more on-app-exit callbacks to process. Tell the app to exit.")
self._is_all_checks_passed = True
# Tell the application to exit
self._application.callLater(self._application.closeApplication)
# This is the callback function which an on-exit callback should call when it finishes, it should provide the
# "should_proceed" flag indicating whether this check has "passed", or in other words, whether quiting the
# application should be blocked. If the last on-exit callback doesn't block the quiting, it will call the next
# registered on-exit callback if available.
def onCurrentCallbackFinished(self, should_proceed: bool = True) -> None:
if not should_proceed:
Logger.log("d", "on-app-exit callback finished and we should not proceed.")
# Reset the state
self.resetCurrentState()
return
self.triggerNextCallback()

View File

View File

@ -457,7 +457,8 @@ class CuraEngineBackend(QObject, Backend):
# Only count sliceable objects # Only count sliceable objects
if node.callDecoration("isSliceable"): if node.callDecoration("isSliceable"):
build_plate_number = node.callDecoration("getBuildPlateNumber") build_plate_number = node.callDecoration("getBuildPlateNumber")
num_objects[build_plate_number] += 1 if build_plate_number is not None:
num_objects[build_plate_number] += 1
return num_objects return num_objects
## Listener for when the scene has changed. ## Listener for when the scene has changed.
@ -490,7 +491,9 @@ class CuraEngineBackend(QObject, Backend):
if mesh_data and mesh_data.getVertices() is None: if mesh_data and mesh_data.getVertices() is None:
return return
build_plate_changed.add(source_build_plate_number) # There are some SceneNodes that do not have any build plate associated, then do not add to the list.
if source_build_plate_number is not None:
build_plate_changed.add(source_build_plate_number)
if not build_plate_changed: if not build_plate_changed:
return return

View File

@ -88,6 +88,25 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._command_received = Event() self._command_received = Event()
self._command_received.set() self._command_received.set()
CuraApplication.getInstance().getOnExitCallbackManager().addCallback(self._checkActivePrintingUponAppExit)
# This is a callback function that checks if there is any printing in progress via USB when the application tries
# to exit. If so, it will show a confirmation before
def _checkActivePrintingUponAppExit(self) -> None:
application = CuraApplication.getInstance()
if not self._is_printing:
# This USB printer is not printing, so we have nothing to do. Call the next callback if exists.
application.triggerNextExitCheck()
return
application.setConfirmExitDialogCallback(self._onConfirmExitDialogResult)
application.showConfirmExitDialog.emit(catalog.i18nc("@label", "A USB print is in progress, closing Cura will stop this print. Are you sure?"))
def _onConfirmExitDialogResult(self, result: bool) -> None:
if result:
application = CuraApplication.getInstance()
application.triggerNextExitCheck()
## Reset USB device settings ## Reset USB device settings
# #
def resetDeviceSettings(self): def resetDeviceSettings(self):
@ -435,9 +454,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._gcode_position += 1 self._gcode_position += 1
def getIsPrinting(self)-> bool:
return self._is_printing
class FirmwareUpdateState(IntEnum): class FirmwareUpdateState(IntEnum):
idle = 0 idle = 0

View File

@ -6,8 +6,7 @@ import platform
import time import time
import serial.tools.list_ports import serial.tools.list_ports
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, QCoreApplication from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
from PyQt5.QtWidgets import QMessageBox
from UM.Logger import Logger from UM.Logger import Logger
from UM.Resources import Resources from UM.Resources import Resources
@ -51,11 +50,6 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin):
self._application.globalContainerStackChanged.connect(self.updateUSBPrinterOutputDevices) self._application.globalContainerStackChanged.connect(self.updateUSBPrinterOutputDevices)
self._application.checkCuraCloseChange.connect(self.checkWheterUSBIsActiveOrNot)
self._lock = threading.Lock()
self._confirm_dialog_visible = False
# The method updates/reset the USB settings for all connected USB devices # The method updates/reset the USB settings for all connected USB devices
def updateUSBPrinterOutputDevices(self): def updateUSBPrinterOutputDevices(self):
for key, device in self._usb_output_devices.items(): for key, device in self._usb_output_devices.items():
@ -190,51 +184,3 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin):
@classmethod @classmethod
def getInstance(cls, *args, **kwargs) -> "USBPrinterOutputDeviceManager": def getInstance(cls, *args, **kwargs) -> "USBPrinterOutputDeviceManager":
return cls.__instance return cls.__instance
# The method checks whether a printer is printing via USB or not before closing cura. If the printer is printing then pop up a
# dialog to confirm stop printing
def checkWheterUSBIsActiveOrNot(self)-> None:
is_printing = False
for key, device in self._usb_output_devices.items():
if type(device) is USBPrinterOutputDevice.USBPrinterOutputDevice:
if device.getIsPrinting():
is_printing = True
break
if is_printing:
if threading.current_thread() != threading.main_thread():
self._lock.acquire()
self._confirm_dialog_visible = True
CuraApplication.getInstance().messageBox(i18n_catalog.i18nc("@window:title", "Confirm stop printing"),
i18n_catalog.i18nc("@window:message","A USB print is in progress, closing Cura will stop this print. Are you sure?"),
buttons=QMessageBox.Yes + QMessageBox.No,
icon=QMessageBox.Question,
callback=self._messageBoxCallback)
# Wait for dialog result
self.waitForClose()
## Block thread until the dialog is closed.
def waitForClose(self)-> None:
if self._confirm_dialog_visible:
if threading.current_thread() != threading.main_thread():
self._lock.acquire()
self._lock.release()
else:
# If this is not run from a separate thread, we need to ensure that the events are still processed.
while self._confirm_dialog_visible:
time.sleep(1 / 50)
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
def _messageBoxCallback(self, button):
if button == QMessageBox.Yes:
self._application.setCuraCanBeClosed(True)
else:
self._application.setCuraCanBeClosed(False)
self._confirm_dialog_visible = False
try:
self._lock.release()
except:
pass

View File

@ -40,6 +40,14 @@
[18, -18] [18, -18]
] ]
}, },
"machine_head_with_fans_polygon": {
"default_value": [
[-75, -18],
[-75, 35],
[18, 35],
[18, -18]
]
},
"gantry_height": { "gantry_height": {
"default_value": 55 "default_value": 55
}, },

View File

@ -1,11 +1,11 @@
// Copyright (c) 2017 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.7
import QtQuick.Controls 1.1 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.2
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
@ -22,12 +22,6 @@ UM.MainWindow
backgroundColor: UM.Theme.getColor("viewport_background") backgroundColor: UM.Theme.getColor("viewport_background")
// Event which does the check before closing the window
onPreCloseChange:
{
event.accepted = CuraApplication.preCloseEventHandler()
}
// This connection is here to support legacy printer output devices that use the showPrintMonitor signal on Application to switch to the monitor stage // This connection is here to support legacy printer output devices that use the showPrintMonitor signal on Application to switch to the monitor stage
// It should be phased out in newer plugin versions. // It should be phased out in newer plugin versions.
Connections Connections
@ -120,31 +114,10 @@ UM.MainWindow
RecentFilesMenu { } RecentFilesMenu { }
MenuSeparator { }
MenuItem
{
text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File");
enabled: UM.Selection.hasSelection;
iconName: "document-save-as";
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetype": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"});
}
MenuItem
{
id: saveAsMenu
text: catalog.i18nc("@title:menu menubar:file", "Save &As...")
onTriggered:
{
var localDeviceId = "local_file";
UM.OutputDeviceManager.requestWriteToDevice(localDeviceId, PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetype": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"});
}
}
MenuItem MenuItem
{ {
id: saveWorkspaceMenu id: saveWorkspaceMenu
text: catalog.i18nc("@title:menu menubar:file","Save &Project...") text: catalog.i18nc("@title:menu menubar:file","&Save...")
onTriggered: onTriggered:
{ {
var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetype": "application/x-curaproject+xml" }; var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetype": "application/x-curaproject+xml" };
@ -160,6 +133,29 @@ UM.MainWindow
} }
} }
MenuSeparator { }
MenuItem
{
id: saveAsMenu
text: catalog.i18nc("@title:menu menubar:file", "&Export...")
onTriggered:
{
var localDeviceId = "local_file";
UM.OutputDeviceManager.requestWriteToDevice(localDeviceId, PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetype": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"});
}
}
MenuItem
{
text: catalog.i18nc("@action:inmenu menubar:file", "Export Selection...");
enabled: UM.Selection.hasSelection;
iconName: "document-save-as";
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetype": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"});
}
MenuSeparator { }
MenuItem { action: Cura.Actions.reloadAll; } MenuItem { action: Cura.Actions.reloadAll; }
MenuSeparator { } MenuSeparator { }
@ -704,10 +700,50 @@ UM.MainWindow
id: contextMenu id: contextMenu
} }
onPreClosing:
{
close.accepted = CuraApplication.getIsAllChecksPassed();
if (!close.accepted)
{
CuraApplication.checkAndExitApplication();
}
}
MessageDialog
{
id: exitConfirmationDialog
title: catalog.i18nc("@title:window", "Closing Cura")
text: catalog.i18nc("@label", "Are you sure you want to exit Cura?")
icon: StandardIcon.Question
modality: Qt.ApplicationModal
standardButtons: StandardButton.Yes | StandardButton.No
onYes: CuraApplication.callConfirmExitDialogCallback(true)
onNo: CuraApplication.callConfirmExitDialogCallback(false)
onRejected: CuraApplication.callConfirmExitDialogCallback(false)
onVisibilityChanged:
{
if (!visible)
{
// reset the text to default because other modules may change the message text.
text = catalog.i18nc("@label", "Are you sure you want to exit Cura?");
}
}
}
Connections
{
target: CuraApplication
onShowConfirmExitDialog:
{
exitConfirmationDialog.text = message;
exitConfirmationDialog.open();
}
}
Connections Connections
{ {
target: Cura.Actions.quit target: Cura.Actions.quit
onTriggered: CuraApplication.closeApplication(); onTriggered: CuraApplication.exitApplication();
} }
Connections Connections

View File

@ -81,7 +81,7 @@ Item {
text: PrintInformation.jobName text: PrintInformation.jobName
horizontalAlignment: TextInput.AlignRight horizontalAlignment: TextInput.AlignRight
onEditingFinished: { onEditingFinished: {
var new_name = text == "" ? "unnamed" : text; var new_name = text == "" ? catalog.i18nc("@text Print job name", "unnamed") : text;
PrintInformation.setJobName(new_name, true); PrintInformation.setJobName(new_name, true);
printJobTextfield.focus = false; printJobTextfield.focus = false;
} }

View File

@ -103,7 +103,6 @@ TabView
onYes: onYes:
{ {
Cura.ContainerManager.setContainerProperty(base.containerId, "material_diameter", "value", new_diameter_value);
base.setMetaDataEntry("approximate_diameter", old_approximate_diameter_value, getApproximateDiameter(new_diameter_value).toString()); base.setMetaDataEntry("approximate_diameter", old_approximate_diameter_value, getApproximateDiameter(new_diameter_value).toString());
base.setMetaDataEntry("properties/diameter", properties.diameter, new_diameter_value); base.setMetaDataEntry("properties/diameter", properties.diameter, new_diameter_value);
} }
@ -230,7 +229,7 @@ TabView
{ {
// This does not use a SettingPropertyProvider, because we need to make the change to all containers // This does not use a SettingPropertyProvider, because we need to make the change to all containers
// which derive from the same base_file // which derive from the same base_file
var old_diameter = Cura.ContainerManager.getContainerProperty(base.containerId, "material_diameter", "value").toString(); var old_diameter = Cura.ContainerManager.getContainerMetaDataEntry(base.containerId, "properties/diameter");
var old_approximate_diameter = Cura.ContainerManager.getContainerMetaDataEntry(base.containerId, "approximate_diameter"); var old_approximate_diameter = Cura.ContainerManager.getContainerMetaDataEntry(base.containerId, "approximate_diameter");
var new_approximate_diameter = getApproximateDiameter(value); var new_approximate_diameter = getApproximateDiameter(value);
if (new_approximate_diameter != Cura.ExtruderManager.getActiveExtruderStack().approximateMaterialDiameter) if (new_approximate_diameter != Cura.ExtruderManager.getActiveExtruderStack().approximateMaterialDiameter)
@ -242,7 +241,6 @@ TabView
confirmDiameterChangeDialog.open() confirmDiameterChangeDialog.open()
} }
else { else {
Cura.ContainerManager.setContainerProperty(base.containerId, "material_diameter", "value", value);
base.setMetaDataEntry("approximate_diameter", old_approximate_diameter, getApproximateDiameter(value).toString()); base.setMetaDataEntry("approximate_diameter", old_approximate_diameter, getApproximateDiameter(value).toString());
base.setMetaDataEntry("properties/diameter", properties.diameter, value); base.setMetaDataEntry("properties/diameter", properties.diameter, value);
} }
@ -271,7 +269,7 @@ TabView
{ {
id: spoolWeightSpinBox id: spoolWeightSpinBox
width: scrollView.columnWidth width: scrollView.columnWidth
value: base.getMaterialPreferenceValue(properties.guid, "spool_weight") value: base.getMaterialPreferenceValue(properties.guid, "spool_weight", Cura.ContainerManager.getContainerMetaDataEntry(properties.container_id, "properties/weight"))
suffix: " g" suffix: " g"
stepSize: 100 stepSize: 100
decimals: 0 decimals: 0
@ -468,7 +466,7 @@ TabView
} }
if(!spoolWeight) if(!spoolWeight)
{ {
spoolWeight = base.getMaterialPreferenceValue(properties.guid, "spool_weight"); spoolWeight = base.getMaterialPreferenceValue(properties.guid, "spool_weight", Cura.ContainerManager.getContainerMetaDataEntry(properties.container_id, "properties/weight"));
} }
if (diameter == 0 || density == 0 || spoolWeight == 0) if (diameter == 0 || density == 0 || spoolWeight == 0)
@ -517,21 +515,34 @@ TabView
// value has not changed // value has not changed
return; return;
} }
materialPreferenceValues[material_guid][entry_name] = new_value; if (entry_name in materialPreferenceValues[material_guid] && new_value.toString() == 0)
{
// no need to store a 0, that's the default, so remove it
materialPreferenceValues[material_guid].delete(entry_name);
if (!(materialPreferenceValues[material_guid]))
{
// remove empty map
materialPreferenceValues.delete(material_guid);
}
}
if (new_value.toString() != 0)
{
// store new value
materialPreferenceValues[material_guid][entry_name] = new_value;
}
// store preference // store preference
UM.Preferences.setValue("cura/material_settings", JSON.stringify(materialPreferenceValues)); UM.Preferences.setValue("cura/material_settings", JSON.stringify(materialPreferenceValues));
} }
function getMaterialPreferenceValue(material_guid, entry_name) function getMaterialPreferenceValue(material_guid, entry_name, default_value)
{ {
if(material_guid in materialPreferenceValues && entry_name in materialPreferenceValues[material_guid]) if(material_guid in materialPreferenceValues && entry_name in materialPreferenceValues[material_guid])
{ {
return materialPreferenceValues[material_guid][entry_name]; return materialPreferenceValues[material_guid][entry_name];
} }
default_value = default_value | 0;
var material_weight = Cura.ContainerManager.getContainerMetaDataEntry(base.containerId, "properties", "weight"); return default_value;
return material_weight || 0;
} }
// update the display name of the material // update the display name of the material

View File

@ -486,6 +486,7 @@ Item
materialProperties.name = currentItem.name ? currentItem.name : "Unknown"; materialProperties.name = currentItem.name ? currentItem.name : "Unknown";
materialProperties.guid = currentItem.guid; materialProperties.guid = currentItem.guid;
materialProperties.container_id = currentItem.container_id;
materialProperties.brand = currentItem.brand ? currentItem.brand : "Unknown"; materialProperties.brand = currentItem.brand ? currentItem.brand : "Unknown";
materialProperties.material = currentItem.material ? currentItem.material : "Unknown"; materialProperties.material = currentItem.material ? currentItem.material : "Unknown";
@ -543,6 +544,7 @@ Item
id: materialProperties id: materialProperties
property string guid: "00000000-0000-0000-0000-000000000000" property string guid: "00000000-0000-0000-0000-000000000000"
property string container_id: "Unknown";
property string name: "Unknown"; property string name: "Unknown";
property string profile_type: "Unknown"; property string profile_type: "Unknown";
property string brand: "Unknown"; property string brand: "Unknown";