This commit is contained in:
fieldOfView 2016-07-07 18:11:29 +02:00
commit 8d56d25a8e
36 changed files with 1902 additions and 749 deletions

View file

@ -32,8 +32,6 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from . import ExtruderManager
from . import ExtrudersModel
from . import PlatformPhysics from . import PlatformPhysics
from . import BuildVolume from . import BuildVolume
from . import CameraAnimation from . import CameraAnimation
@ -42,11 +40,11 @@ from . import CuraActions
from . import MultiMaterialDecorator from . import MultiMaterialDecorator
from . import ZOffsetDecorator from . import ZOffsetDecorator
from . import CuraSplashScreen from . import CuraSplashScreen
from . import MachineManagerModel
from . import ContainerSettingsModel
from . import CameraImageProvider from . import CameraImageProvider
from . import MachineActionManager from . import MachineActionManager
import cura.Settings
from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
from PyQt5.QtGui import QColor, QIcon from PyQt5.QtGui import QColor, QIcon
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
@ -273,7 +271,8 @@ class CuraApplication(QtApplication):
Logger.logException("e", "An exception occurred when serializing container %s", instance.getId()) Logger.logException("e", "An exception occurred when serializing container %s", instance.getId())
continue continue
file_name = urllib.parse.quote_plus(instance.getId()) + ".inst.cfg" mime_type = ContainerRegistry.getMimeTypeForContainer(type(instance))
file_name = urllib.parse.quote_plus(instance.getId()) + "." + mime_type.preferredSuffix
instance_type = instance.getMetaDataEntry("type") instance_type = instance.getMetaDataEntry("type")
path = None path = None
if instance_type == "material": if instance_type == "material":
@ -301,7 +300,8 @@ class CuraApplication(QtApplication):
Logger.logException("e", "An exception occurred when serializing container %s", instance.getId()) Logger.logException("e", "An exception occurred when serializing container %s", instance.getId())
continue continue
file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg" mime_type = ContainerRegistry.getMimeTypeForContainer(type(stack))
file_name = urllib.parse.quote_plus(stack.getId()) + "." + mime_type.preferredSuffix
stack_type = stack.getMetaDataEntry("type", None) stack_type = stack.getMetaDataEntry("type", None)
path = None path = None
if not stack_type or stack_type == "machine": if not stack_type or stack_type == "machine":
@ -378,9 +378,9 @@ class CuraApplication(QtApplication):
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface..."))
# Initialise extruder so as to listen to global container stack changes before the first global container stack is set. # Initialise extruder so as to listen to global container stack changes before the first global container stack is set.
ExtruderManager.ExtruderManager.getInstance() cura.Settings.ExtruderManager.getInstance()
qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", qmlRegisterSingletonType(cura.Settings.MachineManager, "Cura", 1, 0, "MachineManager",
MachineManagerModel.createMachineManagerModel) cura.Settings.MachineManager.createMachineManager)
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
@ -424,6 +424,7 @@ class CuraApplication(QtApplication):
# \param engine The QML engine. # \param engine The QML engine.
def registerObjects(self, engine): def registerObjects(self, engine):
engine.rootContext().setContextProperty("Printer", self) engine.rootContext().setContextProperty("Printer", self)
engine.rootContext().setContextProperty("CuraApplication", self)
self._print_information = PrintInformation.PrintInformation() self._print_information = PrintInformation.PrintInformation()
engine.rootContext().setContextProperty("PrintInformation", self._print_information) engine.rootContext().setContextProperty("PrintInformation", self._print_information)
self._cura_actions = CuraActions.CuraActions(self) self._cura_actions = CuraActions.CuraActions(self)
@ -431,13 +432,16 @@ class CuraApplication(QtApplication):
qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type")
qmlRegisterType(ExtrudersModel.ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") qmlRegisterType(cura.Settings.ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
qmlRegisterType(ContainerSettingsModel.ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel") qmlRegisterType(cura.Settings.ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel")
qmlRegisterType(cura.Settings.MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
qmlRegisterSingletonType(cura.Settings.ContainerManager, "Cura", 1, 0, "ContainerManager", cura.Settings.ContainerManager.createContainerManager)
qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions") qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions")
engine.rootContext().setContextProperty("ExtruderManager", ExtruderManager.ExtruderManager.getInstance()) engine.rootContext().setContextProperty("ExtruderManager", cura.Settings.ExtruderManager.getInstance())
for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles): for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles):
type_name = os.path.splitext(os.path.basename(path))[0] type_name = os.path.splitext(os.path.basename(path))[0]

View file

