diff --git a/.gitignore b/.gitignore
index 72ba4bf565..cc21d3092c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@ docs/html
*.log
resources/i18n/en
resources/i18n/x-test
+resources/firmware
# Editors and IDEs.
*kdev*
@@ -15,3 +16,8 @@ resources/i18n/x-test
*~
*.qm
.idea
+.project
+.pydevproject
+
+# Debian packaging
+debian/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc9f37c76e..98dca222b4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,6 +7,7 @@ include(GNUInstallDirs)
set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository")
set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
+set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
# Macro needed to list all sub-directory of a directory.
diff --git a/cura/ConvexHullDecorator.py b/cura/ConvexHullDecorator.py
index 8fb26858a5..39cdc36232 100644
--- a/cura/ConvexHullDecorator.py
+++ b/cura/ConvexHullDecorator.py
@@ -27,7 +27,9 @@ class ConvexHullDecorator(SceneNodeDecorator):
# Keep track of the previous parent so we can clear its convex hull when the object is reparented
self._parent_node = None
- self._profile = None
+ self._global_stack = None
+ Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
+ self._onGlobalStackChanged()
#Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
#Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveMachineInstanceChanged)
#self._onActiveProfileChanged()
@@ -95,28 +97,30 @@ class ConvexHullDecorator(SceneNodeDecorator):
def setConvexHullNode(self, node):
self._convex_hull_node = node
- def _onActiveProfileChanged(self):
- if self._profile:
- self._profile.settingValueChanged.disconnect(self._onSettingValueChanged)
+ def _onSettingValueChanged(self, key, property_name):
+ if key == "print_sequence" and property_name == "value":
+ self._onChanged()
- self._profile = Application.getInstance().getMachineManager().getWorkingProfile()
-
- if self._profile:
- self._profile.settingValueChanged.connect(self._onSettingValueChanged)
-
- def _onActiveMachineInstanceChanged(self):
+ def _onChanged(self, *args):
if self._convex_hull_job:
self._convex_hull_job.cancel()
self.setConvexHull(None)
- def _onSettingValueChanged(self, setting):
- if setting == "print_sequence":
- if self._convex_hull_job:
- self._convex_hull_job.cancel()
- self.setConvexHull(None)
-
def _onParentChanged(self, node):
# Force updating the convex hull of the parent group if the object is in a group
if self._parent_node and self._parent_node.callDecoration("isGroup"):
self._parent_node.callDecoration("setConvexHull", None)
self._parent_node = self.getNode().getParent()
+
+ def _onGlobalStackChanged(self):
+ if self._global_stack:
+ self._global_stack.propertyChanged.disconnect(self._onSettingValueChanged)
+ self._global_stack.containersChanged.disconnect(self._onChanged)
+
+ self._global_stack = Application.getInstance().getGlobalContainerStack()
+
+ if self._global_stack:
+ self._global_stack.propertyChanged.connect(self._onSettingValueChanged)
+ self._global_stack.containersChanged.connect(self._onChanged)
+
+ self._onChanged()
diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py
index eccb3e4525..7edb0bf8bd 100644
--- a/cura/CuraApplication.py
+++ b/cura/CuraApplication.py
@@ -18,6 +18,7 @@ from UM.JobQueue import JobQueue
from UM.SaveFile import SaveFile
from UM.Scene.Selection import Selection
from UM.Scene.GroupDecorator import GroupDecorator
+import UM.Settings.Validator
from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
@@ -30,6 +31,8 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog
+from . import ExtruderManager
+from . import ExtrudersModel
from . import PlatformPhysics
from . import BuildVolume
from . import CameraAnimation
@@ -42,7 +45,7 @@ from . import MachineManagerModel
from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
from PyQt5.QtGui import QColor, QIcon
-from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType
+from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
import platform
import sys
@@ -61,9 +64,10 @@ if platform.system() == "Linux": # Needed for platform.linux_distribution, which
ctypes.CDLL(find_library('GL'), ctypes.RTLD_GLOBAL)
try:
- from cura.CuraVersion import CuraVersion
+ from cura.CuraVersion import CuraVersion, CuraBuildType
except ImportError:
CuraVersion = "master" # [CodeStyle: Reflecting imported value]
+ CuraBuildType = ""
class CuraApplication(QtApplication):
@@ -88,8 +92,9 @@ class CuraApplication(QtApplication):
# Need to do this before ContainerRegistry tries to load the machines
SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False)
+ SettingDefinition.addSettingType("extruder", int, str, UM.Settings.Validator)
- super().__init__(name = "cura", version = CuraVersion)
+ super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType)
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
@@ -128,17 +133,34 @@ class CuraApplication(QtApplication):
Resources.addStorageType(self.ResourceTypes.QualityInstanceContainer, "quality")
Resources.addStorageType(self.ResourceTypes.VariantInstanceContainer, "variants")
Resources.addStorageType(self.ResourceTypes.MaterialInstanceContainer, "materials")
- Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders")
Resources.addStorageType(self.ResourceTypes.UserInstanceContainer, "user")
+ Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders")
Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances")
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.VariantInstanceContainer)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MaterialInstanceContainer)
- ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.ExtruderStack)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.UserInstanceContainer)
+ ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.ExtruderStack)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MachineStack)
+ # Add empty variant, material and quality containers.
+ # Since they are empty, they should never be serialized and instead just programmatically created.
+ # We need them to simplify the switching between materials.
+ empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
+ empty_variant_container = copy.deepcopy(empty_container)
+ empty_variant_container._id = "empty_variant"
+ empty_variant_container.addMetaDataEntry("type", "variant")
+ ContainerRegistry.getInstance().addContainer(empty_variant_container)
+ empty_material_container = copy.deepcopy(empty_container)
+ empty_material_container._id = "empty_material"
+ empty_material_container.addMetaDataEntry("type", "material")
+ ContainerRegistry.getInstance().addContainer(empty_material_container)
+ empty_quality_container = copy.deepcopy(empty_container)
+ empty_quality_container._id = "empty_quality"
+ empty_quality_container.addMetaDataEntry("type", "quality")
+ ContainerRegistry.getInstance().addContainer(empty_quality_container)
+
ContainerRegistry.getInstance().load()
Preferences.getInstance().addPreference("cura/active_mode", "simple")
@@ -248,9 +270,15 @@ class CuraApplication(QtApplication):
continue
file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg"
- path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name)
- with SaveFile(path, "wt", -1, "utf-8") as f:
- f.write(data)
+ stack_type = stack.getMetaDataEntry("type", None)
+ path = None
+ if not stack_type or stack_type == "machine":
+ path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name)
+ elif stack_type == "extruder":
+ path = Resources.getStoragePath(self.ResourceTypes.ExtruderStack, file_name)
+ if path:
+ with SaveFile(path, "wt", -1, "utf-8") as f:
+ f.write(data)
@pyqtSlot(result = QUrl)
@@ -356,6 +384,9 @@ class CuraApplication(QtApplication):
def getPrintInformation(self):
return self._print_information
+ ## Registers objects for the QML engine to use.
+ #
+ # \param engine The QML engine.
def registerObjects(self, engine):
engine.rootContext().setContextProperty("Printer", self)
self._print_information = PrintInformation.PrintInformation()
@@ -365,6 +396,19 @@ class CuraApplication(QtApplication):
qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type")
+ qmlRegisterType(ExtrudersModel.ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
+
+ qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions")
+
+ engine.rootContext().setContextProperty("ExtruderManager", ExtruderManager.ExtruderManager.getInstance())
+
+ for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles):
+ type_name = os.path.splitext(os.path.basename(path))[0]
+ if type_name in ("Cura", "Actions"):
+ continue
+
+ qmlRegisterType(QUrl.fromLocalFile(path), "Cura", 1, 0, type_name)
+
def onSelectionChanged(self):
if Selection.hasSelection():
if not self.getController().getActiveTool():
@@ -424,21 +468,6 @@ class CuraApplication(QtApplication):
self._platform_activity = True if count > 0 else False
self.activityChanged.emit()
- @pyqtSlot(str)
- def setJobName(self, name):
- # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its
- # extension. This cuts the extension off if necessary.
- name = os.path.splitext(name)[0]
- if self._job_name != name:
- self._job_name = name
- self.jobNameChanged.emit()
-
- jobNameChanged = pyqtSignal()
-
- @pyqtProperty(str, notify = jobNameChanged)
- def jobName(self):
- return self._job_name
-
# Remove all selected objects from the scene.
@pyqtSlot()
def deleteSelection(self):
@@ -707,16 +736,18 @@ class CuraApplication(QtApplication):
def _onActiveMachineChanged(self):
pass
+ fileLoaded = pyqtSignal(str)
+
def _onFileLoaded(self, job):
node = job.getResult()
if node != None:
- self.setJobName(os.path.basename(job.getFileName()))
+ self.fileLoaded.emit(job.getFileName())
node.setSelectable(True)
node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
op.push()
- self.getController().getScene().sceneChanged.emit(node) #F orce scene change.
+ self.getController().getScene().sceneChanged.emit(node) #Force scene change.
def _onJobFinished(self, job):
if type(job) is not ReadMeshJob or not job.getResult():
diff --git a/cura/CuraSplashScreen.py b/cura/CuraSplashScreen.py
index d27c9c0240..f2810d359b 100644
--- a/cura/CuraSplashScreen.py
+++ b/cura/CuraSplashScreen.py
@@ -21,6 +21,9 @@ class CuraSplashScreen(QSplashScreen):
painter.setPen(QColor(0, 0, 0, 255))
version = Application.getInstance().getVersion().split("-")
+ buildtype = Application.getInstance().getBuildType()
+ if buildtype:
+ version[0] += " (%s)" %(buildtype)
painter.setFont(QFont("Proxima Nova Rg", 20 ))
painter.drawText(0, 0, 330 * self._scale, 230 * self._scale, Qt.AlignHCenter | Qt.AlignBottom, version[0])
diff --git a/cura/CuraVersion.py.in b/cura/CuraVersion.py.in
index bb69319ee6..5ad819b1fc 100644
--- a/cura/CuraVersion.py.in
+++ b/cura/CuraVersion.py.in
@@ -2,3 +2,4 @@
# Cura is released under the terms of the AGPLv3 or higher.
CuraVersion = "@CURA_VERSION@"
+CuraBuildType = "@CURA_BUILDTYPE@"
\ No newline at end of file
diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py
new file mode 100644
index 0000000000..df31cbacdf
--- /dev/null
+++ b/cura/ExtruderManager.py
@@ -0,0 +1,164 @@
+# Copyright (c) 2016 Ultimaker B.V.
+# Cura is released under the terms of the AGPLv3 or higher.
+
+from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For communicating data and events to Qt.
+
+import UM.Application #To get the global container stack to find the current machine.
+import UM.Logger
+import UM.Settings.ContainerRegistry #Finding containers by ID.
+
+
+## Manages all existing extruder stacks.
+#
+# This keeps a list of extruder stacks for each machine.
+class ExtruderManager(QObject):
+ ## Signal to notify other components when the list of extruders changes.
+ extrudersChanged = pyqtSignal()
+
+ ## Notify when the user switches the currently active extruder.
+ activeExtruderChanged = pyqtSignal()
+
+ ## Registers listeners and such to listen to changes to the extruders.
+ def __init__(self, parent = None):
+ super().__init__(parent)
+ self._extruder_trains = { } #Extruders for the current machine.
+ self._active_extruder_index = 0
+
+ ## Gets the unique identifier of the currently active extruder stack.
+ #
+ # The currently active extruder stack is the stack that is currently being
+ # edited.
+ #
+ # \return The unique ID of the currently active extruder stack.
+ @pyqtProperty(str, notify = activeExtruderChanged)
+ def activeExtruderStackId(self):
+ if not UM.Application.getInstance().getGlobalContainerStack():
+ return None #No active machine, so no active extruder.
+ try:
+ return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)]
+ except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
+ return None
+
+ __instance = None
+ @classmethod
+ def getInstance(cls):
+ if not cls.__instance:
+ cls.__instance = ExtruderManager()
+ return cls.__instance
+
+ @pyqtSlot(int)
+ def setActiveExtruderIndex(self, index):
+ self._active_extruder_index = index
+ self.activeExtruderChanged.emit()
+
+ ## Adds all extruders of a specific machine definition to the extruder
+ # manager.
+ #
+ # \param machine_definition The machine to add the extruders for.
+ def addMachineExtruders(self, machine_definition):
+ machine_id = machine_definition.getId()
+ if machine_id not in self._extruder_trains:
+ self._extruder_trains[machine_id] = { }
+
+ container_registry = UM.Settings.ContainerRegistry.getInstance()
+ if not container_registry: #Then we shouldn't have any machine definition either. In any case, there are no extruder trains then so bye bye.
+ return
+
+ #Add the extruder trains that don't exist yet.
+ for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition.getId()):
+ position = extruder_definition.getMetaDataEntry("position", None)
+ if not position:
+ UM.Logger.Log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId())
+ if not container_registry.findContainerStacks(machine = machine_id, position = position): #Doesn't exist yet.
+ name = container_registry.uniqueName(extruder_definition.getId()) #Make a name based on the ID of the definition.
+ self.createExtruderTrain(extruder_definition, machine_definition, name, position)
+
+ #Gets the extruder trains that we just created as well as any that still existed.
+ extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_definition.getId())
+ for extruder_train in extruder_trains:
+ self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId()
+ if extruder_trains:
+ self.extrudersChanged.emit()
+
+ ## (Re)populates the collections of extruders by machine.
+ def _repopulate(self):
+ self._extruder_trains = { }
+ if not UM.Application.getInstance().getGlobalContainerStack(): #No machine has been added yet.
+ self.extrudersChanged.emit() #Yes, we just cleared the _extruders list!
+ return #Then leave them empty!
+
+ extruder_trains = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "extruder_train")
+ for extruder_train in extruder_trains:
+ machine_id = extruder_train.getMetaDataEntry("machine")
+ if not machine_id:
+ continue
+ if machine_id not in self._extruder_trains:
+ self._extruder_trains[machine_id] = { }
+ self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId()
+ self.extrudersChanged.emit()
+
+ def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position):
+ container_registry = UM.Settings.ContainerRegistry.getInstance()
+
+ #Create a container stack for this extruder.
+ container_stack = UM.Settings.ContainerStack(extruder_train_id)
+ container_stack.addMetaDataEntry("type", "extruder_train")
+ container_stack.addMetaDataEntry("machine", machine_definition.getId())
+ container_stack.addMetaDataEntry("position", position)
+ container_stack.addContainer(extruder_definition)
+
+ """
+ Yes, I'm committing this code which needs to be transformed to work later.
+ #Find the nozzle to use for this extruder.
+ nozzle = container_registry.getEmptyInstanceContainer()
+ if definition.getMetaDataEntry("has_nozzles", default = "False") == "True":
+ if len(self._nozzles) >= 1: #First add any extruder. Later, overwrite with preference if the preference is valid.
+ self._nozzle = self._nozzles[0]
+ preferred_nozzle_id = definition.getMetaDataEntry("preferred_nozzle")
+ if preferred_nozzle_id:
+ for nozzle in self._nozzles:
+ if nozzle.getId() == preferred_nozzle_id:
+ self._nozzle = nozzle
+ break
+ self._container_stack.addContainer(self._nozzle)
+
+ #Find a material to use for this nozzle.
+ self._material = container_registry.getEmptyInstanceContainer()
+ if self._definition.getMetaDataEntry("has_materials", default = "False") == "True":
+ if self._definition.getMetaDataEntry("has_nozzle_materials", default = "False") == "True":
+ all_materials = container_registry.findInstanceContainers(type = "material", nozzle = self._nozzle.getId())
+ else:
+ all_materials = container_registry.findInstanceContainers(type = "material")
+ if len(all_materials) >= 1:
+ self._material = all_materials[0]
+ preferred_material_id = self._definition.getMetaDataEntry("preferred_material")
+ if preferred_material_id:
+ preferred_material = container_registry.findInstanceContainers(type = "material", id = preferred_material_id.lower())
+ if len(preferred_material) >= 1:
+ self._material = preferred_material[0]
+ self._container_stack.addContainer(self._material)
+
+ #Find a quality to use for this extruder.
+ self._quality = container_registry.getEmptyInstanceContainer()
+ if self._definition.getMetaDataEntry("has_machine_quality"):
+ all_qualities = container_registry.findInstanceContainers(type = "quality")
+ if len(all_qualities) >= 1:
+ self._quality = all_qualities[0]
+ preferred_quality_id = self._definition.getMetaDataEntry("preferred_quality")
+ if preferred_quality_id:
+ preferred_quality = container_registry.findInstanceContainers(type = "quality", id = preferred_quality_id.lower())
+ if len(preferred_quality) >= 1:
+ self._quality = preferred_quality[0]
+ self._container_stack.addContainer(self._quality)
+ """
+
+ #Add an empty user profile.
+ user_profile = UM.Settings.InstanceContainer(extruder_train_id + "_current_settings")
+ user_profile.addMetaDataEntry("type", "user")
+ user_profile.setDefinition(machine_definition)
+ container_stack.addContainer(user_profile)
+ container_registry.addContainer(user_profile)
+
+ container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack())
+
+ container_registry.addContainer(container_stack)
diff --git a/cura/ExtruderManagerModel.py b/cura/ExtruderManagerModel.py
deleted file mode 100644
index 7f0baa7aa8..0000000000
--- a/cura/ExtruderManagerModel.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright (c) 2016 Ultimaker B.V.
-# Cura is released under the terms of the AGPLv3 or higher.
-
-from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
-import re
-
-from UM.Application import Application #To get the global container stack to find the current machine.
-from UM.Logger import Logger
-from UM.Settings.ContainerStack import ContainerStack #To create container stacks for each extruder.
-from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID.
-
-
-## Class that handles the current extruder stack.
-#
-# This finds the extruders that are available for the currently active machine
-# and makes sure that whenever the machine is swapped, this list is kept up to
-# date. It also contains and updates the setting stacks for the extruders.
-class ExtruderManagerModel(QObject):
- ## Registers listeners and such to listen to changes to the extruders.
- #
- # \param parent Parent QObject of this model.
- def __init__(self, parent = None):
- super().__init__(parent)
-
- self._extruderDefinitions = [] #Extruder definitions for the current machine.
- self._nozzles = {} #Nozzle instances for each extruder.
- self._extruderTrains = [] #Container stacks for each of the extruder trains.
-
- Application.getInstance().getGlobalContainerStack().containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine.
-
- ## (Re)loads all extruders of the currently active machine.
- #
- # This looks at the global container stack to see which machine is active.
- # Then it loads the extruder definitions for that machine and the variants
- # of those definitions. Then it puts the new extruder definitions in the
- # appropriate place in the container stacks.
- def _reloadExtruders(self):
- self._extruderDefinitions = []
- self._nozzles = {}
- self._extruderTrains = []
- global_container_stack = Application.getInstance().getGlobalContainerStack()
- if not global_container_stack: #No machine has been added yet.
- return #Then leave them empty!
-
- #Fill the list of extruder trains.
- machine = global_container_stack.getBottom()
- extruder_train_ids = machine.getMetaData("machine_extruder_trains")
- for extruder_train_id in extruder_train_ids:
- extruders = ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway.
- if not extruders: #Empty list or error.
- Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id)
- continue
- self._extruderDefinitions += extruders
-
- #Fill the nozzles for each of the extruder trains.
- for extruder in self._extruderDefinitions:
- self._nozzles[extruder.id] = []
- all_nozzles = ContainerRegistry.getInstance().findInstanceContainers(type="nozzle")
- for nozzle in all_nozzles:
- extruders = nozzle.getMetaDataEntry("definitions").split(",").strip()
- for extruder_id in extruders:
- self._nozzles[extruder_id] = nozzle
-
- #Create the extruder train container stacks.
- for extruder in self._extruderDefinitions:
- self._extruderTrains.append(self._createContainerStack(extruder))
-
- ## Creates a container stack for the specified extruder.
- #
- # This fills in the specified extruder as base definition, then a nozzle
- # that fits in that extruder train, then a material that fits through that
- # nozzle, then a quality profile that can be used with that material, and
- # finally an empty user profile.
- #
- # \param extruder The extruder to create the container stack for.
- # \return A container stack with the specified extruder as base.
- def _createContainerStack(self, extruder):
- container_stack = ContainerStack(self._uniqueName(extruder))
- #TODO: Fill the container stack.
- return container_stack
-
- ## Finds a unique name for an extruder stack.
- #
- # \param extruder Extruder to design a name for.
- # \return A name for an extruder stack that is unique and reasonably
- # human-readable.
- def _uniqueName(self, extruder):
- container_registry = ContainerRegistry.getInstance()
-
- name = extruder.getName().strip()
- num_check = re.compile("(.*?)\s*#\d$").match(name)
- if(num_check): #There is a number in the name.
- name = num_check.group(1) #Filter out the number.
- if name == "": #Wait, that deleted everything!
- name = "Extruder"
- unique_name = name
-
- i = 1
- while(container_registry.findContainers(id = unique_name) or container_registry.findContainers(name = unique_name)): #A container already has this name.
- i += 1 #Try next numbering.
- unique_name = "%s #%d" % (name, i) #Fill name like this: "Extruder #2".
- return unique_name
\ No newline at end of file
diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py
new file mode 100644
index 0000000000..7e00611742
--- /dev/null
+++ b/cura/ExtrudersModel.py
@@ -0,0 +1,56 @@
+# Copyright (c) 2016 Ultimaker B.V.
+# Cura is released under the terms of the AGPLv3 or higher.
+
+from PyQt5.QtCore import Qt
+
+import cura.ExtruderManager
+import UM.Qt.ListModel
+
+## Model that holds extruders.
+#
+# This model is designed for use by any list of extruders, but specifically
+# intended for drop-down lists of extruders in place of settings.
+class ExtrudersModel(UM.Qt.ListModel.ListModel):
+ ## Human-readable name of the extruder.
+ NameRole = Qt.UserRole + 1
+
+ ## Colour of the material loaded in the extruder.
+ ColourRole = Qt.UserRole + 2
+
+ ## Index of the extruder, which is also the value of the setting itself.
+ #
+ # An index of 0 indicates the first extruder, an index of 1 the second
+ # one, and so on. This is the value that will be saved in instance
+ # containers.
+ IndexRole = Qt.UserRole + 3
+
+ ## Initialises the extruders model, defining the roles and listening for
+ # changes in the data.
+ #
+ # \param parent Parent QtObject of this list.
+ def __init__(self, parent = None):
+ super().__init__(parent)
+
+ self.addRoleName(self.NameRole, "name")
+ self.addRoleName(self.ColourRole, "colour")
+ self.addRoleName(self.IndexRole, "index")
+
+ #Listen to changes.
+ manager = cura.ExtruderManager.ExtruderManager.getInstance()
+ manager.extrudersChanged.connect(self._updateExtruders)
+ self._updateExtruders()
+
+ ## Update the list of extruders.
+ #
+ # This should be called whenever the list of extruders changes.
+ def _updateExtruders(self):
+ self.clear()
+ manager = cura.ExtruderManager.ExtruderManager.getInstance()
+ for index, extruder in enumerate(manager._extruder_trains):
+ item = { #Construct an item with only the relevant information.
+ "name": extruder.name,
+ "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"),
+ "index": index
+ }
+ self.appendItem(item)
+ self.sort(lambda item: item["index"])
\ No newline at end of file
diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py
index deef72529b..02d8db8290 100644
--- a/cura/MachineManagerModel.py
+++ b/cura/MachineManagerModel.py
@@ -1,11 +1,18 @@
+import re
+
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
from UM.Application import Application
from UM.Preferences import Preferences
+from UM.Logger import Logger
import UM.Settings
-
-import re
+from UM.Settings.Validator import ValidatorState
+from UM.Settings.InstanceContainer import InstanceContainer
+from UM.Settings.ContainerStack import ContainerStack
+from . import ExtruderManager
+from UM.i18n import i18nCatalog
+catalog = i18nCatalog("cura")
class MachineManagerModel(QObject):
def __init__(self, parent = None):
@@ -13,6 +20,7 @@ class MachineManagerModel(QObject):
self._global_container_stack = None
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
+ self._global_stack_valid = None
self._onGlobalContainerChanged()
## When the global container is changed, active material probably needs to be updated.
@@ -20,10 +28,16 @@ class MachineManagerModel(QObject):
self.globalContainerChanged.connect(self.activeVariantChanged)
self.globalContainerChanged.connect(self.activeQualityChanged)
+ 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_quality_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality")[0]
+
Preferences.getInstance().addPreference("cura/active_machine", "")
active_machine_id = Preferences.getInstance().getValue("cura/active_machine")
+ self._active_extruder_index = 0
+
if active_machine_id != "":
# An active machine was saved, so restore it.
self.setActiveMachine(active_machine_id)
@@ -35,9 +49,37 @@ class MachineManagerModel(QObject):
activeVariantChanged = pyqtSignal()
activeQualityChanged = pyqtSignal()
+ globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed.
+ globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed.
+
+ @pyqtProperty("QVariantMap", notify = globalContainerChanged)
+ def extrudersIds(self):
+ ## Find all extruders that reference the new stack
+ extruders = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(**{"machine": self._global_container_stack.getId()})
+ result = {}
+ for extruder in extruders:
+ result[extruder.getMetaDataEntry("position")] = extruder.getId()
+ return result
+
+ def _onGlobalPropertyChanged(self, key, property_name):
+ if property_name == "value":
+ self.globalValueChanged.emit()
+ if property_name == "validationState":
+ if self._global_stack_valid:
+ changed_validation_state = self._global_container_stack.getProperty(key, property_name)
+ if changed_validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
+ self._global_stack_valid = False
+ self.globalValidationChanged.emit()
+ else:
+ new_validation_state = self._checkStackForErrors(self._global_container_stack)
+ if new_validation_state:
+ self._global_stack_valid = True
+ self.globalValidationChanged.emit()
+
def _onGlobalContainerChanged(self):
if self._global_container_stack:
self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
+ self._global_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged)
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
self.globalContainerChanged.emit()
@@ -45,6 +87,8 @@ class MachineManagerModel(QObject):
if self._global_container_stack:
Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId())
self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
+ self._global_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged)
+ self._global_stack_valid = not self._checkStackForErrors(self._global_container_stack)
def _onInstanceContainersChanged(self, container):
container_type = container.getMetaDataEntry("type")
@@ -62,55 +106,18 @@ class MachineManagerModel(QObject):
Application.getInstance().setGlobalContainerStack(containers[0])
@pyqtSlot(str, str)
- def addMachine(self,name, definition_id):
+ def addMachine(self, name, definition_id):
definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id)
if definitions:
definition = definitions[0]
- name = self._uniqueMachineName(name, definition.getName())
-
+ name = self._createUniqueName("machine", "", name, definition.getName())
new_global_stack = UM.Settings.ContainerStack(name)
new_global_stack.addMetaDataEntry("type", "machine")
UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack)
- empty_container = UM.Settings.ContainerRegistry.getInstance().getEmptyInstanceContainer()
-
- variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id)
- if variants:
- new_global_stack.addMetaDataEntry("has_variants", True)
-
- preferred_variant_id = definitions[0].getMetaDataEntry("preferred_variant")
- variant_instance_container = empty_container
- if preferred_variant_id:
- preferred_variant_id = preferred_variant_id.lower()
- container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id)
- if container:
- variant_instance_container = container[0]
-
- if variants and variant_instance_container == empty_container:
- variant_instance_container = variants[0]
-
- materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id)
- if materials:
- new_global_stack.addMetaDataEntry("has_materials", True)
-
- preferred_material_id = definitions[0].getMetaDataEntry("preferred_material")
- material_instance_container = empty_container
- if preferred_material_id:
- preferred_material_id = preferred_material_id.lower()
- container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_material_id)
- if container:
- material_instance_container = container[0]
-
- if materials and material_instance_container == empty_container:
- material_instance_container = materials[0]
-
- preferred_quality_id = definitions[0].getMetaDataEntry("preferred_quality")
- quality_instance_container = empty_container
- if preferred_quality_id:
- preferred_quality_id = preferred_quality_id.lower()
- container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_quality_id)
- if container:
- quality_instance_container = container[0]
+ variant_instance_container = self._updateVariantContainer(definition)
+ material_instance_container = self._updateMaterialContainer(definition)
+ quality_instance_container = self._updateQualityContainer(definition)
current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings")
current_settings_instance_container.addMetaDataEntry("machine", name)
@@ -119,7 +126,7 @@ class MachineManagerModel(QObject):
UM.Settings.ContainerRegistry.getInstance().addContainer(current_settings_instance_container)
# If a definition is found, its a list. Should only have one item.
- new_global_stack.addContainer(definitions[0])
+ new_global_stack.addContainer(definition)
if variant_instance_container:
new_global_stack.addContainer(variant_instance_container)
if material_instance_container:
@@ -128,27 +135,78 @@ class MachineManagerModel(QObject):
new_global_stack.addContainer(quality_instance_container)
new_global_stack.addContainer(current_settings_instance_container)
+ ExtruderManager.ExtruderManager.getInstance().addMachineExtruders(definition)
+
Application.getInstance().setGlobalContainerStack(new_global_stack)
- # Create a name that is not empty and unique
- def _uniqueMachineName(self, name, fallback_name):
- name = name.strip()
- num_check = re.compile("(.*?)\s*#\d$").match(name)
- if(num_check):
- name = num_check.group(1)
- if name == "":
- name = fallback_name
- unique_name = name
- i = 1
+ ## Create a name that is not empty and unique
+ # \param container_type \type{string} Type of the container (machine, quality, ...)
+ # \param current_name \type{} Current name of the container, which may be an acceptable option
+ # \param new_name \type{string} Base name, which may not be unique
+ # \param fallback_name \type{string} Name to use when (stripped) new_name is empty
+ # \return \type{string} Name that is unique for the specified type and name/id
+ def _createUniqueName(self, container_type, current_name, new_name, fallback_name):
+ new_name = new_name.strip()
+ num_check = re.compile("(.*?)\s*#\d+$").match(new_name)
+ if num_check:
+ new_name = num_check.group(1)
+ if new_name == "":
+ new_name = fallback_name
- #Check both the id and the name, because they may not be the same and it is better if they are both unique
- while UM.Settings.ContainerRegistry.getInstance().findContainers(None, id = unique_name) or \
- UM.Settings.ContainerRegistry.getInstance().findContainers(None, name = unique_name):
- i = i + 1
- unique_name = "%s #%d" % (name, i)
+ unique_name = new_name
+ i = 1
+ # In case we are renaming, the current name of the container is also a valid end-result
+ while self._containerExists(container_type, unique_name) and unique_name != current_name:
+ i += 1
+ unique_name = "%s #%d" % (new_name, i)
return unique_name
+ ## Check if a container with of a certain type and a certain name or id exists
+ # Both the id and the name are checked, because they may not be the same and it is better if they are both unique
+ # \param container_type \type{string} Type of the container (machine, quality, ...)
+ # \param container_name \type{string} Name to check
+ def _containerExists(self, container_type, container_name):
+ container_class = ContainerStack if container_type == "machine" else InstanceContainer
+
+ return UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = container_name, type = container_type) or \
+ UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = container_name, type = container_type)
+
+ ## Convenience function to check if a stack has errors.
+ def _checkStackForErrors(self, stack):
+ if stack is None:
+ return False
+
+ for key in stack.getAllKeys():
+ validation_state = stack.getProperty(key, "validationState")
+ if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
+ return True
+ return False
+
+ ## Remove all instances from the top instanceContainer (effectively removing all user-changed settings)
+ @pyqtSlot()
+ def clearUserSettings(self):
+ if not self._global_container_stack:
+ return
+ user_settings = self._global_container_stack.getTop()
+ user_settings.clear()
+
+ ## Check if the global_container has instances in the user container
+ @pyqtProperty(bool, notify = globalValueChanged)
+ def hasUserSettings(self):
+ if not self._global_container_stack:
+ return
+
+ user_settings = self._global_container_stack.getTop().findInstances(**{})
+ return len(user_settings) != 0
+
+ ## Check if the global profile does not contain error states
+ # Note that the _global_stack_valid is cached due to performance issues
+ # Calling _checkStackForErrors on every change is simply too expensive
+ @pyqtProperty(bool, notify = globalValidationChanged)
+ def isGlobalStackValid(self):
+ return self._global_stack_valid
+
@pyqtProperty(str, notify = globalContainerChanged)
def activeMachineName(self):
if self._global_container_stack:
@@ -197,6 +255,104 @@ class MachineManagerModel(QObject):
return quality.getId()
return ""
+ ## Check if a container is read_only
+ @pyqtSlot(str, result = bool)
+ def isReadOnly(self, container_id):
+ containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id)
+ if not containers or not self._global_container_stack:
+ return True
+ return containers[0].getMetaDataEntry("read_only", False) == "True"
+
+ @pyqtSlot(result = str)
+ def convertUserContainerToQuality(self):
+ if not self._global_container_stack:
+ return
+
+ new_quality_container = InstanceContainer("")
+ name = self._createUniqueName("quality", "", self.activeQualityName, catalog.i18nc("@label", "Custom profile"))
+ user_settings = self._global_container_stack.getTop()
+
+ ## Copy all values
+ new_quality_container.deserialize(user_settings.serialize())
+
+ ## If the currently active machine does not have quality profiles of its own,
+ # make the new quality profile available for all machines that don't have
+ # unique quality profiles (including the current machine)
+ if not self.filterQualityByMachine:
+ new_quality_container.setDefinition(UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter")[0])
+
+ ## Change type / id / name
+ new_quality_container.setMetaDataEntry("type", "quality")
+ new_quality_container.setMetaDataEntry("read_only", False)
+ new_quality_container.setName(name)
+ new_quality_container._id = name
+
+ UM.Settings.ContainerRegistry.getInstance().addContainer(new_quality_container)
+ self.clearUserSettings() # As all users settings are now transfered to the new quality profile, remove them.
+ self.setActiveQuality(name)
+ return name
+
+ @pyqtSlot(str, result=str)
+ def duplicateContainer(self, container_id):
+ if not self._global_container_stack:
+ return
+ containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id)
+ if containers:
+ new_name = self._createUniqueName("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile"))
+
+ new_container = InstanceContainer("")
+
+ ## Copy all values
+ new_container.deserialize(containers[0].serialize())
+
+ new_container.setMetaDataEntry("read_only", False)
+ new_container.setName(new_name)
+ new_container._id = new_name
+ UM.Settings.ContainerRegistry.getInstance().addContainer(new_container)
+ return new_name
+
+ return ""
+
+
+ @pyqtSlot(str, str)
+ def renameQualityContainer(self, container_id, new_name):
+ containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality")
+ if containers:
+ new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile"))
+ containers[0].setName(new_name)
+ self.activeQualityChanged.emit()
+
+
+ @pyqtSlot(str)
+ def removeQualityContainer(self, container_id):
+ containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id)
+ if not containers or not self._global_container_stack:
+ return
+
+ # If the container that is being removed is the currently active container, set another machine as the active container
+ activate_new_container = container_id == self.activeQualityId
+
+ UM.Settings.ContainerRegistry.getInstance().removeContainer(container_id)
+
+ if activate_new_container:
+ definition_id = "fdmprinter" if not self.filterQualityByMachine else self.activeDefinitionId
+ containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition_id)
+ if containers:
+ self.setActiveQuality(containers[0].getId())
+ self.activeQualityChanged.emit()
+
+
+ @pyqtSlot()
+ def updateUserContainerToQuality(self):
+ if not self._global_container_stack:
+ return
+ user_settings = self._global_container_stack.getTop()
+ quality = self._global_container_stack.findContainer({"type": "quality"})
+ for key in user_settings.getAllKeys():
+ quality.setProperty(key, "value", user_settings.getProperty(key, "value"))
+ self.clearUserSettings() # As all users settings are noq a quality, remove them.
+
+
@pyqtSlot(str)
def setActiveMaterial(self, material_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=material_id)
@@ -208,6 +364,8 @@ class MachineManagerModel(QObject):
material_index = self._global_container_stack.getContainerIndex(old_material)
self._global_container_stack.replaceContainer(material_index, containers[0])
+ self.setActiveQuality(self._updateQualityContainer(self._global_container_stack.getBottom(), containers[0]).id)
+
@pyqtSlot(str)
def setActiveVariant(self, variant_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=variant_id)
@@ -219,6 +377,8 @@ class MachineManagerModel(QObject):
variant_index = self._global_container_stack.getContainerIndex(old_variant)
self._global_container_stack.replaceContainer(variant_index, containers[0])
+ self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), containers[0]).id)
+
@pyqtSlot(str)
def setActiveQuality(self, quality_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id)
@@ -261,32 +421,110 @@ class MachineManagerModel(QObject):
def renameMachine(self, machine_id, new_name):
containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id)
if containers:
- new_name = self._uniqueMachineName(new_name, containers[0].getBottom().getName())
+ new_name = self._createUniqueName("machine", containers[0].getName(), new_name, containers[0].getBottom().getName())
containers[0].setName(new_name)
self.globalContainerChanged.emit()
@pyqtSlot(str)
def removeMachine(self, machine_id):
# If the machine that is being removed is the currently active machine, set another machine as the active machine
- if self._global_container_stack and self._global_container_stack.getId() == machine_id:
- containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks()
- if containers:
- Application.getInstance().setGlobalContainerStack(containers[0])
+ activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id)
UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id)
+ if activate_new_machine:
+ stacks = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "machine")
+ if stacks:
+ Application.getInstance().setGlobalContainerStack(stacks[0])
+
@pyqtProperty(bool, notify = globalContainerChanged)
def hasMaterials(self):
if self._global_container_stack:
- return self._global_container_stack.getMetaDataEntry("has_materials", False)
+ return bool(self._global_container_stack.getMetaDataEntry("has_materials", False))
return False
@pyqtProperty(bool, notify = globalContainerChanged)
def hasVariants(self):
if self._global_container_stack:
- return self._global_container_stack.getMetaDataEntry("has_variants", False)
+ return bool(self._global_container_stack.getMetaDataEntry("has_variants", False))
return False
+ @pyqtProperty(bool, notify = globalContainerChanged)
+ def filterMaterialsByMachine(self):
+ if self._global_container_stack:
+ return bool(self._global_container_stack.getMetaDataEntry("has_machine_materials", False))
+
+ return False
+
+ @pyqtProperty(bool, notify = globalContainerChanged)
+ def filterQualityByMachine(self):
+ if self._global_container_stack:
+ return bool(self._global_container_stack.getMetaDataEntry("has_machine_quality", False))
+
+ return False
+
+ def _updateVariantContainer(self, definition):
+ if not definition.getMetaDataEntry("has_variants"):
+ return self._empty_variant_container
+
+ containers = []
+ preferred_variant = definition.getMetaDataEntry("preferred_variant")
+ if preferred_variant:
+ containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id, id = preferred_variant)
+
+ if not containers:
+ containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id)
+
+ if containers:
+ return containers[0]
+
+ return self._empty_variant_container
+
+ def _updateMaterialContainer(self, definition, variant_container = None):
+ if not definition.getMetaDataEntry("has_materials"):
+ return self._empty_material_container
+
+ search_criteria = { "type": "material" }
+
+ if definition.getMetaDataEntry("has_machine_materials"):
+ search_criteria["definition"] = definition.id
+
+ if definition.getMetaDataEntry("has_variants") and variant_container:
+ search_criteria["variant"] = variant_container.id
+ else:
+ search_criteria["definition"] = "fdmprinter"
+
+ preferred_material = definition.getMetaDataEntry("preferred_material")
+ if preferred_material:
+ search_criteria["id"] = preferred_material
+
+ containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
+ if containers:
+ return containers[0]
+
+ return self._empty_material_container
+
+ def _updateQualityContainer(self, definition, material_container = None):
+ search_criteria = { "type": "quality" }
+
+ if definition.getMetaDataEntry("has_machine_quality"):
+ search_criteria["definition"] = definition.id
+
+ if definition.getMetaDataEntry("has_materials") and material_container:
+ search_criteria["material"] = material_container.id
+ else:
+ search_criteria["definition"] = "fdmprinter"
+
+ preferred_quality = definition.getMetaDataEntry("preferred_quality")
+ if preferred_quality:
+ search_criteria["id"] = preferred_quality
+
+ containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
+ if containers:
+ return containers[0]
+
+ return self._empty_quality_container
+
def createMachineManagerModel(engine, script_engine):
return MachineManagerModel()
diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py
index 2663cab5a0..f1eb93de0e 100644
--- a/cura/PrintInformation.py
+++ b/cura/PrintInformation.py
@@ -1,14 +1,17 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
-from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
+from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot
from UM.Application import Application
from UM.Qt.Duration import Duration
+from UM.Preferences import Preferences
import math
+import os.path
+import unicodedata
-## A class for processing and calculating minimum, current and maximum print time.
+## A class for processing and calculating minimum, current and maximum print time as well as managing the job name
#
# This class contains all the logic relating to calculation and slicing for the
# time/quality slider concept. It is a rather tricky combination of event handling
@@ -22,6 +25,8 @@ import math
# - When that is done, we update the minimum print time and start the final slice pass, the "high quality settings pass".
# - When the high quality pass is done, we update the maximum print time.
#
+# This class also mangles the current machine name and the filename of the first loaded mesh into a job name.
+# This job name is requested by the JobSpecs qml file.
class PrintInformation(QObject):
class SlicePass:
CurrentSettings = 1
@@ -45,14 +50,20 @@ class PrintInformation(QObject):
if self._backend:
self._backend.printDurationMessage.connect(self._onPrintDurationMessage)
+ self._job_name = ""
+ self._abbr_machine = ""
+
+ Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName)
+ Application.getInstance().fileLoaded.connect(self.setJobName)
+
currentPrintTimeChanged = pyqtSignal()
-
+
@pyqtProperty(Duration, notify = currentPrintTimeChanged)
def currentPrintTime(self):
return self._current_print_time
materialAmountChanged = pyqtSignal()
-
+
@pyqtProperty(float, notify = materialAmountChanged)
def materialAmount(self):
return self._material_amount
@@ -66,3 +77,46 @@ class PrintInformation(QObject):
r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2)
self.materialAmountChanged.emit()
+
+ @pyqtSlot(str)
+ def setJobName(self, name):
+ # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its
+ # extension. This cuts the extension off if necessary.
+ name = os.path.splitext(name)[0]
+ if self._job_name != name:
+ self._job_name = name
+ self.jobNameChanged.emit()
+
+ jobNameChanged = pyqtSignal()
+
+ @pyqtProperty(str, notify = jobNameChanged)
+ def jobName(self):
+ return self._job_name
+
+ @pyqtSlot(str, result = str)
+ def createJobName(self, base_name):
+ base_name = self._stripAccents(base_name)
+ if Preferences.getInstance().getValue("cura/jobname_prefix"):
+ return self._abbr_machine + "_" + base_name
+ else:
+ return base_name
+
+ ## Created an acronymn-like abbreviated machine name from the currently active machine name
+ # Called each time the global stack is switched
+ def _setAbbreviatedMachineName(self):
+ global_stack_name = Application.getInstance().getGlobalContainerStack().getName()
+ split_name = global_stack_name.split(" ")
+ abbr_machine = ""
+ for word in split_name:
+ if word.lower() == "ultimaker":
+ abbr_machine += "UM"
+ elif word.isdigit():
+ abbr_machine += word
+ else:
+ abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0]
+
+ self._abbr_machine = abbr_machine
+
+ ## Utility method that strips accents from characters (eg: â -> a)
+ def _stripAccents(self, str):
+ return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')
\ No newline at end of file
diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py
index 3e8815ec67..f9878e436c 100644
--- a/cura/SettingOverrideDecorator.py
+++ b/cura/SettingOverrideDecorator.py
@@ -7,7 +7,7 @@ from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Application import Application
-
+import copy
## A decorator that adds a container stack to a Node. This stack should be queried for all settings regarding
# the linked node. The Stack in question will refer to the global stack (so that settings that are not defined by
# this stack still resolve.
@@ -15,14 +15,30 @@ class SettingOverrideDecorator(SceneNodeDecorator):
def __init__(self):
super().__init__()
self._stack = ContainerStack(stack_id = id(self))
+ self._stack.setDirty(False) # This stack does not need to be saved.
self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer")
self._stack.addContainer(self._instance)
+ self._stack.propertyChanged.connect(self._onSettingChanged)
+
ContainerRegistry.getInstance().addContainer(self._stack)
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged)
self._onGlobalContainerStackChanged()
+ def __deepcopy__(self, memo):
+ ## Create a fresh decorator object
+ deep_copy = SettingOverrideDecorator()
+ ## Copy the instance
+ deep_copy._instance = copy.deepcopy(self._instance, memo)
+ ## Set the copied instance as the first (and only) instance container of the stack.
+ deep_copy._stack.replaceContainer(0, deep_copy._instance)
+ return deep_copy
+
+ def _onSettingChanged(self, instance, property):
+ if property == "value": # Only reslice if the value has changed.
+ Application.getInstance().getBackend().forceSlice()
+
def _onGlobalContainerStackChanged(self):
## Ensure that the next stack is always the global stack.
self._stack.setNextStack(Application.getInstance().getGlobalContainerStack())
diff --git a/plugins/ChangeLogPlugin/ChangeLog.py b/plugins/ChangeLogPlugin/ChangeLog.py
index 7c8c81f2c6..d004104f91 100644
--- a/plugins/ChangeLogPlugin/ChangeLog.py
+++ b/plugins/ChangeLogPlugin/ChangeLog.py
@@ -48,7 +48,8 @@ class ChangeLog(Extension, QObject,):
result += "
" + str(version) + "
"
result += ""
for change in logs[version]:
- result += "" + str(change) + "
"
+ if str(change) != "":
+ result += "" + str(change) + "
"
for line in logs[version][change]:
result += str(line) + "
"
result += "
"
@@ -60,20 +61,21 @@ class ChangeLog(Extension, QObject,):
self._change_logs = collections.OrderedDict()
with open(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.txt"), "r",-1, "utf-8") as f:
open_version = None
- open_header = None
+ open_header = "" # Initialise to an empty header in case there is no "*" in the first line of the changelog
for line in f:
line = line.replace("\n","")
if "[" in line and "]" in line:
line = line.replace("[","")
line = line.replace("]","")
open_version = Version(line)
- self._change_logs[Version(line)] = collections.OrderedDict()
+ self._change_logs[open_version] = collections.OrderedDict()
elif line.startswith("*"):
open_header = line.replace("*","")
self._change_logs[open_version][open_header] = []
- else:
- if line != "":
- self._change_logs[open_version][open_header].append(line)
+ elif line != "":
+ if open_header not in self._change_logs[open_version]:
+ self._change_logs[open_version][open_header] = []
+ self._change_logs[open_version][open_header].append(line)
def _onEngineCreated(self):
if not self._version:
@@ -105,4 +107,3 @@ class ChangeLog(Extension, QObject,):
self._changelog_context = QQmlContext(Application.getInstance()._engine.rootContext())
self._changelog_context.setContextProperty("manager", self)
self._changelog_window = component.create(self._changelog_context)
- #print(self._changelog_window)
diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt
index d60154d56b..48e96ce4b6 100644
--- a/plugins/ChangeLogPlugin/ChangeLog.txt
+++ b/plugins/ChangeLogPlugin/ChangeLog.txt
@@ -1,7 +1,6 @@
-[2.1.0]
+[2.1.2]
-*2.1 Beta release
-Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, it’s now also ready for any future developments. For the beginner, Cura makes 3D printing incredibly easy, and for more advanced users, there are over 140 new customisable settings.
+Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, it’s now also ready for any future developments. For the beginner Cura makes 3D printing incredibly easy, and for more advanced users, there are over 140 new customisable settings.
*Select Multiple Objects
You now have the freedom to select and manipulate multiple objects at the same time.
diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py
index cf008e7b6f..dee6f2b64c 100644
--- a/plugins/CuraEngineBackend/StartSliceJob.py
+++ b/plugins/CuraEngineBackend/StartSliceJob.py
@@ -3,7 +3,6 @@
import numpy
from string import Formatter
-import traceback
from enum import IntEnum
from UM.Job import Job
@@ -52,6 +51,20 @@ class StartSliceJob(Job):
def getSliceMessage(self):
return self._slice_message
+ ## Check if a stack has any errors.
+ ## returns true if it has errors, false otherwise.
+ def _checkStackForErrors(self, stack):
+ if stack is None:
+ return False
+
+ for key in stack.getAllKeys():
+ validation_state = stack.getProperty(key, "validationState")
+ if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
+ Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state)
+ return True
+ Job.yieldThread()
+ return False
+
## Runs the job that initiates the slicing.
def run(self):
stack = Application.getInstance().getGlobalContainerStack()
@@ -59,16 +72,20 @@ class StartSliceJob(Job):
self.setResult(StartJobResult.Error)
return
- #Don't slice if there is a setting with an error value.
- for key in stack.getAllKeys():
- validation_state = stack.getProperty(key, "validationState")
- if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
- Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state)
+ # Don't slice if there is a setting with an error value.
+ if self._checkStackForErrors(stack):
+ self.setResult(StartJobResult.SettingError)
+ return
+
+ # Don't slice if there is a per object setting with an error value.
+ for node in DepthFirstIterator(self._scene.getRoot()):
+ if type(node) is not SceneNode or not node.isSelectable():
+ continue
+
+ if self._checkStackForErrors(node.callDecoration("getStack")):
self.setResult(StartJobResult.SettingError)
return
- Job.yieldThread()
-
with self._scene.getSceneLock():
# Remove old layer data.
for node in DepthFirstIterator(self._scene.getRoot()):
diff --git a/plugins/LayerView/LayerView.py b/plugins/LayerView/LayerView.py
index a98fab5c8a..665a910682 100644
--- a/plugins/LayerView/LayerView.py
+++ b/plugins/LayerView/LayerView.py
@@ -41,7 +41,7 @@ class LayerView(View):
self._top_layers_job = None
self._activity = False
- self._solid_layers = 5
+ self._solid_layers = 1
self._top_layer_timer = QTimer()
self._top_layer_timer.setInterval(50)
diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py b/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py
index 9ef2515bed..381d45b1c2 100644
--- a/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py
+++ b/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py
@@ -5,7 +5,8 @@ from UM.Logger import Logger
from cura.SettingOverrideDecorator import SettingOverrideDecorator
-
+## The per object setting visibility handler ensures that only setting defintions that have a matching instance Container
+# are returned as visible.
class PerObjectSettingVisibilityHandler(QObject):
def __init__(self, parent = None, *args, **kwargs):
super().__init__(parent = parent, *args, **kwargs)
diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsModel.py b/plugins/PerObjectSettingsTool/PerObjectSettingsModel.py
deleted file mode 100644
index 74a1fbed9a..0000000000
--- a/plugins/PerObjectSettingsTool/PerObjectSettingsModel.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright (c) 2015 Ultimaker B.V.
-# Uranium is released under the terms of the AGPLv3 or higher.
-
-from PyQt5.QtCore import Qt, pyqtSlot, QUrl
-
-from UM.Application import Application
-from UM.Qt.ListModel import ListModel
-from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
-from UM.Scene.SceneNode import SceneNode
-#from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator
-#from UM.Settings.ProfileOverrideDecorator import ProfileOverrideDecorator
-
-from . import SettingOverrideModel
-
-class PerObjectSettingsModel(ListModel):
- IdRole = Qt.UserRole + 1 # ID of the node
-
- def __init__(self, parent = None):
- super().__init__(parent)
- self._scene = Application.getInstance().getController().getScene()
- self._root = self._scene.getRoot()
- self.addRoleName(self.IdRole,"id")
-
- self._updateModel()
-
- @pyqtSlot("quint64", str)
- def setObjectProfile(self, object_id, profile_name):
- self.setProperty(self.find("id", object_id), "profile", profile_name)
-
- profile = None
- '''if profile_name != "global":
- profile = Application.getInstance().getMachineManager().findProfile(profile_name)
-
- node = self._scene.findObject(object_id)
- if profile:
- if not node.getDecorator(ProfileOverrideDecorator):
- node.addDecorator(ProfileOverrideDecorator())
- node.callDecoration("setProfile", profile)
- else:
- if node.getDecorator(ProfileOverrideDecorator):
- node.removeDecorator(ProfileOverrideDecorator)'''
-
- @pyqtSlot("quint64", str)
- def addOverride(self, object_id, key):
- machine = Application.getInstance().getMachineManager().getActiveMachineInstance()
- if not machine:
- return
-
- node = self._scene.findObject(object_id)
- #if not node.getDecorator(SettingOverrideDecorator):
- # node.addDecorator(SettingOverrideDecorator())
-
- node.callDecoration("addSetting", key)
-
- @pyqtSlot("quint64", str)
- def removerOverride(self, object_id, key):
- node = self._scene.findObject(object_id)
- node.callDecoration("removeSetting", key)
-
- #if len(node.callDecoration("getAllSettings")) == 0:
- # node.removeDecorator(SettingOverrideDecorator)
-
- def _updateModel(self):
- self.clear()
-
- for node in BreadthFirstIterator(self._root):
- if type(node) is not SceneNode or not node.isSelectable():
- continue
-
- node_stack = node.callDecoration("getStack")
-
- if not node_stack:
- self.appendItem({
- "id": id(node)
- })
diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml
index f873ec9a79..9565b0e345 100644
--- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml
+++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml
@@ -45,6 +45,7 @@ Item {
{
Loader
{
+ id: settingLoader
width: UM.Theme.getSize("setting").width;
height: UM.Theme.getSize("section").height;
@@ -55,26 +56,34 @@ Item {
//Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
//In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
//causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
- asynchronous: model.type != "enum"
+ asynchronous: model.type != "enum" && model.type != "extruder"
- source:
+ onLoaded: {
+ settingLoader.item.showRevertButton = false
+ settingLoader.item.showInheritButton = false
+ settingLoader.item.doDepthIdentation = false
+ }
+
+ sourceComponent:
{
- switch(model.type) // TODO: This needs to be fixed properly. Got frustrated with it not working, so this is the patch job!
+ switch(model.type)
{
case "int":
- return "../../resources/qml/Settings/SettingTextField.qml"
+ return settingTextField
case "float":
- return "../../resources/qml/Settings/SettingTextField.qml"
+ return settingTextField
case "enum":
- return "../../resources/qml/Settings/SettingComboBox.qml"
+ return settingComboBox
+ case "extruder":
+ return settingExtruder
case "bool":
- return "../../resources/qml/Settings/SettingCheckBox.qml"
+ return settingCheckBox
case "str":
- return "../../resources/qml/Settings/SettingTextField.qml"
+ return settingTextField
case "category":
- return "../../resources/qml/Settings/SettingCategory.qml"
+ return settingCategory
default:
- return "../../resources/qml/Settings/SettingUnknown.qml"
+ return settingUnknown
}
}
}
@@ -111,7 +120,7 @@ Item {
containerStackId: UM.ActiveTool.properties.getValue("ContainerID")
key: model.key
- watchedProperties: [ "value", "enabled", "state", "validationState" ]
+ watchedProperties: [ "value", "enabled", "validationState" ]
storeIndex: 0
}
}
@@ -250,4 +259,46 @@ Item {
}
SystemPalette { id: palette; }
+
+ Component
+ {
+ id: settingTextField;
+
+ Cura.SettingTextField { }
+ }
+
+ Component
+ {
+ id: settingComboBox;
+
+ Cura.SettingComboBox { }
+ }
+
+ Component
+ {
+ id: settingExtruder;
+
+ Cura.SettingExtruder { }
+ }
+
+ Component
+ {
+ id: settingCheckBox;
+
+ Cura.SettingCheckBox { }
+ }
+
+ Component
+ {
+ id: settingCategory;
+
+ Cura.SettingCategory { }
+ }
+
+ Component
+ {
+ id: settingUnknown;
+
+ Cura.SettingUnknown { }
+ }
}
diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py
index c74800e83d..6ae44c2671 100644
--- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py
+++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py
@@ -6,14 +6,15 @@ from UM.Scene.Selection import Selection
from UM.Application import Application
from UM.Preferences import Preferences
-from . import PerObjectSettingsModel
+## This tool allows the user to add & change settings per node in the scene.
+# The settings per object are kept in a ContainerStack, which is linked to a node by decorator.
class PerObjectSettingsTool(Tool):
def __init__(self):
super().__init__()
self._model = None
- self.setExposedProperties("SelectedObjectId","ContainerID")
+ self.setExposedProperties("SelectedObjectId", "ContainerID")
Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)
Selection.selectionChanged.connect(self.propertyChanged)
@@ -33,21 +34,13 @@ class PerObjectSettingsTool(Tool):
return selected_object_id
def getContainerID(self):
+ selected_object = Selection.getSelectedObject(0)
+ if selected_object.getParent().callDecoration("isGroup"):
+ selected_object = selected_object.getParent()
try:
- selected_object = Selection.getSelectedObject(0)
- if selected_object.getParent().callDecoration("isGroup"):
- selected_object = selected_object.getParent()
- try:
- return selected_object.callDecoration("getStack").getId()
- except:
- print(":(")
- return
- except:
- print(":((")
- return
-
- def setContainerID(self, value):
- pass
+ return selected_object.callDecoration("getStack").getId()
+ except AttributeError:
+ return ""
def _onPreferenceChanged(self, preference):
if preference == "cura/active_mode":
diff --git a/plugins/PerObjectSettingsTool/SettingOverrideModel.py b/plugins/PerObjectSettingsTool/SettingOverrideModel.py
deleted file mode 100644
index d4bebfdfee..0000000000
--- a/plugins/PerObjectSettingsTool/SettingOverrideModel.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# Copyright (c) 2015 Ultimaker B.V.
-# Uranium is released under the terms of the AGPLv3 or higher.
-
-from PyQt5.QtCore import Qt, pyqtSlot, QUrl
-
-from UM.Application import Application
-from UM.Qt.ListModel import ListModel
-#from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator
-
-class SettingOverrideModel(ListModel):
- KeyRole = Qt.UserRole + 1
- LabelRole = Qt.UserRole + 2
- DescriptionRole = Qt.UserRole + 3
- ValueRole = Qt.UserRole + 4
- TypeRole = Qt.UserRole + 5
- UnitRole = Qt.UserRole + 6
- ValidRole = Qt.UserRole + 7
- OptionsRole = Qt.UserRole + 8
- WarningDescriptionRole = Qt.UserRole + 9
- ErrorDescriptionRole = Qt.UserRole + 10
- GlobalOnlyRole = Qt.UserRole + 11
-
- def __init__(self, node, parent = None):
- super().__init__(parent)
-
- self._ignore_setting_change = None
-
- self._node = node
- self._node.decoratorsChanged.connect(self._onDecoratorsChanged)
- self._onDecoratorsChanged(None)
-
- #self._activeProfile = Application.getInstance().getMachineManager().getWorkingProfile() #To be able to get notified when a setting changes.
- #self._activeProfile.settingValueChanged.connect(self._onProfileSettingValueChanged)
- #Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onProfileChanged)
-
- self.addRoleName(self.KeyRole, "key")
- self.addRoleName(self.LabelRole, "label")
- self.addRoleName(self.DescriptionRole, "description")
- self.addRoleName(self.ValueRole,"value")
- self.addRoleName(self.TypeRole, "type")
- self.addRoleName(self.UnitRole, "unit")
- self.addRoleName(self.ValidRole, "valid")
- self.addRoleName(self.OptionsRole, "options")
- self.addRoleName(self.WarningDescriptionRole, "warning_description")
- self.addRoleName(self.ErrorDescriptionRole, "error_description")
- self.addRoleName(self.GlobalOnlyRole, "global_only")
-
- @pyqtSlot(str, "QVariant")
- def setSettingValue(self, key, value):
- if not self._decorator:
- return
-
- self._decorator.setSettingValue(key, value)
-
- def _onDecoratorsChanged(self, node):
- return
- '''if not self._node.getDecorator(SettingOverrideDecorator):
- self.clear()
- return
-
- self._decorator = self._node.getDecorator(SettingOverrideDecorator)
- self._decorator.settingAdded.connect(self._onSettingsChanged)
- self._decorator.settingRemoved.connect(self._onSettingsChanged)
- self._decorator.settingValueChanged.connect(self._onSettingValueChanged)
- self._onSettingsChanged()'''
-
- def _createOptionsModel(self, options):
- if not options:
- return None
-
- model = ListModel()
- model.addRoleName(Qt.UserRole + 1, "value")
- model.addRoleName(Qt.UserRole + 2, "name")
- for value, name in options.items():
- model.appendItem({"value": str(value), "name": str(name)})
- return model
-
- ## Updates the active profile in this model if the active profile is
- # changed.
- #
- # This links the settingValueChanged of the new profile to this model's
- # _onSettingValueChanged function, so that it properly listens to those
- # events again.
- def _onProfileChanged(self):
- if self._activeProfile: #Unlink from the old profile.
- self._activeProfile.settingValueChanged.disconnect(self._onProfileSettingValueChanged)
- old_profile = self._activeProfile
- self._activeProfile = Application.getInstance().getMachineManager().getWorkingProfile()
- self._activeProfile.settingValueChanged.connect(self._onProfileSettingValueChanged) #Re-link to the new profile.
- for setting_name in old_profile.getChangedSettings().keys(): #Update all changed settings in the old and new profiles.
- self._onProfileSettingValueChanged(setting_name)
- for setting_name in self._activeProfile.getChangedSettings().keys():
- self._onProfileSettingValueChanged(setting_name)
-
- ## Updates the global_only property of a setting once a setting value
- # changes.
- #
- # This method should only get called on settings that are dependent on the
- # changed setting.
- #
- # \param setting_name The setting that needs to be updated.
- def _onProfileSettingValueChanged(self, setting_name):
- index = self.find("key", setting_name)
- if index != -1:
- self.setProperty(index, "global_only", Application.getInstance().getMachineManager().getActiveMachineInstance().getMachineDefinition().getSetting(setting_name).getGlobalOnly())
-
- def _onSettingsChanged(self):
- self.clear()
-
- items = []
- for key, setting in self._decorator.getAllSettings().items():
- value = self._decorator.getSettingValue(key)
- items.append({
- "key": key,
- "label": setting.getLabel(),
- "description": setting.getDescription(),
- "value": str(value),
- "type": setting.getType(),
- "unit": setting.getUnit(),
- "valid": setting.validate(value),
- "options": self._createOptionsModel(setting.getOptions()),
- "warning_description": setting.getWarningDescription(),
- "error_description": setting.getErrorDescription(),
- "global_only": setting.getGlobalOnly()
- })
-
- items.sort(key = lambda i: i["key"])
-
- for item in items:
- self.appendItem(item)
-
- def _onSettingValueChanged(self, setting):
- index = self.find("key", setting.getKey())
- value = self._decorator.getSettingValue(setting.getKey())
- if index != -1:
- self.setProperty(index, "value", str(value))
- self.setProperty(index, "valid", setting.validate(value))
- self.setProperty(index, "global_only", setting.getGlobalOnly())
\ No newline at end of file
diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py
index d73beec193..89c7d76e9f 100644
--- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py
+++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py
@@ -45,6 +45,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
self.addMetaDataEntry("material", material.text)
self.addMetaDataEntry("color_name", color.text)
+ continue
+
self.addMetaDataEntry(tag_name, entry.text)
property_values = {}
@@ -78,6 +80,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
if key in self.__material_property_setting_map:
self.setProperty(self.__material_property_setting_map[key], "value", entry.text, self._definition)
global_setting_values[self.__material_property_setting_map[key]] = entry.text
+ else:
+ Logger.log("d", "Unsupported material setting %s", key)
machines = data.iterfind("./um:settings/um:machine", self.__namespaces)
for machine in machines:
@@ -87,6 +91,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
key = entry.get("key")
if key in self.__material_property_setting_map:
machine_setting_values[self.__material_property_setting_map[key]] = entry.text
+ else:
+ Logger.log("d", "Unsupported material setting %s", key)
identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces)
for identifier in identifiers:
@@ -100,28 +106,74 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
Logger.log("w", "No definition found for machine ID %s", machine_id)
continue
+ definition = definitions[0]
+
new_material = XmlMaterialProfile(self.id + "_" + machine_id)
new_material.setName(self.getName())
- new_material.setMetaData(self.getMetaData())
- new_material.setDefinition(definitions[0])
+ new_material.setMetaData(copy.deepcopy(self.getMetaData()))
+ new_material.setDefinition(definition)
for key, value in global_setting_values.items():
- new_material.setProperty(key, "value", value, definitions[0])
+ new_material.setProperty(key, "value", value, definition)
for key, value in machine_setting_values.items():
- new_material.setProperty(key, "value", value, definitions[0])
+ new_material.setProperty(key, "value", value, definition)
new_material._dirty = False
UM.Settings.ContainerRegistry.getInstance().addContainer(new_material)
+ hotends = machine.iterfind("./um:hotend", self.__namespaces)
+ for hotend in hotends:
+ hotend_id = hotend.get("id")
+ if hotend_id is None:
+ continue
+ variant_containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = hotend_id)
+ if not variant_containers:
+ # It is not really properly defined what "ID" is so also search for variants by name.
+ variant_containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(definition = definition.id, name = hotend_id)
+
+ if not variant_containers:
+ Logger.log("d", "No variants found with ID or name %s for machine %s", hotend_id, definition.id)
+ continue
+
+ new_hotend_material = XmlMaterialProfile(self.id + "_" + machine_id + "_" + hotend_id.replace(" ", "_"))
+ new_hotend_material.setName(self.getName())
+ new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData()))
+ new_hotend_material.setDefinition(definition)
+
+ new_hotend_material.addMetaDataEntry("variant", variant_containers[0].id)
+
+ for key, value in global_setting_values.items():
+ new_hotend_material.setProperty(key, "value", value, definition)
+
+ for key, value in machine_setting_values.items():
+ new_hotend_material.setProperty(key, "value", value, definition)
+
+ settings = hotend.iterfind("./um:setting", self.__namespaces)
+ for entry in settings:
+ key = entry.get("key")
+ if key in self.__material_property_setting_map:
+ new_hotend_material.setProperty(self.__material_property_setting_map[key], "value", entry.text, definition)
+ else:
+ Logger.log("d", "Unsupported material setting %s", key)
+
+ new_hotend_material._dirty = False
+ UM.Settings.ContainerRegistry.getInstance().addContainer(new_hotend_material)
+
+
+ # Map XML file setting names to internal names
__material_property_setting_map = {
"print temperature": "material_print_temperature",
"heated bed temperature": "material_bed_temperature",
"standby temperature": "material_standby_temperature",
+ "print cooling": "cool_fan_speed",
+ "retraction amount": "retraction_amount",
+ "retraction speed": "retraction_speed",
}
+ # Map XML file product names to internal ids
__product_id_map = {
"Ultimaker2": "ultimaker2",
"Ultimaker2+": "ultimaker2_plus",
diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json
index f755d72c4a..69797385a1 100644
--- a/resources/definitions/fdmextruder.def.json
+++ b/resources/definitions/fdmextruder.def.json
@@ -22,7 +22,7 @@
{
"label": "Extruder",
"description": "The extruder train used for printing. This is used in multi-extrusion.",
- "type": "int",
+ "type": "extruder",
"default_value": 0,
"minimum_value": "0"
},
diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json
index 6dca68a6c9..79bdf4399a 100644
--- a/resources/definitions/fdmprinter.def.json
+++ b/resources/definitions/fdmprinter.def.json
@@ -24,6 +24,7 @@
"label": "Machine",
"type": "category",
"description": "Machine specific settings",
+ "icon": "category_machine",
"children":
{
"machine_show_variants":
@@ -1116,7 +1117,7 @@
"minimum_value": "0.1",
"maximum_value": "299792458000",
"maximum_value_warning": "150",
- "enabled": "support_roof_enable",
+ "enabled": "support_roof_enable and support_enable",
"value": "speed_support / 1.5",
"global_only": true
}
@@ -2124,7 +2125,7 @@
{
"label": "Platform Adhesion Extruder",
"description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.",
- "type": "int",
+ "type": "extruder",
"default_value": 0,
"minimum_value": "0",
"maximum_value": "machine_extruder_count - 1",
@@ -2134,17 +2135,18 @@
{
"label": "Support Extruder",
"description": "The extruder train to use for printing the support. This is used in multi-extrusion.",
- "type": "int",
+ "type": "extruder",
"default_value": 0,
"minimum_value": "0",
"maximum_value": "machine_extruder_count - 1",
+ "enabled": "support_enable",
"global_only": "True",
"children": {
"support_infill_extruder_nr":
{
"label": "Support Infill Extruder",
"description": "The extruder train to use for printing the infill of the support. This is used in multi-extrusion.",
- "type": "int",
+ "type": "extruder",
"default_value": 0,
"value": "support_extruder_nr",
"minimum_value": "0",
@@ -2155,7 +2157,7 @@
{
"label": "First Layer Support Extruder",
"description": "The extruder train to use for printing the first layer of support infill. This is used in multi-extrusion.",
- "type": "int",
+ "type": "extruder",
"default_value": 0,
"value": "support_extruder_nr",
"minimum_value": "0",
@@ -2166,7 +2168,7 @@
{
"label": "Support Roof Extruder",
"description": "The extruder train to use for printing the roof of the support. This is used in multi-extrusion.",
- "type": "int",
+ "type": "extruder",
"default_value": 0,
"value": "support_extruder_nr",
"minimum_value": "0",
diff --git a/resources/definitions/ultimaker.def.json b/resources/definitions/ultimaker.def.json
index 60e4dbbf40..b33f820198 100644
--- a/resources/definitions/ultimaker.def.json
+++ b/resources/definitions/ultimaker.def.json
@@ -6,9 +6,6 @@
"inherits": "fdmprinter",
"metadata": {
"author": "Ultimaker",
- "manufacturer": "Ultimaker",
- "preferred_profile": "Normal Quality",
- "preferred_nozzle": "0.4 mm",
- "preferred_material": "PLA"
+ "manufacturer": "Ultimaker"
}
}
diff --git a/resources/definitions/ultimaker2_plus.def.json b/resources/definitions/ultimaker2_plus.def.json
index 9f68c2a16b..b29f904095 100644
--- a/resources/definitions/ultimaker2_plus.def.json
+++ b/resources/definitions/ultimaker2_plus.def.json
@@ -12,8 +12,12 @@
"platform": "ultimaker2_platform.obj",
"platform_texture": "Ultimaker2Plusbackplate.png",
"preferred_variant": "ultimaker2_plus_0.4",
- "preferred_material": "pla",
- "preferred_quality": "high"
+ "preferred_material": "*pla*",
+ "preferred_quality": "*normal*",
+ "has_variants": true,
+ "has_materials": true,
+ "has_machine_materials": true,
+ "has_machine_quality": true
},
"overrides": {
diff --git a/resources/definitions/ultimaker_original.def.json b/resources/definitions/ultimaker_original.def.json
index 1dbdb95d8c..55668946a0 100644
--- a/resources/definitions/ultimaker_original.def.json
+++ b/resources/definitions/ultimaker_original.def.json
@@ -11,6 +11,9 @@
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker.png",
"platform": "ultimaker_platform.stl",
+ "has_materials": true,
+ "preferred_material": "*pla*",
+ "preferred_quality": "*normal*",
"pages": [
"SelectUpgradedParts",
"UpgradeFirmware",
diff --git a/resources/instances/high_quality.inst.cfg b/resources/instances/high_quality.inst.cfg
deleted file mode 100644
index 2e860cf380..0000000000
--- a/resources/instances/high_quality.inst.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-[general]
-version = 2
-name = high
-definition = fdmprinter
-
-[metadata]
-type = quality
-
-[values]
diff --git a/resources/instances/normal_quality.inst.cfg b/resources/instances/normal_quality.inst.cfg
deleted file mode 100644
index 6bb23d841c..0000000000
--- a/resources/instances/normal_quality.inst.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-[general]
-version = 2
-name = normal
-definition = fdmprinter
-
-[metadata]
-type = quality
-
-[values]
diff --git a/resources/materials/abs.inst.cfg b/resources/materials/abs.inst.cfg
deleted file mode 100644
index 0d64e81437..0000000000
--- a/resources/materials/abs.inst.cfg
+++ /dev/null
@@ -1,12 +0,0 @@
-[general]
-version = 2
-name = ABS
-definition = fdmprinter
-
-[metadata]
-type = material
-
-[values]
-material_print_temperature = 250
-material_bed_temperature = 80
-material_flow = 107
diff --git a/resources/materials/cpe.inst.cfg b/resources/materials/cpe.inst.cfg
deleted file mode 100644
index ca30cba046..0000000000
--- a/resources/materials/cpe.inst.cfg
+++ /dev/null
@@ -1,11 +0,0 @@
-[general]
-version = 2
-name = CPE
-definition = fdmprinter
-
-[metadata]
-type = material
-
-[values]
-material_print_temperature = 250
-material_bed_temperature = 70
\ No newline at end of file
diff --git a/resources/materials/generic_abs.xml.fdm_material b/resources/materials/generic_abs.xml.fdm_material
new file mode 100644
index 0000000000..654b06d221
--- /dev/null
+++ b/resources/materials/generic_abs.xml.fdm_material
@@ -0,0 +1,34 @@
+
+
+
+
+
+ Generic
+ ABS
+ Generic
+
+ 506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9
+ 0
+ #FF0000
+
+
+ 1.07
+ 2.85
+
+
+ 250
+ 80
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/materials/generic_cpe.xml.fdm_material b/resources/materials/generic_cpe.xml.fdm_material
new file mode 100644
index 0000000000..bbe6e328d2
--- /dev/null
+++ b/resources/materials/generic_cpe.xml.fdm_material
@@ -0,0 +1,34 @@
+
+
+
+
+
+ Generic
+ CPE
+ Generic
+
+ 506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9
+ 0
+ #0000FF
+
+
+ 0.94
+ 2.85
+
+
+ 250
+ 70
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/materials/generic_pla.xml.fdm_material b/resources/materials/generic_pla.xml.fdm_material
index a4fe02c195..40432d5849 100644
--- a/resources/materials/generic_pla.xml.fdm_material
+++ b/resources/materials/generic_pla.xml.fdm_material
@@ -11,7 +11,7 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9
0
- #FFFFFF
+ #00FF00
1.3
@@ -20,28 +20,15 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
210
60
- 175
- 150
-
-
-
-
-
-
-
-
- 150
-
- 80
-
-
- 100
-
+
+
+
+
diff --git a/resources/materials/pla.inst.cfg b/resources/materials/pla.inst.cfg
deleted file mode 100644
index dfa9c62469..0000000000
--- a/resources/materials/pla.inst.cfg
+++ /dev/null
@@ -1,10 +0,0 @@
-[general]
-version = 2
-name = PLA
-definition = fdmprinter
-
-[metadata]
-type = material
-
-[values]
-material_bed_temperature = 60
diff --git a/resources/profiles/general/High+Quality.cfg b/resources/profiles/general/High+Quality.cfg
deleted file mode 100644
index a006c7a995..0000000000
--- a/resources/profiles/general/High+Quality.cfg
+++ /dev/null
@@ -1,10 +0,0 @@
-[general]
-version = 1
-name = High Quality
-weight = -3
-
-[settings]
-layer_height = 0.06
-speed_topbottom = 15
-speed_infill = 80
-
diff --git a/resources/profiles/general/Normal+Quality.cfg b/resources/profiles/general/Normal+Quality.cfg
deleted file mode 100644
index 575c3343e2..0000000000
--- a/resources/profiles/general/Normal+Quality.cfg
+++ /dev/null
@@ -1,8 +0,0 @@
-[general]
-version = 1
-name = Normal Quality
-weight = -2
-
-[settings]
-speed_topbottom = 15
-speed_infill = 80
\ No newline at end of file
diff --git a/resources/profiles/general/Ulti+Quality.cfg b/resources/profiles/general/Ulti+Quality.cfg
deleted file mode 100644
index 1fa9b6085c..0000000000
--- a/resources/profiles/general/Ulti+Quality.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-[general]
-version = 1
-name = Ulti Quality
-weight = -4
-
-[settings]
-layer_height = 0.04
-speed_topbottom = 15
-speed_infill = 80
\ No newline at end of file
diff --git a/resources/profiles/materials/abs.cfg b/resources/profiles/materials/abs.cfg
deleted file mode 100644
index 67abc32810..0000000000
--- a/resources/profiles/materials/abs.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-[general]
-version = 1
-type = material
-name = ABS
-
-[settings]
-material_print_temperature = 250
-material_bed_temperature = 80
-material_flow = 107
diff --git a/resources/profiles/materials/cpe.cfg b/resources/profiles/materials/cpe.cfg
deleted file mode 100644
index 0621260745..0000000000
--- a/resources/profiles/materials/cpe.cfg
+++ /dev/null
@@ -1,8 +0,0 @@
-[general]
-version = 1
-type = material
-name = CPE
-
-[settings]
-material_print_temperature = 250
-material_bed_temperature = 70
\ No newline at end of file
diff --git a/resources/profiles/materials/pla.cfg b/resources/profiles/materials/pla.cfg
deleted file mode 100644
index b5af61b9b6..0000000000
--- a/resources/profiles/materials/pla.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-[general]
-version = 1
-type = material
-name = PLA
-
-[settings]
-material_bed_temperature = 60
\ No newline at end of file
diff --git a/resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile
deleted file mode 100644
index db091d8e8d..0000000000
--- a/resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile
+++ /dev/null
@@ -1,21 +0,0 @@
-[general]
-version = 1
-name = Ulti Quality
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = PLA
-weight = -4
-
-[settings]
-line_width = 0.35
-layer_height = 0.04
-layer_height_0 = 0.26
-wall_thickness = 1.4
-top_bottom_thickness = 1.12
-infill_sparse_density = 25
-speed_print = 30
-speed_infill = 50
-speed_wall_x = 40
-speed_topbottom = 20
-speed_layer_0 = 25
-cool_min_layer_time_fan_speed_max = 15
diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml
index f3bce7b993..e09b6b5424 100644
--- a/resources/qml/Actions.qml
+++ b/resources/qml/Actions.qml
@@ -6,6 +6,7 @@ pragma Singleton
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.1 as UM
+import Cura 1.0 as Cura
Item
{
@@ -109,23 +110,23 @@ Item
Action
{
id: updateProfileAction;
- enabled: UM.ActiveProfile.valid && !UM.ActiveProfile.readOnly && UM.ActiveProfile.hasCustomisedValues
+ enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
text: catalog.i18nc("@action:inmenu menubar:profile","&Update Current Profile");
- onTriggered: UM.ActiveProfile.updateProfile();
+ onTriggered: Cura.MachineManager.updateUserContainerToQuality()
}
Action
{
id: resetProfileAction;
- enabled: UM.ActiveProfile.valid && UM.ActiveProfile.hasCustomisedValues
+ enabled: Cura.MachineManager.hasUserSettings
text: catalog.i18nc("@action:inmenu menubar:profile","&Reload Current Profile");
- onTriggered: UM.ActiveProfile.discardChanges();
+ onTriggered: Cura.MachineManager.clearUserSettings();
}
Action
{
id: addProfileAction;
- enabled: UM.ActiveProfile.valid
+ enabled: Cura.MachineManager.isGlobalStackValid
text: catalog.i18nc("@action:inmenu menubar:profile","&Create New Profile...");
}
diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml
index a7f4a43c22..46ebc25369 100644
--- a/resources/qml/Cura.qml
+++ b/resources/qml/Cura.qml
@@ -10,8 +10,6 @@ import QtQuick.Dialogs 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
-import "."
-
UM.MainWindow
{
id: base
@@ -56,7 +54,7 @@ UM.MainWindow
title: catalog.i18nc("@title:menu menubar:toplevel","&File");
MenuItem {
- action: Actions.open;
+ action: Cura.Actions.open;
}
Menu
@@ -95,7 +93,7 @@ UM.MainWindow
text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File");
enabled: UM.Selection.hasSelection;
iconName: "document-save-as";
- onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", Printer.jobName, { "filter_by_machine": false });
+ onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false });
}
Menu
{
@@ -111,18 +109,18 @@ UM.MainWindow
MenuItem
{
text: model.description;
- onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, Printer.jobName, { "filter_by_machine": false });
+ onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, PrintInformation.jobName, { "filter_by_machine": false });
}
onObjectAdded: saveAllMenu.insertItem(index, object)
onObjectRemoved: saveAllMenu.removeItem(object)
}
}
- MenuItem { action: Actions.reloadAll; }
+ MenuItem { action: Cura.Actions.reloadAll; }
MenuSeparator { }
- MenuItem { action: Actions.quit; }
+ MenuItem { action: Cura.Actions.quit; }
}
Menu
@@ -130,17 +128,17 @@ UM.MainWindow
//: Edit menu
title: catalog.i18nc("@title:menu menubar:toplevel","&Edit");
- MenuItem { action: Actions.undo; }
- MenuItem { action: Actions.redo; }
+ MenuItem { action: Cura.Actions.undo; }
+ MenuItem { action: Cura.Actions.redo; }
MenuSeparator { }
- MenuItem { action: Actions.deleteSelection; }
- MenuItem { action: Actions.deleteAll; }
- MenuItem { action: Actions.resetAllTranslation; }
- MenuItem { action: Actions.resetAll; }
+ MenuItem { action: Cura.Actions.deleteSelection; }
+ MenuItem { action: Cura.Actions.deleteAll; }
+ MenuItem { action: Cura.Actions.resetAllTranslation; }
+ MenuItem { action: Cura.Actions.resetAll; }
MenuSeparator { }
- MenuItem { action: Actions.groupObjects;}
- MenuItem { action: Actions.mergeObjects;}
- MenuItem { action: Actions.unGroupObjects;}
+ MenuItem { action: Cura.Actions.groupObjects;}
+ MenuItem { action: Cura.Actions.mergeObjects;}
+ MenuItem { action: Cura.Actions.unGroupObjects;}
}
Menu
@@ -180,7 +178,7 @@ UM.MainWindow
text: model.name;
checkable: true;
checked: Cura.MachineManager.activeMachineId == model.id
- exclusiveGroup: machineSelectionMenuGroup;
+ exclusiveGroup: machineMenuGroup;
onTriggered: Cura.MachineManager.setActiveMachine(model.id);
}
onObjectAdded: machineMenu.insertItem(index, object)
@@ -216,8 +214,8 @@ UM.MainWindow
MenuSeparator { visible: Cura.MachineManager.hasVariants; }
- MenuItem { action: Actions.addMachine; }
- MenuItem { action: Actions.configureMachines; }
+ MenuItem { action: Cura.Actions.addMachine; }
+ MenuItem { action: Cura.Actions.configureMachines; }
}
Menu
@@ -228,7 +226,26 @@ UM.MainWindow
Instantiator
{
id: profileMenuInstantiator
-// model: UM.ProfilesModel {}
+ 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 {
@@ -241,13 +258,13 @@ UM.MainWindow
{
//Insert a separator between readonly and custom profiles
if(separatorIndex < 0 && index > 0) {
- if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) {
+ if(model.getItem(index-1).metadata.read_only != model.getItem(index).metadata.read_only) {
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);
+ profileMenu.insertItem((model.getItem(index).metadata.read_only) ? index : index + 1, object.item);
}
onObjectRemoved:
{
@@ -271,30 +288,20 @@ UM.MainWindow
{
id: item
text: model_data ? model_data.name : ""
- checkable: true;
- checked: model_data ? model_data.active : false;
- exclusiveGroup: profileMenuGroup;
- onTriggered:
- {
- UM.MachineManager.setActiveProfile(model_data.name);
- if (!model_data.active) {
- //Selecting a profile was canceled; undo menu selection
- profileMenuInstantiator.model.setProperty(model_index, "active", false);
- var activeProfileName = UM.MachineManager.activeProfile;
- var activeProfileIndex = profileMenuInstantiator.model.find("name", activeProfileName);
- profileMenuInstantiator.model.setProperty(activeProfileIndex, "active", true);
- }
- }
+ checkable: true
+ checked: Cura.MachineManager.activeQualityId == model_data.id
+ exclusiveGroup: profileMenuGroup
+ onTriggered: Cura.MachineManager.setActiveQuality(model_data.id)
}
}
MenuSeparator { id: profileMenuSeparator }
- MenuItem { action: Actions.updateProfile; }
- MenuItem { action: Actions.resetProfile; }
- MenuItem { action: Actions.addProfile; }
+ MenuItem { action: Cura.Actions.updateProfile; }
+ MenuItem { action: Cura.Actions.resetProfile; }
+ MenuItem { action: Cura.Actions.addProfile; }
MenuSeparator { }
- MenuItem { action: Actions.manageProfiles; }
+ MenuItem { action: Cura.Actions.manageProfiles; }
}
Menu
@@ -305,7 +312,7 @@ UM.MainWindow
Instantiator
{
- id: extenions
+ id: extensions
model: UM.ExtensionModel { }
Menu
@@ -320,7 +327,7 @@ UM.MainWindow
MenuItem
{
text: model.text
- onTriggered: extenions.model.subMenuTriggered(name, model.text)
+ onTriggered: extensions.model.subMenuTriggered(name, model.text)
}
onObjectAdded: sub_menu.insertItem(index, object)
onObjectRemoved: sub_menu.removeItem(object)
@@ -337,7 +344,7 @@ UM.MainWindow
//: Settings menu
title: catalog.i18nc("@title:menu menubar:toplevel","&Settings");
- MenuItem { action: Actions.preferences; }
+ MenuItem { action: Cura.Actions.preferences; }
}
Menu
@@ -345,11 +352,11 @@ UM.MainWindow
//: Help menu
title: catalog.i18nc("@title:menu menubar:toplevel","&Help");
- MenuItem { action: Actions.showEngineLog; }
- MenuItem { action: Actions.documentation; }
- MenuItem { action: Actions.reportBug; }
+ MenuItem { action: Cura.Actions.showEngineLog; }
+ MenuItem { action: Cura.Actions.documentation; }
+ MenuItem { action: Cura.Actions.reportBug; }
MenuSeparator { }
- MenuItem { action: Actions.about; }
+ MenuItem { action: Cura.Actions.about; }
}
}
@@ -439,7 +446,7 @@ UM.MainWindow
left: parent.left;
//leftMargin: UM.Theme.getSize("loadfile_margin").width
}
- action: Actions.open;
+ action: Cura.Actions.open;
}
Image
@@ -527,12 +534,12 @@ UM.MainWindow
width: UM.Theme.getSize("sidebar").width;
- addMachineAction: Actions.addMachine;
- configureMachinesAction: Actions.configureMachines;
- addProfileAction: Actions.addProfile;
- updateProfileAction: Actions.updateProfile;
- resetProfileAction: Actions.resetProfile;
- manageProfilesAction: Actions.manageProfiles;
+ addMachineAction: Cura.Actions.addMachine;
+ configureMachinesAction: Cura.Actions.configureMachines;
+ addProfileAction: Cura.Actions.addProfile;
+ updateProfileAction: Cura.Actions.updateProfile;
+ resetProfileAction: Cura.Actions.resetProfile;
+ manageProfilesAction: Cura.Actions.manageProfiles;
}
}
}
@@ -573,16 +580,16 @@ UM.MainWindow
Connections
{
- target: Actions.preferences
+ target: Cura.Actions.preferences
onTriggered: preferences.visible = true
}
Connections
{
- target: Actions.addProfile
+ target: Cura.Actions.addProfile
onTriggered:
{
- UM.MachineManager.createProfile();
+ Cura.MachineManager.convertUserContainerToQuality();
preferences.setPage(5);
preferences.show();
@@ -593,7 +600,7 @@ UM.MainWindow
Connections
{
- target: Actions.configureMachines
+ target: Cura.Actions.configureMachines
onTriggered:
{
preferences.visible = true;
@@ -603,7 +610,7 @@ UM.MainWindow
Connections
{
- target: Actions.manageProfiles
+ target: Cura.Actions.manageProfiles
onTriggered:
{
preferences.visible = true;
@@ -613,7 +620,7 @@ UM.MainWindow
Connections
{
- target: Actions.configureSettingVisibility
+ target: Cura.Actions.configureSettingVisibility
onTriggered:
{
preferences.visible = true;
@@ -636,22 +643,22 @@ UM.MainWindow
id: objectContextMenu;
property variant objectId: -1;
- MenuItem { action: Actions.centerObject; }
- MenuItem { action: Actions.deleteObject; }
- MenuItem { action: Actions.multiplyObject; }
+ MenuItem { action: Cura.Actions.centerObject; }
+ MenuItem { action: Cura.Actions.deleteObject; }
+ MenuItem { action: Cura.Actions.multiplyObject; }
MenuSeparator { }
- MenuItem { action: Actions.deleteAll; }
- MenuItem { action: Actions.reloadAll; }
- MenuItem { action: Actions.resetAllTranslation; }
- MenuItem { action: Actions.resetAll; }
+ MenuItem { action: Cura.Actions.deleteAll; }
+ MenuItem { action: Cura.Actions.reloadAll; }
+ MenuItem { action: Cura.Actions.resetAllTranslation; }
+ MenuItem { action: Cura.Actions.resetAll; }
MenuSeparator { }
- MenuItem { action: Actions.groupObjects; }
- MenuItem { action: Actions.mergeObjects; }
- MenuItem { action: Actions.unGroupObjects; }
+ MenuItem { action: Cura.Actions.groupObjects; }
+ MenuItem { action: Cura.Actions.mergeObjects; }
+ MenuItem { action: Cura.Actions.unGroupObjects; }
Connections
{
- target: Actions.deleteObject
+ target: Cura.Actions.deleteObject
onTriggered:
{
if(objectContextMenu.objectId != 0)
@@ -664,7 +671,7 @@ UM.MainWindow
Connections
{
- target: Actions.multiplyObject
+ target: Cura.Actions.multiplyObject
onTriggered:
{
if(objectContextMenu.objectId != 0)
@@ -677,7 +684,7 @@ UM.MainWindow
Connections
{
- target: Actions.centerObject
+ target: Cura.Actions.centerObject
onTriggered:
{
if(objectContextMenu.objectId != 0)
@@ -692,14 +699,14 @@ UM.MainWindow
Menu
{
id: contextMenu;
- MenuItem { action: Actions.deleteAll; }
- MenuItem { action: Actions.reloadAll; }
- MenuItem { action: Actions.resetAllTranslation; }
- MenuItem { action: Actions.resetAll; }
+ MenuItem { action: Cura.Actions.deleteAll; }
+ MenuItem { action: Cura.Actions.reloadAll; }
+ MenuItem { action: Cura.Actions.resetAllTranslation; }
+ MenuItem { action: Cura.Actions.resetAll; }
MenuSeparator { }
- MenuItem { action: Actions.groupObjects; }
- MenuItem { action: Actions.mergeObjects; }
- MenuItem { action: Actions.unGroupObjects; }
+ MenuItem { action: Cura.Actions.groupObjects; }
+ MenuItem { action: Cura.Actions.mergeObjects; }
+ MenuItem { action: Cura.Actions.unGroupObjects; }
}
Connections
@@ -720,13 +727,13 @@ UM.MainWindow
Connections
{
- target: Actions.quit
+ target: Cura.Actions.quit
onTriggered: base.visible = false;
}
Connections
{
- target: Actions.toggleFullScreen
+ target: Cura.Actions.toggleFullScreen
onTriggered: base.toggleFullscreen();
}
@@ -756,7 +763,7 @@ UM.MainWindow
Connections
{
- target: Actions.open
+ target: Cura.Actions.open
onTriggered: openDialog.open()
}
@@ -767,7 +774,7 @@ UM.MainWindow
Connections
{
- target: Actions.showEngineLog
+ target: Cura.Actions.showEngineLog
onTriggered: engineLog.visible = true;
}
@@ -778,7 +785,7 @@ UM.MainWindow
Connections
{
- target: Actions.addMachine
+ target: Cura.Actions.addMachine
onTriggered: addMachineDialog.visible = true;
}
@@ -789,7 +796,7 @@ UM.MainWindow
Connections
{
- target: Actions.about
+ target: Cura.Actions.about
onTriggered: aboutDialog.visible = true;
}
diff --git a/resources/qml/GeneralPage.qml b/resources/qml/GeneralPage.qml
index dcd5c66d73..0ae783916b 100644
--- a/resources/qml/GeneralPage.qml
+++ b/resources/qml/GeneralPage.qml
@@ -5,7 +5,6 @@ import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
-import QtQml.Models 2.2
import UM 1.1 as UM
@@ -207,10 +206,11 @@ UM.PreferencesPage
}
}
- DelegateModel
+ ListView
{
id: plugins
model: UM.PluginsModel { }
+ visible: false
}
}
}
diff --git a/resources/qml/JobSpecs.qml b/resources/qml/JobSpecs.qml
index 9551e3bcf5..e73bf145de 100644
--- a/resources/qml/JobSpecs.qml
+++ b/resources/qml/JobSpecs.qml
@@ -10,62 +10,25 @@ import UM 1.1 as UM
import Cura 1.0 as Cura
Rectangle {
- id: base;
+ id: base
- property bool activity: Printer.getPlatformActivity;
+ property bool activity: Printer.getPlatformActivity
property string fileBaseName
property variant activeMachineName: Cura.MachineManager.activeMachineName
onActiveMachineNameChanged:
{
- base.createFileName()
+ printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
}
UM.I18nCatalog { id: catalog; name:"cura"}
- property variant printDuration: PrintInformation.currentPrintTime;
- property real printMaterialAmount: PrintInformation.materialAmount;
+ property variant printDuration: PrintInformation.currentPrintTime
+ property real printMaterialAmount: PrintInformation.materialAmount
height: childrenRect.height
color: "transparent"
- function createFileName()
- {
- var splitMachineName = Cura.MachineManager.activeMachineName.split(" ")
- var abbrMachine = "";
- if ((UM.Preferences.getValue("cura/jobname_prefix")))
- {
- for (var i = 0; i < splitMachineName.length; i++)
- {
- if (splitMachineName[i].search(/ultimaker/i) != -1)
- {
- abbrMachine += "UM";
- }
- else
- {
- if (splitMachineName[i].charAt(0).search(/[0-9]/g) == -1)
- {
- abbrMachine += splitMachineName[i].charAt(0);
- }
- }
- }
- var regExpAdditives = /[0-9\+]/g;
- var resultAdditives = splitMachineName[i].match(regExpAdditives);
- if (resultAdditives != null)
- {
- for (var j = 0; j < resultAdditives.length; j++)
- {
- abbrMachine += resultAdditives[j];
- }
- }
- printJobTextfield.text = abbrMachine + "_" + base.fileBaseName;
- }
- else
- {
- printJobTextfield.text = base.fileBaseName;
- }
- }
-
Connections
{
target: backgroundItem
@@ -78,20 +41,20 @@ Rectangle {
onActivityChanged: {
if (activity == true && base.fileBaseName == ''){
//this only runs when you open a file from the terminal (or something that works the same way; for example when you drag a file on the icon in MacOS or use 'open with' on Windows)
- base.fileBaseName = Printer.jobName //it gets the fileBaseName from CuraApplication.py because this saves the filebase when the file is opened using the terminal (or something alike)
- base.createFileName()
+ base.fileBaseName = PrintInformation.jobName; //get the fileBaseName from PrintInformation.py because this saves the filebase when the file is opened using the terminal (or something alike)
+ printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
}
if (activity == true && base.fileBaseName != ''){
//this runs in all other cases where there is a mesh on the buildplate (activity == true). It uses the fileBaseName from the hasMesh signal
- base.createFileName()
+ printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
}
if (activity == false){
//When there is no mesh in the buildplate; the printJobTextField is set to an empty string so it doesn't set an empty string as a jobName (which is later used for saving the file)
- printJobTextfield.text = ''
+ printJobTextfield.text = '';
}
}
- Rectangle
+ Rectangle
{
id: jobNameRow
anchors.top: parent.top
@@ -112,22 +75,22 @@ Rectangle {
width: UM.Theme.getSize("save_button_specs_icons").width
height: UM.Theme.getSize("save_button_specs_icons").height
- onClicked:
+ onClicked:
{
- printJobTextfield.selectAll()
- printJobTextfield.focus = true
+ printJobTextfield.selectAll();
+ printJobTextfield.focus = true;
}
style: ButtonStyle
{
background: Rectangle
{
color: "transparent"
- UM.RecolorImage
+ UM.RecolorImage
{
- width: UM.Theme.getSize("save_button_specs_icons").width
- height: UM.Theme.getSize("save_button_specs_icons").height
- sourceSize.width: width
- sourceSize.height: width
+ width: UM.Theme.getSize("save_button_specs_icons").width;
+ height: UM.Theme.getSize("save_button_specs_icons").height;
+ sourceSize.width: width;
+ sourceSize.height: width;
color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("text");
source: UM.Theme.getIcon("pencil");
}
@@ -147,15 +110,15 @@ Rectangle {
text: ''
horizontalAlignment: TextInput.AlignRight
onTextChanged: {
- Printer.setJobName(text)
+ PrintInformation.setJobName(text);
}
onEditingFinished: {
if (printJobTextfield.text != ''){
- printJobTextfield.focus = false
+ printJobTextfield.focus = false;
}
}
validator: RegExpValidator {
- regExp: /^[^\\ \/ \.]*$/
+ regExp: /^[^\\ \/ \*\?\|\[\]]*$/
}
style: TextFieldStyle{
textColor: UM.Theme.getColor("setting_control_text");
@@ -200,7 +163,7 @@ Rectangle {
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.getColor("text_subtext")
- source: UM.Theme.getIcon("print_time");
+ source: UM.Theme.getIcon("print_time")
}
Label{
id: timeSpec
@@ -221,7 +184,7 @@ Rectangle {
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.getColor("text_subtext")
- source: UM.Theme.getIcon("category_material");
+ source: UM.Theme.getIcon("category_material")
}
Label{
id: lengthSpec
@@ -229,7 +192,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
font: UM.Theme.getFont("small")
color: UM.Theme.getColor("text_subtext")
- text: base.printMaterialAmount <= 0 ? catalog.i18nc("@label", "0.0 m") : catalog.i18nc("@label", "%1 m").arg(base.printMaterialAmount)
+ text: catalog.i18nc("@label", "%1 m").arg(base.printMaterialAmount > 0 ? base.printMaterialAmount : 0)
}
}
}
diff --git a/resources/qml/MachinesPage.qml b/resources/qml/MachinesPage.qml
index 00ebcfc0af..faef019deb 100644
--- a/resources/qml/MachinesPage.qml
+++ b/resources/qml/MachinesPage.qml
@@ -17,6 +17,16 @@ UM.ManagementPage
filter: {"type": "machine"}
}
+ activeId: Cura.MachineManager.activeMachineId
+ activeIndex: {
+ for(var i = 0; i < model.rowCount(); i++) {
+ if (model.getItem(i).id == Cura.MachineManager.activeMachineId) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
onAddObject: Printer.requestAddPrinter()
onRemoveObject: confirmDialog.open();
onRenameObject: renameDialog.open();
diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml
index 03ede39a5c..af0f0c1bd2 100644
--- a/resources/qml/Preferences/MaterialsPage.qml
+++ b/resources/qml/Preferences/MaterialsPage.qml
@@ -14,13 +14,37 @@ UM.ManagementPage
title: catalog.i18nc("@title:tab", "Materials");
- model: UM.InstanceContainersModel { filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } }
-/*
- onAddObject: { var selectedMaterial = UM.MaterialManager.createProfile(); base.selectMaterial(selectedMaterial); }
- onRemoveObject: confirmDialog.open();
- onRenameObject: { renameDialog.open(); renameDialog.selectText(); }
-*/
-// activateEnabled: false
+ 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
+ }
+ }
+
+ activeId: Cura.MachineManager.activeMaterialId
+ activeIndex: {
+ for(var i = 0; i < model.rowCount(); i++) {
+ if (model.getItem(i).id == Cura.MachineManager.activeMaterialId) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
addEnabled: false
removeEnabled: false
renameEnabled: false
@@ -185,7 +209,7 @@ UM.ManagementPage
onCurrentItemChanged:
{
- if(!currentItem == null)
+ if(currentItem == null)
{
return
}
diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml
index 10acc8beef..ed9c20f65f 100644
--- a/resources/qml/Preferences/ProfilesPage.qml
+++ b/resources/qml/Preferences/ProfilesPage.qml
@@ -15,18 +15,47 @@ UM.ManagementPage
title: catalog.i18nc("@title:tab", "Profiles");
addText: catalog.i18nc("@label", "Duplicate")
- model: UM.InstanceContainersModel { filter: { "type": "quality" } }
+ 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
+ }
+ }
+
+ activeId: Cura.MachineManager.activeQualityId
+ activeIndex: {
+ for(var i = 0; i < model.rowCount(); i++) {
+ if (model.getItem(i).id == Cura.MachineManager.activeQualityId) {
+ return i;
+ }
+ }
+ return -1;
+ }
onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id)
onAddObject: {
- var selectedProfile;
+ var selectedContainer;
if (objectList.currentIndex == 0) {
// Current settings
- selectedProfile = UM.MachineManager.createProfile();
+ selectedContainer = Cura.MachineManager.convertUserContainerToQuality();
} else {
- selectedProfile = UM.MachineManager.duplicateProfile(currentItem.name);
+ selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id);
}
- base.selectProfile(selectedProfile);
+ base.selectContainer(selectedContainer);
renameDialog.removeWhenRejected = true;
renameDialog.open();
@@ -37,14 +66,17 @@ UM.ManagementPage
activateEnabled: currentItem != null ? currentItem.id != Cura.MachineManager.activeQualityId : false;
addEnabled: currentItem != null;
- removeEnabled: currentItem != null ? !currentItem.readOnly : false;
- renameEnabled: currentItem != null ? !currentItem.readOnly : false;
+ removeEnabled: currentItem != null ? !currentItem.metadata.read_only : false;
+ renameEnabled: currentItem != null ? !currentItem.metadata.read_only : false;
- scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(UM.MachineManager.activeMachineInstance)
+ scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName)
- signal selectProfile(string name)
- onSelectProfile: {
- objectList.currentIndex = objectList.model.find("name", name);
+ signal showProfileNameDialog()
+ onShowProfileNameDialog: { renameDialog.removeWhenRejected = true; renameDialog.open(); renameDialog.selectText(); }
+
+ signal selectContainer(string id)
+ onSelectContainer: {
+ objectList.currentIndex = objectList.model.find("id", id);
}
Item {
@@ -59,70 +91,63 @@ UM.ManagementPage
elide: Text.ElideRight
}
- ScrollView {
+ Row {
+ id: currentSettingsActions
+ visible: base.currentItem.id == -1 || currentItem.id == Cura.MachineManager.activeQualityId
+
anchors.left: parent.left
anchors.top: profileName.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
+
+ Button
+ {
+ text: {
+ var profileName = Cura.MachineManager.activeQualityName;
+ profileName = (profileName.length > 20) ? profileName.substring(0, 20) + '...' : profileName;
+ return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName));
+ }
+ enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
+ onClicked: Cura.MachineManager.updateUserContainerToQuality()
+ }
+
+ Button
+ {
+ text: catalog.i18nc("@action:button", "Discard changes");
+ enabled: Cura.MachineManager.hasUserSettings
+ onClicked: Cura.MachineManager.clearUserSettings();
+ }
+ }
+
+ ScrollView {
+ id: scrollView
+
+ anchors.left: parent.left
+ anchors.top: currentSettingsActions.visible ? currentSettingsActions.bottom : profileName.bottom
+ anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.right: parent.right
anchors.bottom: parent.bottom
- Column
- {
- spacing: UM.Theme.getSize("default_margin").height
-
- Row
- {
- visible: base.currentItem.id == -1 || currentItem.id == Cura.MachineManager.activeQualityId
- Button
- {
- text: {
- var profileName = UM.MachineManager.activeProfile;
- profileName = (profileName.length > 20) ? profileName.substring(0, 20) + '...' : profileName;
- return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName));
- }
- enabled: UM.ActiveProfile.hasCustomisedValues && !UM.ActiveProfile.readOnly
- onClicked: UM.ActiveProfile.updateProfile()
+ ListView {
+ model: base.currentItem ? base.currentItem.settings: null
+ delegate: Row {
+ spacing: UM.Theme.getSize("default_margin").width
+ Label {
+ text: model.label
+ elide: Text.ElideMiddle
+ width: scrollView.width / 100 * 40
}
-
- Button
- {
- text: catalog.i18nc("@action:button", "Discard changes");
- enabled: UM.ActiveProfile.hasCustomisedValues
- onClicked: UM.ActiveProfile.discardChanges()
+ Label {
+ text: model.value.toString()
+ }
+ Label {
+ text: model.unit
}
}
-
- Grid
- {
- id: containerGrid
- columns: 2
- spacing: UM.Theme.getSize("default_margin").width
-
- Label {
- text: base.currentItem == null ? "" :
- base.currentItem.id == -1 ? catalog.i18nc("@label", "Based on") : catalog.i18nc("@label", "Profile type")
- }
- Label {
- text: base.currentItem == null ? "" :
- base.currentItem.id == -1 ? UM.MachineManager.activeProfile :
- base.currentItem.readOnly ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile")
- }
-
- Column {
- Repeater {
- model: base.currentItem ? base.currentItem.settings : null
- Label {
- text: modelData.name.toString();
- elide: Text.ElideMiddle;
- }
- }
- }
- Column {
- Repeater {
- model: base.currentItem ? base.currentItem.settings : null
- Label { text: modelData.value.toString(); }
- }
- }
+ section.property: "category"
+ section.criteria: ViewSection.FullString
+ section.delegate: Label {
+ text: section
+ font.bold: true
}
}
}
@@ -139,9 +164,10 @@ UM.ManagementPage
Button
{
- text: catalog.i18nc("@action:button", "Export");
- iconName: "document-export";
- onClicked: exportDialog.open();
+ text: catalog.i18nc("@action:button", "Export")
+ iconName: "document-export"
+ onClicked: exportDialog.open()
+ enabled: currentItem != null
}
}
@@ -151,19 +177,19 @@ UM.ManagementPage
UM.ConfirmRemoveDialog
{
- id: confirmDialog;
- object: base.currentItem != null ? base.currentItem.name : "";
- onYes: base.model.removeProfile(base.currentItem.name);
+ id: confirmDialog
+ object: base.currentItem != null ? base.currentItem.name : ""
+ onYes: Cura.MachineManager.removeQualityContainer(base.currentItem.id)
}
UM.RenameDialog
{
id: renameDialog;
- object: base.currentItem != null ? base.currentItem.name : "";
- property bool removeWhenRejected: false;
- onAccepted: base.model.renameProfile(base.currentItem.name, newName.trim());
+ object: base.currentItem != null ? base.currentItem.name : ""
+ property bool removeWhenRejected: false
+ onAccepted: Cura.MachineManager.renameQualityContainer(base.currentItem.id, newName)
onRejected: {
if(removeWhenRejected) {
- base.model.removeProfile(base.currentItem.name)
+ Cura.MachineManager.removeQualityContainer(base.currentItem.id)
}
}
}
@@ -211,7 +237,7 @@ UM.ManagementPage
folder: base.model.getDefaultPath()
onAccepted:
{
- var result = base.model.exportProfile(base.currentItem.id, base.currentItem.name, fileUrl, selectedNameFilter)
+ var result = base.model.exportProfile(base.currentItem.id, fileUrl)
if(result && result.status == "error")
{
messageDialog.icon = StandardIcon.Critical
diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml
index 95aed3685c..c6291c8c85 100644
--- a/resources/qml/ProfileSetup.qml
+++ b/resources/qml/ProfileSetup.qml
@@ -59,7 +59,23 @@ Item{
id: profileSelectionInstantiator
model: UM.InstanceContainersModel
{
- filter: {"type": "quality"}
+ 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
@@ -72,13 +88,13 @@ Item{
{
//Insert a separator between readonly and custom profiles
if(separatorIndex < 0 && index > 0) {
- if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) {
+ if(model.getItem(index-1).metadata.read_only != model.getItem(index).metadata.read_only) {
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);
+ profileSelectionMenu.insertItem((model.getItem(index).metadata.read_only) ? index : index + 1, object.item);
}
onObjectRemoved:
{
@@ -101,20 +117,10 @@ Item{
{
id: item
text: model_data ? model_data.name : ""
- checkable: true;
+ checkable: true
checked: Cura.MachineManager.activeQualityId == model_data.id
exclusiveGroup: profileSelectionMenuGroup;
- onTriggered:
- {
- Cura.MachineManager.setActiveQuality(model_data.id);
- /*if (!model_data.active) {
- //Selecting a profile was canceled; undo menu selection
- profileSelectionInstantiator.model.setProperty(model_index, "active", false);
- var activeProfileName = UM.MachineManager.activeProfile;
- var activeProfileIndex = profileSelectionInstantiator.model.find("name", activeProfileName);
- profileSelectionInstantiator.model.setProperty(activeProfileIndex, "active", true);
- }*/
- }
+ onTriggered: Cura.MachineManager.setActiveQuality(model_data.id)
}
}
diff --git a/resources/qml/SaveButton.qml b/resources/qml/SaveButton.qml
index 1307e8f820..8b95de15ee 100644
--- a/resources/qml/SaveButton.qml
+++ b/resources/qml/SaveButton.qml
@@ -98,7 +98,7 @@ Rectangle {
text: UM.OutputDeviceManager.activeDeviceShortDescription
onClicked:
{
- UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, Printer.jobName, { "filter_by_machine": true })
+ UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName, { "filter_by_machine": true })
}
style: ButtonStyle {
diff --git a/resources/qml/Settings/SettingCategory.qml b/resources/qml/Settings/SettingCategory.qml
index f4e3dbe5ae..f4c35f876e 100644
--- a/resources/qml/Settings/SettingCategory.qml
+++ b/resources/qml/Settings/SettingCategory.qml
@@ -7,8 +7,7 @@ import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.1 as UM
-
-import ".."
+import Cura 1.0 as Cura
Button {
id: base;
@@ -45,7 +44,7 @@ Button {
iconSource: UM.Theme.getIcon("settings");
onClicked: {
- Actions.configureSettingVisibility.trigger(definition)
+ Cura.Actions.configureSettingVisibility.trigger(definition)
}
}
diff --git a/resources/qml/Settings/SettingCheckBox.qml b/resources/qml/Settings/SettingCheckBox.qml
index 6f0314160e..1d66e509d0 100644
--- a/resources/qml/Settings/SettingCheckBox.qml
+++ b/resources/qml/Settings/SettingCheckBox.qml
@@ -16,6 +16,7 @@ SettingItem
{
id: control
anchors.fill: parent
+ hoverEnabled: true
property bool checked:
{
diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml
new file mode 100644
index 0000000000..0160dab7fa
--- /dev/null
+++ b/resources/qml/Settings/SettingExtruder.qml
@@ -0,0 +1,114 @@
+// 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.Controls.Styles 1.1
+
+import UM 1.1 as UM
+import Cura 1.0 as Cura
+
+SettingItem
+{
+ id: base
+
+ contents: ComboBox
+ {
+ id: control
+
+ model: Cura.ExtrudersModel
+ {
+ id: extruders_model
+ }
+ textRole: "name"
+
+ anchors.fill: parent
+
+ MouseArea
+ {
+ anchors.fill: parent
+ acceptedButtons: Qt.NoButton
+ onWheel: wheel.accepted = true;
+ }
+
+ style: ComboBoxStyle
+ {
+ background: Rectangle
+ {
+ color:
+ {
+ if (!enabled)
+ {
+ return UM.Theme.getColor("setting_control_disabled");
+ }
+ if(control.hovered || base.activeFocus)
+ {
+ return UM.Theme.getColor("setting_control_highlight");
+ }
+ else
+ {
+ return extruders_model.getItem(index).colour;
+ }
+ }
+ border.width: UM.Theme.getSize("default_lining").width
+ border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : control.hovered ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border")
+ }
+ label: Item
+ {
+ Label
+ {
+ anchors.left: parent.left
+ anchors.leftMargin: UM.Theme.getSize("default_lining").width
+ anchors.right: downArrow.left
+ anchors.rightMargin: UM.Theme.getSize("default_lining").width
+ anchors.verticalCenter: parent.verticalCenter
+
+ text: control.currentText
+ font: UM.Theme.getFont("default")
+ color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : extruders_model.getItem(index).colour
+
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ UM.RecolorImage
+ {
+ id: downArrow
+ anchors.right: parent.right
+ anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2
+ anchors.verticalCenter: parent.verticalCenter
+
+ source: UM.Theme.getIcon("arrow_bottom")
+ width: UM.Theme.getSize("standard_arrow").width
+ height: UM.Theme.getSize("standard_arrow").height
+ sourceSize.width: width + 5
+ sourceSize.height: width + 5
+
+ color: UM.Theme.getColor("setting_control_text")
+ }
+ }
+ }
+
+ onActivated: provider.setPropertyValue("value", extruders_model.getItem(index).index);
+ onModelChanged: updateCurrentIndex();
+
+ Connections
+ {
+ target: provider
+ onPropertiesChanged: control.updateCurrentIndex();
+ }
+
+ function updateCurrentIndex()
+ {
+ for(var i = 0; i < extruders_model.rowCount(); ++i)
+ {
+ if(extruders_model.getItem(i).index == provider.properties.value)
+ {
+ currentIndex = i;
+ return;
+ }
+ }
+ currentIndex = -1;
+ }
+ }
+}
diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml
index c1666a8157..e4edc267ef 100644
--- a/resources/qml/Settings/SettingItem.qml
+++ b/resources/qml/Settings/SettingItem.qml
@@ -18,10 +18,50 @@ Item {
property alias contents: controlContainer.children;
property alias hovered: mouse.containsMouse
+ property var showRevertButton: true
+ property var showInheritButton: true
+ property var doDepthIdentation: true
+
+ // Create properties to put property provider stuff in (bindings break in qt 5.5.1 otherwise)
+ property var state: propertyProvider.properties.state
+ property var stackLevel: propertyProvider.stackLevel
+
signal contextMenuRequested()
signal showTooltip(string text);
signal hideTooltip();
+ property string tooltipText:
+ {
+ var affects = settingDefinitionsModel.getRequiredBy(definition.key, "value")
+ var affected_by = settingDefinitionsModel.getRequires(definition.key, "value")
+
+ var affected_by_list = ""
+ for(var i in affected_by)
+ {
+ affected_by_list += "%1\n".arg(affected_by[i].label)
+ }
+
+ var affects_list = ""
+ for(var i in affects)
+ {
+ affects_list += "%1\n".arg(affects[i].label)
+ }
+
+ var tooltip = "%1\n%2
".arg(definition.label).arg(definition.description)
+
+ if(affects_list != "")
+ {
+ tooltip += "
%1\n".arg(catalog.i18nc("@label", "Affects")).arg(affects_list)
+ }
+
+ if(affected_by_list != "")
+ {
+ tooltip += "
%1\n".arg(catalog.i18nc("@label", "Affected By")).arg(affected_by_list)
+ }
+
+ return tooltip
+ }
+
MouseArea
{
id: mouse;
@@ -52,34 +92,7 @@ Item {
onTriggered:
{
- var affects = settingDefinitionsModel.getRequiredBy(definition.key, "value")
- var affected_by = settingDefinitionsModel.getRequires(definition.key, "value")
-
- var affected_by_list = ""
- for(var i in affected_by)
- {
- affected_by_list += "%1\n".arg(affected_by[i].label)
- }
-
- var affects_list = ""
- for(var i in affects)
- {
- affects_list += "%1\n".arg(affects[i].label)
- }
-
- var tooltip = "%1
\n%2
".arg(definition.label).arg(definition.description)
-
- if(affects_list != "")
- {
- tooltip += "
%1
\n".arg(catalog.i18nc("@label", "Affects")).arg(affects_list)
- }
-
- if(affected_by_list != "")
- {
- tooltip += "
%1
\n".arg(catalog.i18nc("@label", "Affected By")).arg(affected_by_list)
- }
-
- base.showTooltip(tooltip);
+ base.showTooltip(base.tooltipText);
}
}
@@ -88,7 +101,7 @@ Item {
id: label;
anchors.left: parent.left;
- anchors.leftMargin: (UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width)
+ anchors.leftMargin: doDepthIdentation ? (UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width) : 0
anchors.right: settingControls.left;
anchors.verticalCenter: parent.verticalCenter
@@ -119,7 +132,7 @@ Item {
{
id: revertButton;
- visible: propertyProvider.stackLevel == 0
+ visible: base.stackLevel == 0 && base.showRevertButton
height: parent.height;
width: height;
@@ -136,8 +149,8 @@ Item {
propertyProvider.removeFromContainer(0)
}
- onEntered: base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile."))
- onExited: base.showTooltip(definition.description);
+ onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) }
+ onExited: base.showTooltip(base.tooltipText);
}
UM.SimpleButton
@@ -146,14 +159,14 @@ Item {
id: inheritButton;
//visible: has_profile_value && base.has_inherit_function && base.is_enabled
- visible: propertyProvider.properties.state == "InstanceState.User" && propertyProvider.stackLevel > 0
+ visible: base.state == "InstanceState.User" && base.stackLevel > 0 && base.showInheritButton
height: parent.height;
width: height;
onClicked: {
focus = true;
- propertyProvider.removeFromContainer(propertyProvider.stackLevel)
+ propertyProvider.removeFromContainer(base.stackLevel)
}
backgroundColor: UM.Theme.getColor("setting_control");
@@ -163,8 +176,8 @@ Item {
iconSource: UM.Theme.getIcon("notice");
- onEntered: base.showTooltip(catalog.i18nc("@label", "This setting is normally calculated, but it currently has an absolute value set.\n\nClick to restore the calculated value."))
- onExited: base.showTooltip(definition.description);
+ onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting is normally calculated, but it currently has an absolute value set.\n\nClick to restore the calculated value.")) }
+ onExited: base.showTooltip(base.tooltipText);
}
}
diff --git a/resources/qml/Settings/SettingTextField.qml b/resources/qml/Settings/SettingTextField.qml
index 9972f83aa1..2a1fb96330 100644
--- a/resources/qml/Settings/SettingTextField.qml
+++ b/resources/qml/Settings/SettingTextField.qml
@@ -16,8 +16,6 @@ SettingItem
anchors.fill: parent
- property alias hovered: mouseArea.containsMouse;
-
border.width: UM.Theme.getSize("default_lining").width
border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : hovered ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border")
@@ -74,7 +72,7 @@ SettingItem
{
id: mouseArea
anchors.fill: parent;
- hoverEnabled: true;
+ //hoverEnabled: true;
cursorShape: Qt.IBeamCursor
}
diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml
index 560e7b0803..6261496c84 100644
--- a/resources/qml/Settings/SettingView.qml
+++ b/resources/qml/Settings/SettingView.qml
@@ -9,8 +9,6 @@ import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
-import ".."
-
ScrollView
{
id: base;
@@ -26,6 +24,7 @@ ScrollView
{
id: contents
spacing: UM.Theme.getSize("default_lining").height;
+ cacheBuffer: 1000000; // Set a large cache to effectively just cache every list item.
model: UM.SettingDefinitionsModel {
id: definitionsModel;
@@ -50,8 +49,9 @@ ScrollView
//Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
//In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
- //causing nasty issues when selecting differnt options. So disable asynchronous loading of enum type completely.
- asynchronous: model.type != "enum"
+ //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
+ asynchronous: model.type != "enum" && model.type != "extruder"
+ active: model.type != undefined
source:
{
@@ -63,6 +63,8 @@ ScrollView
return "SettingTextField.qml"
case "enum":
return "SettingComboBox.qml"
+ case "extruder":
+ return "SettingExtruder.qml"
case "bool":
return "SettingCheckBox.qml"
case "str":
@@ -78,7 +80,7 @@ ScrollView
{
id: provider
- containerStackId: Cura.MachineManager.activeMachineId
+ containerStackId: ExtruderManager.activeExtruderStackId ? ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId
key: model.key
watchedProperties: [ "value", "enabled", "state", "validationState" ]
storeIndex: 0
@@ -134,7 +136,7 @@ ScrollView
//: Settings context menu action
text: catalog.i18nc("@action:menu", "Configure setting visiblity...");
- onTriggered: Actions.configureSettingVisibility.trigger(contextMenu);
+ onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu);
}
}
}
diff --git a/resources/qml/Settings/SettingsConfigurationPage.qml b/resources/qml/Settings/SettingsConfigurationPage.qml
deleted file mode 100644
index a2889d410a..0000000000
--- a/resources/qml/Settings/SettingsConfigurationPage.qml
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (c) 2015 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.Layouts 1.1
-import QtQuick.Dialogs 1.1
-import QtQuick.Controls.Styles 1.1
-import QtQml 2.2
-
-import UM 1.1 as UM
-
-import "../Preferences"
-
-PreferencesPage
-{
- //: Machine configuration page title.
- title: catalog.i18nc("@title:tab","Machine");
- id: base
-
- contents: ColumnLayout
- {
- z: base.z
- anchors.fill: parent;
- UM.I18nCatalog { id: catalog; name:"uranium"}
- RowLayout
- {
- //: Active machine combo box label
- Label { text: catalog.i18nc("@label:listbox","Active Machine:"); }
- ComboBox
- {
- id: machineCombo;
- Layout.fillWidth: true;
- model: UM.Models.machinesModel;
- textRole: "name";
- onActivated:
- {
- if(index != -1)
- UM.Models.machinesModel.setActive(index);
- }
-
- Connections
- {
- id: machineChange
- target: UM.Application
- onMachineChanged: machineCombo.currentIndex = machineCombo.find(UM.Application.machineName);
- }
-
- Component.onCompleted: machineCombo.currentIndex = machineCombo.find(UM.Application.machineName);
- }
- //: Remove active machine button
- Button { text: catalog.i18nc("@action:button","Remove"); onClicked: confirmRemoveDialog.open(); }
- }
- ScrollView
- {
- id: settingsScrollView
- Layout.fillWidth: true;
- Layout.fillHeight: true;
-
- ListView
- {
- id: settingsListView
- delegate: settingDelegate
- model: UM.Models.settingsModel
- x: 0
-
- section.property: "category"
- section.delegate: Label { text: section }
- }
- }
- }
-
- Component
- {
- id: settingDelegate
- CheckBox
- {
- z:0
- id: settingCheckBox
- text: model.name;
- x: depth * 25
- checked: model.visibility
- onClicked: ListView.view.model.setVisibility(model.key, checked)
- //enabled: !model.disabled
-
- onHoveredChanged:
- {
- if(hovered)
- {
- var xPos = parent.x + settingCheckBox.width;
- var yPos = parent.y;
- toolTip.show(model.description, 1000, 200, undefined, undefined) //tooltip-text, hover-delay in msec, animation-length in msec, position X, position Y (both y en x == undefined: gives the tooltip a standard placement in the right corner)
- } else
- {
- toolTip.hide(0, 0)//hover-delay in msec, animation-length in msec
- }
- }
- }
- }
-
- PreferencesToolTip
- {
- id: toolTip;
- }
-
- MessageDialog
- {
- id: confirmRemoveDialog;
-
- icon: StandardIcon.Question;
- //: Remove machine confirmation dialog title
- title: catalog.i18nc("@title:window","Confirm Machine Deletion");
- //: Remove machine confirmation dialog text
- text: catalog.i18nc("@label","Are you sure you wish to remove the machine?");
- standardButtons: StandardButton.Yes | StandardButton.No;
-
- onYes: UM.Models.machinesModel.removeMachine(machineCombo.currentIndex);
- }
-}
diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml
index 282fa8af25..237746ac0d 100644
--- a/resources/qml/SidebarHeader.qml
+++ b/resources/qml/SidebarHeader.qml
@@ -108,7 +108,11 @@ Item
exclusiveGroup: extruderMenuGroup;
checkable: true;
checked: base.currentExtruderIndex == index
- onClicked: base.currentExtruderIndex = index
+ onClicked:
+ {
+ base.currentExtruderIndex = index
+ ExtruderManager.setActiveExtruderIndex(index)
+ }
style: ButtonStyle {
background: Rectangle {
@@ -266,7 +270,23 @@ Item
id: materialSelectionInstantiator
model: UM.InstanceContainersModel
{
- filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId }
+ 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
{
diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml
index c828b5d3db..80870ac29f 100644
--- a/resources/qml/SidebarSimple.qml
+++ b/resources/qml/SidebarSimple.qml
@@ -28,13 +28,13 @@ Item
id: infillCellLeft
anchors.top: parent.top
anchors.left: parent.left
- width: base.width/100* 35 - UM.Theme.getSize("default_margin").width
+ width: base.width / 100 * 35 - UM.Theme.getSize("default_margin").width
height: childrenRect.height
Label{
id: infillLabel
//: Infill selection label
- text: catalog.i18nc("@label","Infill:");
+ text: catalog.i18nc("@label", "Infill:");
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
anchors.top: parent.top
@@ -85,7 +85,7 @@ Item
{
return UM.Theme.getColor("setting_control_selected")
}
- else if(mousearea.containsMouse)
+ else if(infillMouseArea.containsMouse)
{
return UM.Theme.getColor("setting_control_border_highlight")
}
@@ -106,7 +106,7 @@ Item
}
MouseArea {
- id: mousearea
+ id: infillMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
@@ -187,28 +187,29 @@ Item
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: brimCheckBox.verticalCenter
- width: parent.width/100*35 - 3 * UM.Theme.getSize("default_margin").width
+ width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width
//: Bed adhesion label
- text: catalog.i18nc("@label:listbox","Bed Adhesion:");
+ text: catalog.i18nc("@label:listbox", "Bed Adhesion:");
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
CheckBox{
id: brimCheckBox
- property bool hovered_ex: false
+ property alias _hovered: brimMouseArea.containsMouse
anchors.top: parent.top
anchors.left: adhesionHelperLabel.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
//: Setting enable skirt adhesion checkbox
- text: catalog.i18nc("@option:check","Print Brim");
+ text: catalog.i18nc("@option:check", "Print Brim");
style: UM.Theme.styles.checkbox;
checked: platformAdhesionType.properties.value == "brim"
MouseArea {
+ id: brimMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked:
@@ -217,13 +218,11 @@ Item
}
onEntered:
{
- parent.hovered_ex = true
base.showTooltip(brimCheckBox, Qt.point(-brimCheckBox.x, 0),
catalog.i18nc("@label", "Enable printing a brim. This will add a single-layer-thick flat area around your object which is easy to cut off afterwards."));
}
onExited:
{
- parent.hovered_ex = false
base.hideTooltip();
}
}
@@ -234,9 +233,9 @@ Item
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: supportCheckBox.verticalCenter
- width: parent.width/100*35 - 3 * UM.Theme.getSize("default_margin").width
+ width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width
//: Support label
- text: catalog.i18nc("@label:listbox","Support:");
+ text: catalog.i18nc("@label:listbox", "Support:");
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
@@ -244,7 +243,7 @@ Item
CheckBox{
id: supportCheckBox
visible: machineExtruderCount.properties.value <= 1
- property bool hovered_ex: false
+ property alias _hovered: supportMouseArea.containsMouse
anchors.top: brimCheckBox.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
@@ -252,11 +251,12 @@ Item
anchors.leftMargin: UM.Theme.getSize("default_margin").width
//: Setting enable support checkbox
- text: catalog.i18nc("@option:check","Print Support Structure");
+ text: catalog.i18nc("@option:check", "Print Support Structure");
style: UM.Theme.styles.checkbox;
checked: supportEnabled.properties.value == "True"
MouseArea {
+ id: supportMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked:
@@ -265,13 +265,11 @@ Item
}
onEntered:
{
- parent.hovered_ex = true
base.showTooltip(supportCheckBox, Qt.point(-supportCheckBox.x, 0),
catalog.i18nc("@label", "Enable printing support structures. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air."));
}
onExited:
{
- parent.hovered_ex = false
base.hideTooltip();
}
}
@@ -286,10 +284,10 @@ Item
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: supportHelperLabel.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
- width: parent.width/100*45
+ width: parent.width / 100 * 45
style: UM.Theme.styles.combobox
- property bool hovered_ex: false
+ property alias _hovered: supportExtruderMouseArea.containsMouse
currentIndex: supportEnabled.properties.value == "True" ? parseFloat(supportExtruderNr.properties.value) + 1 : 0
onActivated: {
@@ -301,18 +299,17 @@ Item
}
}
MouseArea {
+ id: supportExtruderMouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
onEntered:
{
- parent.hovered_ex = true
base.showTooltip(supportExtruderCombobox, Qt.point(-supportExtruderCombobox.x, 0),
catalog.i18nc("@label", "Select which extruder to use for support. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air."));
}
onExited:
{
- parent.hovered_ex = false
base.hideTooltip();
}
}
@@ -358,7 +355,7 @@ Item
anchors.rightMargin: UM.Theme.getSize("default_margin").width
wrapMode: Text.WordWrap
//: Tips label
- text: catalog.i18nc("@label","Need help improving your prints? Read the Ultimaker Troubleshooting Guides").arg("https://ultimaker.com/en/troubleshooting");
+ text: catalog.i18nc("@label", "Need help improving your prints? Read the Ultimaker Troubleshooting Guides").arg("https://ultimaker.com/en/troubleshooting");
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
linkColor: UM.Theme.getColor("text_link")
@@ -374,8 +371,6 @@ Item
key: "infill_sparse_density"
watchedProperties: [ "value" ]
storeIndex: 0
-
- onPropertiesChanged: console.log(properties.value)
}
UM.SettingPropertyProvider
diff --git a/resources/qml/qmldir b/resources/qml/qmldir
deleted file mode 100644
index 096561aca5..0000000000
--- a/resources/qml/qmldir
+++ /dev/null
@@ -1,3 +0,0 @@
-module Cura
-
-singleton Actions 1.0 Actions.qml
diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg
index 0329e9ffe1..86df9dab92 100644
--- a/resources/quality/high.inst.cfg
+++ b/resources/quality/high.inst.cfg
@@ -5,6 +5,9 @@ definition = fdmprinter
[metadata]
type = quality
+read_only = True
[values]
layer_height = 0.06
+speed_topbottom = 15
+speed_infill = 80
diff --git a/resources/profiles/general/Low+Quality.cfg b/resources/quality/low.inst.cfg
similarity index 69%
rename from resources/profiles/general/Low+Quality.cfg
rename to resources/quality/low.inst.cfg
index f7f4e5d6b7..6cebc46dd5 100644
--- a/resources/profiles/general/Low+Quality.cfg
+++ b/resources/quality/low.inst.cfg
@@ -1,9 +1,13 @@
[general]
-version = 1
+version = 2
name = Low Quality
-weight = -1
+definition = fdmprinter
-[settings]
+[metadata]
+type = quality
+read_only = True
+
+[values]
infill_sparse_density = 10
layer_height = 0.15
cool_min_layer_time = 3
@@ -12,4 +16,3 @@ speed_wall_x = 80
speed_infill = 100
wall_thickness = 1
speed_topbottom = 30
-
diff --git a/resources/quality/normal.inst.cfg b/resources/quality/normal.inst.cfg
index 6d317cdf7a..b12603f921 100644
--- a/resources/quality/normal.inst.cfg
+++ b/resources/quality/normal.inst.cfg
@@ -5,5 +5,6 @@ definition = fdmprinter
[metadata]
type = quality
+read_only = True
[values]
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg
new file mode 100644
index 0000000000..07d3fae601
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg
@@ -0,0 +1,23 @@
+[general]
+version = 2
+name = High Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_extended_plus_0.25_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.06
+wall_thickness = 0.88
+top_bottom_thickness = 0.72
+infill_sparse_density = 22
+speed_print = 30
+cool_min_layer_time = 3
+cool_fan_speed_min = 20
+cool_min_speed = 10
+cool_min_layer_time_fan_speed_max = 15
+
+
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg
new file mode 100644
index 0000000000..f554c7f058
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg
@@ -0,0 +1,24 @@
+[general]
+version = 2
+name = Fast Print
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_extended_plus_0.4_mm
+weight = -1
+read_only = True
+
+[values]
+layer_height = 0.15
+wall_thickness = 0.7
+top_bottom_thickness = 0.75
+infill_sparse_density = 18
+speed_print = 55
+speed_travel = 150
+speed_layer_0 = 30
+cool_min_layer_time = 3
+cool_fan_speed_min = 20
+cool_min_speed = 10
+cool_min_layer_time_fan_speed_max = 15
+
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg
new file mode 100644
index 0000000000..c1a8136cf5
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg
@@ -0,0 +1,22 @@
+[general]
+version = 2
+name = High Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_extended_plus_0.4_mm
+weight = -3
+read_only = True
+
+[values]
+layer_height = 0.06
+wall_thickness = 1.05
+top_bottom_thickness = 0.72
+infill_sparse_density = 22
+speed_print = 45
+cool_min_layer_time = 3
+cool_fan_speed_min = 20
+cool_min_speed = 10
+cool_min_layer_time_fan_speed_max = 15
+
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg
new file mode 100644
index 0000000000..eabc9827a1
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg
@@ -0,0 +1,21 @@
+[general]
+version = 2
+name = Normal Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_extended_plus_0.4_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.1
+wall_thickness = 1.05
+top_bottom_thickness = 0.8
+infill_sparse_density = 20
+speed_print = 45
+cool_min_layer_time = 3
+cool_fan_speed_min = 20
+cool_min_speed = 10
+cool_min_layer_time_fan_speed_max = 15
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg
new file mode 100644
index 0000000000..64e0ec72fb
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg
@@ -0,0 +1,23 @@
+[general]
+version = 2
+name = Normal Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_extended_plus_0.6_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.15
+wall_thickness = 1.59
+top_bottom_thickness = 1.2
+infill_sparse_density = 20
+speed_print = 40
+cool_min_layer_time = 3
+cool_fan_speed_min = 50
+cool_min_speed = 20
+cool_min_layer_time_fan_speed_max = 20
+
+
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg
new file mode 100644
index 0000000000..8857db6cc1
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg
@@ -0,0 +1,22 @@
+[general]
+version = 2
+name = Fast Print
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_extended_plus_0.8_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.2
+wall_thickness = 2.1
+top_bottom_thickness = 1.2
+infill_sparse_density = 20
+speed_print = 40
+cool_min_layer_time = 3
+cool_fan_speed_min = 50
+cool_min_speed = 15
+cool_min_layer_time_fan_speed_max = 25
+
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg
new file mode 100644
index 0000000000..d34ea88798
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg
@@ -0,0 +1,22 @@
+[general]
+version = 2
+name = High Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_extended_plus_0.25_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.06
+wall_thickness = 0.88
+top_bottom_thickness = 0.72
+infill_sparse_density = 22
+speed_print = 30
+cool_min_layer_time = 2
+cool_fan_speed_min = 20
+cool_min_speed = 15
+cool_min_layer_time_fan_speed_max = 15
+
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg
new file mode 100644
index 0000000000..ae9b437010
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg
@@ -0,0 +1,25 @@
+[general]
+version = 2
+name = Fast Print
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_extended_plus_0.4_mm
+weight = -1
+read_only = True
+
+[values]
+layer_height = 0.15
+wall_thickness = 0.7
+top_bottom_thickness = 0.75
+infill_sparse_density = 18
+speed_print = 45
+speed_travel = 150
+speed_layer_0 = 30
+cool_min_layer_time = 3
+cool_fan_speed_min = 80
+cool_min_speed = 10
+cool_min_layer_time_fan_speed_max = 15
+
+
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg
new file mode 100644
index 0000000000..e3fa254a74
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg
@@ -0,0 +1,21 @@
+[general]
+version = 2
+name = High Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_extended_plus_0.4_mm
+weight = -3
+read_only = True
+
+[values]
+layer_height = 0.06
+wall_thickness = 1.05
+top_bottom_thickness = 0.72
+infill_sparse_density = 22
+speed_print = 45
+cool_min_layer_time = 2
+cool_fan_speed_min = 80
+cool_min_speed = 15
+cool_min_layer_time_fan_speed_max = 15
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg
new file mode 100644
index 0000000000..48e767e1cb
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg
@@ -0,0 +1,22 @@
+[general]
+version = 2
+name = Normal Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_extended_plus_0.4_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.1
+wall_thickness = 1.05
+top_bottom_thickness = 0.8
+infill_sparse_density = 20
+speed_print = 45
+cool_min_layer_time = 3
+cool_fan_speed_min = 80
+cool_min_speed = 10
+cool_min_layer_time_fan_speed_max = 15
+
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg
new file mode 100644
index 0000000000..675c949364
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg
@@ -0,0 +1,21 @@
+[general]
+version = 2
+name = Normal Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_extended_plus_0.6_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.15
+wall_thickness = 1.59
+top_bottom_thickness = 1.2
+infill_sparse_density = 20
+speed_print = 40
+cool_min_layer_time = 5
+cool_fan_speed_min = 80
+cool_min_speed = 8
+cool_min_layer_time_fan_speed_max = 20
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg
new file mode 100644
index 0000000000..b631baea42
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg
@@ -0,0 +1,21 @@
+[general]
+version = 2
+name = Fast Print
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_extended_plus_0.8_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.2
+wall_thickness = 2.1
+top_bottom_thickness = 1.2
+infill_sparse_density = 20
+speed_print = 40
+cool_min_layer_time = 3
+cool_fan_speed_min = 80
+cool_min_speed = 8
+cool_min_layer_time_fan_speed_max = 25
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg
new file mode 100644
index 0000000000..142ee42b71
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg
@@ -0,0 +1,19 @@
+[general]
+version = 2
+name = High Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_pla_ultimaker2_extended_plus_0.25_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.06
+wall_thickness = 0.88
+top_bottom_thickness = 0.72
+infill_sparse_density = 22
+speed_print = 30
+cool_min_layer_time = 5
+cool_min_speed = 10
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg
new file mode 100644
index 0000000000..8fd8fedf4c
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg
@@ -0,0 +1,21 @@
+[general]
+version = 2
+name = Fast Print
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_pla_ultimaker2_extended_plus_0.4_mm
+weight = -1
+read_only = True
+
+[values]
+layer_height = 0.15
+wall_thickness = 0.7
+top_bottom_thickness = 0.75
+infill_sparse_density = 18
+speed_print = 60
+speed_travel = 150
+speed_layer_0 = 30
+cool_min_layer_time = 5
+cool_min_speed = 10
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg
new file mode 100644
index 0000000000..3fc5cb39a0
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg
@@ -0,0 +1,19 @@
+[general]
+version = 2
+name = High Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_pla_ultimaker2_extended_plus_0.4_mm
+weight = -3
+read_only = True
+
+[values]
+layer_height = 0.06
+wall_thickness = 1.05
+top_bottom_thickness = 0.72
+infill_sparse_density = 22
+speed_print = 50
+cool_min_layer_time = 5
+cool_min_speed = 10
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg
new file mode 100644
index 0000000000..94816b233c
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg
@@ -0,0 +1,19 @@
+[general]
+version = 2
+name = Normal Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+type = quality
+material = generic_pla_ultimaker2_extended_plus_0.4_mm
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.1
+wall_thickness = 1.05
+top_bottom_thickness = 0.8
+infill_sparse_density = 20
+speed_print = 50
+cool_min_layer_time = 5
+cool_min_speed = 10
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg
new file mode 100644
index 0000000000..2de9b6a482
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg
@@ -0,0 +1,19 @@
+[general]
+version = 2
+name = Normal Quality
+definition = ultimaker2_extended_plus
+
+[metadata]
+material = generic_pla_ultimaker2_extended_plus_0.6_mm
+type = quality
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.15
+wall_thickness = 1.59
+top_bottom_thickness = 1.2
+infill_sparse_density = 20
+speed_print = 55
+cool_min_layer_time = 5
+cool_min_speed = 10
diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg
new file mode 100644
index 0000000000..f3a1a14f73
--- /dev/null
+++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg
@@ -0,0 +1,19 @@
+[general]
+version = 2
+name = Fast Print
+definition = ultimaker2_extended_plus
+
+[metadata]
+material = generic_pla_ultimaker2_extended_plus_0.8_mm
+type = quality
+weight = -2
+read_only = True
+
+[values]
+layer_height = 0.2
+wall_thickness = 2.1
+top_bottom_thickness = 1.2
+infill_sparse_density = 20
+speed_print = 40
+cool_min_layer_time = 5
+cool_min_speed = 10
diff --git a/resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg
similarity index 58%
rename from resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile
rename to resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg
index 63c1fc9fdd..7a1da403ff 100644
--- a/resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = High Quality
-machine_type = ultimaker2plus
-machine_variant = 0.25 mm
-material = PLA
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_pla_ultimaker2_plus_0.25_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.06
wall_thickness = 0.88
top_bottom_thickness = 0.72
diff --git a/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg
similarity index 62%
rename from resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile
rename to resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg
index 06e401c139..54f180379d 100644
--- a/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile
+++ b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Fast Print
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = PLA
-weight = -1
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_pla_ultimaker2_plus_0.4_mm
+weight = -1
+read_only = True
+
+[values]
layer_height = 0.15
wall_thickness = 0.7
top_bottom_thickness = 0.75
diff --git a/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg
similarity index 58%
rename from resources/profiles/ultimaker2+/pla_0.4_high.curaprofile
rename to resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg
index 5e2f762354..926bcdcae7 100644
--- a/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile
+++ b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = High Quality
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = PLA
-weight = -3
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_pla_ultimaker2_plus_0.4_mm
+weight = -3
+read_only = True
+
+[values]
layer_height = 0.06
wall_thickness = 1.05
top_bottom_thickness = 0.72
diff --git a/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg
similarity index 58%
rename from resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile
rename to resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg
index 689a3251b2..f65544307e 100644
--- a/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Normal Quality
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = PLA
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_pla_ultimaker2_plus_0.4_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.1
wall_thickness = 1.05
top_bottom_thickness = 0.8
diff --git a/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg
similarity index 59%
rename from resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile
rename to resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg
index 188ed42a95..906613dc23 100644
--- a/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Normal Quality
-machine_type = ultimaker2plus
-machine_variant = 0.6 mm
-material = PLA
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+material = generic_pla_ultimaker2_plus_0.6_mm
+type = quality
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.15
wall_thickness = 1.59
top_bottom_thickness = 1.2
diff --git a/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg
similarity index 58%
rename from resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile
rename to resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg
index 92cb4a6054..5cad44ec9c 100644
--- a/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Fast Print
-machine_type = ultimaker2plus
-machine_variant = 0.8 mm
-material = PLA
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+material = generic_pla_ultimaker2_plus_0.8_mm
+type = quality
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.2
wall_thickness = 2.1
top_bottom_thickness = 1.2
diff --git a/resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg
similarity index 65%
rename from resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg
index 9f45e9d01a..0b7a371ff1 100644
--- a/resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = High Quality
-machine_type = ultimaker2plus
-machine_variant = 0.25 mm
-material = ABS
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_plus_0.25_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.06
wall_thickness = 0.88
top_bottom_thickness = 0.72
diff --git a/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg
similarity index 68%
rename from resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg
index 50018372b5..e9593b10a7 100644
--- a/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Fast Print
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = ABS
-weight = -1
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_plus_0.4_mm
+weight = -1
+read_only = True
+
+[values]
layer_height = 0.15
wall_thickness = 0.7
top_bottom_thickness = 0.75
diff --git a/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg
similarity index 65%
rename from resources/profiles/ultimaker2+/abs_0.4_high.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg
index 341c9cc34f..2bd3b4fa1a 100644
--- a/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = High Quality
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = ABS
-weight = -3
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_plus_0.4_mm
+weight = -3
+read_only = True
+
+[values]
layer_height = 0.06
wall_thickness = 1.05
top_bottom_thickness = 0.72
diff --git a/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg
similarity index 65%
rename from resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg
index d8fce8a4dd..34bb28d20a 100644
--- a/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Normal Quality
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = ABS
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_plus_0.4_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.1
wall_thickness = 1.05
top_bottom_thickness = 0.8
diff --git a/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg
similarity index 65%
rename from resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg
index 5512450471..2c4656a4d9 100644
--- a/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Normal Quality
-machine_type = ultimaker2plus
-machine_variant = 0.6 mm
-material = ABS
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_plus_0.6_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.15
wall_thickness = 1.59
top_bottom_thickness = 1.2
diff --git a/resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg
similarity index 65%
rename from resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg
index e5f27c51a2..d5b9557ebb 100644
--- a/resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Fast Print
-machine_type = ultimaker2plus
-machine_variant = 0.8 mm
-material = ABS
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_abs_ultimaker2_plus_0.8_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.2
wall_thickness = 2.1
top_bottom_thickness = 1.2
diff --git a/resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg
similarity index 65%
rename from resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg
index c4c09932d8..eaab2ff2b6 100644
--- a/resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = High Quality
-machine_type = ultimaker2plus
-machine_variant = 0.25 mm
-material = CPE
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_plus_0.25_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.06
wall_thickness = 0.88
top_bottom_thickness = 0.72
diff --git a/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg
similarity index 68%
rename from resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg
index f9050e5ce5..e20f5ec96b 100644
--- a/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Fast Print
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = CPE
-weight = -1
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_plus_0.4_mm
+weight = -1
+read_only = True
+
+[values]
layer_height = 0.15
wall_thickness = 0.7
top_bottom_thickness = 0.75
diff --git a/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg
similarity index 65%
rename from resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg
index 377ab5b257..9b64b5580c 100644
--- a/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = High Quality
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = CPE
-weight = -3
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_plus_0.4_mm
+weight = -3
+read_only = True
+
+[values]
layer_height = 0.06
wall_thickness = 1.05
top_bottom_thickness = 0.72
diff --git a/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg
similarity index 65%
rename from resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg
index e8142405ff..6ec06e1fb9 100644
--- a/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Normal Quality
-machine_type = ultimaker2plus
-machine_variant = 0.4 mm
-material = CPE
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_plus_0.4_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.1
wall_thickness = 1.05
top_bottom_thickness = 0.8
diff --git a/resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg
similarity index 65%
rename from resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg
index 034fa17e1b..f19032a95e 100644
--- a/resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Normal Quality
-machine_type = ultimaker2plus
-machine_variant = 0.6 mm
-material = CPE
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_plus_0.6_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.15
wall_thickness = 1.59
top_bottom_thickness = 1.2
diff --git a/resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg
similarity index 64%
rename from resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile
rename to resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg
index 523a5d3243..45372fdf39 100644
--- a/resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile
+++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg
@@ -1,12 +1,15 @@
[general]
-version = 1
+version = 2
name = Fast Print
-machine_type = ultimaker2plus
-machine_variant = 0.8 mm
-material = CPE
-weight = -2
+definition = ultimaker2_plus
-[settings]
+[metadata]
+type = quality
+material = generic_cpe_ultimaker2_plus_0.8_mm
+weight = -2
+read_only = True
+
+[values]
layer_height = 0.2
wall_thickness = 2.1
top_bottom_thickness = 1.2
diff --git a/resources/themes/cura/styles.qml b/resources/themes/cura/styles.qml
index b2c2329169..1428c3d40a 100644
--- a/resources/themes/cura/styles.qml
+++ b/resources/themes/cura/styles.qml
@@ -283,14 +283,14 @@ QtObject {
property Component combobox: Component {
ComboBoxStyle {
background: Rectangle {
- implicitHeight: UM.Theme.getSize("setting_control").height;
- implicitWidth: UM.Theme.getSize("setting_control").width;
+ implicitHeight: Theme.getSize("setting_control").height;
+ implicitWidth: Theme.getSize("setting_control").width;
- color: (control.hovered || control.hovered_ex) ? Theme.getColor("setting_control_highlight") : Theme.getColor("setting_control");
+ color: (control.hovered || control._hovered) ? Theme.getColor("setting_control_highlight") : Theme.getColor("setting_control");
Behavior on color { ColorAnimation { duration: 50; } }
border.width: Theme.getSize("default_lining").width;
- border.color: (control.hovered || control.hovered_ex) ? Theme.getColor("setting_control_border_highlight") : Theme.getColor("setting_control_border");
+ border.color: (control.hovered || control._hovered) ? Theme.getColor("setting_control_border_highlight") : Theme.getColor("setting_control_border");
}
label: Item {
Label {
@@ -301,7 +301,7 @@ QtObject {
anchors.verticalCenter: parent.verticalCenter;
text: control.currentText;
- font: UM.Theme.getFont("default");
+ font: Theme.getFont("default");
color: !enabled ? Theme.getColor("setting_control_disabled_text") : Theme.getColor("setting_control_text");
elide: Text.ElideRight;
@@ -314,9 +314,9 @@ QtObject {
anchors.rightMargin: Theme.getSize("default_lining").width * 2;
anchors.verticalCenter: parent.verticalCenter;
- source: UM.Theme.getIcon("arrow_bottom")
- width: UM.Theme.getSize("standard_arrow").width
- height: UM.Theme.getSize("standard_arrow").height
+ source: Theme.getIcon("arrow_bottom")
+ width: Theme.getSize("standard_arrow").width
+ height: Theme.getSize("standard_arrow").height
sourceSize.width: width + 5
sourceSize.height: width + 5
@@ -333,13 +333,13 @@ QtObject {
implicitWidth: Theme.getSize("checkbox").width;
implicitHeight: Theme.getSize("checkbox").height;
- color: (control.hovered || control.hovered_ex) ? Theme.getColor("checkbox_hover") : Theme.getColor("checkbox");
+ color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_hover") : Theme.getColor("checkbox");
Behavior on color { ColorAnimation { duration: 50; } }
radius: control.exclusiveGroup ? Theme.getSize("checkbox").width / 2 : 0
border.width: Theme.getSize("default_lining").width;
- border.color: (control.hovered || control.hovered_ex) ? Theme.getColor("checkbox_border_hover") : Theme.getColor("checkbox_border");
+ border.color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_border_hover") : Theme.getColor("checkbox_border");
UM.RecolorImage {
anchors.verticalCenter: parent.verticalCenter