@ -0,0 +1,383 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import os.path
import urllib
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal, QUrl
from PyQt5.QtWidgets import QMessageBox
import UM.PluginRegistry
import UM.Settings
import UM.SaveFile
import UM.Platform
import UM.MimeTypeDatabase
import UM.Logger
from UM.MimeTypeDatabase import MimeTypeNotFoundError
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
## Manager class that contains common actions to deal with containers in Cura.
#
# This is primarily intended as a class to be able to perform certain actions
# from within QML. We want to be able to trigger things like removing a container
# when a certain action happens. This can be done through this class.
class ContainerManager(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self._registry = UM.Settings.ContainerRegistry.getInstance()
self._container_name_filters = {}
## Create a duplicate of the specified container
#
# This will create and add a duplicate of the container corresponding
# to the container ID.
#
# \param container_id \type{str} The ID of the container to duplicate.
#
# \return The ID of the new container, or an empty string if duplication failed.
@pyqtSlot(str, result = str)
def duplicateContainer(self, container_id):
containers = self._registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could duplicate container %s because it was not found.", container_id)
return ""
container = containers[0]
new_container = None
new_name = self._registry.uniqueName(container.getName())
# Only InstanceContainer has a duplicate method at the moment.
# So fall back to serialize/deserialize when no duplicate method exists.
if hasattr(container, "duplicate"):
new_container = container.duplicate(new_name)
else:
new_container = container.__class__(new_name)
new_container.deserialize(container.serialize())
new_container.setName(new_name)
if new_container:
self._registry.addContainer(new_container)
return new_container.getId()
## Change the name of a specified container to a new name.
#
# \param container_id \type{str} The ID of the container to change the name of.
# \param new_id \type{str} The new ID of the container.
# \param new_name \type{str} The new name of the specified container.
#
# \return True if successful, False if not.
@pyqtSlot(str, str, str, result = bool)
def renameContainer(self, container_id, new_id, new_name):
containers = self._registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could rename container %s because it was not found.", container_id)
return False
container = containers[0]
# First, remove the container from the registry. This will clean up any files related to the container.
self._registry.removeContainer(container)
# Ensure we have a unique name for the container
new_name = self._registry.uniqueName(new_name)
# Then, update the name and ID of the container
container.setName(new_name)
container._id = new_id # TODO: Find a nicer way to set a new, unique ID
# Finally, re-add the container so it will be properly serialized again.
self._registry.addContainer(container)
return True
## Remove the specified container.
#
# \param container_id \type{str} The ID of the container to remove.
#
# \return True if the container was successfully removed, False if not.
@pyqtSlot(str, result = bool)
def removeContainer(self, container_id):
containers = self._registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could remove container %s because it was not found.", container_id)
return False
self._registry.removeContainer(containers[0].getId())
return True
## Merge a container with another.
#
# This will try to merge one container into the other, by going through the container
# and setting the right properties on the other container.
#
# \param merge_into_id \type{str} The ID of the container to merge into.
# \param merge_id \type{str} The ID of the container to merge.
#
# \return True if successfully merged, False if not.
@pyqtSlot(str, result = bool)
def mergeContainers(self, merge_into_id, merge_id):
containers = self._registry.findContainers(None, id = merge_into_id)
if not containers:
UM.Logger.log("w", "Could merge into container %s because it was not found.", merge_into_id)
return False
merge_into = containers[0]
containers = self._registry.findContainers(None, id = merge_id)
if not containers:
UM.Logger.log("w", "Could not merge container %s because it was not found", merge_id)
return False
merge = containers[0]
if type(merge) != type(merge_into):
UM.Logger.log("w", "Cannot merge two containers of different types")
return False
for key in merge.getAllKeys():
merge_into.setProperty(key, "value", merge.getProperty(key, "value"))
return True
## Clear the contents of a container.
#
# \param container_id \type{str} The ID of the container to clear.
#
# \return True if successful, False if not.
@pyqtSlot(str, result = bool)
def clearContainer(self, container_id):
containers = self._registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could clear container %s because it was not found.", container_id)
return False
if containers[0].isReadOnly():
UM.Logger.log("w", "Cannot clear read-only container %s", container_id)
return False
containers[0].clear()
return True
## Set a metadata entry of the specified container.
#
# This will set the specified entry of the container's metadata to the specified
# value. Note that entries containing dictionaries can have their entries changed
# by using "/" as a separator. For example, to change an entry "foo" in a
# dictionary entry "bar", you can specify "bar/foo" as entry name.
#
# \param container_id \type{str} The ID of the container to change.
# \param entry_name \type{str} The name of the metadata entry to change.
# \param entry_value The new value of the entry.
#
# \return True if successful, False if not.
@pyqtSlot(str, str, str, result = bool)
def setContainerMetaDataEntry(self, container_id, entry_name, entry_value):
containers = UM.Settings.ContainerRegistry.getInstance().findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could set metadata of container %s because it was not found.", container_id)
return False
container = containers[0]
if container.isReadOnly():
UM.Logger.log("w", "Cannot set metadata of read-only container %s.", container_id)
return False
entries = entry_name.split("/")
entry_name = entries.pop()
if entries:
root_name = entries.pop(0)
root = container.getMetaDataEntry(root_name)
item = root
for entry in entries:
item = item.get(entries.pop(0), { })
item[entry_name] = entry_value
entry_name = root_name
entry_value = root
container.setMetaDataEntry(entry_name, entry_value)
return True
## Find instance containers matching certain criteria.
#
# This effectively forwards to ContainerRegistry::findInstanceContainers.
#
# \param criteria A dict of key - value pairs to search for.
#
# \return A list of container IDs that match the given criteria.
@pyqtSlot("QVariantMap", result = "QVariantList")
def findInstanceContainers(self, criteria):
result = []
for entry in self._registry.findInstanceContainers(**criteria):
result.append(entry.getId())
return result
## Get a list of string that can be used as name filters for a Qt File Dialog
#
# This will go through the list of available container types and generate a list of strings
# out of that. The strings are formatted as "description (*.extension)" and can be directly
# passed to a nameFilters property of a Qt File Dialog.
#
# \param type_name Which types of containers to list. These types correspond to the "type"
# key of the plugin metadata.
#
# \return A string list with name filters.
@pyqtSlot(str, result = "QStringList")
def getContainerNameFilters(self, type_name):
if not self._container_name_filters:
self._updateContainerNameFilters()
filters = []
for filter_string, entry in self._container_name_filters.items():
if not type_name or entry["type"] == type_name:
filters.append(filter_string)
return filters
## Export a container to a file
#
# \param container_id The ID of the container to export
# \param file_type The type of file to save as. Should be in the form of "description (*.extension, *.ext)"
# \param file_url The URL where to save the file.
#
# \return A dictionary containing a key "status" with a status code and a key "message" with a message
# explaining the status.
# The status code can be one of "error", "cancelled", "success"
@pyqtSlot(str, str, QUrl, result = "QVariantMap")
def exportContainer(self, container_id, file_type, file_url):
if not container_id or not file_type or not file_url:
return { "status": "error", "message": "Invalid arguments"}
if isinstance(file_url, QUrl):
file_url = file_url.toLocalFile()
if not file_url:
return { "status": "error", "message": "Invalid path"}
mime_type = None
if not file_type in self._container_name_filters:
try:
mime_type = UM.MimeTypeDatabase.getMimeTypeForFile(file_url)
except MimeTypeNotFoundError:
return { "status": "error", "message": "Unknown File Type" }
else:
mime_type = self._container_name_filters[file_type]["mime"]
containers = UM.Settings.ContainerRegistry.getInstance().findContainers(None, id = container_id)
if not containers:
return { "status": "error", "message": "Container not found"}
container = containers[0]
for suffix in mime_type.suffixes:
if file_url.endswith(suffix):
break
else:
file_url += "." + mime_type.preferredSuffix
if not UM.Platform.isWindows():
if os.path.exists(file_url):
result = QMessageBox.question(None, catalog.i18nc("@title:window", "File Already Exists"),
catalog.i18nc("@label", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_url))
if result == QMessageBox.No:
return { "status": "cancelled", "message": "User cancelled"}
try:
contents = container.serialize()
except NotImplementedError:
return { "status": "error", "message": "Unable to serialize container"}
with UM.SaveFile(file_url, "w") as f:
f.write(contents)
return { "status": "success", "message": "Succesfully exported container"}
## Imports a profile from a file
#
# \param file_url A URL that points to the file to import.
#
# \return \type{Dict} dict with a 'status' key containing the string 'success' or 'error', and a 'message' key
# containing a message for the user
@pyqtSlot(QUrl, result = "QVariantMap")
def importContainer(self, file_url):
if not file_url:
return { "status": "error", "message": "Invalid path"}
if isinstance(file_url, QUrl):
file_url = file_url.toLocalFile()
if not file_url or not os.path.exists(file_url):
return { "status": "error", "message": "Invalid path" }
try:
mime_type = UM.MimeTypeDatabase.getMimeTypeForFile(file_url)
except MimeTypeNotFoundError:
return { "status": "error", "message": "Could not determine mime type of file" }
container_type = UM.Settings.ContainerRegistry.getContainerForMimeType(mime_type)
if not container_type:
return { "status": "error", "message": "Could not find a container to handle the specified file."}
container_id = urllib.parse.unquote_plus(mime_type.stripExtension(os.path.basename(file_url)))
container_id = UM.Settings.ContainerRegistry.getInstance().uniqueName(container_id)
container = container_type(container_id)
try:
with open(file_url, "rt") as f:
container.deserialize(f.read())
except PermissionError:
return { "status": "error", "message": "Permission denied when trying to read the file"}
container.setName(container_id)
UM.Settings.ContainerRegistry.getInstance().addContainer(container)
return { "status": "success", "message": "Successfully imported container {0}".format(container.getName()) }
def _updateContainerNameFilters(self):
self._container_name_filters = {}
for plugin_id, container_type in UM.Settings.ContainerRegistry.getContainerTypes():
serialize_type = ""
try:
plugin_metadata = UM.PluginRegistry.getInstance().getMetaData(plugin_id)
if plugin_metadata:
serialize_type = plugin_metadata["settings_container"]["type"]
else:
continue
except KeyError as e:
continue
mime_type = UM.Settings.ContainerRegistry.getMimeTypeForContainer(container_type)
entry = {
"type": serialize_type,
"mime": mime_type,
"container": container_type
}
suffix_list = "*." + mime_type.preferredSuffix
for suffix in mime_type.suffixes:
if suffix == mime_type.preferredSuffix:
continue
suffix_list += ", *." + suffix
name_filter = "{0} ({1})".format(mime_type.comment, suffix_list)
self._container_name_filters[name_filter] = entry
# Factory function, used by QML
@staticmethod
def createContainerManager(engine, js_engine):
return ContainerManager()

View file

@ -90,4 +90,4 @@ class ContainerSettingsModel(ListModel):
containersChanged = pyqtSignal() containersChanged = pyqtSignal()
@pyqtProperty("QVariantList", fset = setContainers, notify = containersChanged) @pyqtProperty("QVariantList", fset = setContainers, notify = containersChanged)
def containers(self): def containers(self):
return self.container_ids return self.container_ids

View file

@ -3,9 +3,10 @@
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty
import cura.ExtruderManager
import UM.Qt.ListModel import UM.Qt.ListModel
from . import ExtruderManager
## Model that holds extruders. ## Model that holds extruders.
# #
# This model is designed for use by any list of extruders, but specifically # This model is designed for use by any list of extruders, but specifically
@ -49,7 +50,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
self._active_extruder_stack = None self._active_extruder_stack = None
#Listen to changes. #Listen to changes.
manager = cura.ExtruderManager.ExtruderManager.getInstance() manager = ExtruderManager.getInstance()
manager.extrudersChanged.connect(self._updateExtruders) #When the list of extruders changes in general. manager.extrudersChanged.connect(self._updateExtruders) #When the list of extruders changes in general.
UM.Application.getInstance().globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes. UM.Application.getInstance().globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes.
self._updateExtruders() self._updateExtruders()
@ -69,7 +70,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
return self._add_global return self._add_global
def _onActiveExtruderChanged(self): def _onActiveExtruderChanged(self):
manager = cura.ExtruderManager.ExtruderManager.getInstance() manager = ExtruderManager.getInstance()
active_extruder_stack = manager.getActiveExtruderStack() active_extruder_stack = manager.getActiveExtruderStack()
if self._active_extruder_stack != active_extruder_stack: if self._active_extruder_stack != active_extruder_stack:
if self._active_extruder_stack: if self._active_extruder_stack:
@ -93,7 +94,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
# This should be called whenever the list of extruders changes. # This should be called whenever the list of extruders changes.
def _updateExtruders(self): def _updateExtruders(self):
self.clear() self.clear()
manager = cura.ExtruderManager.ExtruderManager.getInstance() manager = ExtruderManager.getInstance()
global_container_stack = UM.Application.getInstance().getGlobalContainerStack() global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
if not global_container_stack: if not global_container_stack:
return #There is no machine to get the extruders of. return #There is no machine to get the extruders of.

View file

@ -2,22 +2,21 @@
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
from UM.Application import Application from UM.Application import Application
from UM.Preferences import Preferences from UM.Preferences import Preferences
from UM.Logger import Logger from UM.Logger import Logger
import UM.Settings import UM.Settings
from UM.Settings.Validator import ValidatorState
from UM.Settings.InstanceContainer import InstanceContainer
from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutputDevice import PrinterOutputDevice
from UM.Settings.ContainerStack import ContainerStack
from . import ExtruderManager from . import ExtruderManager
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
class MachineManager(QObject):
class MachineManagerModel(QObject):
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
@ -28,7 +27,7 @@ class MachineManagerModel(QObject):
self._global_stack_valid = None self._global_stack_valid = None
self._onGlobalContainerChanged() self._onGlobalContainerChanged()
ExtruderManager.ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged) ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
self.globalContainerChanged.connect(self._onActiveExtruderStackChanged) self.globalContainerChanged.connect(self._onActiveExtruderStackChanged)
self._onActiveExtruderStackChanged() self._onActiveExtruderStackChanged()
@ -36,13 +35,13 @@ class MachineManagerModel(QObject):
self.globalContainerChanged.connect(self.activeMaterialChanged) self.globalContainerChanged.connect(self.activeMaterialChanged)
self.globalContainerChanged.connect(self.activeVariantChanged) self.globalContainerChanged.connect(self.activeVariantChanged)
self.globalContainerChanged.connect(self.activeQualityChanged) self.globalContainerChanged.connect(self.activeQualityChanged)
ExtruderManager.ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeMaterialChanged) ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeMaterialChanged)
ExtruderManager.ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeVariantChanged) ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeVariantChanged)
ExtruderManager.ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeQualityChanged) ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeQualityChanged)
self.globalContainerChanged.connect(self.activeStackChanged) self.globalContainerChanged.connect(self.activeStackChanged)
self.globalValueChanged.connect(self.activeStackChanged) self.globalValueChanged.connect(self.activeStackChanged)
ExtruderManager.ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeStackChanged) ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeStackChanged)
self._empty_variant_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_variant")[0] self._empty_variant_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_variant")[0]
self._empty_material_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_material")[0] self._empty_material_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_material")[0]
@ -126,7 +125,7 @@ class MachineManagerModel(QObject):
if property_name == "validationState": if property_name == "validationState":
if self._global_stack_valid: if self._global_stack_valid:
changed_validation_state = self._active_container_stack.getProperty(key, property_name) changed_validation_state = self._active_container_stack.getProperty(key, property_name)
if changed_validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): if changed_validation_state in (UM.Settings.ValidatorState.Exception, UM.Settings.ValidatorState.MaximumError, UM.Settings.ValidatorState.MinimumError):
self._global_stack_valid = False self._global_stack_valid = False
self.globalValidationChanged.emit() self.globalValidationChanged.emit()
else: else:
@ -155,7 +154,7 @@ class MachineManagerModel(QObject):
self._active_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged) self._active_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
self._active_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged) self._active_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged)
self._active_container_stack = ExtruderManager.ExtruderManager.getInstance().getActiveExtruderStack() self._active_container_stack = ExtruderManager.getInstance().getActiveExtruderStack()
if self._active_container_stack: if self._active_container_stack:
self._active_container_stack.containersChanged.connect(self._onInstanceContainersChanged) self._active_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
self._active_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged) self._active_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged)
@ -207,7 +206,7 @@ class MachineManagerModel(QObject):
new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(quality_instance_container)
new_global_stack.addContainer(current_settings_instance_container) new_global_stack.addContainer(current_settings_instance_container)
ExtruderManager.ExtruderManager.getInstance().addMachineExtruders(definition) ExtruderManager.getInstance().addMachineExtruders(definition)
Application.getInstance().setGlobalContainerStack(new_global_stack) Application.getInstance().setGlobalContainerStack(new_global_stack)
@ -228,7 +227,7 @@ class MachineManagerModel(QObject):
for key in stack.getAllKeys(): for key in stack.getAllKeys():
validation_state = stack.getProperty(key, "validationState") validation_state = stack.getProperty(key, "validationState")
if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): if validation_state in (UM.Settings.ValidatorState.Exception, UM.Settings.ValidatorState.MaximumError, UM.Settings.ValidatorState.MinimumError):
return True return True
return False return False
@ -552,6 +551,10 @@ class MachineManagerModel(QObject):
if containers: if containers:
return containers[0].getBottom().getId() return containers[0].getBottom().getId()
@staticmethod
def createMachineManager(engine, script_engine):
return MachineManager()
def _updateVariantContainer(self, definition): def _updateVariantContainer(self, definition):
if not definition.getMetaDataEntry("has_variants"): if not definition.getMetaDataEntry("has_variants"):
return self._empty_variant_container return self._empty_variant_container
@ -637,6 +640,3 @@ class MachineManagerModel(QObject):
return containers[0] return containers[0]
return self._empty_quality_container return self._empty_quality_container
def createMachineManagerModel(engine, script_engine):
return MachineManagerModel()

View file

@ -0,0 +1,19 @@
# Copyright (c) 2016 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.
import UM.Settings.Models
class MaterialSettingsVisibilityHandler(UM.Settings.Models.SettingVisibilityHandler):
def __init__(self, parent = None, *args, **kwargs):
super().__init__(parent = parent, *args, **kwargs)
material_settings = set([
"material_print_temperature",
"material_bed_temperature",
"material_standby_temperature",
"cool_fan_speed",
"retraction_amount",
"retraction_speed",
])
self.setVisible(material_settings)

12
cura/Settings/__init__.py Normal file
View file

@ -0,0 +1,12 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from .MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
from .ContainerManager import ContainerManager
from .ContainerSettingsModel import ContainerSettingsModel
from .CuraContainerRegistry import CuraContainerRegistry
from .ExtruderManager import ExtruderManager
from .ExtrudersModel import ExtrudersModel
from .MachineManager import MachineManager
from .MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
from .SettingOverrideDecorator import SettingOverrideDecorator

View file

@ -35,7 +35,7 @@ sys.excepthook = exceptHook
import Arcus #@UnusedImport import Arcus #@UnusedImport
from UM.Platform import Platform from UM.Platform import Platform
import cura.CuraApplication import cura.CuraApplication
import cura.CuraContainerRegistry import cura.Settings.CuraContainerRegistry
if Platform.isWindows() and hasattr(sys, "frozen"): if Platform.isWindows() and hasattr(sys, "frozen"):
dirpath = os.path.expanduser("~/AppData/Local/cura/") dirpath = os.path.expanduser("~/AppData/Local/cura/")
@ -44,7 +44,7 @@ if Platform.isWindows() and hasattr(sys, "frozen"):
sys.stderr = open(os.path.join(dirpath, "stderr.log"), "w") sys.stderr = open(os.path.join(dirpath, "stderr.log"), "w")
# Force an instance of CuraContainerRegistry to be created and reused later. # Force an instance of CuraContainerRegistry to be created and reused later.
cura.CuraContainerRegistry.CuraContainerRegistry.getInstance() cura.Settings.CuraContainerRegistry.getInstance()
app = cura.CuraApplication.CuraApplication.getInstance() app = cura.CuraApplication.CuraApplication.getInstance()
app.run() app.run()

View file

@ -13,7 +13,7 @@ from UM.Resources import Resources
from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then. from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then.
from UM.Platform import Platform from UM.Platform import Platform
from cura.ExtruderManager import ExtruderManager import cura.Settings
from cura.OneAtATimeIterator import OneAtATimeIterator from cura.OneAtATimeIterator import OneAtATimeIterator
from . import ProcessSlicedLayersJob from . import ProcessSlicedLayersJob
@ -63,7 +63,7 @@ class CuraEngineBackend(Backend):
self._onGlobalStackChanged() self._onGlobalStackChanged()
self._active_extruder_stack = None self._active_extruder_stack = None
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged) cura.Settings.ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
self._onActiveExtruderChanged() self._onActiveExtruderChanged()
#When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired. #When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired.
@ -386,7 +386,8 @@ class CuraEngineBackend(Backend):
self._active_extruder_stack.propertyChanged.disconnect(self._onSettingChanged) self._active_extruder_stack.propertyChanged.disconnect(self._onSettingChanged)
self._active_extruder_stack.containersChanged.disconnect(self._onChanged) self._active_extruder_stack.containersChanged.disconnect(self._onChanged)
self._active_extruder_stack = ExtruderManager.getInstance().getActiveExtruderStack() self._active_extruder_stack = cura.Settings.ExtruderManager.getInstance().getActiveExtruderStack()
if self._active_extruder_stack: if self._active_extruder_stack:
self._active_extruder_stack.propertyChanged.connect(self._onSettingChanged) # Note: Only starts slicing when the value changed. self._active_extruder_stack.propertyChanged.connect(self._onSettingChanged) # Note: Only starts slicing when the value changed.
self._active_extruder_stack.containersChanged.connect(self._onChanged) self._active_extruder_stack.containersChanged.connect(self._onChanged)

View file

@ -15,7 +15,8 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Settings.Validator import ValidatorState from UM.Settings.Validator import ValidatorState
from cura.OneAtATimeIterator import OneAtATimeIterator from cura.OneAtATimeIterator import OneAtATimeIterator
from cura.ExtruderManager import ExtruderManager
import cura.Settings
class StartJobResult(IntEnum): class StartJobResult(IntEnum):
Finished = 1 Finished = 1
@ -128,7 +129,7 @@ class StartSliceJob(Job):
self._buildGlobalSettingsMessage(stack) self._buildGlobalSettingsMessage(stack)
for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getBottom().getId()): for extruder_stack in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(stack.getBottom().getId()):
self._buildExtruderMessage(extruder_stack) self._buildExtruderMessage(extruder_stack)
for group in object_groups: for group in object_groups:
@ -208,4 +209,4 @@ class StartSliceJob(Job):
setting = message.addRepeatedMessage("settings") setting = message.addRepeatedMessage("settings")
setting.name = key setting.name = key
setting.value = str(stack.getProperty(key, "value")).encode("utf-8") setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
Job.yieldThread() Job.yieldThread()

View file

@ -69,7 +69,7 @@ Item
// Ensure that the cursor is at the first position. On some systems the text isnt fully visible // Ensure that the cursor is at the first position. On some systems the text isnt fully visible
// Seems to have to do something with different dpi densities that QML doesn't quite handle. // Seems to have to do something with different dpi densities that QML doesn't quite handle.
// Another option would be to increase the size even further, but that gives pretty ugly results. // Another option would be to increase the size even further, but that gives pretty ugly results.
onTextChanged: cursorPosition = 0 onEditingFinished: cursorPosition = 0
style: TextFieldStyle style: TextFieldStyle
{ {
textColor: UM.Theme.getColor("setting_control_text"); textColor: UM.Theme.getColor("setting_control_text");

View file

@ -10,7 +10,7 @@ from UM.View.Renderer import Renderer
from UM.View.GL.OpenGL import OpenGL from UM.View.GL.OpenGL import OpenGL
from cura.ExtrudersModel import ExtrudersModel import cura.Settings
import math import math
@ -24,7 +24,7 @@ class SolidView(View):
self._enabled_shader = None self._enabled_shader = None
self._disabled_shader = None self._disabled_shader = None
self._extruders_model = ExtrudersModel() self._extruders_model = cura.Settings.ExtrudersModel()
def beginRendering(self): def beginRendering(self):
scene = self.getController().getScene() scene = self.getController().getScene()

View file

@ -3,32 +3,224 @@
import math import math
import copy import copy
import io
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import uuid
from UM.Logger import Logger from UM.Logger import Logger
import UM.Dictionary
import UM.Settings import UM.Settings
# The namespace is prepended to the tag name but between {}. ## Handles serializing and deserializing material containers from an XML file
# We are only interested in the actual tag name, so discard everything
# before the last }
def _tag_without_namespace(element):
return element.tag[element.tag.rfind("}") + 1:]
class XmlMaterialProfile(UM.Settings.InstanceContainer): class XmlMaterialProfile(UM.Settings.InstanceContainer):
def __init__(self, container_id, *args, **kwargs): def __init__(self, container_id, *args, **kwargs):
super().__init__(container_id, *args, **kwargs) super().__init__(container_id, *args, **kwargs)
def serialize(self): ## Overridden from InstanceContainer
raise NotImplementedError("Writing material profiles has not yet been implemented") def duplicate(self, new_id, new_name = None):
base_file = self.getMetaDataEntry("base_file", "")
new_uuid = str(uuid.uuid4())
if base_file:
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = base_file)
if containers:
new_basefile = containers[0].duplicate(self.getMetaDataEntry("brand") + "_" + new_id, new_name)
new_basefile.setMetaDataEntry("GUID", new_uuid)
base_file = new_basefile.id
UM.Settings.ContainerRegistry.getInstance().addContainer(new_basefile)
new_id = self.getMetaDataEntry("brand") + "_" + new_id + "_" + self.getDefinition().getId()
variant = self.getMetaDataEntry("variant")
if variant:
variant_containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = variant)
if variant_containers:
new_id += "_" + variant_containers[0].getName().replace(" ", "_")
result = super().duplicate(new_id, new_name)
result.setMetaDataEntry("GUID", new_uuid)
result.setMetaDataEntry("base_file", base_file)
return result
## Overridden from InstanceContainer
def setReadOnly(self, read_only):
super().setReadOnly(read_only)
for container in UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(GUID = self.getMetaDataEntry("GUID")):
container._read_only = read_only
## Overridden from InstanceContainer
def setMetaDataEntry(self, key, value):
if self.isReadOnly():
return
super().setMetaDataEntry(key, value)
for container in UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(GUID = self.getMetaDataEntry("GUID")):
container.setMetaData(copy.deepcopy(self._metadata))
## Overridden from InstanceContainer
def setProperty(self, key, property_name, property_value, container = None):
if self.isReadOnly():
return
super().setProperty(key, property_name, property_value)
for container in UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(GUID = self.getMetaDataEntry("GUID")):
container._dirty = True
## Overridden from InstanceContainer
def serialize(self):
registry = UM.Settings.ContainerRegistry.getInstance()
base_file = self.getMetaDataEntry("base_file", "")
if base_file and self.id != base_file:
# Since we create an instance of XmlMaterialProfile for each machine and nozzle in the profile,
# we should only serialize the "base" material definition, since that can then take care of
# serializing the machine/nozzle specific profiles.
raise NotImplementedError("Cannot serialize non-root XML materials")
builder = ET.TreeBuilder()
root = builder.start("fdmmaterial", { "xmlns": "http://www.ultimaker.com/material"})
## Begin Metadata Block
builder.start("metadata")
metadata = copy.deepcopy(self.getMetaData())
properties = metadata.pop("properties", {})
# Metadata properties that should not be serialized.
metadata.pop("status", "")
metadata.pop("variant", "")
metadata.pop("type", "")
metadata.pop("base_file", "")
## Begin Name Block
builder.start("name")
builder.start("brand")
builder.data(metadata.pop("brand", ""))
builder.end("brand")
builder.start("material")
builder.data(metadata.pop("material", ""))
builder.end("material")
builder.start("color")
builder.data(metadata.pop("color_name", ""))
builder.end("color")
builder.end("name")
## End Name Block
for key, value in metadata.items():
builder.start(key)
builder.data(value)
builder.end(key)
builder.end("metadata")
## End Metadata Block
## Begin Properties Block
builder.start("properties")
for key, value in properties.items():
builder.start(key)
builder.data(value)
builder.end(key)
builder.end("properties")
## End Properties Block
## Begin Settings Block
builder.start("settings")
if self.getDefinition().id == "fdmprinter":
for instance in self.findInstances():
self._addSettingElement(builder, instance)
machine_container_map = {}
machine_nozzle_map = {}
all_containers = registry.findInstanceContainers(GUID = self.getMetaDataEntry("GUID"))
for container in all_containers:
definition_id = container.getDefinition().id
if definition_id == "fdmprinter":
continue
if definition_id not in machine_container_map:
machine_container_map[definition_id] = container
if definition_id not in machine_nozzle_map:
machine_nozzle_map[definition_id] = {}
variant = container.getMetaDataEntry("variant")
if variant:
machine_nozzle_map[definition_id][variant] = container
continue
machine_container_map[definition_id] = container
for definition_id, container in machine_container_map.items():
definition = container.getDefinition()
try:
product = UM.Dictionary.findKey(self.__product_id_map, definition_id)
except ValueError:
continue
builder.start("machine")
builder.start("machine_identifier", { "manufacturer": definition.getMetaDataEntry("manufacturer", ""), "product": product})
builder.end("machine_identifier")
for instance in container.findInstances():
if self.getDefinition().id == "fdmprinter" and self.getInstance(instance.definition.key) and self.getProperty(instance.definition.key, "value") == instance.value:
# If the settings match that of the base profile, just skip since we inherit the base profile.
continue
self._addSettingElement(builder, instance)
# Find all hotend sub-profiles corresponding to this material and machine and add them to this profile.
for hotend_id, hotend in machine_nozzle_map[definition_id].items():
variant_containers = registry.findInstanceContainers(id = hotend.getMetaDataEntry("variant"))
if not variant_containers:
continue
builder.start("hotend", { "id": variant_containers[0].getName() })
for instance in hotend.findInstances():
if container.getInstance(instance.definition.key) and container.getProperty(instance.definition.key, "value") == instance.value:
# If the settings match that of the machine profile, just skip since we inherit the machine profile.
continue
self._addSettingElement(builder, instance)
builder.end("hotend")
builder.end("machine")
builder.end("settings")
## End Settings Block
builder.end("fdmmaterial")
root = builder.close()
_indent(root)
stream = io.StringIO()
tree = ET.ElementTree(root)
tree.write(stream, "unicode", True)
return stream.getvalue()
## Overridden from InstanceContainer
def deserialize(self, serialized): def deserialize(self, serialized):
data = ET.fromstring(serialized) data = ET.fromstring(serialized)
self.addMetaDataEntry("type", "material") self.addMetaDataEntry("type", "material")
# TODO: Add material verfication # TODO: Add material verfication
self.addMetaDataEntry("status", "Unknown") self.addMetaDataEntry("status", "unknown")
metadata = data.iterfind("./um:metadata/*", self.__namespaces) metadata = data.iterfind("./um:metadata/*", self.__namespaces)
for entry in metadata: for entry in metadata:
@ -39,7 +231,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
material = entry.find("./um:material", self.__namespaces) material = entry.find("./um:material", self.__namespaces)
color = entry.find("./um:color", self.__namespaces) color = entry.find("./um:color", self.__namespaces)
self.setName("{0} {1} ({2})".format(brand.text, material.text, color.text)) self.setName(material.text)
self.addMetaDataEntry("brand", brand.text) self.addMetaDataEntry("brand", brand.text)
self.addMetaDataEntry("material", material.text) self.addMetaDataEntry("material", material.text)
@ -49,6 +241,12 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
self.addMetaDataEntry(tag_name, entry.text) self.addMetaDataEntry(tag_name, entry.text)
if not "description" in self.getMetaData():
self.addMetaDataEntry("description", "")
if not "adhesion_info" in self.getMetaData():
self.addMetaDataEntry("adhesion_info", "")
property_values = {} property_values = {}
properties = data.iterfind("./um:properties/*", self.__namespaces) properties = data.iterfind("./um:properties/*", self.__namespaces)
for entry in properties: for entry in properties:
@ -58,17 +256,6 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
diameter = float(property_values.get("diameter", 2.85)) # In mm diameter = float(property_values.get("diameter", 2.85)) # In mm
density = float(property_values.get("density", 1.3)) # In g/cm3 density = float(property_values.get("density", 1.3)) # In g/cm3
weight_per_cm = (math.pi * (diameter / 20) ** 2 * 0.1) * density
spool_weight = property_values.get("spool_weight")
spool_length = property_values.get("spool_length")
if spool_weight:
length = float(spool_weight) / weight_per_cm
property_values["spool_length"] = str(length / 100)
elif spool_length:
weight = (float(spool_length) * 100) * weight_per_cm
property_values["spool_weight"] = str(weight)
self.addMetaDataEntry("properties", property_values) self.addMetaDataEntry("properties", property_values)
self.setDefinition(UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter")[0]) self.setDefinition(UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter")[0])
@ -83,6 +270,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
else: else:
Logger.log("d", "Unsupported material setting %s", key) Logger.log("d", "Unsupported material setting %s", key)
self._dirty = False
machines = data.iterfind("./um:settings/um:machine", self.__namespaces) machines = data.iterfind("./um:settings/um:machine", self.__namespaces)
for machine in machines: for machine in machines:
machine_setting_values = {} machine_setting_values = {}
@ -112,6 +301,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
new_material.setName(self.getName()) new_material.setName(self.getName())
new_material.setMetaData(copy.deepcopy(self.getMetaData())) new_material.setMetaData(copy.deepcopy(self.getMetaData()))
new_material.setDefinition(definition) new_material.setDefinition(definition)
new_material.addMetaDataEntry("base_file", self.id)
for key, value in global_setting_values.items(): for key, value in global_setting_values.items():
new_material.setProperty(key, "value", value, definition) new_material.setProperty(key, "value", value, definition)
@ -142,6 +332,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
new_hotend_material.setName(self.getName()) new_hotend_material.setName(self.getName())
new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData())) new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData()))
new_hotend_material.setDefinition(definition) new_hotend_material.setDefinition(definition)
new_hotend_material.addMetaDataEntry("base_file", self.id)
new_hotend_material.addMetaDataEntry("variant", variant_containers[0].id) new_hotend_material.addMetaDataEntry("variant", variant_containers[0].id)
@ -162,6 +353,15 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
new_hotend_material._dirty = False new_hotend_material._dirty = False
UM.Settings.ContainerRegistry.getInstance().addContainer(new_hotend_material) UM.Settings.ContainerRegistry.getInstance().addContainer(new_hotend_material)
def _addSettingElement(self, builder, instance):
try:
key = UM.Dictionary.findKey(self.__material_property_setting_map, instance.definition.key)
except ValueError:
return
builder.start("setting", { "key": key })
builder.data(str(instance.value))
builder.end("setting")
# Map XML file setting names to internal names # Map XML file setting names to internal names
__material_property_setting_map = { __material_property_setting_map = {
@ -174,6 +374,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
} }
# Map XML file product names to internal ids # Map XML file product names to internal ids
# TODO: Move this to definition's metadata
__product_id_map = { __product_id_map = {
"Ultimaker2": "ultimaker2", "Ultimaker2": "ultimaker2",
"Ultimaker2+": "ultimaker2_plus", "Ultimaker2+": "ultimaker2_plus",
@ -184,6 +385,30 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
"Ultimaker Original+": "ultimaker_original_plus" "Ultimaker Original+": "ultimaker_original_plus"
} }
# Map of recognised namespaces with a proper prefix.
__namespaces = { __namespaces = {
"um": "http://www.ultimaker.com/material" "um": "http://www.ultimaker.com/material"
} }
## Helper function for pretty-printing XML because ETree is stupid
def _indent(elem, level = 0):
i = "\n" + level * " "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
_indent(elem, level + 1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
# The namespace is prepended to the tag name but between {}.
# We are only interested in the actual tag name, so discard everything
# before the last }
def _tag_without_namespace(element):
return element.tag[element.tag.rfind("}") + 1:]

View file

@ -17,6 +17,7 @@ def getMetaData():
"api": 3 "api": 3
}, },
"settings_container": { "settings_container": {
"type": "material",
"mimetype": "application/x-ultimaker-material-profile" "mimetype": "application/x-ultimaker-material-profile"
} }
} }

View file

@ -39,6 +39,8 @@ Item
property alias resetProfile: resetProfileAction; property alias resetProfile: resetProfileAction;
property alias manageProfiles: manageProfilesAction; property alias manageProfiles: manageProfilesAction;
property alias manageMaterials: manageMaterialsAction;
property alias preferences: preferencesAction; property alias preferences: preferencesAction;
property alias showEngineLog: showEngineLogAction; property alias showEngineLog: showEngineLogAction;
@ -90,7 +92,7 @@ Item
Action Action
{ {
id: preferencesAction; id: preferencesAction;
text: catalog.i18nc("@action:inmenu menubar:settings","&Preferences..."); text: catalog.i18nc("@action:inmenu","Configure Cura...");
iconName: "configure"; iconName: "configure";
} }
@ -107,6 +109,13 @@ Item
iconName: "configure"; iconName: "configure";
} }
Action
{
id: manageMaterialsAction
text: catalog.i18nc("@action:inmenu", "Manage Materials...")
iconName: "configure"
}
Action Action
{ {
id: updateProfileAction; id: updateProfileAction;
@ -273,5 +282,6 @@ Item
{ {
id: configureSettingVisibilityAction id: configureSettingVisibilityAction
text: catalog.i18nc("@action:menu", "Configure setting visiblity..."); text: catalog.i18nc("@action:menu", "Configure setting visiblity...");
iconName: "configure"
} }
} }

View file

@ -10,6 +10,8 @@ import QtQuick.Dialogs 1.1
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
import "Menus"
UM.MainWindow UM.MainWindow
{ {
id: base id: base
@ -55,41 +57,13 @@ UM.MainWindow
Menu Menu
{ {
id: fileMenu id: fileMenu
//: File menu
title: catalog.i18nc("@title:menu menubar:toplevel","&File"); title: catalog.i18nc("@title:menu menubar:toplevel","&File");
MenuItem { MenuItem {
action: Cura.Actions.open; action: Cura.Actions.open;
} }
Menu RecentFilesMenu { }
{
id: recentFilesMenu;
title: catalog.i18nc("@title:menu menubar:file", "Open &Recent")
iconName: "document-open-recent";
enabled: Printer.recentFiles.length > 0;
Instantiator
{
model: Printer.recentFiles
MenuItem
{
text:
{
var path = modelData.toString()
return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1);
}
onTriggered: {
UM.MeshFileHandler.readLocalFile(modelData);
var meshName = backgroundItem.getMeshName(modelData.toString())
backgroundItem.hasMesh(decodeURIComponent(meshName))
}
}
onObjectAdded: recentFilesMenu.insertItem(index, object)
onObjectRemoved: recentFilesMenu.removeItem(object)
}
}
MenuSeparator { } MenuSeparator { }
@ -130,7 +104,6 @@ UM.MainWindow
Menu Menu
{ {
//: Edit menu
title: catalog.i18nc("@title:menu menubar:toplevel","&Edit"); title: catalog.i18nc("@title:menu menubar:toplevel","&Edit");
MenuItem { action: Cura.Actions.undo; } MenuItem { action: Cura.Actions.undo; }
@ -146,173 +119,45 @@ UM.MainWindow
MenuItem { action: Cura.Actions.unGroupObjects;} MenuItem { action: Cura.Actions.unGroupObjects;}
} }
ViewMenu { title: catalog.i18nc("@title:menu", "&View") }
Menu Menu
{ {
title: catalog.i18nc("@title:menu menubar:toplevel","&View"); id: settingsMenu
id: top_view_menu title: catalog.i18nc("@title:menu", "&Settings")
Instantiator
{ PrinterMenu { title: catalog.i18nc("@title:menu menubar:toplevel", "&Printer") }
model: UM.ViewModel { }
MenuItem
{
text: model.name;
checkable: true;
checked: model.active;
exclusiveGroup: view_menu_top_group;
onTriggered: UM.Controller.setActiveView(model.id);
}
onObjectAdded: top_view_menu.insertItem(index, object)
onObjectRemoved: top_view_menu.removeItem(object)
}
ExclusiveGroup { id: view_menu_top_group; }
}
Menu
{
id: machineMenu;
//: Machine menu
title: catalog.i18nc("@title:menu menubar:toplevel","&Printer");
Instantiator Instantiator
{ {
model: UM.ContainerStacksModel model: Cura.ExtrudersModel { }
{ Menu {
filter: {"type": "machine"} title: model.name
NozzleMenu { title: catalog.i18nc("@title:menu", "&Nozzle"); visible: Cura.MachineManager.hasVariants }
MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials }
ProfileMenu { title: catalog.i18nc("@title:menu", "&Profile"); }
MenuSeparator { }
MenuItem { text: "Set as Active Extruder" }
} }
MenuItem onObjectAdded: settingsMenu.insertItem(index, object)
{ onObjectRemoved: settingsMenu.removeItem(object)
text: model.name;
checkable: true;
checked: Cura.MachineManager.activeMachineId == model.id
exclusiveGroup: machineMenuGroup;
onTriggered: Cura.MachineManager.setActiveMachine(model.id);
}
onObjectAdded: machineMenu.insertItem(index, object)
onObjectRemoved: machineMenu.removeItem(object)
} }
ExclusiveGroup { id: machineMenuGroup; } NozzleMenu { title: catalog.i18nc("@title:menu", "&Nozzle"); visible: machineExtruderCount.properties.value <= 1 && Cura.MachineManager.hasVariants }
MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: machineExtruderCount.properties.value <= 1 && Cura.MachineManager.hasMaterials }
ProfileMenu { title: catalog.i18nc("@title:menu", "&Profile"); visible: machineExtruderCount.properties.value <= 1 }
MenuSeparator { } MenuSeparator { }
Instantiator MenuItem { action: Cura.Actions.configureSettingVisibility }
{
model: UM.InstanceContainersModel
{
filter:
{
"type": "variant",
"definition": Cura.MachineManager.activeDefinitionId //Only show variants of this machine
}
}
MenuItem {
text: model.name;
checkable: true;
checked: model.id == Cura.MachineManager.activeVariantId;
exclusiveGroup: machineVariantsGroup;
onTriggered: Cura.MachineManager.setActiveVariant(model.id)
}
onObjectAdded: machineMenu.insertItem(index, object)
onObjectRemoved: machineMenu.removeItem(object)
}
ExclusiveGroup { id: machineVariantsGroup; }
MenuSeparator { visible: Cura.MachineManager.hasVariants; }
MenuItem { action: Cura.Actions.addMachine; }
MenuItem { action: Cura.Actions.configureMachines; }
}
Menu
{
id: profileMenu
title: catalog.i18nc("@title:menu menubar:toplevel", "P&rofile")
Instantiator
{
id: profileMenuInstantiator
model: UM.InstanceContainersModel
{
filter:
{
var result = { "type": "quality" };
if(Cura.MachineManager.filterQualityByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId;
if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}
property int separatorIndex: -1
Loader {
property QtObject model_data: model
property int model_index: index
sourceComponent: profileMenuItemDelegate
}
onObjectAdded:
{
//Insert a separator between readonly and custom profiles
if(separatorIndex < 0 && index > 0) {
if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) {
profileMenu.insertSeparator(index);
separatorIndex = index;
}
}
//Because of the separator, custom profiles move one index lower
profileMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item);
}
onObjectRemoved:
{
//When adding a profile, the menu is rebuild by removing all items.
//If a separator was added, we need to remove that too.
if(separatorIndex >= 0)
{
profileMenu.removeItem(profileMenu.items[separatorIndex])
separatorIndex = -1;
}
profileMenu.removeItem(object.item);
}
}
ExclusiveGroup { id: profileMenuGroup; }
Component
{
id: profileMenuItemDelegate
MenuItem
{
id: item
text: model_data ? model_data.name : ""
checkable: true
checked: model_data != null ? Cura.MachineManager.activeQualityId == model_data.id : false
exclusiveGroup: profileMenuGroup
onTriggered: Cura.MachineManager.setActiveQuality(model_data.id)
}
}
MenuSeparator { id: profileMenuSeparator }
MenuItem { action: Cura.Actions.addProfile }
MenuItem { action: Cura.Actions.updateProfile }
MenuItem { action: Cura.Actions.resetProfile }
MenuSeparator { }
MenuItem { action: Cura.Actions.manageProfiles }
} }
Menu Menu
{ {
id: extension_menu id: extension_menu
//: Extensions menu
title: catalog.i18nc("@title:menu menubar:toplevel","E&xtensions"); title: catalog.i18nc("@title:menu menubar:toplevel","E&xtensions");
Instantiator Instantiator
@ -346,8 +191,7 @@ UM.MainWindow
Menu Menu
{ {
//: Settings menu title: catalog.i18nc("@title:menu menubar:toplevel","P&references");
title: catalog.i18nc("@title:menu menubar:toplevel","&Settings");
MenuItem { action: Cura.Actions.preferences; } MenuItem { action: Cura.Actions.preferences; }
} }
@ -365,6 +209,16 @@ UM.MainWindow
} }
} }
UM.SettingPropertyProvider
{
id: machineExtruderCount
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_extruder_count"
watchedProperties: [ "value" ]
storeIndex: 0
}
Item Item
{ {
id: contentItem; id: contentItem;
@ -411,14 +265,9 @@ UM.MainWindow
{ {
id: view_panel id: view_panel
//anchors.left: parent.left;
//anchors.right: parent.right;
//anchors.bottom: parent.bottom
anchors.top: viewModeButton.bottom anchors.top: viewModeButton.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height; anchors.topMargin: UM.Theme.getSize("default_margin").height;
anchors.left: viewModeButton.left; anchors.left: viewModeButton.left;
//anchors.bottom: buttons.top;
//anchors.bottomMargin: UM.Theme.getSize("default_margin").height;
height: childrenRect.height; height: childrenRect.height;
@ -428,7 +277,6 @@ UM.MainWindow
Button Button
{ {
id: openFileButton; id: openFileButton;
//style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button;
text: catalog.i18nc("@action:button","Open File"); text: catalog.i18nc("@action:button","Open File");
iconSource: UM.Theme.getIcon("load") iconSource: UM.Theme.getIcon("load")
style: UM.Theme.styles.tool_button style: UM.Theme.styles.tool_button
@ -436,9 +284,7 @@ UM.MainWindow
anchors anchors
{ {
top: parent.top; top: parent.top;
//topMargin: UM.Theme.getSize("loadfile_margin").height
left: parent.left; left: parent.left;
//leftMargin: UM.Theme.getSize("loadfile_margin").width
} }
action: Cura.Actions.open; action: Cura.Actions.open;
} }
@ -478,27 +324,7 @@ UM.MainWindow
style: UM.Theme.styles.tool_button; style: UM.Theme.styles.tool_button;
tooltip: ''; tooltip: '';
menu: Menu menu: ViewMenu { }
{
id: viewMenu;
Instantiator
{
id: viewMenuInstantiator
model: UM.ViewModel { }
MenuItem
{
text: model.name
checkable: true;
checked: model.active
exclusiveGroup: viewMenuGroup;
onTriggered: UM.Controller.setActiveView(model.id);
}
onObjectAdded: viewMenu.insertItem(index, object)
onObjectRemoved: viewMenu.removeItem(object)
}
ExclusiveGroup { id: viewMenuGroup; }
}
} }
Toolbar Toolbar
@ -650,6 +476,16 @@ UM.MainWindow
} }
} }
Connections
{
target: Cura.Actions.manageMaterials
onTriggered:
{
preferences.visible = true;
preferences.setPage(3)
}
}
Connections Connections
{ {
target: Cura.Actions.configureSettingVisibility target: Cura.Actions.configureSettingVisibility

View file

@ -0,0 +1,72 @@
// Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Menu
{
id: menu
title: "Material"
Instantiator
{
model: UM.InstanceContainersModel
{
filter:
{
var result = { "type": "material" }
if(Cura.MachineManager.filterMaterialsByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId
if(Cura.MachineManager.hasVariants)
{
result.variant = Cura.MachineManager.activeVariantId
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}
MenuItem
{
text:
{
var result = model.name
if(model.metadata.brand != undefined && model.metadata.brand != "Generic")
{
result = model.metadata.brand + " " + result
}
if(model.metadata.color_name != undefined && model.metadata.color_name != "Generic")
{
result = result + " (%1)".arg(model.metadata.color_name)
}
return result
}
checkable: true;
checked: model.id == Cura.MachineManager.activeMaterialId;
exclusiveGroup: group;
onTriggered:
{
Cura.MachineManager.setActiveMaterial(model.id);
}
}
onObjectAdded: menu.insertItem(index, object)
onObjectRemoved: menu.removeItem(object)
}
ExclusiveGroup { id: group }
MenuSeparator { }
MenuItem { action: Cura.Actions.manageMaterials }
}

View file

@ -0,0 +1,37 @@
// Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Menu
{
id: menu
title: "Nozzle"
Instantiator
{
model: UM.InstanceContainersModel
{
filter:
{
"type": "variant",
"definition": Cura.MachineManager.activeDefinitionId //Only show variants of this machine
}
}
MenuItem {
text: model.name;
checkable: true;
checked: model.id == Cura.MachineManager.activeVariantId;
exclusiveGroup: group
onTriggered: Cura.MachineManager.setActiveVariant(model.id)
}
onObjectAdded: menu.insertItem(index, object)
onObjectRemoved: menu.removeItem(object)
}
ExclusiveGroup { id: group }
}

View file

@ -0,0 +1,38 @@
// Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Menu
{
id: menu;
Instantiator
{
model: UM.ContainerStacksModel
{
filter: {"type": "machine"}
}
MenuItem
{
text: model.name;
checkable: true;
checked: Cura.MachineManager.activeMachineId == model.id
exclusiveGroup: group;
onTriggered: Cura.MachineManager.setActiveMachine(model.id);
}
onObjectAdded: menu.insertItem(index, object)
onObjectRemoved: menu.removeItem(object)
}
ExclusiveGroup { id: group; }
MenuSeparator { }
MenuItem { action: Cura.Actions.addMachine; }
MenuItem { action: Cura.Actions.configureMachines; }
}

View file

@ -0,0 +1,86 @@
// Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Menu
{
id: menu
Instantiator
{
model: UM.InstanceContainersModel { filter: menu.getFilter({ "read_only": true }); }
MenuItem
{
text: model.name
checkable: true
checked: Cura.MachineManager.activeQualityId == model.id
exclusiveGroup: group
onTriggered: Cura.MachineManager.setActiveQuality(model.id)
}
onObjectAdded: menu.insertItem(index, object);
onObjectRemoved: menu.removeItem(object);
}
MenuSeparator { id: customSeparator }
Instantiator
{
model: UM.InstanceContainersModel
{
id: customProfilesModel;
filter: menu.getFilter({ "read_only": false });
onRowsInserted: customSeparator.visible = rowCount() > 1
onRowsRemoved: customSeparator.visible = rowCount() > 1
onModelReset: customSeparator.visible = rowCount() > 1
}
MenuItem
{
text: model.name
checkable: true
checked: Cura.MachineManager.activeQualityId == model.id
exclusiveGroup: group
onTriggered: Cura.MachineManager.setActiveQuality(model.id)
}
onObjectAdded: menu.insertItem(index, object);
onObjectRemoved: menu.removeItem(object);
}
ExclusiveGroup { id: group; }
MenuSeparator { id: profileMenuSeparator }
MenuItem { action: Cura.Actions.addProfile }
MenuItem { action: Cura.Actions.updateProfile }
MenuItem { action: Cura.Actions.resetProfile }
MenuSeparator { }
MenuItem { action: Cura.Actions.manageProfiles }
function getFilter(initial_conditions)
{
var result = initial_conditions;
result.type = "quality"
if(Cura.MachineManager.filterQualityByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId;
if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}

View file

@ -0,0 +1,37 @@
// Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Menu
{
id: menu
title: catalog.i18nc("@title:menu menubar:file", "Open &Recent")
iconName: "document-open-recent";
enabled: Printer.recentFiles.length > 0;
Instantiator
{
model: Printer.recentFiles
MenuItem
{
text:
{
var path = modelData.toString()
return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1);
}
onTriggered: {
UM.MeshFileHandler.readLocalFile(modelData);
var meshName = backgroundItem.getMeshName(modelData.toString())
backgroundItem.hasMesh(decodeURIComponent(meshName))
}
}
onObjectAdded: menu.insertItem(index, object)
onObjectRemoved: menu.removeItem(object)
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Menu
{
title: catalog.i18nc("@title:menu menubar:toplevel", "&View");
id: menu
Instantiator
{
model: UM.ViewModel { }
MenuItem
{
text: model.name;
checkable: true;
checked: model.active;
exclusiveGroup: group;
onTriggered: UM.Controller.setActiveView(model.id);
}
onObjectAdded: menu.insertItem(index, object)
onObjectRemoved: menu.removeItem(object)
}
ExclusiveGroup { id: group; }
}

View file

@ -27,14 +27,35 @@ UM.ManagementPage
return -1; return -1;
} }
onAddObject: Printer.requestAddPrinter() buttons: [
onRemoveObject: confirmDialog.open(); Button
onRenameObject: renameDialog.open(); {
onActivateObject: Cura.MachineManager.setActiveMachine(base.currentItem.id) text: catalog.i18nc("@action:button", "Activate");
iconName: "list-activate";
removeEnabled: base.currentItem != null && model.rowCount() > 1 enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId
renameEnabled: base.currentItem != null onClicked: Cura.MachineManager.setActiveMachine(base.currentItem.id)
activateEnabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMachineId },
Button
{
text: catalog.i18nc("@action:button", "Add");
iconName: "list-add";
onClicked: Printer.requestAddPrinter()
},
Button
{
text: catalog.i18nc("@action:button", "Remove");
iconName: "list-remove";
enabled: base.currentItem != null && model.rowCount() > 1
onClicked: confirmDialog.open();
},
Button
{
text: catalog.i18nc("@action:button", "Rename");
iconName: "edit-rename";
enabled: base.currentItem != null
onClicked: renameDialog.open();
}
]
Item Item
{ {

View file

@ -0,0 +1,252 @@
// Copyright (c) 2016 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2
import UM 1.2 as UM
import Cura 1.0 as Cura
TabView
{
id: base
property QtObject properties;
property bool editingEnabled: false;
property string currency: UM.Preferences.getValue("general/currency") ? UM.Preferences.getValue("general/currency") : "€"
property real firstColumnWidth: width * 0.45
property real secondColumnWidth: width * 0.45
property string containerId: ""
Tab
{
title: "Information"
anchors
{
leftMargin: UM.Theme.getSize("default_margin").width
topMargin: UM.Theme.getSize("default_margin").height
bottomMargin: UM.Theme.getSize("default_margin").height
rightMargin: 0
}
ScrollView
{
anchors.fill: parent
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
Flow
{
id: containerGrid
width: base.width;
property real rowHeight: textField.height;
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Brand") }
ReadOnlyTextField
{
id: textField;
width: base.secondColumnWidth;
text: properties.supplier;
readOnly: !base.editingEnabled;
onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "brand", text)
}
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Material Type") }
ReadOnlyTextField
{
width: base.secondColumnWidth;
text: properties.material_type;
readOnly: !base.editingEnabled;
onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "material", text)
}
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") }
Row
{
width: base.secondColumnWidth;
height: parent.rowHeight;
spacing: UM.Theme.getSize("default_margin").width/2
Rectangle
{
id: colorSelector
color: properties.color_code
onColorChanged: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "color_code", color)
width: colorLabel.height * 0.75
height: colorLabel.height * 0.75
border.width: UM.Theme.getSize("default_lining").height
anchors.verticalCenter: parent.verticalCenter
MouseArea { anchors.fill: parent; onClicked: colorDialog.open(); enabled: base.editingEnabled }
}
ReadOnlyTextField
{
id: colorLabel;
text: properties.color_name;
readOnly: !base.editingEnabled
onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "color_name", text)
}
ColorDialog { id: colorDialog; color: properties.color_code; onAccepted: colorSelector.color = color }
}
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: "<b>" + catalog.i18nc("@label", "Properties") + "</b>" }
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Density") }
ReadOnlySpinBox
{
width: base.secondColumnWidth;
value: properties.density;
decimals: 2
suffix: "g/cm"
stepSize: 0.01
readOnly: !base.editingEnabled;
onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "properties/density", value)
}
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Diameter") }
ReadOnlySpinBox
{
width: base.secondColumnWidth;
value: properties.diameter;
decimals: 2
suffix: "mm³"
stepSize: 0.01
readOnly: !base.editingEnabled;
onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "properties/diameter", value)
}
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament Cost") }
SpinBox
{
width: base.secondColumnWidth;
value: properties.spool_cost;
prefix: base.currency
enabled: false
}
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament weight") }
SpinBox
{
width: base.secondColumnWidth;
value: properties.spool_weight;
suffix: "g";
stepSize: 10
enabled: false
}
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament length") }
SpinBox
{
width: base.secondColumnWidth;
value: parseFloat(properties.spool_length);
suffix: "m";
enabled: false
}
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Cost per Meter (Approx.)") }
SpinBox
{
width: base.secondColumnWidth;
value: parseFloat(properties.cost_per_meter);
suffix: catalog.i18nc("@label", "%1/m".arg(base.currency));
enabled: false
}
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Description") }
ReadOnlyTextArea
{
text: properties.description;
width: base.firstColumnWidth + base.secondColumnWidth
wrapMode: Text.WordWrap
readOnly: !base.editingEnabled;
onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "description", text)
}
Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Adhesion Information") }
ReadOnlyTextArea
{
text: properties.adhesion_info;
width: base.firstColumnWidth + base.secondColumnWidth
wrapMode: Text.WordWrap
readOnly: !base.editingEnabled;
onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "adhesion_info", text)
}
}
}
}
Tab
{
title: catalog.i18nc("@label", "Print settings")
anchors
{
leftMargin: UM.Theme.getSize("default_margin").width
topMargin: UM.Theme.getSize("default_margin").height
bottomMargin: UM.Theme.getSize("default_margin").height
rightMargin: 0
}
ScrollView
{
anchors.fill: parent;
ListView
{
model: UM.SettingDefinitionsModel
{
containerId: Cura.MachineManager.activeDefinitionId
visibilityHandler: Cura.MaterialSettingsVisibilityHandler { }
expanded: ["*"]
}
delegate: UM.TooltipArea
{
width: childrenRect.width
height: childrenRect.height
text: model.description
Label
{
id: label
width: base.firstColumnWidth;
height: spinBox.height
text: model.label
}
ReadOnlySpinBox
{
id: spinBox
anchors.left: label.right
value: parseFloat(provider.properties.value);
width: base.secondColumnWidth;
readOnly: !base.editingEnabled
suffix: model.unit
maximumValue: 99999
decimals: model.unit == "mm" ? 2 : 0
onEditingFinished: provider.setPropertyValue("value", value)
}
UM.ContainerPropertyProvider { id: provider; containerId: base.containerId; watchedProperties: [ "value" ]; key: model.key }
}
}
}
}
}

View file

@ -33,6 +33,8 @@ UM.ManagementPage
} }
return result return result
} }
sectionProperty: "brand"
} }
activeId: Cura.MachineManager.activeMaterialId activeId: Cura.MachineManager.activeMaterialId
@ -45,14 +47,64 @@ UM.ManagementPage
return -1; return -1;
} }
addEnabled: false scrollviewCaption: "Printer: %1, Nozzle: %2".arg(Cura.MachineManager.activeMachineName).arg(Cura.MachineManager.activeVariantName)
removeEnabled: false
renameEnabled: false
scrollviewCaption: " "
detailsVisible: true detailsVisible: true
property string currency: UM.Preferences.getValue("general/currency") section.property: "section"
section.delegate: Label { text: section }
buttons: [
Button
{
text: catalog.i18nc("@action:button", "Activate");
iconName: "list-activate";
enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId
onClicked: Cura.MachineManager.setActiveMaterial(base.currentItem.id)
},
Button
{
text: catalog.i18nc("@action:button", "Duplicate");
iconName: "list-add";
enabled: base.currentItem != null
onClicked:
{
var material_id = Cura.ContainerManager.duplicateContainer(base.currentItem.id)
if(material_id == "")
{
return
}
if(Cura.MachineManager.filterQualityByMachine)
{
var quality_id = Cura.ContainerManager.duplicateContainer(Cura.MachineManager.activeQualityId)
Cura.ContainerManager.setContainerMetaDataEntry(quality_id, "material", material_id)
Cura.MachineManager.setActiveQuality(quality_id)
}
Cura.MachineManager.setActiveMaterial(material_id)
}
},
Button
{
text: catalog.i18nc("@action:button", "Remove");
iconName: "list-remove";
enabled: base.currentItem != null && !base.currentItem.readOnly
onClicked: confirmDialog.open()
},
Button
{
text: catalog.i18nc("@action:button", "Import");
iconName: "document-import";
onClicked: importDialog.open();
},
Button
{
text: catalog.i18nc("@action:button", "Export")
iconName: "document-export"
onClicked: exportDialog.open()
enabled: currentItem != null
}
]
Item { Item {
UM.I18nCatalog { id: catalog; name: "cura"; } UM.I18nCatalog { id: catalog; name: "cura"; }
@ -60,126 +112,42 @@ UM.ManagementPage
visible: base.currentItem != null visible: base.currentItem != null
anchors.fill: parent anchors.fill: parent
Label { id: profileName; text: materialProperties.name; font: UM.Theme.getFont("large"); width: parent.width; } Item
{
id: profileName
TabView { width: parent.width;
id: scrollView height: childrenRect.height
anchors.left: parent.left
anchors.right: parent.right
anchors.top: profileName.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.bottom: parent.bottom
Tab { Label { text: materialProperties.name; font: UM.Theme.getFont("large"); }
title: "Information" Button
anchors.margins: UM.Theme.getSize("default_margin").height {
id: editButton
anchors.right: parent.right;
text: catalog.i18nc("@action:button", "Edit");
iconName: "document-edit";
Flow { enabled: base.currentItem != null && !base.currentItem.readOnly
id: containerGrid
width: scrollView.width; checkable: true
property real columnWidth: width / 2
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "Profile Type") }
Label { width: parent.columnWidth; text: materialProperties.profile_type }
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "Supplier") }
Label { width: parent.columnWidth; text: materialProperties.supplier }
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "Material Type") }
Label { width: parent.columnWidth; text: materialProperties.material_type }
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "Color") }
Row {
width: parent.columnWidth;
spacing: UM.Theme.getSize("default_margin").width/2
Rectangle {
color: materialProperties.color_code
width: colorLabel.height
height: colorLabel.height
border.width: UM.Theme.getSize("default_lining").height
}
Label { id: colorLabel; text: materialProperties.color_name }
}
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
Label { width: parent.width; text: "<b>" + catalog.i18nc("@label", "Properties") + "</b>" }
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "Density") }
Label { width: parent.columnWidth; text: materialProperties.density }
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "Diameter") }
Label { width: parent.columnWidth; text: materialProperties.diameter }
Label {
text: catalog.i18nc("@label", "Filament cost")
width: parent.columnWidth;
height: spoolCostInput.height
verticalAlignment: Text.AlignVCenter
}
Row {
width: parent.columnWidth;
Label {
text: base.currency ? base.currency + " " : " "
anchors.verticalCenter: parent.verticalCenter
}
TextField {
id: spoolCostInput
text: materialProperties.spool_cost
}
}
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "Filament weight") }
Label { width: parent.columnWidth; text: materialProperties.spool_weight + " " + "g" }
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "Filament length") }
Label { width: parent.columnWidth; text: materialProperties.spool_length + " " + "m" }
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "Cost per meter") }
Label { width: parent.columnWidth; text: catalog.i18nc("@label", "approx. %1 %2/m").arg(materialProperties.cost_per_meter).arg(base.currency); }
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
Label {
text: materialProperties.description ? "<b>" + catalog.i18nc("@label", "Information") + "</b><br>" + materialProperties.description : "";
width: parent.width
wrapMode: Text.WordWrap
}
Label {
text: materialProperties.adhesion_info ? "<b>" + catalog.i18nc("@label", "Adhesion") + "</b><br>" + materialProperties.adhesion_info : "";
width: parent.width
wrapMode: Text.WordWrap
}
}
} }
Tab { }
title: catalog.i18nc("@label", "Print settings")
anchors.margins: UM.Theme.getSize("default_margin").height
Grid { MaterialView
columns: 2 {
spacing: UM.Theme.getSize("default_margin").width anchors
{
Column { left: parent.left
Repeater { right: parent.right
model: base.currentItem ? base.currentItem.settings : null top: profileName.bottom
Label { topMargin: UM.Theme.getSize("default_margin").height
text: modelData.name.toString(); bottom: parent.bottom
elide: Text.ElideMiddle;
}
}
}
Column {
Repeater {
model: base.currentItem ? base.currentItem.settings : null
Label { text: modelData.value.toString() + " " + modelData.unit.toString(); }
}
}
}
} }
editingEnabled: base.currentItem != null && !base.currentItem.readOnly && editButton.checked;
properties: materialProperties
containerId: base.currentItem.id
} }
QtObject QtObject
@ -194,17 +162,100 @@ UM.ManagementPage
property string color_name: "Yellow"; property string color_name: "Yellow";
property color color_code: "yellow"; property color color_code: "yellow";
property string density: "Unknown"; property real density: 0.0;
property string diameter: "Unknown"; property real diameter: 0.0;
property string spool_cost: "Unknown"; property real spool_cost: 0.0;
property string spool_weight: "Unknown"; property real spool_weight: 0.0;
property string spool_length: "Unknown"; property real spool_length: 0.0;
property string cost_per_meter: "Unknown"; property real cost_per_meter: 0.0;
property string description: ""; property string description: "";
property string adhesion_info: ""; property string adhesion_info: "";
} }
UM.ConfirmRemoveDialog
{
id: confirmDialog
object: base.currentItem != null ? base.currentItem.name : ""
onYes:
{
var containers = Cura.ContainerManager.findInstanceContainers({"GUID": base.currentItem.metadata.GUID})
for(var i in containers)
{
Cura.ContainerManager.removeContainer(containers[i])
}
}
}
FileDialog
{
id: importDialog;
title: catalog.i18nc("@title:window", "Import Material");
selectExisting: true;
nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
folder: CuraApplication.getDefaultPath()
onAccepted:
{
var result = Cura.ContainerManager.importContainer(fileUrl)
messageDialog.title = catalog.i18nc("@title:window", "Import Material")
messageDialog.text = catalog.i18nc("@info:status", "Could not import material <filename>%1</filename>: <message>%2</message>").arg(fileUrl).arg(result.message)
if(result.status == "success")
{
messageDialog.icon = StandardIcon.Information
messageDialog.text = catalog.i18nc("@info:status", "Successfully imported material <filename>%1</filename>").arg(fileUrl)
}
else if(result.status == "duplicate")
{
messageDialog.icon = StandardIcon.Warning
}
else
{
messageDialog.icon = StandardIcon.Critical
}
messageDialog.open()
}
}
FileDialog
{
id: exportDialog;
title: catalog.i18nc("@title:window", "Export Material");
selectExisting: false;
nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
folder: CuraApplication.getDefaultPath()
onAccepted:
{
if(base.currentItem.metadata.base_file)
{
var result = Cura.ContainerManager.exportContainer(base.currentItem.metadata.base_file, selectedNameFilter, fileUrl)
}
else
{
var result = Cura.ContainerManager.exportContainer(base.currentItem.id, selectedNameFilter, fileUrl)
}
messageDialog.title = catalog.i18nc("@title:window", "Export Material")
if(result.status == "error")
{
messageDialog.icon = StandardIcon.Critical
messageDialog.text = catalog.i18nc("@info:status", "Failed to export material to <filename>%1</filename>: <message>%2</message>").arg(fileUrl).arg(result.message)
messageDialog.open()
}
else if(result.status == "success")
{
messageDialog.icon = StandardIcon.Information
messageDialog.text = catalog.i18nc("@info:status", "Successfully exported material to <filename>%1</filename>").arg(fileUrl)
messageDialog.open()
}
}
}
MessageDialog
{
id: messageDialog
}
} }
onCurrentItemChanged: onCurrentItemChanged:
@ -228,13 +279,13 @@ UM.ManagementPage
if(currentItem.metadata.properties != undefined && currentItem.metadata.properties != null) if(currentItem.metadata.properties != undefined && currentItem.metadata.properties != null)
{ {
materialProperties.density = currentItem.metadata.properties.density ? currentItem.metadata.properties.density : "Unknown"; materialProperties.density = currentItem.metadata.properties.density ? currentItem.metadata.properties.density : 0.0;
materialProperties.diameter = currentItem.metadata.properties.diameter ? currentItem.metadata.properties.diameter : "Unknown"; materialProperties.diameter = currentItem.metadata.properties.diameter ? currentItem.metadata.properties.diameter : 0.0;
} }
else else
{ {
materialProperties.density = "Unknown"; materialProperties.density = 0.0;
materialProperties.diameter = "Unknown"; materialProperties.diameter = 0.0;
} }
} }
} }

View file

@ -13,7 +13,6 @@ UM.ManagementPage
id: base; id: base;
title: catalog.i18nc("@title:tab", "Profiles"); title: catalog.i18nc("@title:tab", "Profiles");
addText: base.currentItem && (base.currentItem.id == Cura.MachineManager.activeQualityId) ? catalog.i18nc("@label", "Create") : catalog.i18nc("@label", "Duplicate")
model: UM.InstanceContainersModel model: UM.InstanceContainersModel
{ {
@ -60,27 +59,62 @@ UM.ManagementPage
return -1; return -1;
} }
onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id) buttons: [
onAddObject: { Button
var selectedContainer; {
if (objectList.currentItem.id == Cura.MachineManager.activeQualityId) { text: catalog.i18nc("@action:button", "Activate");
selectedContainer = Cura.MachineManager.newQualityContainerFromQualityAndUser(); iconName: "list-activate";
} else { enabled: base.currentItem != null ? base.currentItem.id != Cura.MachineManager.activeQualityId : false;
selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id); onClicked: Cura.MachineManager.setActiveQuality(base.currentItem.id)
},
Button
{
text: base.currentItem && (base.currentItem.id == Cura.MachineManager.activeQualityId) ? catalog.i18nc("@label", "Create") : catalog.i18nc("@label", "Duplicate")
iconName: "list-add";
onClicked:
{
var selectedContainer;
if (objectList.currentItem.id == Cura.MachineManager.activeQualityId) {
selectedContainer = Cura.MachineManager.newQualityContainerFromQualityAndUser();
} else {
selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id);
}
base.selectContainer(selectedContainer);
renameDialog.removeWhenRejected = true;
renameDialog.open();
renameDialog.selectText();
}
},
Button
{
text: catalog.i18nc("@action:button", "Remove");
iconName: "list-remove";
enabled: base.currentItem != null ? !base.currentItem.readOnly : false;
onClicked: confirmDialog.open();
},
Button
{
text: catalog.i18nc("@action:button", "Rename");
iconName: "edit-rename";
enabled: base.currentItem != null ? !base.currentItem.readOnly : false;
onClicked: { renameDialog.removeWhenRejected = false; renameDialog.open(); renameDialog.selectText(); }
},
Button
{
text: catalog.i18nc("@action:button", "Import");
iconName: "document-import";
onClicked: importDialog.open();
},
Button
{
text: catalog.i18nc("@action:button", "Export")
iconName: "document-export"
onClicked: exportDialog.open()
enabled: currentItem != null
} }
base.selectContainer(selectedContainer); ]
renameDialog.removeWhenRejected = true;
renameDialog.open();
renameDialog.selectText();
}
onRemoveObject: confirmDialog.open();
onRenameObject: { renameDialog.removeWhenRejected = false; renameDialog.open(); renameDialog.selectText(); }
activateEnabled: currentItem != null ? currentItem.id != Cura.MachineManager.activeQualityId : false;
addEnabled: currentItem != null;
removeEnabled: currentItem != null ? !currentItem.readOnly : false;
renameEnabled: currentItem != null ? !currentItem.readOnly : false;
scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName) scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName)
@ -211,24 +245,6 @@ UM.ManagementPage
} }
} }
buttons: Row {
Button
{
text: catalog.i18nc("@action:button", "Import");
iconName: "document-import";
onClicked: importDialog.open();
}
Button
{
text: catalog.i18nc("@action:button", "Export")
iconName: "document-export"
onClicked: exportDialog.open()
enabled: currentItem != null
}
}
Item Item
{ {
UM.I18nCatalog { id: catalog; name: "uranium"; } UM.I18nCatalog { id: catalog; name: "uranium"; }

View file

@ -0,0 +1,52 @@
// Copyright (c) 2016 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.2
Item
{
id: base
property alias value: spinBox.value
property alias minimumValue: spinBox.minimumValue
property alias maximumValue: spinBox.maximumValue
property alias stepSize: spinBox.stepSize
property alias prefix: spinBox.prefix
property alias suffix: spinBox.suffix
property alias decimals: spinBox.decimals
signal editingFinished();
property bool readOnly: false
width: spinBox.width
height: spinBox.height
SpinBox
{
id: spinBox
enabled: !base.readOnly
opacity: base.readOnly ? 0.5 : 1.0
anchors.fill: parent
onEditingFinished: base.editingFinished()
}
Label
{
visible: base.readOnly
text: base.prefix + base.value.toFixed(spinBox.decimals) + base.suffix
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: spinBox.__style ? spinBox.__style.padding.left : 0
color: palette.buttonText
}
SystemPalette { id: palette }
}

View file

@ -0,0 +1,46 @@
// Copyright (c) 2016 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.2
Item
{
id: base
property alias text: textArea.text
property alias wrapMode: textArea.wrapMode
signal editingFinished();
property bool readOnly: false
width: textArea.width
height: textArea.height
TextArea
{
id: textArea
enabled: !base.readOnly
opacity: base.readOnly ? 0.5 : 1.0
anchors.fill: parent
onEditingFinished: base.editingFinished()
}
Label
{
visible: base.readOnly
text: textArea.text
anchors.fill: parent
anchors.margins: textArea.__style ? textArea.__style.textMargin : 4
color: palette.buttonText
}
SystemPalette { id: palette }
}

View file

@ -0,0 +1,46 @@
// Copyright (c) 2016 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.2
Item
{
id: base
property alias text: textField.text
signal editingFinished();
property bool readOnly: false
width: textField.width
height: textField.height
TextField
{
id: textField
enabled: !base.readOnly
opacity: base.readOnly ? 0.5 : 1.0
anchors.fill: parent
onEditingFinished: base.editingFinished()
}
Label
{
visible: base.readOnly
text: textField.text
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: textField.__panel ? textField.__panel.leftMargin : 0
color: palette.buttonText
}
SystemPalette { id: palette }
}

View file

@ -0,0 +1,118 @@
// Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Column
{
id: printMonitor
Loader
{
sourceComponent: monitorSection
property string label: catalog.i18nc("@label", "Temperatures")
}
Repeater
{
model: machineExtruderCount.properties.value
delegate: Loader
{
sourceComponent: monitorItem
property string label: machineExtruderCount.properties.value > 1 ? catalog.i18nc("@label", "Hotend Temperature %1").arg(index + 1) : catalog.i18nc("@label", "Hotend Temperature")
property string value: printerConnected ? Math.round(Cura.MachineManager.printerOutputDevices[0].hotendTemperatures[index]) + "°C" : ""
}
}
Repeater
{
model: machineHeatedBed.properties.value == "True" ? 1 : 0
delegate: Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Bed Temperature")
property string value: printerConnected ? Math.round(Cura.MachineManager.printerOutputDevices[0].bedTemperature) + "°C" : ""
}
}
Loader
{
sourceComponent: monitorSection
property string label: catalog.i18nc("@label", "Active print")
}
Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Job Name")
property string value: printerConnected ? Cura.MachineManager.printerOutputDevices[0].jobName : ""
}
Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Printing Time")
property string value: printerConnected ? getPrettyTime(Cura.MachineManager.printerOutputDevices[0].timeTotal) : ""
}
Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Estimated time left")
property string value: printerConnected ? getPrettyTime(Cura.MachineManager.printerOutputDevices[0].timeTotal - Cura.MachineManager.printerOutputDevices[0].timeElapsed) : ""
}
Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Current Layer")
property string value: printerConnected ? "0" : ""
}
Component
{
id: monitorItem
Row
{
height: UM.Theme.getSize("setting_control").height
Label
{
text: label
color: printerConnected ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
width: base.width * 0.4
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
}
Label
{
text: value
color: printerConnected ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
anchors.verticalCenter: parent.verticalCenter
}
}
}
Component
{
id: monitorSection
Rectangle
{
color: UM.Theme.getColor("setting_category")
width: base.width - 2 * UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("section").height
Label
{
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
text: label
font: UM.Theme.getFont("setting_category")
color: UM.Theme.getColor("setting_category_text")
}
}
}
}

View file

@ -285,122 +285,16 @@ Rectangle
} }
} }
// Item that shows the print monitor properties Loader
Column
{ {
id: printMonitor
anchors.bottom: footerSeparator.top anchors.bottom: footerSeparator.top
anchors.top: monitorLabel.bottom anchors.top: monitorLabel.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: base.left anchors.left: base.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: base.right anchors.right: base.right
visible: monitoringPrint source: monitoringPrint ? "PrintMonitor.qml": "SidebarContents.qml"
}
Loader
{
sourceComponent: monitorSection
property string label: catalog.i18nc("@label", "Temperatures")
}
Repeater
{
model: machineExtruderCount.properties.value
delegate: Loader
{
sourceComponent: monitorItem
property string label: machineExtruderCount.properties.value > 1 ? catalog.i18nc("@label", "Hotend Temperature %1").arg(index + 1) : catalog.i18nc("@label", "Hotend Temperature")
property string value: printerConnected ? Math.round(Cura.MachineManager.printerOutputDevices[0].hotendTemperatures[index]) + "°C" : ""
}
}
Repeater
{
model: machineHeatedBed.properties.value == "True" ? 1 : 0
delegate: Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Bed Temperature")
property string value: printerConnected ? Math.round(Cura.MachineManager.printerOutputDevices[0].bedTemperature) + "°C" : ""
}
}
Loader
{
sourceComponent: monitorSection
property string label: catalog.i18nc("@label", "Active print")
}
Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Job Name")
property string value: printerConnected ? Cura.MachineManager.printerOutputDevices[0].jobName : ""
}
Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Printing Time")
property string value: printerConnected ? getPrettyTime(Cura.MachineManager.printerOutputDevices[0].timeTotal) : ""
}
Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Estimated time left")
property string value: printerConnected ? getPrettyTime(Cura.MachineManager.printerOutputDevices[0].timeTotal - Cura.MachineManager.printerOutputDevices[0].timeElapsed) : ""
}
Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Current Layer")
property string value: printerConnected ? "0" : ""
}
Component
{
id: monitorItem
Row
{
height: UM.Theme.getSize("setting_control").height
Label
{
text: label
color: printerConnected ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
width: base.width * 0.4
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
}
Label
{
text: value
color: printerConnected ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
anchors.verticalCenter: parent.verticalCenter
}
}
}
Component
{
id: monitorSection
Rectangle
{
color: UM.Theme.getColor("setting_category")
width: base.width - 2 * UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("section").height
Label
{
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
text: label
font: UM.Theme.getFont("setting_category")
color: UM.Theme.getColor("setting_category_text")
}
}
}
}
Rectangle Rectangle
{ {

View file

@ -0,0 +1,43 @@
// Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
StackView
{
id: sidebarContents
delegate: StackViewDelegate
{
function transitionFinished(properties)
{
properties.exitItem.opacity = 1
}
pushTransition: StackViewTransition
{
PropertyAnimation
{
target: enterItem
property: "opacity"
from: 0
to: 1
duration: 100
}
PropertyAnimation
{
target: exitItem
property: "opacity"
from: 1
to: 0
duration: 100
}
}
}
}

View file

@ -8,6 +8,8 @@ import QtQuick.Controls.Styles 1.1
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
import "Menus"
Column Column
{ {
id: base; id: base;
@ -56,34 +58,7 @@ Column
width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width
menu: Menu menu: PrinterMenu { }
{
id: machineSelectionMenu
Instantiator
{
model: UM.ContainerStacksModel
{
filter: {"type": "machine"}
}
MenuItem
{
text: model.name;
checkable: true;
checked: Cura.MachineManager.activeMachineId == model.id
exclusiveGroup: machineSelectionMenuGroup;
onTriggered: Cura.MachineManager.setActiveMachine(model.id);
}
onObjectAdded: machineSelectionMenu.insertItem(index, object)
onObjectRemoved: machineSelectionMenu.removeItem(object)
}
ExclusiveGroup { id: machineSelectionMenuGroup; }
MenuSeparator { }
MenuItem { action: Cura.Actions.addMachine; }
MenuItem { action: Cura.Actions.configureMachines; }
}
} }
} }
@ -236,37 +211,7 @@ Column
anchors.left: parent.left anchors.left: parent.left
style: UM.Theme.styles.sidebar_header_button style: UM.Theme.styles.sidebar_header_button
menu: Menu menu: NozzleMenu { }
{
id: variantsSelectionMenu
Instantiator
{
id: variantSelectionInstantiator
model: UM.InstanceContainersModel
{
filter:
{
"type": "variant",
"definition": Cura.MachineManager.activeDefinitionId //Only show variants of this machine
}
}
MenuItem
{
text: model.name;
checkable: true;
checked: model.id == Cura.MachineManager.activeVariantId;
exclusiveGroup: variantSelectionMenuGroup;
onTriggered:
{
Cura.MachineManager.setActiveVariant(model.id);
}
}
onObjectAdded: variantsSelectionMenu.insertItem(index, object)
onObjectRemoved: variantsSelectionMenu.removeItem(object)
}
ExclusiveGroup { id: variantSelectionMenuGroup; }
}
} }
ToolButton { ToolButton {
@ -281,49 +226,7 @@ Column
anchors.right: parent.right anchors.right: parent.right
style: UM.Theme.styles.sidebar_header_button style: UM.Theme.styles.sidebar_header_button
menu: Menu menu: MaterialMenu { }
{
id: materialSelectionMenu
Instantiator
{
id: materialSelectionInstantiator
model: UM.InstanceContainersModel
{
filter:
{
var result = { "type": "material" }
if(Cura.MachineManager.filterMaterialsByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId
if(Cura.MachineManager.hasVariants)
{
result.variant = Cura.MachineManager.activeVariantId
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}
MenuItem
{
text: model.name;
checkable: true;
checked: model.id == Cura.MachineManager.activeMaterialId;
exclusiveGroup: materialSelectionMenuGroup;
onTriggered:
{
Cura.MachineManager.setActiveMaterial(model.id);
}
}
onObjectAdded: materialSelectionMenu.insertItem(index, object)
onObjectRemoved: materialSelectionMenu.removeItem(object)
}
ExclusiveGroup { id: materialSelectionMenuGroup; }
}
} }
} }
} }
@ -360,88 +263,7 @@ Column
tooltip: Cura.MachineManager.activeQualityName tooltip: Cura.MachineManager.activeQualityName
style: UM.Theme.styles.sidebar_header_button style: UM.Theme.styles.sidebar_header_button
menu: Menu menu: ProfileMenu { }
{
id: profileSelectionMenu
Instantiator
{
id: profileSelectionInstantiator
model: UM.InstanceContainersModel
{
filter:
{
var result = { "type": "quality" };
if(Cura.MachineManager.filterQualityByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId;
if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}
property int separatorIndex: -1
Loader {
property QtObject model_data: model
property int model_index: index
sourceComponent: menuItemDelegate
}
onObjectAdded:
{
//Insert a separator between readonly and custom profiles
if(separatorIndex < 0 && index > 0)
{
if(model.getItem(index-1).readOnly != model.getItem(index).readOnly)
{
profileSelectionMenu.insertSeparator(index);
separatorIndex = index;
}
}
//Because of the separator, custom profiles move one index lower
profileSelectionMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item);
}
onObjectRemoved:
{
//When adding a profile, the menu is rebuilt by removing all items.
//If a separator was added, we need to remove that too.
if(separatorIndex >= 0)
{
profileSelectionMenu.removeItem(profileSelectionMenu.items[separatorIndex])
separatorIndex = -1;
}
profileSelectionMenu.removeItem(object.item);
}
}
ExclusiveGroup { id: profileSelectionMenuGroup; }
Component
{
id: menuItemDelegate
MenuItem
{
id: item
text: model_data ? model_data.name : ""
checkable: true
checked: model_data != null ? Cura.MachineManager.activeQualityId == model_data.id : false
exclusiveGroup: profileSelectionMenuGroup;
onTriggered: Cura.MachineManager.setActiveQuality(model_data.id)
}
}
MenuSeparator { }
MenuItem { action: Cura.Actions.addProfile }
MenuItem { action: Cura.Actions.updateProfile }
MenuItem { action: Cura.Actions.resetProfile }
MenuSeparator { }
MenuItem { action: Cura.Actions.manageProfiles }
}
UM.SimpleButton UM.SimpleButton
{ {