From 4de0a208d15faa6474e733878b50ed3ce8803f1a Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 19 May 2016 14:48:34 +0200 Subject: [PATCH 001/182] Fix version number and remove beta tag in Changelog Fixes CURA-1575 --- plugins/ChangeLogPlugin/ChangeLog.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index 8dc6a61dd8..6cf0b5a488 100644 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -1,6 +1,5 @@ -[2.1.0] +[2.1.1] -*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. *Select Multiple Objects From f8c8de86bc47ccf69ae520a58a22e6f8aae07499 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 23 May 2016 11:35:01 +0200 Subject: [PATCH 002/182] Fix showing changelog when the first item in the changelog doesn't start with an "*" CURA-1583 --- plugins/ChangeLogPlugin/ChangeLog.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) 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) From 740f3775fa5c2703a6ff43c347aee6d5e23bec6c Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 13 May 2016 13:05:58 +0200 Subject: [PATCH 003/182] Reset stored layer data as soon as a new slice operation starts This prevents layer view showing a combination of stale and fresh data Fixes CURA-1370 (and CURA-1519) --- plugins/CuraEngineBackend/CuraEngineBackend.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index e3f9a4542e..d3d3469fbc 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -119,6 +119,7 @@ class CuraEngineBackend(Backend): ## Perform a slice of the scene. def slice(self): + self._stored_layer_data = [] if not self._enabled: return From 7e33b76fe2b744db682b5a0bf4277906178647fb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 30 May 2016 16:18:54 +0200 Subject: [PATCH 004/182] Increment version number Contributes to issue CURA-1583. --- plugins/ChangeLogPlugin/ChangeLog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index 6cf0b5a488..48e96ce4b6 100644 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -1,4 +1,4 @@ -[2.1.1] +[2.1.2] 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. From 23cb386b7c99f4070900a32ebfe0c9406f57e950 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Tue, 31 May 2016 17:41:36 +0200 Subject: [PATCH 005/182] Set default version to 2.1.2 While discussing on #718 I noticed that the splash screen still shows "master" when built from [2.1]. This sets the version to 2.1.2. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc9f37c76e..6a23ffe94f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,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_VERSION "2.1.2" CACHE STRING "Version name of Cura") configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY) # Macro needed to list all sub-directory of a directory. From 4dffc414fb0ee775ef6d5fc21e2a8cc85ee98858 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 17:59:03 +0200 Subject: [PATCH 006/182] Make convex hull decorator respond properly to property change events Fixes CURA-1460 --- cura/ConvexHullDecorator.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/cura/ConvexHullDecorator.py b/cura/ConvexHullDecorator.py index 8fb26858a5..6639d12dc7 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): 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() From f21e48adbbebb11630b90ac339d34f1a5e8bda9c Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 18:00:26 +0200 Subject: [PATCH 007/182] Register all QML files in Cura's QML directory as part of the Cura module Jaime asked for it. --- cura/CuraApplication.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index eccb3e4525..d7e5768116 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -42,7 +42,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 @@ -365,6 +365,15 @@ class CuraApplication(QtApplication): qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") + qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions") + + 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(): From 3b51c3d339a07effb593339b9fa7202e3f36c358 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 18:06:20 +0200 Subject: [PATCH 008/182] Remove qmldir from qml resources and use proper Cura namespace for everything Since we now properly expose all the qml files in the Cura namespace we should also use it from there. --- resources/qml/Cura.qml | 124 ++++++++++----------- resources/qml/Settings/SettingCategory.qml | 5 +- resources/qml/Settings/SettingView.qml | 4 +- resources/qml/qmldir | 3 - 4 files changed, 64 insertions(+), 72 deletions(-) delete mode 100644 resources/qml/qmldir diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index a7f4a43c22..a043567c0f 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 @@ -118,11 +116,11 @@ UM.MainWindow } } - 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 @@ -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 @@ -290,11 +288,11 @@ UM.MainWindow 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 @@ -337,7 +335,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 +343,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 +437,7 @@ UM.MainWindow left: parent.left; //leftMargin: UM.Theme.getSize("loadfile_margin").width } - action: Actions.open; + action: Cura.Actions.open; } Image @@ -527,12 +525,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,13 +571,13 @@ 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(); @@ -593,7 +591,7 @@ UM.MainWindow Connections { - target: Actions.configureMachines + target: Cura.Actions.configureMachines onTriggered: { preferences.visible = true; @@ -603,7 +601,7 @@ UM.MainWindow Connections { - target: Actions.manageProfiles + target: Cura.Actions.manageProfiles onTriggered: { preferences.visible = true; @@ -613,7 +611,7 @@ UM.MainWindow Connections { - target: Actions.configureSettingVisibility + target: Cura.Actions.configureSettingVisibility onTriggered: { preferences.visible = true; @@ -636,22 +634,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 +662,7 @@ UM.MainWindow Connections { - target: Actions.multiplyObject + target: Cura.Actions.multiplyObject onTriggered: { if(objectContextMenu.objectId != 0) @@ -677,7 +675,7 @@ UM.MainWindow Connections { - target: Actions.centerObject + target: Cura.Actions.centerObject onTriggered: { if(objectContextMenu.objectId != 0) @@ -692,14 +690,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 +718,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 +754,7 @@ UM.MainWindow Connections { - target: Actions.open + target: Cura.Actions.open onTriggered: openDialog.open() } @@ -767,7 +765,7 @@ UM.MainWindow Connections { - target: Actions.showEngineLog + target: Cura.Actions.showEngineLog onTriggered: engineLog.visible = true; } @@ -778,7 +776,7 @@ UM.MainWindow Connections { - target: Actions.addMachine + target: Cura.Actions.addMachine onTriggered: addMachineDialog.visible = true; } @@ -789,7 +787,7 @@ UM.MainWindow Connections { - target: Actions.about + target: Cura.Actions.about onTriggered: aboutDialog.visible = true; } 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/SettingView.qml b/resources/qml/Settings/SettingView.qml index 560e7b0803..48380e9a95 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; @@ -134,7 +132,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/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 From 3953da7a509886f002e305b8f62587504af5a37d Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 31 May 2016 18:13:47 +0200 Subject: [PATCH 009/182] JSON fix: support roof speed was visible when roof enabled but support not (CURA-1498) --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 6dca68a6c9..ce7c17c41c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1116,7 +1116,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 } From 38c9d9e4a12e65ccead5f784feaf9abfd7dab2b0 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 10:47:04 +0200 Subject: [PATCH 010/182] Fix highlighting the currently active (printer|quality|material) on their management pages CURA-1278 --- resources/qml/MachinesPage.qml | 10 ++++++++++ resources/qml/Preferences/MaterialsPage.qml | 10 ++++++++++ resources/qml/Preferences/ProfilesPage.qml | 10 ++++++++++ 3 files changed, 30 insertions(+) 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..0b606ced77 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -15,6 +15,16 @@ UM.ManagementPage title: catalog.i18nc("@title:tab", "Materials"); model: UM.InstanceContainersModel { filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } } + + 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; + } /* onAddObject: { var selectedMaterial = UM.MaterialManager.createProfile(); base.selectMaterial(selectedMaterial); } onRemoveObject: confirmDialog.open(); diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 10acc8beef..9561bba521 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -17,6 +17,16 @@ UM.ManagementPage model: UM.InstanceContainersModel { filter: { "type": "quality" } } + 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; From 2a288cd7a2107f43239143623fe4184264eb3b9b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 11:51:42 +0200 Subject: [PATCH 011/182] Fix typo causing a minor error when opening MaterialsPage.qml CURA-339 --- resources/qml/Preferences/MaterialsPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 0b606ced77..ed35a32fdf 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -195,7 +195,7 @@ UM.ManagementPage onCurrentItemChanged: { - if(!currentItem == null) + if(currentItem == null) { return } From a08e71774d2386d57e52aaa8e353bda0a8202d77 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 31 May 2016 10:59:32 +0200 Subject: [PATCH 012/182] Make ExtruderManagerModel no longer a PyQt model It is still a model according to the MVC paradigm but not according to Qt. To be consistent with the rest, don't call it a model any more. Contributes to issues CURA-1278 and CURA-351. --- cura/{ExtruderManagerModel.py => ExtruderManager.py} | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) rename cura/{ExtruderManagerModel.py => ExtruderManager.py} (95%) diff --git a/cura/ExtruderManagerModel.py b/cura/ExtruderManager.py similarity index 95% rename from cura/ExtruderManagerModel.py rename to cura/ExtruderManager.py index 7f0baa7aa8..c99ac4be00 100644 --- a/cura/ExtruderManagerModel.py +++ b/cura/ExtruderManager.py @@ -1,7 +1,6 @@ # 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. @@ -15,13 +14,9 @@ from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers # 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): +class ExtruderManager: ## 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) - + def __init__(self): 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. From 6164112bf2d8f78c30b6fe39cda29b5223686da4 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 1 Jun 2016 13:35:09 +0200 Subject: [PATCH 013/182] Setting textfield now updates correctly, even when mouse is hovering another text field. CURA-1278 --- resources/qml/Settings/SettingTextField.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 } From 48eb8de9a10b870aa3d0f26386a67c9d8f5e47c1 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 13:35:30 +0200 Subject: [PATCH 014/182] Add basic extruder implementation This implementation can load an extruder from a definition container, but doesn't expose anything (yet). It is intended to function in much the same way as a definition model, so it must expose its relevant properties to QML. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 cura/Extruder.py diff --git a/cura/Extruder.py b/cura/Extruder.py new file mode 100644 index 0000000000..f9f957dfe3 --- /dev/null +++ b/cura/Extruder.py @@ -0,0 +1,85 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +import re #To parse container registry names to increment the duplicates-resolving number. + +import UM.Settings.ContainerRegistry #To search for nozzles, materials, etc. +import UM.Settings.ContainerStack #To create a container stack for this extruder. + +class Extruder: + ## Creates a new extruder from the specified definition container. + # + # \param definition The definition container defining this extruder. + def __init__(self, definition): + self._definition = definition + + container_registry = UM.Settings.ContainerRegistry.getInstance() + + #Find the nozzles that fit on this extruder. + self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId() + ",*") + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId()) + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId() + ",*") + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId()) + + #Create a container stack for this extruder. + self._container_stack = UM.Settings.ContainerStack(self._uniqueName(self._definition.getId())) + self._container_stack.addMetaDataEntry("type", "extruder_train") + self._container_stack.addContainer(self._definition) + + #Find the nozzle to use for this extruder. + self._nozzle = container_registry.getEmptyInstanceContainer() + 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 = self._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() + 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() + 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) + + ## Finds a unique name for an extruder stack. + # + # \param extruder An extruder definition 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 = UM.Settings.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 From 377fed206c0d581c74b72d534fe8bf988ca3b5ef Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 13:41:25 +0200 Subject: [PATCH 015/182] Remove extruder creation logic from manager This logic is now in cura/Extruder.py. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 68 ++++++----------------------------------- 1 file changed, 9 insertions(+), 59 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index c99ac4be00..924c6a1e21 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -3,6 +3,7 @@ import re +from cura.Extruder import Extruder #The individual extruders managed by this manager. 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. @@ -26,72 +27,21 @@ class ExtruderManager: ## (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. + # Then it loads the extruders for that machine and loads each of them in a + # list of extruders. def _reloadExtruders(self): - self._extruderDefinitions = [] - self._nozzles = {} - self._extruderTrains = [] + self._extruders = [] 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. + #Get the extruder definitions belonging to the current machine. 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. + extruder_definitions = ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. + if not extruder_definitions: #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 + for extruder_definition in extruder_definitions: + self._extruders.append(Extruder(extruder_definition)) \ No newline at end of file From 60a71fcc332da5f7b20939e7458609b7c2be845c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 14:54:30 +0200 Subject: [PATCH 016/182] Only list extruders in extruder manager Let the extruders themselves take care of which profiles are attached to each. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 924c6a1e21..d0dea31206 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -18,9 +18,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers class ExtruderManager: ## Registers listeners and such to listen to changes to the extruders. def __init__(self): - 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. + self._extruders = [] #Extruders for the current machine. Application.getInstance().getGlobalContainerStack().containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. From d1566ef637a5c244c0e7a20611f4998a0fd104f3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 14:55:15 +0200 Subject: [PATCH 017/182] Also reload extruders at init Not a reload really, just a load. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index d0dea31206..4d95a9008d 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -21,6 +21,7 @@ class ExtruderManager: self._extruders = [] #Extruders for the current machine. Application.getInstance().getGlobalContainerStack().containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. + self._reloadExtruders() ## (Re)loads all extruders of the currently active machine. # From 91fc90a42323ef64258555c36b3e805881713e22 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 15:05:14 +0200 Subject: [PATCH 018/182] Link extruder stack to global container stack Each extruder stack is linked to the same global container stack. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index f9f957dfe3..8fa1b71ab1 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -3,6 +3,7 @@ import re #To parse container registry names to increment the duplicates-resolving number. +import UM.Application #To link the stack to the global container stack. import UM.Settings.ContainerRegistry #To search for nozzles, materials, etc. import UM.Settings.ContainerStack #To create a container stack for this extruder. @@ -62,6 +63,8 @@ class Extruder: self._quality = preferred_quality[0] self._container_stack.addContainer(self._quality) + self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + ## Finds a unique name for an extruder stack. # # \param extruder An extruder definition to design a name for. From 0e108f0c04b8be53f51ee7ef18ad23946b3d7e5c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 15:12:20 +0200 Subject: [PATCH 019/182] Document filtering nozzles by extruder better Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index 8fa1b71ab1..5f74bd036f 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -17,7 +17,7 @@ class Extruder: container_registry = UM.Settings.ContainerRegistry.getInstance() #Find the nozzles that fit on this extruder. - self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId() + ",*") + self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId() + ",*") #Extruder needs to be delimited by either a comma or the end of string. self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId()) self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId() + ",*") self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId()) From faf647dca05bb39f988637d56f7e2fbdaf5ad769 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 15:14:03 +0200 Subject: [PATCH 020/182] Git ignore resources/firmware It is also compiled and will only be included by including the cura-binary-data repository. However it is also useful to have this in your testing environment. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 72ba4bf565..f60e268711 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* From 49e5b1938a8a367d4d47ca04dc877e065982a940 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 1 Jun 2016 15:45:54 +0200 Subject: [PATCH 021/182] Reduce number of top layer to increase processing speed --- plugins/LayerView/LayerView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/LayerView/LayerView.py b/plugins/LayerView/LayerView.py index 9f65a8e783..27bb7f022c 100644 --- a/plugins/LayerView/LayerView.py +++ b/plugins/LayerView/LayerView.py @@ -44,7 +44,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) From ffa6a0376d44d7189cdaea9ff7fafd2d5eefaf49 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 21:44:56 +0200 Subject: [PATCH 022/182] Fix typo Contributes to CURA-1540, CURA-1278 --- resources/qml/Cura.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index a043567c0f..32e1e79029 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -303,7 +303,7 @@ UM.MainWindow Instantiator { - id: extenions + id: extensions model: UM.ExtensionModel { } Menu @@ -318,7 +318,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) From c6dd9d2c8c8028b3798080ad0192bfd165707226 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 22:21:12 +0200 Subject: [PATCH 023/182] Fix codestyle and change faux-"hovered" property mechanism hovered_ex was a bool property that was set in onEntered and onExited, and has been replaced with an alias to the mouseArea.containsMouse that necessitated the clutch. CURA-790 --- resources/qml/SidebarSimple.qml | 39 +++++++++++++++----------------- resources/themes/cura/styles.qml | 20 ++++++++-------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index c828b5d3db..c95cb54b1f 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") 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 From 7d65475bf99d88b6ed8d66154b733147b4112669 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 23:59:09 +0200 Subject: [PATCH 024/182] Fix mouseover highlight of checkbox settings CURA-1278 --- resources/qml/Settings/SettingCheckBox.qml | 1 + 1 file changed, 1 insertion(+) 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: { From 907de8b586192f51909a7233b85ffeea80e7b51b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 00:01:08 +0200 Subject: [PATCH 025/182] Improve performance of advanced sidebar Prevent a delegate being loaded when the item is "filtered out" by the model. CURA-1278 --- resources/qml/Settings/SettingView.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 48380e9a95..9dabbaee98 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -50,6 +50,7 @@ ScrollView //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" + active: model.type != undefined source: { From ed3d01ed7b53d6a83e3ce274fe35455214382504 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 06:38:57 +0200 Subject: [PATCH 026/182] Add icon to Machine category to squelch some warnings CURA-1278 --- resources/definitions/fdmprinter.def.json | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ce7c17c41c..48952c2c99 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": From d5aa75f2cf7beba2f6f2ba5243dc7d7cc8d18c46 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 01:47:44 +0200 Subject: [PATCH 027/182] Remove obsolete file --- .../Settings/SettingsConfigurationPage.qml | 119 ------------------ 1 file changed, 119 deletions(-) delete mode 100644 resources/qml/Settings/SettingsConfigurationPage.qml 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); - } -} From 803dcdcec703c69896dafc5263476c00c1ee9643 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 01:48:21 +0200 Subject: [PATCH 028/182] Stop the Item's hover timer when showing a different tooltip --- resources/qml/Settings/SettingItem.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index c1666a8157..4c14ee4039 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -136,7 +136,7 @@ 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.")) + 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(definition.description); } @@ -163,7 +163,7 @@ 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.")) + 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(definition.description); } From e0fab7aa11532b9243a42d8b7c1f9eb0093c9591 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:03:24 +0200 Subject: [PATCH 029/182] Add some logging and documentation to XmlMaterialProfile Contributes to CURA-339 --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index d73beec193..9cfca1c535 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: @@ -116,12 +122,15 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): UM.Settings.ContainerRegistry.getInstance().addContainer(new_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", } + # Map XML file product names to internal ids __product_id_map = { "Ultimaker2": "ultimaker2", "Ultimaker2+": "ultimaker2_plus", From f491405eb19f6504969a4f031aa630c5ba8b2526 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:04:06 +0200 Subject: [PATCH 030/182] Use a copy of the metadata for Xml materials Contributes to CURA-339 --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 9cfca1c535..bdffc3d60f 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -106,16 +106,18 @@ 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 From 90ac1c1380cb904ee07b33317954fdf65aa0d2d2 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:04:43 +0200 Subject: [PATCH 031/182] Add support for hotend-specfic overrides to XmlMaterialProfile Contributes to CURA-339 --- .../XmlMaterialProfile/XmlMaterialProfile.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index bdffc3d60f..c97dbe85ed 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -123,6 +123,44 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): 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 From eaea940aa2a9a4cbccdc23459088fb12064bdaf0 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:05:11 +0200 Subject: [PATCH 032/182] Add support for some additional properties to XmlMaterialProfile Contributes to CURA-339 --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index c97dbe85ed..89c7d76e9f 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -168,6 +168,9 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): "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 From 123af4e3e46e0f5ca0c5e6e801a27008b0dd956a Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:07:04 +0200 Subject: [PATCH 033/182] Use metadata to determine what materials/qualities to use when adding a machine Contributes to CURA-1612 --- cura/MachineManagerModel.py | 97 ++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 33 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index deef72529b..83b8e87859 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -1,11 +1,13 @@ +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 class MachineManagerModel(QObject): def __init__(self, parent = None): @@ -74,43 +76,48 @@ class MachineManagerModel(QObject): 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 definition.getMetaDataEntry("has_variants"): + variant_instance_container = self._getPreferredContainer(definition, "preferred_variant", empty_container) - if variants and variant_instance_container == empty_container: - variant_instance_container = variants[0] + if variant_instance_container == empty_container: + variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) + if variants: + 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) + if variant_instance_container == empty_container: + Logger.log("w", "Machine %s defines it has variants but no variants found", definition.id) - 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 definition.getMetaDataEntry("has_materials"): + material_instance_container = self._getPreferredContainer(definition, "preferred_material", empty_container) - if materials and material_instance_container == empty_container: - material_instance_container = materials[0] + if material_instance_container == empty_container: + materials = None + if definition.getMetaDataEntry("has_machine_materials"): + if variant_instance_container != empty_container: + materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id, variant = variant_instance_container.id) + else: + materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id) + else: + materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = "fdmprinter") - 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] + if materials: + material_instance_container = materials[0] + + quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", empty_container) + + if quality_instance_container == empty_container: + if definition.getMetaDataEntry("has_machine_quality"): + if material_instance_container: + qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id, material = material_instance_container.id) + else: + qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id) + else: + qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = "fdmprinter") + + if qualities: + quality_instance_container = qualities[0] current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings") current_settings_instance_container.addMetaDataEntry("machine", name) @@ -277,16 +284,40 @@ class MachineManagerModel(QObject): @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 _getPreferredContainer(self, definition, property_name, default_container): + preferred_id = definition.getMetaDataEntry(property_name) + if preferred_id: + preferred_variant_id = preferred_variant_id.lower() + container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id) + if container: + return container[0] + + return default_container + def createMachineManagerModel(engine, script_engine): return MachineManagerModel() From ceb21ce89b6f7e8cbc89fcc17a4546f57f72f3ed Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:07:51 +0200 Subject: [PATCH 034/182] Filter material/quality by machine only when we should filter Contributes to CURA-1612 --- resources/qml/ProfileSetup.qml | 18 +++++++++++++++++- resources/qml/SidebarHeader.qml | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml index 95aed3685c..3175a4e2b3 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 diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 282fa8af25..4b48584174 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -266,7 +266,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 { From 2b91e3639ed6e28985ee3b3f82345f0be2c57808 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:08:21 +0200 Subject: [PATCH 035/182] Add basic ABS and CPE material profiles Contributes to CURA-1612 --- .../materials/generic_abs.xml.fdm_material | 34 +++++++++++++++++++ .../materials/generic_cpe.xml.fdm_material | 34 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 resources/materials/generic_abs.xml.fdm_material create mode 100644 resources/materials/generic_cpe.xml.fdm_material 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 + + + + + + + + + + + + From 6847365e097420c12e2824923ef85bbd70972933 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:08:56 +0200 Subject: [PATCH 036/182] Indicate the UM2+ should use machine specific materials and qualities Contributes to CURA-1612 --- resources/definitions/ultimaker.def.json | 5 +---- resources/definitions/ultimaker2_plus.def.json | 8 ++++++-- 2 files changed, 7 insertions(+), 6 deletions(-) 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..75501fb158 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": "generic_pla_ultimaker2_plus_0.4mm", + "preferred_quality": "pla_0.4_normal", + "has_variants": true, + "has_materials": true, + "has_machine_materials": true, + "has_machine_quality": true }, "overrides": { From 48c8e7a1897961cd504edd510931e19cd4fc3478 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:09:14 +0200 Subject: [PATCH 037/182] Update generic PLA profile Contributes to CURA-1612 --- .../materials/generic_pla.xml.fdm_material | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) 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 - + + + + From 5ce9bc64f4ec9145d53d481a3f0f1f8638f79032 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:09:38 +0200 Subject: [PATCH 038/182] Remove non-xml material profiles Contributes to CURA-1612 --- resources/materials/abs.inst.cfg | 12 ------------ resources/materials/cpe.inst.cfg | 11 ----------- resources/materials/pla.inst.cfg | 10 ---------- 3 files changed, 33 deletions(-) delete mode 100644 resources/materials/abs.inst.cfg delete mode 100644 resources/materials/cpe.inst.cfg delete mode 100644 resources/materials/pla.inst.cfg 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/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 From 7f7b56ff08988058ea1ba28b4496f5c2310fef0a Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:10:32 +0200 Subject: [PATCH 039/182] Add additional quality profiles Low quality and machine-specific qualities for UM2+ Contributes to CURA-1612 --- resources/quality/low.inst.cfg | 10 +++++++++ .../ultimaker2_plus/pla_0.25_normal.inst.cfg | 18 ++++++++++++++++ .../ultimaker2_plus/pla_0.4_fast.inst.cfg | 20 ++++++++++++++++++ .../ultimaker2_plus/pla_0.4_high.inst.cfg | 18 ++++++++++++++++ .../ultimaker2_plus/pla_0.4_normal.inst.cfg | 18 ++++++++++++++++ .../ultimaker2_plus/pla_0.4_ulti.inst.cfg | 21 +++++++++++++++++++ .../ultimaker2_plus/pla_0.6_normal.inst.cfg | 18 ++++++++++++++++ .../ultimaker2_plus/pla_0.8_normal.inst.cfg | 18 ++++++++++++++++ 8 files changed, 141 insertions(+) create mode 100644 resources/quality/low.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg diff --git a/resources/quality/low.inst.cfg b/resources/quality/low.inst.cfg new file mode 100644 index 0000000000..d684bd81b9 --- /dev/null +++ b/resources/quality/low.inst.cfg @@ -0,0 +1,10 @@ +[general] +version = 2 +name = Low Quality +definition = fdmprinter + +[metadata] +type = quality + +[values] +layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg new file mode 100644 index 0000000000..9a44582610 --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_plus_0.25_mm +weight = -2 + +[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_plus/pla_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg new file mode 100644 index 0000000000..be1e1ce992 --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg @@ -0,0 +1,20 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_plus_0.4_mm +weight = -1 + +[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_plus/pla_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg new file mode 100644 index 0000000000..b058d17fbd --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_plus_0.4_mm +weight = -3 + +[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_plus/pla_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg new file mode 100644 index 0000000000..78ee8cf566 --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_plus_0.4_mm +weight = -2 + +[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_plus/pla_0.4_ulti.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg new file mode 100644 index 0000000000..db091d8e8d --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg @@ -0,0 +1,21 @@ +[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/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg new file mode 100644 index 0000000000..f8f966e25a --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[metadata] +material = generic_pla_ultimaker2_plus_0.6_mm +type = quality +weight = -2 + +[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_plus/pla_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg new file mode 100644 index 0000000000..ec53d15867 --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[metadata] +material = generic_pla_ultimaker2_plus_0.8_mm +type = quality +weight = -2 + +[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 From 72bc68f38ac8209170d1d60693fe8fab7c2f74a1 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 15:16:39 +0200 Subject: [PATCH 040/182] Use self._definition instead of local definition parameter This is supposedly more defensive coding. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index 5f74bd036f..b8783026f1 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -17,10 +17,10 @@ class Extruder: container_registry = UM.Settings.ContainerRegistry.getInstance() #Find the nozzles that fit on this extruder. - self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId() + ",*") #Extruder needs to be delimited by either a comma or the end of string. - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId()) - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId() + ",*") - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId()) + self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + self._definition.getId() + ",*") #Extruder needs to be delimited by either a comma or the end of string. + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + self._definition.getId()) + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId() + ",*") + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) #Create a container stack for this extruder. self._container_stack = UM.Settings.ContainerStack(self._uniqueName(self._definition.getId())) From 7993775feb6887874dd5947160760101955883d7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 16:33:24 +0200 Subject: [PATCH 041/182] Make profiles only load if the extruder says it has them For instance, only load materials if has_materials is True. Contributes to issues CURA-351 and CURA-1278. --- cura/Extruder.py | 60 ++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index b8783026f1..d0c5478270 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -29,39 +29,45 @@ class Extruder: #Find the nozzle to use for this extruder. self._nozzle = container_registry.getEmptyInstanceContainer() - 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 = self._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) + if self._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 = self._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() - 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) + 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() - 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) + 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) self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) From 9772d95984e4d52261de5dd6df18488abe363521 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 16:47:52 +0200 Subject: [PATCH 042/182] Add user profile to extruder stack This profile is empty to start with. The user can fill it. Contributes to issues CURA-351 and CURA-1278. --- cura/Extruder.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index d0c5478270..c51f3106a2 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -23,7 +23,8 @@ class Extruder: self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) #Create a container stack for this extruder. - self._container_stack = UM.Settings.ContainerStack(self._uniqueName(self._definition.getId())) + name = self._uniqueName(self._definition.getId()) + self._container_stack = UM.Settings.ContainerStack(name) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) @@ -69,6 +70,11 @@ class Extruder: self._quality = preferred_quality[0] self._container_stack.addContainer(self._quality) + #Add an empty user profile. + self._user_profile = UM.Settings.InstanceContainer(name + "_current_settings") + self._user_profile.addMetaDataEntry("type", "user") + self._container_stack.addContainer(self._user_profile) + self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) ## Finds a unique name for an extruder stack. From 1603bb3075d0bd90d3f11cef1587709d8fa0a46f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 10:55:03 +0200 Subject: [PATCH 043/182] Give access to nozzle, material and quality profiles You can now swap them out in the extruder model. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index c51f3106a2..5be05c713c 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -4,8 +4,10 @@ import re #To parse container registry names to increment the duplicates-resolving number. import UM.Application #To link the stack to the global container stack. +import UM.Logger import UM.Settings.ContainerRegistry #To search for nozzles, materials, etc. import UM.Settings.ContainerStack #To create a container stack for this extruder. +import UM.Signal #To notify people of changing extruder stacks. class Extruder: ## Creates a new extruder from the specified definition container. @@ -77,6 +79,73 @@ class Extruder: self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + nozzle_changed = UM.Signal.Signal() + material_changed = UM.Signal.Signal() + quality_changed = UM.Signal.Signal() + + ## Gets the currently active material on this extruder. + # + # \return The currently active material on this extruder. + @property + def material(self): + return self._material + + ## Changes the currently active material in this extruder. + # + # \param value The new material to extrude through this extruder. + @material.setter + def material(self, value): + try: + position = self._container_stack.index(self._material) + except ValueError: #Material is not in the list. + UM.Logger.log("e", "I've lost my old material, so I can't find where to insert the new material.") + return + self._container_stack.replaceContainer(position, value) + self._material = value + self.material_changed.emit() + + ## Gets the currently active nozzle on this extruder. + # + # \return The currently active nozzle on this extruder. + @property + def nozzle(self): + return self._nozzle + + ## Changes the currently active nozzle on this extruder. + # + # \param value The new nozzle to use with this extruder. + @nozzle.setter + def nozzle(self, value): + try: + position = self._container_stack.index(self._nozzle) + except ValueError: #Nozzle is not in the list. + UM.Logger.log("e", "I've lost my old nozzle, so I can't find where to insert the new nozzle.") + return + self._container_stack.replaceContainer(position, value) + self._nozzle = value + self.nozzle_changed.emit() + + ## Gets the currently active quality on this extruder. + # + # \return The currently active quality on this extruder. + @property + def quality(self): + return self._quality + + ## Changes the currently active quality to use with this extruder. + # + # \param value The new quality to use with this extruder. + @quality.setter + def quality(self, value): + try: + position = self._container_stack.index(self._quality) + except ValueError: #Quality is not in the list. + UM.Logger.log("e", "I've lost my old quality, so I can't find where to insert the new quality.") + return + self._container_stack.replaceContainer(position, value) + self._quality = value + self.quality_changed.emit() + ## Finds a unique name for an extruder stack. # # \param extruder An extruder definition to design a name for. From e03f65c47158474d48e1d5643433baf4e3828524 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 11:12:37 +0200 Subject: [PATCH 044/182] Remove stray debug print CURA-1278 --- resources/qml/SidebarSimple.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index c95cb54b1f..80870ac29f 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -371,8 +371,6 @@ Item key: "infill_sparse_density" watchedProperties: [ "value" ] storeIndex: 0 - - onPropertiesChanged: console.log(properties.value) } UM.SettingPropertyProvider From c369202957e4e5c10fe7b1a889a5e704ffbab337 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:08:22 +0200 Subject: [PATCH 045/182] Fix unknown variable Was probably a copy-paste mistake here. Fixed it for him. Contributes to issue CURA-1278. --- cura/MachineManagerModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 83b8e87859..c3b57ca8d0 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -312,8 +312,8 @@ class MachineManagerModel(QObject): def _getPreferredContainer(self, definition, property_name, default_container): preferred_id = definition.getMetaDataEntry(property_name) if preferred_id: - preferred_variant_id = preferred_variant_id.lower() - container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id) + preferred_id = preferred_id.lower() + container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_id) if container: return container[0] From 73f12ffd99e0b4c7fba37dd845f36928d2d884e4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:15:52 +0200 Subject: [PATCH 046/182] Incorporate switching of global extruder stack When the global extruder stack switches, we need to re-connect the reloading of extruders to the new containersChanged signal of the new global container stack. This now also bootstraps the listening for the first time, when the global container stack changes from None to the first stack. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 4d95a9008d..71b636ad6f 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -19,9 +19,17 @@ class ExtruderManager: ## Registers listeners and such to listen to changes to the extruders. def __init__(self): self._extruders = [] #Extruders for the current machine. + self._global_container_stack = None - Application.getInstance().getGlobalContainerStack().containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. - self._reloadExtruders() + Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. + + ## When the global container stack changes, this reconnects to the new + # signal for containers changing. + def _reconnectExtruderReload(self): + if self._global_container_stack: + self._global_container_stack.containersChanged.disconnect(self._reloadExtruders) #Disconnect from the old global container stack. + self._global_container_stack = Application.getInstance().getGlobalContainerStack() + self._global_container_stack.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. # @@ -30,12 +38,11 @@ class ExtruderManager: # list of extruders. def _reloadExtruders(self): self._extruders = [] - global_container_stack = Application.getInstance().getGlobalContainerStack() - if not global_container_stack: #No machine has been added yet. + if not self._global_container_stack: #No machine has been added yet. return #Then leave them empty! #Get the extruder definitions belonging to the current machine. - machine = global_container_stack.getBottom() + machine = self._global_container_stack.getBottom() extruder_train_ids = machine.getMetaData("machine_extruder_trains") for extruder_train_id in extruder_train_ids: extruder_definitions = ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. From 95e633f16cf1746b97405d63ae86e63959ac241f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:17:39 +0200 Subject: [PATCH 047/182] Load extruder manager on start-up This will consequently also load all extruder stacks of the current machine whenever the current machine changes. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index d7e5768116..49fcbbf405 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -30,6 +30,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog +from . import ExtruderManager from . import PlatformPhysics from . import BuildVolume from . import CameraAnimation @@ -326,6 +327,8 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) + self._extruder_manager = ExtruderManager.ExtruderManager() + self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) self.initializeEngine() From 14a8b8a1a40ea3e889fb2a1715f4637eb3e10fa1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 13:30:26 +0200 Subject: [PATCH 048/182] Fix showing formatted tooltip when exiting reset-value-icon CURA-1278 --- resources/qml/Settings/SettingItem.qml | 65 ++++++++++++++------------ 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 4c14ee4039..aa4ef5be85 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -22,6 +22,38 @@ Item { 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
      \n%2
    ".arg(catalog.i18nc("@label", "Affects")).arg(affects_list) + } + + if(affected_by_list != "") + { + tooltip += "
    %1\n
      \n%2
    ".arg(catalog.i18nc("@label", "Affected By")).arg(affected_by_list) + } + + return tooltip + } + MouseArea { id: mouse; @@ -52,34 +84,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
      \n%2
    ".arg(catalog.i18nc("@label", "Affects")).arg(affects_list) - } - - if(affected_by_list != "") - { - tooltip += "
    %1
    \n
      \n%2
    ".arg(catalog.i18nc("@label", "Affected By")).arg(affected_by_list) - } - - base.showTooltip(tooltip); + base.showTooltip(base.tooltipText); } } @@ -137,7 +142,7 @@ Item { } 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(definition.description); + onExited: base.showTooltip(base.tooltipText); } UM.SimpleButton @@ -164,7 +169,7 @@ Item { iconSource: UM.Theme.getIcon("notice"); 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(definition.description); + onExited: base.showTooltip(base.tooltipText); } } From 1af6e63b35f8483bac5674ae7315bed1dcf867e2 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 13:41:46 +0200 Subject: [PATCH 049/182] Removed unused model --- .../PerObjectSettingsModel.py | 75 ------------------- .../PerObjectSettingsTool.py | 1 - 2 files changed, 76 deletions(-) delete mode 100644 plugins/PerObjectSettingsTool/PerObjectSettingsModel.py 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/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index c74800e83d..f702d0b939 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -6,7 +6,6 @@ from UM.Scene.Selection import Selection from UM.Application import Application from UM.Preferences import Preferences -from . import PerObjectSettingsModel class PerObjectSettingsTool(Tool): def __init__(self): From ca218d7a1fb6e46a4092ab072062458c56e44273 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 13:52:11 +0200 Subject: [PATCH 050/182] Removed too generic exception handling CURA-1278 --- .../PerObjectSettingsTool.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index f702d0b939..a06ecd297f 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -32,18 +32,14 @@ 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 + return selected_object.callDecoration("getStack").getId() + except AttributeError: + return "" def setContainerID(self, value): pass From b9f2d498b4ddfc0d02f36b8d109180abf90a42a7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:25:38 +0200 Subject: [PATCH 051/182] Fix typo in documentation --- resources/qml/Settings/SettingView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 9dabbaee98..6a11136966 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -48,7 +48,7 @@ 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. + //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. asynchronous: model.type != "enum" active: model.type != undefined From 1f9805a73c0b7cdfba3b57405062703e0e6b9d97 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:43:02 +0200 Subject: [PATCH 052/182] Remove unused imports These are unused because the code was moved to Extruder.py Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 71b636ad6f..60d452ae73 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -1,12 +1,9 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -import re - from cura.Extruder import Extruder #The individual extruders managed by this manager. 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. From 06f7f90bb08c5a5dea6e216a670cf05d112125a9 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 12:04:19 +0200 Subject: [PATCH 053/182] Make ExtruderManager into a singleton This way we don't need to load it in CuraApplication but we can just load it whenever it is first needed. ExtruderManager should be robust against initialising it at any point in Cura's runtime. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 2 -- cura/ExtruderManager.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 49fcbbf405..b8cef52d0c 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -327,8 +327,6 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) - self._extruder_manager = ExtruderManager.ExtruderManager() - self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) self.initializeEngine() diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 60d452ae73..34dbfd7c0c 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -13,6 +13,9 @@ from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers # 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 ExtruderManager: + ## The singleton instance of this manager. + __instance = None + ## Registers listeners and such to listen to changes to the extruders. def __init__(self): self._extruders = [] #Extruders for the current machine. @@ -20,6 +23,16 @@ class ExtruderManager: Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. + ## Gets an instance of this extruder manager. + # + # If an instance was already created, the old instance is returned. This + # implements the singleton pattern. + @classmethod + def getInstance(cls): + if not cls.__instance: + cls.__instance = ExtruderManager() + return cls.__instance + ## When the global container stack changes, this reconnects to the new # signal for containers changing. def _reconnectExtruderReload(self): From 8a8b0016ba314fbf7167710f24cf139beb0ce8ce Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 12:55:01 +0200 Subject: [PATCH 054/182] Add signal for when extruder list changes The ExtrudersModel will need to listen to this. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 34dbfd7c0c..3477a3175f 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -5,6 +5,7 @@ from cura.Extruder import Extruder #The individual extruders managed by this man from UM.Application import Application #To get the global container stack to find the current machine. from UM.Logger import Logger from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID. +import UM.Signal #To notify other components of changes in the extruders. ## Class that handles the current extruder stack. @@ -16,6 +17,9 @@ class ExtruderManager: ## The singleton instance of this manager. __instance = None + ## Signal to notify other components when the list of extruders changes. + extrudersChanged = UM.Signal() + ## Registers listeners and such to listen to changes to the extruders. def __init__(self): self._extruders = [] #Extruders for the current machine. @@ -49,6 +53,7 @@ class ExtruderManager: def _reloadExtruders(self): self._extruders = [] if not self._global_container_stack: #No machine has been added yet. + self.extrudersChanged.emit() #Yes, we just cleared the _extruders list! return #Then leave them empty! #Get the extruder definitions belonging to the current machine. @@ -60,4 +65,5 @@ class ExtruderManager: Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) continue for extruder_definition in extruder_definitions: - self._extruders.append(Extruder(extruder_definition)) \ No newline at end of file + self._extruders.append(Extruder(extruder_definition)) + self.extrudersChanged.emit() \ No newline at end of file From 83693162369851aff7f287de64095066205edcd3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 12:56:55 +0200 Subject: [PATCH 055/182] Use modern import method This is more robust to cyclic dependencies, and also the intended way of importing these classes in Python in general. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 3477a3175f..51faa0a5e2 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -2,9 +2,9 @@ # Cura is released under the terms of the AGPLv3 or higher. from cura.Extruder import Extruder #The individual extruders managed by this manager. -from UM.Application import Application #To get the global container stack to find the current machine. -from UM.Logger import Logger -from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID. +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. import UM.Signal #To notify other components of changes in the extruders. @@ -25,7 +25,7 @@ class ExtruderManager: self._extruders = [] #Extruders for the current machine. self._global_container_stack = None - Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. + UM.Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. ## Gets an instance of this extruder manager. # @@ -42,7 +42,7 @@ class ExtruderManager: def _reconnectExtruderReload(self): if self._global_container_stack: self._global_container_stack.containersChanged.disconnect(self._reloadExtruders) #Disconnect from the old global container stack. - self._global_container_stack = Application.getInstance().getGlobalContainerStack() + self._global_container_stack = UM.Application.getInstance().getGlobalContainerStack() self._global_container_stack.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. @@ -60,9 +60,9 @@ class ExtruderManager: machine = self._global_container_stack.getBottom() extruder_train_ids = machine.getMetaData("machine_extruder_trains") for extruder_train_id in extruder_train_ids: - extruder_definitions = ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. + extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. if not extruder_definitions: #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) + UM.Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) continue for extruder_definition in extruder_definitions: self._extruders.append(Extruder(extruder_definition)) From 8a8de959692e4ea65135166de3ad4c2bba84d585 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:11:02 +0200 Subject: [PATCH 056/182] Add iteration over extruder manager This iteration iterates over the extruders. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 51faa0a5e2..3c1e50d9bd 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -24,6 +24,7 @@ class ExtruderManager: def __init__(self): self._extruders = [] #Extruders for the current machine. self._global_container_stack = None + self._next_item = 0 #For when you use this class as iterator. UM.Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. @@ -37,6 +38,12 @@ class ExtruderManager: cls.__instance = ExtruderManager() return cls.__instance + ## Creates an iterator over the extruders in this manager. + # + # \return An iterator over the extruders in this manager. + def __iter__(self): + return iter(self._extruders) + ## When the global container stack changes, this reconnects to the new # signal for containers changing. def _reconnectExtruderReload(self): From 25a6a992869e7f84511e838211f951e17df2ab61 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:15:33 +0200 Subject: [PATCH 057/182] Make name of extruder a property This stores the name for later use, for instance when displaying the extruder. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index 5be05c713c..cff5f3e6d0 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -25,8 +25,8 @@ class Extruder: self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) #Create a container stack for this extruder. - name = self._uniqueName(self._definition.getId()) - self._container_stack = UM.Settings.ContainerStack(name) + self._name = self._uniqueName(self._definition.getId()) + self._container_stack = UM.Settings.ContainerStack(self._name) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) @@ -73,15 +73,16 @@ class Extruder: self._container_stack.addContainer(self._quality) #Add an empty user profile. - self._user_profile = UM.Settings.InstanceContainer(name + "_current_settings") + self._user_profile = UM.Settings.InstanceContainer(self._name + "_current_settings") self._user_profile.addMetaDataEntry("type", "user") self._container_stack.addContainer(self._user_profile) self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) - nozzle_changed = UM.Signal.Signal() - material_changed = UM.Signal.Signal() - quality_changed = UM.Signal.Signal() + material_changed = UM.Signal() + name_changed = UM.Signal() + nozzle_changed = UM.Signal() + quality_changed = UM.Signal() ## Gets the currently active material on this extruder. # @@ -104,6 +105,19 @@ class Extruder: self._material = value self.material_changed.emit() + ## Gets the name of this extruder. + # + # \return The name of this extruder. + @property + def name(self): + return self._name + + ## Changes the name of this extruder. + @name.setter + def name(self, value): + self._name = value + self.name_changed.emit() + ## Gets the currently active nozzle on this extruder. # # \return The currently active nozzle on this extruder. From df363a024a7a9e3c31ee9dfbc629da180e71b40d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:24:53 +0200 Subject: [PATCH 058/182] Expose definition container of extruders This contains important metadata which we'll need. It's also more consistent with the rest. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index cff5f3e6d0..9f2a8ab493 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -79,11 +79,33 @@ class Extruder: self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + definition_changed = UM.Signal() material_changed = UM.Signal() name_changed = UM.Signal() nozzle_changed = UM.Signal() quality_changed = UM.Signal() + ## Gets the definition container of this extruder. + # + # \return The definition container of this extruder. + @property + def definition(self): + return self._definition + + ## Changes the definition container of this extruder. + # + # \param value The new definition for this extruder. + @definition.setter + def definition(self, value): + try: + position = self._container_stack.index(self._definition) + except ValueError: #Definition is not in the list. Big trouble! + UM.Logger.log("e", "I've lost my old extruder definition, so I can't find where to insert the new definition.") + return + self._container_stack.replaceContainer(position, value) + self._definition = value + self.definition_changed.emit() + ## Gets the currently active material on this extruder. # # \return The currently active material on this extruder. From e16fedf2d8640146fa4059b28a1a0fea51b2e68e Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:27:11 +0200 Subject: [PATCH 059/182] Changing name of extruder also changes name in container stack This name may be used to get a unique human-readable name. Just for consistency really. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index 9f2a8ab493..4bbe24183d 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -135,9 +135,12 @@ class Extruder: return self._name ## Changes the name of this extruder. + # + # \param value The new name for this extruder. @name.setter def name(self, value): self._name = value + self._container_stack.setName(value) #Also update in container stack, being defensive. self.name_changed.emit() ## Gets the currently active nozzle on this extruder. From c24f4be8ae3403223141d991d29fe4ca085c8d3f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:42:02 +0200 Subject: [PATCH 060/182] Add extruders model Hasn't been tested much because there is no display for this in the front-end yet. It needs a setting data type to go with in order to display it. This model is for the drop-down boxes to select an extruder to print, for instance, the support with. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtrudersModel.py | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 cura/ExtrudersModel.py diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py new file mode 100644 index 0000000000..08f349c1ff --- /dev/null +++ b/cura/ExtrudersModel.py @@ -0,0 +1,55 @@ +# 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): + ## 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()) + + ## 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): + 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 From f18eeba793e148088f9d34fad2455fbb126fa374 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:02:44 +0200 Subject: [PATCH 061/182] Add extruder setting type This is a new data type. It behaves and saves just like an integer, but it's actually just an index of the extruder to use. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index b8cef52d0c..a5357b10d7 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 @@ -89,6 +90,7 @@ 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) From 45d01bf37186c065f73eb16ce793cfb2c43cb619 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:03:33 +0200 Subject: [PATCH 062/182] Remove unused import This was no longer needed since ExtruderManager is now a singleton. It's no longer in CuraApplication. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a5357b10d7..3c3415aefe 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -31,7 +31,6 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog -from . import ExtruderManager from . import PlatformPhysics from . import BuildVolume from . import CameraAnimation From c994cb6bef743e96edad69c9c740bf0048c163fe Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 14:19:39 +0200 Subject: [PATCH 063/182] Slicing no longer occurs when a perObject setting is in error state CURA-1288 --- plugins/CuraEngineBackend/StartSliceJob.py | 19 +++++++++++++++++-- .../PerObjectSettingsTool.py | 1 - 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index cf008e7b6f..0851261877 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 @@ -59,7 +58,7 @@ class StartSliceJob(Job): self.setResult(StartJobResult.Error) return - #Don't slice if there is a setting with an error value. + # 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): @@ -69,6 +68,22 @@ class StartSliceJob(Job): Job.yieldThread() + # 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 + + node_stack = node.callDecoration("getStack") + if node_stack: + for key in node_stack.getAllKeys(): + validation_state = node_stack.getProperty(key, "validationState") + if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): + Logger.log("w", "Per object setting %s is not valid, but %s. Aborting slicing.", key, validation_state) + 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/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index a06ecd297f..ee653ae339 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -32,7 +32,6 @@ 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() From 388a345140ace9f11af6b22451acfb3377a52f98 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 14:42:48 +0200 Subject: [PATCH 064/182] Changing a per-object setting now forces a re-slice CURA-1278 --- cura/SettingOverrideDecorator.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 3e8815ec67..e212d93dac 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -18,11 +18,17 @@ class SettingOverrideDecorator(SceneNodeDecorator): 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 _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()) From 64e4cd0041127f1c31eb28d356dd98f8a348264d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 15:52:25 +0200 Subject: [PATCH 065/182] Added properties to make setting items more customisable CURA-1278 --- resources/qml/Settings/SettingItem.qml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index aa4ef5be85..f476349c42 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -18,6 +18,10 @@ Item { property alias contents: controlContainer.children; property alias hovered: mouse.containsMouse + property var showRevertButton: true + property var showInheritButton: true + property var doDepthIdentation: true + signal contextMenuRequested() signal showTooltip(string text); signal hideTooltip(); @@ -93,7 +97,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 @@ -124,7 +128,7 @@ Item { { id: revertButton; - visible: propertyProvider.stackLevel == 0 + visible: propertyProvider.stackLevel == 0 && base.showRevertButton height: parent.height; width: height; @@ -151,7 +155,7 @@ Item { id: inheritButton; //visible: has_profile_value && base.has_inherit_function && base.is_enabled - visible: propertyProvider.properties.state == "InstanceState.User" && propertyProvider.stackLevel > 0 + visible: propertyProvider.properties.state == "InstanceState.User" && propertyProvider.stackLevel > 0 && base.showInheritButton height: parent.height; width: height; From edd5eecc3dacf626ff5aadb0c343ced12e7e7a72 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 15:53:00 +0200 Subject: [PATCH 066/182] Per object settings no longer show depth identation, revert/inherit buttons CURA-1278 --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index f873ec9a79..d707fe9810 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; @@ -57,6 +58,12 @@ Item { //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. asynchronous: model.type != "enum" + onLoaded: { + settingLoader.item.showRevertButton = false + settingLoader.item.showInheritButton = false + settingLoader.item.doDepthIdentation = false + } + source: { switch(model.type) // TODO: This needs to be fixed properly. Got frustrated with it not working, so this is the patch job! From 2ed518c47edfb8853abf998876dfa6db5f08f39a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 16:02:47 +0200 Subject: [PATCH 067/182] Removed no longer used code CURA-1278 --- .../SettingOverrideModel.py | 138 ------------------ 1 file changed, 138 deletions(-) delete mode 100644 plugins/PerObjectSettingsTool/SettingOverrideModel.py 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 From 1ae69b25fad24303e132830c8c576c77081d11d6 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 16:07:09 +0200 Subject: [PATCH 068/182] Added documentation --- .../PerObjectSettingVisibilityHandler.py | 3 ++- plugins/PerObjectSettingsTool/PerObjectSettingsTool.py | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) 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/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index ee653ae339..6ae44c2671 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -7,12 +7,14 @@ from UM.Application import Application from UM.Preferences import Preferences +## 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) @@ -40,9 +42,6 @@ class PerObjectSettingsTool(Tool): except AttributeError: return "" - def setContainerID(self, value): - pass - def _onPreferenceChanged(self, preference): if preference == "cura/active_mode": enabled = Preferences.getInstance().getValue(preference)==1 From 64ef5ab3a404aca828c9ecffb2ea9ab5707c994f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:58:11 +0200 Subject: [PATCH 069/182] Inherit from class, not module This is an import fail on my part, sorry. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 08f349c1ff..3eac9ce17b 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -10,7 +10,7 @@ import UM.Qt.ListModel # # 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): +class ExtrudersModel(UM.Qt.ListModel.ListModel): ## Human-readable name of the extruder. NameRole = Qt.UserRole + 1 From 05243a4fcab2ae763bcc4dc448beb7993166bd5b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:59:01 +0200 Subject: [PATCH 070/182] Connect to function, not result of function The result of the function was None, but I don't need None to be called whenever extruders changed. I need the function itself to be called. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtrudersModel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 3eac9ce17b..eb63bc4257 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -37,7 +37,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): #Listen to changes. manager = cura.ExtruderManager.ExtruderManager.getInstance() - manager.extrudersChanged.connect(self._updateExtruders()) + manager.extrudersChanged.connect(self._updateExtruders) + self._updateExtruders() ## Update the list of extruders. # From 84fc7948ce7831dd26315dc58041b08f88a5230c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 15:00:40 +0200 Subject: [PATCH 071/182] Expose ExtrudersModel to QML It is required by the drop-down for extruder settings. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 3c3415aefe..323d0b349a 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -31,6 +31,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog +from . import ExtrudersModel from . import PlatformPhysics from . import BuildVolume from . import CameraAnimation @@ -367,6 +368,8 @@ 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") for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles): From 7146c9ab7d537390dc5b254b396c6ba685772548 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 15:27:21 +0200 Subject: [PATCH 072/182] Make a drop-down box for selecting an extruder For use by settings such as infill_extruder_nr. Contributes to issues CURA-351 and CURA-1278. --- resources/qml/Settings/SettingExtruder.qml | 112 +++++++++++++++++++++ resources/qml/Settings/SettingView.qml | 2 + 2 files changed, 114 insertions(+) create mode 100644 resources/qml/Settings/SettingExtruder.qml diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml new file mode 100644 index 0000000000..86ab728fc1 --- /dev/null +++ b/resources/qml/Settings/SettingExtruder.qml @@ -0,0 +1,112 @@ +// 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 UM.Theme.getColor("setting_control") + } + } + 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") : UM.Theme.getColor("setting_control_text"); + + 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/SettingView.qml b/resources/qml/Settings/SettingView.qml index 6a11136966..1555149d22 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -62,6 +62,8 @@ ScrollView return "SettingTextField.qml" case "enum": return "SettingComboBox.qml" + case "extruder": + return "SettingExtruder.qml" case "bool": return "SettingCheckBox.qml" case "str": From 1a30dd96b1acbb3f8e5af545bac49e6bd57ed837 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 15:30:39 +0200 Subject: [PATCH 073/182] Change setting type for extruder_nr settings This way it can determine the difference between an integer and an index in the extruder list. Contributes to issues CURA-1278. --- resources/definitions/fdmextruder.def.json | 2 +- resources/definitions/fdmprinter.def.json | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) 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 48952c2c99..ec27abd9f5 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2125,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", @@ -2135,7 +2135,7 @@ { "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", @@ -2145,7 +2145,7 @@ { "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", @@ -2156,7 +2156,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", @@ -2167,7 +2167,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", From 186eca160b507a6d417e4c9cb7759eea0a80b99f Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 12:01:19 +0200 Subject: [PATCH 074/182] Fix containersChanged signal handlers Fixes CURA-1642 --- cura/ConvexHullDecorator.py | 2 +- cura/ExtruderManager.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/ConvexHullDecorator.py b/cura/ConvexHullDecorator.py index 6639d12dc7..39cdc36232 100644 --- a/cura/ConvexHullDecorator.py +++ b/cura/ConvexHullDecorator.py @@ -101,7 +101,7 @@ class ConvexHullDecorator(SceneNodeDecorator): if key == "print_sequence" and property_name == "value": self._onChanged() - def _onChanged(self): + def _onChanged(self, *args): if self._convex_hull_job: self._convex_hull_job.cancel() self.setConvexHull(None) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 3c1e50d9bd..bfce380a70 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -57,7 +57,7 @@ class ExtruderManager: # This looks at the global container stack to see which machine is active. # Then it loads the extruders for that machine and loads each of them in a # list of extruders. - def _reloadExtruders(self): + def _reloadExtruders(self, *args): self._extruders = [] if not self._global_container_stack: #No machine has been added yet. self.extrudersChanged.emit() #Yes, we just cleared the _extruders list! @@ -65,7 +65,7 @@ class ExtruderManager: #Get the extruder definitions belonging to the current machine. machine = self._global_container_stack.getBottom() - extruder_train_ids = machine.getMetaData("machine_extruder_trains") + extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains") for extruder_train_id in extruder_train_ids: extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. if not extruder_definitions: #Empty list or error. From bb18bf6a30914e7127d7e40a4dbf3baa5baf1d3e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 16:38:06 +0200 Subject: [PATCH 075/182] Fix creating a jobname after loading a file Moves jobname creation out of qml and into python. CURA-1619 --- cura/CuraApplication.py | 15 ------- cura/PrintInformation.py | 56 ++++++++++++++++++++++-- resources/qml/Cura.qml | 4 +- resources/qml/JobSpecs.qml | 85 ++++++++++-------------------------- resources/qml/SaveButton.qml | 2 +- 5 files changed, 79 insertions(+), 83 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 49fcbbf405..3e3ab28010 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -436,21 +436,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): diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 2663cab5a0..dd15d7a264 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,17 @@ class PrintInformation(QObject): if self._backend: self._backend.printDurationMessage.connect(self._onPrintDurationMessage) + self._job_name = "" + Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + 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 +74,43 @@ 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 + + def _onGlobalStackChanged(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 + + 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/resources/qml/Cura.qml b/resources/qml/Cura.qml index 32e1e79029..cf99b39864 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -93,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 { @@ -109,7 +109,7 @@ 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) 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/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 { From 4cd224aeb2ea6f5fbf7523fc16e1c8bbf4ec1927 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 17:19:47 +0200 Subject: [PATCH 076/182] Add empty variant, material and quality containers Since we need these for making container switching work. Contributes to CURA-1612 --- cura/CuraApplication.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 39c3ed924f..dc5eb70394 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -142,6 +142,23 @@ class CuraApplication(QtApplication): ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.UserInstanceContainer) 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") From e36397fa29bd5999655502d599b1904512eaa202 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 17:21:18 +0200 Subject: [PATCH 077/182] Use the new empty type-specific containers when adding a new machine Contributes to CURA-1612 --- cura/MachineManagerModel.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c3b57ca8d0..77dfa39d3b 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -22,6 +22,10 @@ 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") @@ -74,28 +78,26 @@ class MachineManagerModel(QObject): new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) - empty_container = UM.Settings.ContainerRegistry.getInstance().getEmptyInstanceContainer() - - variant_instance_container = empty_container + variant_instance_container = self._empty_variant_container if definition.getMetaDataEntry("has_variants"): - variant_instance_container = self._getPreferredContainer(definition, "preferred_variant", empty_container) + variant_instance_container = self._getPreferredContainer(definition, "preferred_variant", self._empty_variant_container) - if variant_instance_container == empty_container: + if variant_instance_container == self._empty_variant_container: variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) if variants: variant_instance_container = variants[0] - if variant_instance_container == empty_container: + if variant_instance_container == self._empty_variant_container: Logger.log("w", "Machine %s defines it has variants but no variants found", definition.id) - material_instance_container = empty_container + material_instance_container = self._empty_material_container if definition.getMetaDataEntry("has_materials"): - material_instance_container = self._getPreferredContainer(definition, "preferred_material", empty_container) + material_instance_container = self._getPreferredContainer(definition, "preferred_material", self._empty_material_container) - if material_instance_container == empty_container: + if material_instance_container == self._empty_material_container: materials = None if definition.getMetaDataEntry("has_machine_materials"): - if variant_instance_container != empty_container: + if variant_instance_container != self._empty_material_container: materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id, variant = variant_instance_container.id) else: materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id) @@ -105,9 +107,11 @@ class MachineManagerModel(QObject): if materials: material_instance_container = materials[0] - quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", empty_container) + if material_instance_container == self._empty_materials_container: + Logger.log("w", "Machine %s defines it has materials but no matererials found", definition.id) - if quality_instance_container == empty_container: + quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", self._empty_quality_container) + if quality_instance_container == self._empty_quality_container: if definition.getMetaDataEntry("has_machine_quality"): if material_instance_container: qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id, material = material_instance_container.id) From 95a0c69662ec6ac7bd68bd2bd16055831297c7ae Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 17:25:34 +0200 Subject: [PATCH 078/182] Bit of code refactoring to prevent duplication CURA-1288 --- plugins/CuraEngineBackend/StartSliceJob.py | 38 ++++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 0851261877..dee6f2b64c 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -51,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,30 +73,18 @@ class StartSliceJob(Job): 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) - self.setResult(StartJobResult.SettingError) - return - - Job.yieldThread() + 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 - node_stack = node.callDecoration("getStack") - if node_stack: - for key in node_stack.getAllKeys(): - validation_state = node_stack.getProperty(key, "validationState") - if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): - Logger.log("w", "Per object setting %s is not valid, but %s. Aborting slicing.", key, validation_state) - self.setResult(StartJobResult.SettingError) - return - - Job.yieldThread() + if self._checkStackForErrors(node.callDecoration("getStack")): + self.setResult(StartJobResult.SettingError) + return with self._scene.getSceneLock(): # Remove old layer data. From 11cb9af97f819b362a719ff66ba8e6c7f8ac0464 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 17:32:26 +0200 Subject: [PATCH 079/182] fixed typo --- cura/MachineManagerModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 77dfa39d3b..4bd42c9c9d 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -107,7 +107,7 @@ class MachineManagerModel(QObject): if materials: material_instance_container = materials[0] - if material_instance_container == self._empty_materials_container: + if material_instance_container == self._empty_material_container: Logger.log("w", "Machine %s defines it has materials but no matererials found", definition.id) quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", self._empty_quality_container) From 0dec0aafcfbff6091d1e3a92908d9699b5ff11b7 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 17:44:06 +0200 Subject: [PATCH 080/182] Fix exception when loading an object CURA-1619 --- cura/CuraApplication.py | 6 ++++-- cura/PrintInformation.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 39c3ed924f..3c4d776df8 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -706,16 +706,18 @@ class CuraApplication(QtApplication): def _onActiveMachineChanged(self): pass + fileLoaded = pyqtSignal() + 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/PrintInformation.py b/cura/PrintInformation.py index dd15d7a264..22bc562502 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -52,6 +52,7 @@ class PrintInformation(QObject): self._job_name = "" Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + Application.getInstance().fileLoaded.connect(self.setJobName) currentPrintTimeChanged = pyqtSignal() From ad35c9f070a6321f5328c92390fd7baef93fe566 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 10:06:08 +0200 Subject: [PATCH 081/182] Added reload profile (simply clears user instance container) CURA-1278 --- cura/MachineManagerModel.py | 22 ++++++++++++++++++++++ resources/qml/Actions.qml | 5 +++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 4bd42c9c9d..d34e392720 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -41,9 +41,15 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() + globalPropertyChanged = pyqtSignal() # Emitted whenever a property inside global container is changed. + + def _onGlobalPropertyChanged(self, key, property_name): + self.globalPropertyChanged.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() @@ -51,6 +57,7 @@ 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) def _onInstanceContainersChanged(self, container): container_type = container.getMetaDataEntry("type") @@ -160,6 +167,21 @@ class MachineManagerModel(QObject): return unique_name + @pyqtSlot() + def clearUserSettings(self): + if not self._global_container_stack: + return + user_settings = self._global_container_stack.getTop() + user_settings.clear() + + @pyqtProperty(bool, notify = globalPropertyChanged) + def hasUserSettings(self): + if not self._global_container_stack: + return + + user_settings = self._global_container_stack.getTop().findInstances(**{}) + return len(user_settings) != 0 + @pyqtProperty(str, notify = globalContainerChanged) def activeMachineName(self): if self._global_container_stack: diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index f3bce7b993..6dd851c3d5 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 { @@ -117,9 +118,9 @@ Item 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 From 171adde6be95a11d751c892f565a732da42152b5 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 10:15:01 +0200 Subject: [PATCH 082/182] Fixed broken signal when file was loaded --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 41dec309d9..d22fed73ce 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -723,7 +723,7 @@ class CuraApplication(QtApplication): def _onActiveMachineChanged(self): pass - fileLoaded = pyqtSignal() + fileLoaded = pyqtSignal(str) def _onFileLoaded(self, job): node = job.getResult() From 113da81db527773f32746bd84fd29e6103e8f7d3 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 10:29:19 +0200 Subject: [PATCH 083/182] Added isValidGlobalStack property to MachineManager CURA-1585 --- cura/MachineManagerModel.py | 16 ++++++++++++++++ resources/qml/Actions.qml | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index d34e392720..e9b8ba7d55 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -7,6 +7,7 @@ from UM.Preferences import Preferences from UM.Logger import Logger import UM.Settings +from UM.Settings.Validator import ValidatorState class MachineManagerModel(QObject): @@ -167,6 +168,17 @@ class MachineManagerModel(QObject): return unique_name + ## 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 + @pyqtSlot() def clearUserSettings(self): if not self._global_container_stack: @@ -182,6 +194,10 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop().findInstances(**{}) return len(user_settings) != 0 + @pyqtProperty(bool, notify = globalPropertyChanged) + def isGlobalStackValid(self): + return not self._checkStackForErrors(self._global_container_stack) + @pyqtProperty(str, notify = globalContainerChanged) def activeMachineName(self): if self._global_container_stack: diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 6dd851c3d5..4769b53b05 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -110,7 +110,7 @@ Item Action { id: updateProfileAction; - enabled: UM.ActiveProfile.valid && !UM.ActiveProfile.readOnly && UM.ActiveProfile.hasCustomisedValues + enabled: Cura.MachineManager.isGlobalStackValid && !UM.ActiveProfile.readOnly && Cura.MachineManager.hasUserSettings text: catalog.i18nc("@action:inmenu menubar:profile","&Update Current Profile"); onTriggered: UM.ActiveProfile.updateProfile(); } @@ -126,7 +126,7 @@ Item Action { id: addProfileAction; - enabled: UM.ActiveProfile.valid + enabled: Cura.MachineManager.isGlobalStackValid text: catalog.i18nc("@action:inmenu menubar:profile","&Create New Profile..."); } From 4fc565711d3675fef2c860c38531c8013fe9f39d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 11:19:33 +0200 Subject: [PATCH 084/182] Added read-only property to profiles CURA-1585 --- cura/MachineManagerModel.py | 9 +++++++++ resources/qml/Actions.qml | 2 +- resources/quality/high.inst.cfg | 1 + resources/quality/low.inst.cfg | 1 + resources/quality/normal.inst.cfg | 1 + .../quality/ultimaker2_plus/pla_0.25_normal.inst.cfg | 1 + resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg | 1 + resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg | 1 + .../quality/ultimaker2_plus/pla_0.4_normal.inst.cfg | 1 + .../quality/ultimaker2_plus/pla_0.6_normal.inst.cfg | 1 + .../quality/ultimaker2_plus/pla_0.8_normal.inst.cfg | 1 + 11 files changed, 19 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e9b8ba7d55..5a43f8cbf1 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -246,6 +246,15 @@ 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(str) def setActiveMaterial(self, material_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=material_id) diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 4769b53b05..2e89ce043a 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -110,7 +110,7 @@ Item Action { id: updateProfileAction; - enabled: Cura.MachineManager.isGlobalStackValid && !UM.ActiveProfile.readOnly && Cura.MachineManager.hasUserSettings + 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(); } diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index 0329e9ffe1..546d11326b 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -5,6 +5,7 @@ definition = fdmprinter [metadata] type = quality +read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/low.inst.cfg b/resources/quality/low.inst.cfg index d684bd81b9..11a0094aca 100644 --- a/resources/quality/low.inst.cfg +++ b/resources/quality/low.inst.cfg @@ -5,6 +5,7 @@ definition = fdmprinter [metadata] type = quality +read_only = True [values] layer_height = 0.15 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_plus/pla_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg index 9a44582610..7a1da403ff 100644 --- a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg @@ -7,6 +7,7 @@ definition = ultimaker2_plus type = quality material = generic_pla_ultimaker2_plus_0.25_mm weight = -2 +read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg index be1e1ce992..54f180379d 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg @@ -7,6 +7,7 @@ definition = ultimaker2_plus type = quality material = generic_pla_ultimaker2_plus_0.4_mm weight = -1 +read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg index b058d17fbd..926bcdcae7 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg @@ -7,6 +7,7 @@ definition = ultimaker2_plus type = quality material = generic_pla_ultimaker2_plus_0.4_mm weight = -3 +read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg index 78ee8cf566..f65544307e 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg @@ -7,6 +7,7 @@ definition = ultimaker2_plus type = quality material = generic_pla_ultimaker2_plus_0.4_mm weight = -2 +read_only = True [values] layer_height = 0.1 diff --git a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg index f8f966e25a..906613dc23 100644 --- a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg @@ -7,6 +7,7 @@ definition = ultimaker2_plus material = generic_pla_ultimaker2_plus_0.6_mm type = quality weight = -2 +read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg index ec53d15867..5cad44ec9c 100644 --- a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg @@ -7,6 +7,7 @@ definition = ultimaker2_plus material = generic_pla_ultimaker2_plus_0.8_mm type = quality weight = -2 +read_only = True [values] layer_height = 0.2 From d29cc37d6bcbca9306a8ecffc73566a90af28ff1 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 11:58:59 +0200 Subject: [PATCH 085/182] Adds way to convert user settings into quality settings CURA-1585 --- cura/MachineManagerModel.py | 32 +++++++++++++++++++++++++++----- resources/qml/Cura.qml | 2 +- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 5a43f8cbf1..130b492ff4 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -8,6 +8,7 @@ from UM.Logger import Logger import UM.Settings from UM.Settings.Validator import ValidatorState +from UM.Settings.InstanceContainer import InstanceContainer class MachineManagerModel(QObject): @@ -80,7 +81,7 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._uniqueMachineName(name, definition.getName()) + name = self._createUniqueStackName(name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) new_global_stack.addMetaDataEntry("type", "machine") @@ -150,7 +151,7 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique - def _uniqueMachineName(self, name, fallback_name): + def _createUniqueStackName(self, name, fallback_name): name = name.strip() num_check = re.compile("(.*?)\s*#\d$").match(name) if(num_check): @@ -160,10 +161,10 @@ class MachineManagerModel(QObject): unique_name = name i = 1 - #Check both the id and the name, because they may not be the same and it is better if they are both unique + # 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 + i += 1 unique_name = "%s #%d" % (name, i) return unique_name @@ -254,6 +255,27 @@ class MachineManagerModel(QObject): return True return containers[0].getMetaDataEntry("read_only", False) == "True" + @pyqtSlot() + def convertUserContainerToQuality(self): + if not self._global_container_stack: + return + + name = self._createUniqueStackName("Custom profile", "") + user_settings = self._global_container_stack.getTop() + new_quality_container = InstanceContainer("") + + ## Copy all values + new_quality_container.deserialize(user_settings.serialize()) + + ## Change type / id / name + new_quality_container.setMetaDataEntry("type","quality") + 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 noq a quality, remove them. + self.setActiveQuality(name) + @pyqtSlot(str) def setActiveMaterial(self, material_id): @@ -319,7 +341,7 @@ 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._createUniqueStackName(new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) self.globalContainerChanged.emit() diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index cf99b39864..2b7a4ccea7 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -580,7 +580,7 @@ UM.MainWindow target: Cura.Actions.addProfile onTriggered: { - UM.MachineManager.createProfile(); + Cura.MachineManager.convertUserContainerToQuality(); preferences.setPage(5); preferences.show(); From 0dece95f0f0b9c25026f0c00dcf5a03f53e250ed Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:03:56 +0200 Subject: [PATCH 086/182] Updating non-readonly profiles is now possible again CURA-1585 --- cura/MachineManagerModel.py | 10 ++++++++++ resources/qml/Actions.qml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 130b492ff4..b9d6a9d37c 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -276,6 +276,16 @@ class MachineManagerModel(QObject): self.clearUserSettings() # As all users settings are noq a quality, remove them. self.setActiveQuality(name) + @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): diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 2e89ce043a..e09b6b5424 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -112,7 +112,7 @@ Item id: updateProfileAction; 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 From 7b87143e65f4b14c0a9859e415db185b7ef0b39e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:07:35 +0200 Subject: [PATCH 087/182] Only value property events are now used This speeds the num events up a bit, but it's still a tad to slow CURA-1585 --- cura/MachineManagerModel.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index b9d6a9d37c..c03c8074f5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -43,10 +43,11 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() - globalPropertyChanged = pyqtSignal() # Emitted whenever a property inside global container is changed. + globalValueChanged = pyqtSignal() # Emitted whenever a property inside global container is changed. def _onGlobalPropertyChanged(self, key, property_name): - self.globalPropertyChanged.emit() + if property_name == "value": + self.globalValueChanged.emit() def _onGlobalContainerChanged(self): if self._global_container_stack: @@ -187,7 +188,7 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop() user_settings.clear() - @pyqtProperty(bool, notify = globalPropertyChanged) + @pyqtProperty(bool, notify = globalValueChanged) def hasUserSettings(self): if not self._global_container_stack: return @@ -195,7 +196,7 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop().findInstances(**{}) return len(user_settings) != 0 - @pyqtProperty(bool, notify = globalPropertyChanged) + @pyqtProperty(bool, notify = globalValueChanged) def isGlobalStackValid(self): return not self._checkStackForErrors(self._global_container_stack) From 5faf2f024fb9118df7c146b40905fb14be3389cc Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:14:49 +0200 Subject: [PATCH 088/182] Added signal for validation state This improves the runtime speed somewhat CURA-1585 --- cura/MachineManagerModel.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c03c8074f5..3496252bb5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -43,11 +43,14 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() - globalValueChanged = pyqtSignal() # Emitted whenever a property inside global container is changed. + globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed. + globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed. def _onGlobalPropertyChanged(self, key, property_name): if property_name == "value": self.globalValueChanged.emit() + if property_name == "validationState": + self.globalValidationChanged.emit() def _onGlobalContainerChanged(self): if self._global_container_stack: @@ -196,7 +199,7 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop().findInstances(**{}) return len(user_settings) != 0 - @pyqtProperty(bool, notify = globalValueChanged) + @pyqtProperty(bool, notify = globalValidationChanged) def isGlobalStackValid(self): return not self._checkStackForErrors(self._global_container_stack) From 2b91b81f2d85eb3d5b3e1bfe1165c91a990c01e8 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:24:23 +0200 Subject: [PATCH 089/182] Added documentation CURA-1585 --- cura/MachineManagerModel.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3496252bb5..ef0de37774 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -174,6 +174,7 @@ class MachineManagerModel(QObject): return unique_name ## Convenience function to check if a stack has errors. + # TODO; This is a rather expensive check, which we run way to often. def _checkStackForErrors(self, stack): if stack is None: return False @@ -184,6 +185,7 @@ class MachineManagerModel(QObject): 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: @@ -191,6 +193,7 @@ class MachineManagerModel(QObject): 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: @@ -199,6 +202,8 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop().findInstances(**{}) return len(user_settings) != 0 + ## Check if the global profile does not contain error states + # TODO; Way to expensive step. We should probably cache this. @pyqtProperty(bool, notify = globalValidationChanged) def isGlobalStackValid(self): return not self._checkStackForErrors(self._global_container_stack) From b6b154e153e92dab90a59ab10e1d062453662e2e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:34:06 +0200 Subject: [PATCH 090/182] Fixed slowdown caused by validation check CURA-1585 --- cura/MachineManagerModel.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index ef0de37774..d9d62ecc1d 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -17,6 +17,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. @@ -32,6 +33,8 @@ class MachineManagerModel(QObject): active_machine_id = Preferences.getInstance().getValue("cura/active_machine") + + if active_machine_id != "": # An active machine was saved, so restore it. self.setActiveMachine(active_machine_id) @@ -50,7 +53,16 @@ class MachineManagerModel(QObject): if property_name == "value": self.globalValueChanged.emit() if property_name == "validationState": - self.globalValidationChanged.emit() + 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: @@ -64,6 +76,7 @@ class MachineManagerModel(QObject): 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 = self._checkStackForErrors(self._global_container_stack) def _onInstanceContainersChanged(self, container): container_type = container.getMetaDataEntry("type") @@ -174,7 +187,6 @@ class MachineManagerModel(QObject): return unique_name ## Convenience function to check if a stack has errors. - # TODO; This is a rather expensive check, which we run way to often. def _checkStackForErrors(self, stack): if stack is None: return False @@ -203,10 +215,11 @@ class MachineManagerModel(QObject): return len(user_settings) != 0 ## Check if the global profile does not contain error states - # TODO; Way to expensive step. We should probably cache this. + # 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 not self._checkStackForErrors(self._global_container_stack) + return self._global_stack_valid @pyqtProperty(str, notify = globalContainerChanged) def activeMachineName(self): From ea73f00aacc9dc024f544b385dec7f285dd5c18a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 14:39:36 +0200 Subject: [PATCH 091/182] Fixed case where validation state was set incorrectly CURA-1585 --- cura/MachineManagerModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index d9d62ecc1d..f89920e407 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -76,7 +76,7 @@ class MachineManagerModel(QObject): 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 = self._checkStackForErrors(self._global_container_stack) + self._global_stack_valid = not self._checkStackForErrors(self._global_container_stack) def _onInstanceContainersChanged(self, container): container_type = container.getMetaDataEntry("type") From cd8df448127449136323cebc45b5c61d43aa8f94 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 14:40:28 +0200 Subject: [PATCH 092/182] Changed multiple properties in profile page to new API CURA-1285 --- resources/qml/Preferences/ProfilesPage.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 9561bba521..982f612943 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -90,15 +90,15 @@ UM.ManagementPage 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 + enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) onClicked: UM.ActiveProfile.updateProfile() } Button { text: catalog.i18nc("@action:button", "Discard changes"); - enabled: UM.ActiveProfile.hasCustomisedValues - onClicked: UM.ActiveProfile.discardChanges() + enabled: Cura.MachineManager.hasUserSettings + onClicked: Cura.MachineManager.clearUserSettings(); } } @@ -114,7 +114,7 @@ UM.ManagementPage } Label { text: base.currentItem == null ? "" : - base.currentItem.id == -1 ? UM.MachineManager.activeProfile : + base.currentItem.id == -1 ? Cura.MachineManager.activeQualityName: base.currentItem.readOnly ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") } From 80f24b6c5420b80d0d90823fd3352cfc588995fd Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 14:56:42 +0200 Subject: [PATCH 093/182] Removed ulti quality, as that got in 2.1 by mistake As it got in there by mistake, it has no place here either! --- .../ultimaker2_plus/pla_0.4_ulti.inst.cfg | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg diff --git a/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg deleted file mode 100644 index db091d8e8d..0000000000 --- a/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg +++ /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 From 01999f7ddd6b101ab128141ef7c17525823f64f5 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 15:00:09 +0200 Subject: [PATCH 094/182] Custom profiles can now be renamed --- resources/qml/Preferences/ProfilesPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 982f612943..fb133a08ec 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -170,7 +170,7 @@ UM.ManagementPage id: renameDialog; object: base.currentItem != null ? base.currentItem.name : ""; property bool removeWhenRejected: false; - onAccepted: base.model.renameProfile(base.currentItem.name, newName.trim()); + onAccepted: base.model.rename(base.currentItem.id, newName.trim()); onRejected: { if(removeWhenRejected) { base.model.removeProfile(base.currentItem.name) From d1d60e27cc2719431aece5cea292bfcc8d17be48 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 15:25:08 +0200 Subject: [PATCH 095/182] Added function to duplicate container CURA-1427 --- cura/MachineManagerModel.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index f89920e407..355fc188d3 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -277,8 +277,9 @@ class MachineManagerModel(QObject): return True return containers[0].getMetaDataEntry("read_only", False) == "True" - @pyqtSlot() + @pyqtSlot(result = str) def convertUserContainerToQuality(self): + print("convertUserContainerToQuality") if not self._global_container_stack: return @@ -297,6 +298,23 @@ class MachineManagerModel(QObject): UM.Settings.ContainerRegistry.getInstance().addContainer(new_quality_container) self.clearUserSettings() # As all users settings are noq a quality, remove them. self.setActiveQuality(name) + return name + + @pyqtSlot(str, result=str) + def duplicateContainer(self, container_id): + print("convertUserContainerToQuality") + if not self._global_container_stack: + return + container_to_duplicate = self._global_container_stack.findContainer({"id": container_id}) + if container_to_duplicate: + new_name = self._createUniqueStackName(container_to_duplicate.getName(), "") + new_container = InstanceContainer("") + new_container.setName(new_name) + new_container._id = new_name + UM.Settings.ContainerRegistry.getInstance().addContainer(new_container) + return new_name + + return "" @pyqtSlot() def updateUserContainerToQuality(self): From fdbd6d7c5f3114760a8d11dd4bdc6264041b203c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 15:29:41 +0200 Subject: [PATCH 096/182] Updating profile now also works in profile page CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index fb133a08ec..594b15e066 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -29,14 +29,14 @@ UM.ManagementPage 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(currentItem.id); } - base.selectProfile(selectedProfile); + base.selectContainer(selectedContainer); renameDialog.removeWhenRejected = true; renameDialog.open(); @@ -50,11 +50,11 @@ UM.ManagementPage removeEnabled: currentItem != null ? !currentItem.readOnly : false; renameEnabled: currentItem != null ? !currentItem.readOnly : 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 selectContainer(string id) + onSelectContainer: { + objectList.currentIndex = objectList.model.find("id", id); } Item { @@ -86,12 +86,12 @@ UM.ManagementPage Button { text: { - var profileName = UM.MachineManager.activeProfile; + 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: UM.ActiveProfile.updateProfile() + onClicked: Cura.MachineManager.updateUserContainerToQuality() } Button From 490a8724e589365f0136b11f2851a906f9c9d8dd Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 16:29:46 +0200 Subject: [PATCH 097/182] Fixed duplication of profiles CURA-1427 --- cura/MachineManagerModel.py | 13 ++++++++----- resources/qml/Preferences/ProfilesPage.qml | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 355fc188d3..609d2a77f8 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -279,7 +279,6 @@ class MachineManagerModel(QObject): @pyqtSlot(result = str) def convertUserContainerToQuality(self): - print("convertUserContainerToQuality") if not self._global_container_stack: return @@ -302,13 +301,17 @@ class MachineManagerModel(QObject): @pyqtSlot(str, result=str) def duplicateContainer(self, container_id): - print("convertUserContainerToQuality") if not self._global_container_stack: return - container_to_duplicate = self._global_container_stack.findContainer({"id": container_id}) - if container_to_duplicate: - new_name = self._createUniqueStackName(container_to_duplicate.getName(), "") + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) + if containers: + new_name = self._createUniqueStackName(containers[0].getName(), "") + new_container = InstanceContainer("") + + ## Copy all values + new_container.deserialize(containers[0].serialize()) + new_container.setName(new_name) new_container._id = new_name UM.Settings.ContainerRegistry.getInstance().addContainer(new_container) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 594b15e066..8182eb1bb6 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -34,7 +34,7 @@ UM.ManagementPage // Current settings selectedContainer = Cura.MachineManager.convertUserContainerToQuality(); } else { - selectedContainer = Cura.MachineManager.duplicateContainer(currentItem.id); + selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id); } base.selectContainer(selectedContainer); From c62ab6e937460e7fe81ca0765fbb3393f9e6e69d Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Sat, 4 Jun 2016 13:55:35 +0200 Subject: [PATCH 098/182] Adding a field of the build type to the spashscreen. For example, if the community distributes Cura in a different way, they can set CURA_BUILDTYPE via 'cmake -DCURA_BUILDTYPE=' and whenever Cura is launched " (PPA)" will be appended. Of course, this could be done by appending " (PPA)" to CURA_VERSION, but in case of my Ubuntu/Debian packaging it will only need one modification in debian/changelog to change the version. During build (debian/rules) this version will be read from debian/changelog. Changing the version number across different files, is a waste of time. Finally, we can use that field in the future to indicate debug or other other special builds. --- CMakeLists.txt | 1 + cura/CuraApplication.py | 5 +++-- cura/CuraSplashScreen.py | 3 +++ cura/CuraVersion.py.in | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) 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/CuraApplication.py b/cura/CuraApplication.py index eccb3e4525..ac95529a5d 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -61,9 +61,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): @@ -89,7 +90,7 @@ class CuraApplication(QtApplication): # Need to do this before ContainerRegistry tries to load the machines SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False) - super().__init__(name = "cura", version = CuraVersion) + super().__init__(name = "cura", version = CuraVersion, build_type = CuraBuildType) self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) diff --git a/cura/CuraSplashScreen.py b/cura/CuraSplashScreen.py index d27c9c0240..8f677986df 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 += " (%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 From b33ce573c1522e8b1864882e2429709de80ab4a0 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 19:22:42 +0200 Subject: [PATCH 099/182] Also filter materials and profiles preference pages by machine etc. when desired Contriubtes to CURA-1612 --- resources/qml/Preferences/MaterialsPage.qml | 28 +++++++++++++++------ resources/qml/Preferences/ProfilesPage.qml | 21 +++++++++++++++- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index ed35a32fdf..af0f0c1bd2 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -14,7 +14,26 @@ UM.ManagementPage title: catalog.i18nc("@title:tab", "Materials"); - model: UM.InstanceContainersModel { filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } } + 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: { @@ -25,12 +44,7 @@ UM.ManagementPage } return -1; } -/* - onAddObject: { var selectedMaterial = UM.MaterialManager.createProfile(); base.selectMaterial(selectedMaterial); } - onRemoveObject: confirmDialog.open(); - onRenameObject: { renameDialog.open(); renameDialog.selectText(); } -*/ -// activateEnabled: false + addEnabled: false removeEnabled: false renameEnabled: false diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 8182eb1bb6..b7261afcec 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -15,7 +15,26 @@ 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: { From 6a3b321e5a597e92b1257fd838569bdd1a6b190b Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 19:23:46 +0200 Subject: [PATCH 100/182] Re-enable commented code --- resources/qml/SidebarHeader.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 4b48584174..bb7aeebae7 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -271,7 +271,7 @@ Item var result = { "type": "material" } if(Cura.MachineManager.filterMaterialsByMachine) { -// result.definition = Cura.MachineManager.activeDefinitionId + result.definition = Cura.MachineManager.activeDefinitionId if(Cura.MachineManager.hasVariants) { result.variant = Cura.MachineManager.activeVariantId From 8f21ec39807f3aeec50954f74f0bc4147194728d Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 20:51:53 +0200 Subject: [PATCH 101/182] Add PLA profiles for UM2Extended+ Contributes to CURA-1612 --- .../um2ep_pla_0.25_normal.inst.cfg | 19 +++++++++++++++++ .../um2ep_pla_0.4_fast.inst.cfg | 21 +++++++++++++++++++ .../um2ep_pla_0.4_high.inst.cfg | 19 +++++++++++++++++ .../um2ep_pla_0.4_normal.inst.cfg | 19 +++++++++++++++++ .../um2ep_pla_0.6_normal.inst.cfg | 19 +++++++++++++++++ .../um2ep_pla_0.8_normal.inst.cfg | 19 +++++++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg 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 From 3a3314aad1e6c14d0eb8c2af7efb2e53edee525e Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:16:39 +0200 Subject: [PATCH 102/182] Remove all old profiles Contributes to CURA-1612 --- resources/instances/high_quality.inst.cfg | 9 -------- resources/instances/normal_quality.inst.cfg | 9 -------- resources/profiles/general/High+Quality.cfg | 10 --------- resources/profiles/general/Low+Quality.cfg | 15 ------------- resources/profiles/general/Normal+Quality.cfg | 8 ------- resources/profiles/general/Ulti+Quality.cfg | 9 -------- resources/profiles/materials/abs.cfg | 9 -------- resources/profiles/materials/cpe.cfg | 8 ------- resources/profiles/materials/pla.cfg | 7 ------ .../ultimaker2+/abs_0.25_normal.curaprofile | 20 ----------------- .../ultimaker2+/abs_0.4_fast.curaprofile | 21 ------------------ .../ultimaker2+/abs_0.4_high.curaprofile | 19 ---------------- .../ultimaker2+/abs_0.4_normal.curaprofile | 18 --------------- .../ultimaker2+/abs_0.6_normal.curaprofile | 20 ----------------- .../ultimaker2+/abs_0.8_normal.curaprofile | 19 ---------------- .../ultimaker2+/cpe_0.25_normal.curaprofile | 19 ---------------- .../ultimaker2+/cpe_0.4_fast.curaprofile | 22 ------------------- .../ultimaker2+/cpe_0.4_high.curaprofile | 18 --------------- .../ultimaker2+/cpe_0.4_normal.curaprofile | 19 ---------------- .../ultimaker2+/cpe_0.6_normal.curaprofile | 18 --------------- .../ultimaker2+/cpe_0.8_normal.curaprofile | 18 --------------- .../ultimaker2+/pla_0.25_normal.curaprofile | 16 -------------- .../ultimaker2+/pla_0.4_fast.curaprofile | 18 --------------- .../ultimaker2+/pla_0.4_high.curaprofile | 16 -------------- .../ultimaker2+/pla_0.4_normal.curaprofile | 16 -------------- .../ultimaker2+/pla_0.4_ulti.curaprofile | 21 ------------------ .../ultimaker2+/pla_0.6_normal.curaprofile | 16 -------------- .../ultimaker2+/pla_0.8_normal.curaprofile | 16 -------------- 28 files changed, 434 deletions(-) delete mode 100644 resources/instances/high_quality.inst.cfg delete mode 100644 resources/instances/normal_quality.inst.cfg delete mode 100644 resources/profiles/general/High+Quality.cfg delete mode 100644 resources/profiles/general/Low+Quality.cfg delete mode 100644 resources/profiles/general/Normal+Quality.cfg delete mode 100644 resources/profiles/general/Ulti+Quality.cfg delete mode 100644 resources/profiles/materials/abs.cfg delete mode 100644 resources/profiles/materials/cpe.cfg delete mode 100644 resources/profiles/materials/pla.cfg delete mode 100644 resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.4_high.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.4_high.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile 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/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/Low+Quality.cfg b/resources/profiles/general/Low+Quality.cfg deleted file mode 100644 index f7f4e5d6b7..0000000000 --- a/resources/profiles/general/Low+Quality.cfg +++ /dev/null @@ -1,15 +0,0 @@ -[general] -version = 1 -name = Low Quality -weight = -1 - -[settings] -infill_sparse_density = 10 -layer_height = 0.15 -cool_min_layer_time = 3 -speed_wall_0 = 40 -speed_wall_x = 80 -speed_infill = 100 -wall_thickness = 1 -speed_topbottom = 30 - 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+/abs_0.25_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile deleted file mode 100644 index 9f45e9d01a..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile +++ /dev/null @@ -1,20 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.25 mm -material = ABS -weight = -2 - -[settings] -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/profiles/ultimaker2+/abs_0.4_fast.curaprofile b/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile deleted file mode 100644 index 50018372b5..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile +++ /dev/null @@ -1,21 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = ABS -weight = -1 - -[settings] -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/profiles/ultimaker2+/abs_0.4_high.curaprofile b/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile deleted file mode 100644 index 341c9cc34f..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile +++ /dev/null @@ -1,19 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = ABS -weight = -3 - -[settings] -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/profiles/ultimaker2+/abs_0.4_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile deleted file mode 100644 index d8fce8a4dd..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = ABS -weight = -2 - -[settings] -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/profiles/ultimaker2+/abs_0.6_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile deleted file mode 100644 index 5512450471..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile +++ /dev/null @@ -1,20 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.6 mm -material = ABS -weight = -2 - -[settings] -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/profiles/ultimaker2+/abs_0.8_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile deleted file mode 100644 index e5f27c51a2..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile +++ /dev/null @@ -1,19 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.8 mm -material = ABS -weight = -2 - -[settings] -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/profiles/ultimaker2+/cpe_0.25_normal.curaprofile b/resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile deleted file mode 100644 index c4c09932d8..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile +++ /dev/null @@ -1,19 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.25 mm -material = CPE -weight = -2 - -[settings] -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/profiles/ultimaker2+/cpe_0.4_fast.curaprofile b/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile deleted file mode 100644 index f9050e5ce5..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile +++ /dev/null @@ -1,22 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = CPE -weight = -1 - -[settings] -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/profiles/ultimaker2+/cpe_0.4_high.curaprofile b/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile deleted file mode 100644 index 377ab5b257..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = CPE -weight = -3 - -[settings] -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/profiles/ultimaker2+/cpe_0.4_normal.curaprofile b/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile deleted file mode 100644 index e8142405ff..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile +++ /dev/null @@ -1,19 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = CPE -weight = -2 - -[settings] -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/profiles/ultimaker2+/cpe_0.6_normal.curaprofile b/resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile deleted file mode 100644 index 034fa17e1b..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.6 mm -material = CPE -weight = -2 - -[settings] -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/profiles/ultimaker2+/cpe_0.8_normal.curaprofile b/resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile deleted file mode 100644 index 523a5d3243..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.8 mm -material = CPE -weight = -2 - -[settings] -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/profiles/ultimaker2+/pla_0.25_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile deleted file mode 100644 index 63c1fc9fdd..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.25 mm -material = PLA -weight = -2 - -[settings] -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/profiles/ultimaker2+/pla_0.4_fast.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile deleted file mode 100644 index 06e401c139..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = PLA -weight = -1 - -[settings] -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/profiles/ultimaker2+/pla_0.4_high.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile deleted file mode 100644 index 5e2f762354..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = PLA -weight = -3 - -[settings] -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/profiles/ultimaker2+/pla_0.4_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile deleted file mode 100644 index 689a3251b2..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = PLA -weight = -2 - -[settings] -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/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/profiles/ultimaker2+/pla_0.6_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile deleted file mode 100644 index 188ed42a95..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.6 mm -material = PLA -weight = -2 - -[settings] -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/profiles/ultimaker2+/pla_0.8_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile deleted file mode 100644 index 92cb4a6054..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.8 mm -material = PLA -weight = -2 - -[settings] -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 From 3413334c6d0b8409307c5d234fbaf65f79c9eb66 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:17:27 +0200 Subject: [PATCH 103/182] Update active material/quality when changing one of the lower levels Contributes to CURA-1612 --- cura/MachineManagerModel.py | 119 ++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 609d2a77f8..24020f50a4 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -104,50 +104,9 @@ class MachineManagerModel(QObject): new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) - variant_instance_container = self._empty_variant_container - if definition.getMetaDataEntry("has_variants"): - variant_instance_container = self._getPreferredContainer(definition, "preferred_variant", self._empty_variant_container) - - if variant_instance_container == self._empty_variant_container: - variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) - if variants: - variant_instance_container = variants[0] - - if variant_instance_container == self._empty_variant_container: - Logger.log("w", "Machine %s defines it has variants but no variants found", definition.id) - - material_instance_container = self._empty_material_container - if definition.getMetaDataEntry("has_materials"): - material_instance_container = self._getPreferredContainer(definition, "preferred_material", self._empty_material_container) - - if material_instance_container == self._empty_material_container: - materials = None - if definition.getMetaDataEntry("has_machine_materials"): - if variant_instance_container != self._empty_material_container: - materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id, variant = variant_instance_container.id) - else: - materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id) - else: - materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = "fdmprinter") - - if materials: - material_instance_container = materials[0] - - if material_instance_container == self._empty_material_container: - Logger.log("w", "Machine %s defines it has materials but no matererials found", definition.id) - - quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", self._empty_quality_container) - if quality_instance_container == self._empty_quality_container: - if definition.getMetaDataEntry("has_machine_quality"): - if material_instance_container: - qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id, material = material_instance_container.id) - else: - qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id) - else: - qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = "fdmprinter") - - if qualities: - quality_instance_container = qualities[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) @@ -341,6 +300,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) @@ -352,6 +313,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) @@ -435,15 +398,67 @@ class MachineManagerModel(QObject): return False - def _getPreferredContainer(self, definition, property_name, default_container): - preferred_id = definition.getMetaDataEntry(property_name) - if preferred_id: - preferred_id = preferred_id.lower() - container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_id) - if container: - return container[0] + def _updateVariantContainer(self, definition): + if not definition.getMetaDataEntry("has_variants"): + return self._empty_variant_container - return default_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): + 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): + 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() From 65a563027de5b8dad9c5b4edba766a2ee33c7ba8 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:19:05 +0200 Subject: [PATCH 104/182] Specify preferred material/quality as wildcards This way it becomes a lot simpler to match them Contributes to CURA-1612 --- resources/definitions/ultimaker2_plus.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/ultimaker2_plus.def.json b/resources/definitions/ultimaker2_plus.def.json index 75501fb158..b29f904095 100644 --- a/resources/definitions/ultimaker2_plus.def.json +++ b/resources/definitions/ultimaker2_plus.def.json @@ -12,8 +12,8 @@ "platform": "ultimaker2_platform.obj", "platform_texture": "Ultimaker2Plusbackplate.png", "preferred_variant": "ultimaker2_plus_0.4", - "preferred_material": "generic_pla_ultimaker2_plus_0.4mm", - "preferred_quality": "pla_0.4_normal", + "preferred_material": "*pla*", + "preferred_quality": "*normal*", "has_variants": true, "has_materials": true, "has_machine_materials": true, From e0ebe960acc9e0d8d9eea9448d3df82909c8ff03 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:19:29 +0200 Subject: [PATCH 105/182] Update standard quality profiles Contributes to CURA-1612 --- resources/quality/high.inst.cfg | 2 ++ resources/quality/low.inst.cfg | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index 546d11326b..86df9dab92 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -9,3 +9,5 @@ read_only = True [values] layer_height = 0.06 +speed_topbottom = 15 +speed_infill = 80 diff --git a/resources/quality/low.inst.cfg b/resources/quality/low.inst.cfg index 11a0094aca..6cebc46dd5 100644 --- a/resources/quality/low.inst.cfg +++ b/resources/quality/low.inst.cfg @@ -8,4 +8,11 @@ type = quality read_only = True [values] +infill_sparse_density = 10 layer_height = 0.15 +cool_min_layer_time = 3 +speed_wall_0 = 40 +speed_wall_x = 80 +speed_infill = 100 +wall_thickness = 1 +speed_topbottom = 30 From 312097c523fe81ea51913698517b9c319ba792b5 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:21:24 +0200 Subject: [PATCH 106/182] Specify UMO as having materials Contributes to CURA-1612 --- resources/definitions/ultimaker_original.def.json | 3 +++ 1 file changed, 3 insertions(+) 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", From 2d77ddada41915cc410f731230e229e8d518a434 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:21:57 +0200 Subject: [PATCH 107/182] Add ABS/CPE quality profiles for UM2(E)+ Contributes to CURA-1612 --- .../um2ep_abs_0.25_normal.inst.cfg | 23 +++++++++++++++++ .../um2ep_abs_0.4_fast.inst.cfg | 24 ++++++++++++++++++ .../um2ep_abs_0.4_high.inst.cfg | 22 ++++++++++++++++ .../um2ep_abs_0.4_normal.inst.cfg | 21 ++++++++++++++++ .../um2ep_abs_0.6_normal.inst.cfg | 23 +++++++++++++++++ .../um2ep_abs_0.8_normal.inst.cfg | 22 ++++++++++++++++ .../um2ep_cpe_0.25_normal.inst.cfg | 22 ++++++++++++++++ .../um2ep_cpe_0.4_fast.inst.cfg | 25 +++++++++++++++++++ .../um2ep_cpe_0.4_high.inst.cfg | 21 ++++++++++++++++ .../um2ep_cpe_0.4_normal.inst.cfg | 22 ++++++++++++++++ .../um2ep_cpe_0.6_normal.inst.cfg | 21 ++++++++++++++++ .../um2ep_cpe_0.8_normal.inst.cfg | 21 ++++++++++++++++ .../um2p_abs_0.25_normal.inst.cfg | 23 +++++++++++++++++ .../um2p_abs_0.4_fast.inst.cfg | 24 ++++++++++++++++++ .../um2p_abs_0.4_high.inst.cfg | 22 ++++++++++++++++ .../um2p_abs_0.4_normal.inst.cfg | 21 ++++++++++++++++ .../um2p_abs_0.6_normal.inst.cfg | 23 +++++++++++++++++ .../um2p_abs_0.8_normal.inst.cfg | 22 ++++++++++++++++ .../um2p_cpe_0.25_normal.inst.cfg | 22 ++++++++++++++++ .../um2p_cpe_0.4_fast.inst.cfg | 25 +++++++++++++++++++ .../um2p_cpe_0.4_high.inst.cfg | 21 ++++++++++++++++ .../um2p_cpe_0.4_normal.inst.cfg | 22 ++++++++++++++++ .../um2p_cpe_0.6_normal.inst.cfg | 21 ++++++++++++++++ .../um2p_cpe_0.8_normal.inst.cfg | 21 ++++++++++++++++ 24 files changed, 534 insertions(+) create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg 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_plus/um2p_abs_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg new file mode 100644 index 0000000000..0b7a371ff1 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[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 +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_plus/um2p_abs_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg new file mode 100644 index 0000000000..e9593b10a7 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg @@ -0,0 +1,24 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[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 +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_plus/um2p_abs_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg new file mode 100644 index 0000000000..2bd3b4fa1a --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[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 +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_plus/um2p_abs_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg new file mode 100644 index 0000000000..34bb28d20a --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[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 +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_plus/um2p_abs_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg new file mode 100644 index 0000000000..2c4656a4d9 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[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 +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_plus/um2p_abs_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg new file mode 100644 index 0000000000..d5b9557ebb --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[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 +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_plus/um2p_cpe_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg new file mode 100644 index 0000000000..eaab2ff2b6 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[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 +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_plus/um2p_cpe_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg new file mode 100644 index 0000000000..e20f5ec96b --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg @@ -0,0 +1,25 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[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 +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_plus/um2p_cpe_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg new file mode 100644 index 0000000000..9b64b5580c --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[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 +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_plus/um2p_cpe_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg new file mode 100644 index 0000000000..6ec06e1fb9 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[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 +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_plus/um2p_cpe_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg new file mode 100644 index 0000000000..f19032a95e --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[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 +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_plus/um2p_cpe_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg new file mode 100644 index 0000000000..45372fdf39 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[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 +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 From 0a9382aa114d1315c8b701f4448278ac61f309af Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:22:21 +0200 Subject: [PATCH 108/182] Fix exclusiveGroup for machine selection in the menu Contributes to CURA-1278 --- resources/qml/Cura.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 2b7a4ccea7..851e7c984f 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -178,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) From 2f3352bfa0cc38675230f05a0b2cece1d5759b5a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 10:45:47 +0200 Subject: [PATCH 109/182] Added default values when adding variant & materials CURA-1612 --- cura/MachineManagerModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 24020f50a4..3e4c7a0411 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -415,7 +415,7 @@ class MachineManagerModel(QObject): return self._empty_variant_container - def _updateMaterialContainer(self, definition, variant_container): + def _updateMaterialContainer(self, definition, variant_container = None): if not definition.getMetaDataEntry("has_materials"): return self._empty_material_container @@ -439,7 +439,7 @@ class MachineManagerModel(QObject): return self._empty_material_container - def _updateQualityContainer(self, definition, material_container): + def _updateQualityContainer(self, definition, material_container = None): search_criteria = { "type": "quality" } if definition.getMetaDataEntry("has_machine_quality"): From d6acb78bd4c310b5ded6180e6cc17394872672a6 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Sun, 5 Jun 2016 09:59:57 +0100 Subject: [PATCH 110/182] Fixing a typo Had that change locally here, but for a reason I forgot to commit that fix. Oops.. --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index ac95529a5d..8668a746fb 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -90,7 +90,7 @@ class CuraApplication(QtApplication): # Need to do this before ContainerRegistry tries to load the machines SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False) - super().__init__(name = "cura", version = CuraVersion, build_type = CuraBuildType) + super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType) self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) From c79b7bdd7ad2ed7df481f718c87346a489ba5da9 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 11:34:29 +0200 Subject: [PATCH 111/182] Machine manager now creates ExtruderTrainStacks CURA-340 --- cura/CuraApplication.py | 12 +++++++++--- cura/MachineManagerModel.py | 27 ++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index df72a4208d..729264767e 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -269,9 +269,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: + 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) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3e4c7a0411..c69ddbc3c2 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -33,8 +33,6 @@ class MachineManagerModel(QObject): active_machine_id = Preferences.getInstance().getValue("cura/active_machine") - - if active_machine_id != "": # An active machine was saved, so restore it. self.setActiveMachine(active_machine_id) @@ -46,9 +44,15 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() + activeExtrudersChanged = 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 = activeExtrudersChanged) + def activeExtruders(self): + return {} + def _onGlobalPropertyChanged(self, key, property_name): if property_name == "value": self.globalValueChanged.emit() @@ -115,7 +119,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: @@ -124,6 +128,23 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) + ## Check if the machine has extruder trains + extruder_trains = definition.getMetaDataEntry("machine_extruder_trains", {}) + for extruder in extruder_trains: + extruder_train_stack = UM.Settings.ContainerStack(name + "_extruder_" + extruder) + extruder_train_stack.addMetaDataEntry("type", "extruder") + extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=extruder_trains[extruder]) + if extruder_definitions: + extruder_train_stack.addContainer(extruder_definitions[0]) + current_settings_container_extruder = UM.Settings.InstanceContainer(extruder_train_stack.getName() + "_current_settings") + current_settings_container_extruder.addMetaDataEntry("machine", name) + current_settings_container_extruder.addMetaDataEntry("type", "user") + extruder_train_stack.addContainer(current_settings_container_extruder) + extruder_train_stack.setNextStack(new_global_stack) + UM.Settings.ContainerRegistry.getInstance().addContainer(extruder_train_stack) + else: + Logger.log("W", "Unable to find definition for extruder") + Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique From 1e44abb9bea42cb1374127be7df46127d954d3cd Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 12:01:46 +0200 Subject: [PATCH 112/182] Added activeExtruder stack to machineManager model CURA-340 --- cura/MachineManagerModel.py | 26 ++++++++++++++++++++++---- resources/qml/SidebarHeader.qml | 6 +++++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c69ddbc3c2..1134e36a38 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -33,6 +33,8 @@ class MachineManagerModel(QObject): 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) @@ -44,14 +46,28 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() - activeExtrudersChanged = pyqtSignal() + activeExtruderChanged = 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 = activeExtrudersChanged) - def activeExtruders(self): - return {} + @pyqtProperty(str, notify=activeExtruderChanged) + def activeExtruderStackId(self): + return self.extrudersIds[str(self._active_extruder_index)] + + @pyqtSlot(int) + def setActiveExtruderIndex(self, index): + self._active_extruder_index = index + self.activeExtruderChanged.emit() + + @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": @@ -133,6 +149,8 @@ class MachineManagerModel(QObject): for extruder in extruder_trains: extruder_train_stack = UM.Settings.ContainerStack(name + "_extruder_" + extruder) extruder_train_stack.addMetaDataEntry("type", "extruder") + extruder_train_stack.addMetaDataEntry("machine", name) # What global stack is this extruder linked with? + extruder_train_stack.addMetaDataEntry("position", extruder) # What is the position of the extruder (as defined by machine definition) extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=extruder_trains[extruder]) if extruder_definitions: extruder_train_stack.addContainer(extruder_definitions[0]) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index bb7aeebae7..61ccbb998d 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 + Cura.MachineManager.setActiveExtruderIndex(index) + } style: ButtonStyle { background: Rectangle { From 783134031bd43b6125fe3c5bd8236a99e2e00121 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 12:17:35 +0200 Subject: [PATCH 113/182] Settings can now be set by extruder CURA-340 --- cura/MachineManagerModel.py | 1 + resources/qml/Settings/SettingView.qml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 1134e36a38..1423744263 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -157,6 +157,7 @@ class MachineManagerModel(QObject): current_settings_container_extruder = UM.Settings.InstanceContainer(extruder_train_stack.getName() + "_current_settings") current_settings_container_extruder.addMetaDataEntry("machine", name) current_settings_container_extruder.addMetaDataEntry("type", "user") + current_settings_container_extruder.setDefinition(definition) extruder_train_stack.addContainer(current_settings_container_extruder) extruder_train_stack.setNextStack(new_global_stack) UM.Settings.ContainerRegistry.getInstance().addContainer(extruder_train_stack) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 1555149d22..7430932b65 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -79,7 +79,7 @@ ScrollView { id: provider - containerStackId: Cura.MachineManager.activeMachineId + containerStackId: Cura.MachineManager.activeExtruderStackId key: model.key watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 From d13b5adda6549064ec9eca0e0f19aa35f73cef79 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 5 Jun 2016 12:22:23 +0200 Subject: [PATCH 114/182] Codestyle & comments CURA-1619 --- cura/PrintInformation.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 22bc562502..47d3989b55 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -51,7 +51,7 @@ class PrintInformation(QObject): self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._job_name = "" - Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) currentPrintTimeChanged = pyqtSignal() @@ -99,12 +99,14 @@ class PrintInformation(QObject): else: return base_name - def _onGlobalStackChanged(self): + ## 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"): + if word.lower() == "ultimaker": abbr_machine += "UM" elif word.isdigit(): abbr_machine += word @@ -113,5 +115,6 @@ class PrintInformation(QObject): 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 From b63c3086940dfa208ceabb3742d830c1f125b1df Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 12:45:02 +0200 Subject: [PATCH 115/182] Changed order of loading containers so extruder stacks don't fail anymore CURA-340 --- cura/CuraApplication.py | 4 ++-- cura/MachineManagerModel.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 22ae244286..1198f4523d 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -132,15 +132,15 @@ 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. diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 1423744263..50098dfa1b 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -158,6 +158,7 @@ class MachineManagerModel(QObject): current_settings_container_extruder.addMetaDataEntry("machine", name) current_settings_container_extruder.addMetaDataEntry("type", "user") current_settings_container_extruder.setDefinition(definition) + UM.Settings.ContainerRegistry.getInstance().addContainer(current_settings_container_extruder) extruder_train_stack.addContainer(current_settings_container_extruder) extruder_train_stack.setNextStack(new_global_stack) UM.Settings.ContainerRegistry.getInstance().addContainer(extruder_train_stack) From cb742cf7ce749c5f4111f07ab43f4e3160e0ce9d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 12:53:41 +0200 Subject: [PATCH 116/182] Fixed saving of machines again --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 1198f4523d..a067ae659b 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -271,7 +271,7 @@ class CuraApplication(QtApplication): file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg" stack_type = stack.getMetaDataEntry("type", None) path = None - if not stack_type: + if stack_type == "machine": path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name) elif stack_type == "extruder": path = Resources.getStoragePath(self.ResourceTypes.ExtruderStack, file_name) From ead91db06291dcfa08c2b9ece9275d0a65ba1b95 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 5 Jun 2016 13:54:55 +0200 Subject: [PATCH 117/182] Fix activating another container stack when the currently active stack is removed CURA-1632 --- cura/MachineManagerModel.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 50098dfa1b..a0af119636 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -405,11 +405,13 @@ class MachineManagerModel(QObject): @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): From c21475abd78a103bfc394e098cd92194a461dd8a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 5 Jun 2016 14:05:56 +0200 Subject: [PATCH 118/182] Prevent multiple machines having the same custom name Caused by container vs containerstack confusion Fixes CURA-1606 and CURA-1649 --- cura/MachineManagerModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index a0af119636..75b273e1f5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -179,8 +179,8 @@ class MachineManagerModel(QObject): i = 1 # 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): + while UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = unique_name, type = "machine") or \ + UM.Settings.ContainerRegistry.getInstance().findContainerStacks(name = unique_name, type = "machine"): i += 1 unique_name = "%s #%d" % (name, i) From 9aa8ca329221f8e8b8b0ec78830eaa34dc97d287 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 5 Jun 2016 16:03:31 +0200 Subject: [PATCH 119/182] Fix uninitialised variable CURA-1619 --- cura/PrintInformation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 47d3989b55..f1eb93de0e 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -51,6 +51,8 @@ class PrintInformation(QObject): self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._job_name = "" + self._abbr_machine = "" + Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) From d810c7ddbb9d9594ec622b2be9ac372cba4225dc Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:00:38 +0200 Subject: [PATCH 120/182] Properly reload extruders at the start The extruder manager was too late to catch the initial global stack switch and machine switch. Now it just always reloads the extruders at the beginning. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 4 +++- cura/ExtrudersModel.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index bfce380a70..46cdeabc91 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -27,6 +27,7 @@ class ExtruderManager: self._next_item = 0 #For when you use this class as iterator. UM.Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. + self._reconnectExtruderReload() ## Gets an instance of this extruder manager. # @@ -51,6 +52,7 @@ class ExtruderManager: self._global_container_stack.containersChanged.disconnect(self._reloadExtruders) #Disconnect from the old global container stack. self._global_container_stack = UM.Application.getInstance().getGlobalContainerStack() self._global_container_stack.containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. + self._reloadExtruders() ## (Re)loads all extruders of the currently active machine. # @@ -66,7 +68,7 @@ class ExtruderManager: #Get the extruder definitions belonging to the current machine. machine = self._global_container_stack.getBottom() extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains") - for extruder_train_id in extruder_train_ids: + for _,extruder_train_id in extruder_train_ids.items(): extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. if not extruder_definitions: #Empty list or error. UM.Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index eb63bc4257..60514e8708 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -53,4 +53,5 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): "index": index } self.appendItem(item) + print("Appending extruder " + extruder.name + " to presenter.") self.sort(lambda item: item["index"]) \ No newline at end of file From 9b2acf03174410b09bc6f0e35c3975a5cf507723 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:12:22 +0200 Subject: [PATCH 121/182] Remove print statement Contributes to issues CURA-1278 and CURA-351. --- cura/ExtrudersModel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 60514e8708..eb63bc4257 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -53,5 +53,4 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): "index": index } self.appendItem(item) - print("Appending extruder " + extruder.name + " to presenter.") self.sort(lambda item: item["index"]) \ No newline at end of file From b4782e9b122ff4b5eaff134d2e4c7cef25540abb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:13:30 +0200 Subject: [PATCH 122/182] Pass definition to _uniqueName instead of name This function expects the entire definition. Contributes to issueS CURA-1278 and CURA-351. --- cura/Extruder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index 4bbe24183d..f27cd061bd 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -25,7 +25,7 @@ class Extruder: self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) #Create a container stack for this extruder. - self._name = self._uniqueName(self._definition.getId()) + self._name = self._uniqueName(self._definition) self._container_stack = UM.Settings.ContainerStack(self._name) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) From c50d0a97dab3b23042bdd90da889450864f1556e Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:18:09 +0200 Subject: [PATCH 123/182] Load extruder combobox synchronously Asynchronously causes Qt 5.4 to give a segfault. Contributes to issues CURA-351 and CURA-1278. --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 2 +- resources/qml/Settings/SettingView.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index d707fe9810..8ab05e90c1 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -56,7 +56,7 @@ 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" onLoaded: { settingLoader.item.showRevertButton = false diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 7430932b65..1ffc2f939f 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -49,7 +49,7 @@ 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 different options. So disable asynchronous loading of enum type completely. - asynchronous: model.type != "enum" + asynchronous: model.type != "enum" && model.type != "extruder" active: model.type != undefined source: From a948c7bcc67fafbc3e32c593a127eac51cd5b6b2 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:29:26 +0200 Subject: [PATCH 124/182] Set colours of extruder selection to material colour Ubuntu Unity doesn't seem to listen to these colours at all though. Contributes to issues CURA-1278 and CURA-351. --- resources/qml/Settings/SettingExtruder.qml | 60 +++++++++++----------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 86ab728fc1..0160dab7fa 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -16,17 +16,18 @@ SettingItem { id: control - model: Cura.ExtrudersModel { + model: Cura.ExtrudersModel + { id: extruders_model } - textRole: "name"; + textRole: "name" anchors.fill: parent MouseArea { - anchors.fill: parent; - acceptedButtons: Qt.NoButton; + anchors.fill: parent + acceptedButtons: Qt.NoButton onWheel: wheel.accepted = true; } @@ -38,44 +39,44 @@ SettingItem { if (!enabled) { - return UM.Theme.getColor("setting_control_disabled") + return UM.Theme.getColor("setting_control_disabled"); } if(control.hovered || base.activeFocus) { - return UM.Theme.getColor("setting_control_highlight") + return UM.Theme.getColor("setting_control_highlight"); } else { - return UM.Theme.getColor("setting_control") + 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"); + 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.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; + 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") : UM.Theme.getColor("setting_control_text"); + 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; + 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; + 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 @@ -83,29 +84,30 @@ SettingItem sourceSize.width: width + 5 sourceSize.height: width + 5 - color: UM.Theme.getColor("setting_control_text"); - + color: UM.Theme.getColor("setting_control_text") } } } - onActivated: provider.setPropertyValue("value", extruders_model.getItem(index).index) + onActivated: provider.setPropertyValue("value", extruders_model.getItem(index).index); onModelChanged: updateCurrentIndex(); Connections { target: provider - onPropertiesChanged: control.updateCurrentIndex() + onPropertiesChanged: control.updateCurrentIndex(); } - function updateCurrentIndex() { - for(var i = 0; i < extruders_model.rowCount(); ++i) { - if(extruders_model.getItem(i).index == provider.properties.value) { + 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; } } From e03c3b95c527347c92939257b44d8d450b41c929 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Mon, 6 Jun 2016 06:36:30 +0100 Subject: [PATCH 125/182] Splashscreen: Another (and last) correction Now all the needed changes should be done. --- cura/CuraSplashScreen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraSplashScreen.py b/cura/CuraSplashScreen.py index 8f677986df..f2810d359b 100644 --- a/cura/CuraSplashScreen.py +++ b/cura/CuraSplashScreen.py @@ -23,7 +23,7 @@ class CuraSplashScreen(QSplashScreen): version = Application.getInstance().getVersion().split("-") buildtype = Application.getInstance().getBuildType() if buildtype: - version += " (%s)" %(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]) From 1171bf112c79f3f3586fb0d030d9dea20db9b961 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Mon, 6 Jun 2016 06:43:07 +0100 Subject: [PATCH 126/182] Ignoring Eclipse+PyDev project files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 72ba4bf565..925de00391 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ resources/i18n/x-test *~ *.qm .idea +.project +.pydevproject From b88f2847ef58cf27b4aab96398ef160a483b9c63 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 08:39:38 +0200 Subject: [PATCH 127/182] Fix saving machine instances to the cura profile CURA-340, see https://github.com/Ultimaker/Cura/commit/c79b7bdd7ad2ed7df481f718c87346a489ba5da9 --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 1198f4523d..4f02d2dab5 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -271,7 +271,7 @@ class CuraApplication(QtApplication): file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg" stack_type = stack.getMetaDataEntry("type", None) path = None - if not stack_type: + 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) From a3e5c065727270d5175c6f76d557115ebb17d97b Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Mon, 6 Jun 2016 06:40:34 +0100 Subject: [PATCH 128/182] Adding debian to gitignore Got a link here my packaging files. As Cura does not come with packaging files itself, we can add this ignore here. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 76f470544f..cc21d3092c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ resources/firmware .idea .project .pydevproject + +# Debian packaging +debian/ From c7340c3b21fbf10c36d6ddf9ec96c95e75703eeb Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 6 Jun 2016 10:18:19 +0200 Subject: [PATCH 129/182] Temporary removed multi extruder stack so slicing works again --- resources/qml/Settings/SettingView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 7430932b65..1555149d22 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -79,7 +79,7 @@ ScrollView { id: provider - containerStackId: Cura.MachineManager.activeExtruderStackId + containerStackId: Cura.MachineManager.activeMachineId key: model.key watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 From 22857bf3e1599367ac82e0b30e1334658005e7b0 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 12:14:10 +0200 Subject: [PATCH 130/182] Disable export profile button when no profile is selected CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index b7261afcec..3f7c696d9d 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -168,9 +168,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 } } From 3752a6bbef2f534efc92d7666dc5397f7d0f62f8 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 13:02:20 +0200 Subject: [PATCH 131/182] Show rename profile dialog after creating a profile from the profiles dropdown CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 3f7c696d9d..0b57405b56 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -71,6 +71,9 @@ UM.ManagementPage scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName) + signal showProfileNameDialog() + onShowProfileNameDialog: { renameDialog.removeWhenRejected = true; renameDialog.open(); renameDialog.selectText(); } + signal selectContainer(string id) onSelectContainer: { objectList.currentIndex = objectList.model.find("id", id); From a139809b75d956773f4a3164f7623a3acdd5ebd0 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 13:39:11 +0200 Subject: [PATCH 132/182] Fix showing profiles created using the dropdown menu in the dropdown and on the profiles manager CURA-1585 --- cura/MachineManagerModel.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 75b273e1f5..3a584a2797 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -289,6 +289,12 @@ class MachineManagerModel(QObject): ## 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.setName(name) From a2db4740b9654fde55f0f811cb33797dc9e63320 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 15:09:21 +0200 Subject: [PATCH 133/182] Fix removing custom (quality) profiles CURA-1585 --- cura/MachineManagerModel.py | 22 +++++++++++++++++++++- resources/qml/Preferences/ProfilesPage.qml | 8 ++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3a584a2797..6e1a6185e7 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -301,7 +301,7 @@ class MachineManagerModel(QObject): new_quality_container._id = name UM.Settings.ContainerRegistry.getInstance().addContainer(new_quality_container) - self.clearUserSettings() # As all users settings are noq a quality, remove them. + self.clearUserSettings() # As all users settings are now transfered to the new quality profile, remove them. self.setActiveQuality(name) return name @@ -325,6 +325,26 @@ class MachineManagerModel(QObject): return "" + + @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: + old_container = self._global_container_stack.findInstanceContainers({"type": "quality"}) + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = container_type) + if containers and old_container: + container_index = self._global_container_stack.getContainerIndex(old_container) + self._global_container_stack.replaceContainer(container_index, containers[0]) + + @pyqtSlot() def updateUserContainerToQuality(self): if not self._global_container_stack: diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 0b57405b56..f5d3169508 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -66,8 +66,8 @@ 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(Cura.MachineManager.activeMachineName) @@ -137,7 +137,7 @@ UM.ManagementPage Label { text: base.currentItem == null ? "" : base.currentItem.id == -1 ? Cura.MachineManager.activeQualityName: - base.currentItem.readOnly ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") + base.currentItem.metadata.read_only ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") } Column { @@ -186,7 +186,7 @@ UM.ManagementPage { id: confirmDialog; object: base.currentItem != null ? base.currentItem.name : ""; - onYes: base.model.removeProfile(base.currentItem.name); + onYes: Cura.MachineManager.removeQualityContainer(base.currentItem.id); } UM.RenameDialog { From 2660b2a68f892dad154fdcbd034d90a402515ec7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 09:37:25 +0200 Subject: [PATCH 134/182] Give default empty machine_extruder_ids Works also if the machine has no machine_extruder_ids metadata. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 46cdeabc91..7222a1c0f8 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -67,7 +67,7 @@ class ExtruderManager: #Get the extruder definitions belonging to the current machine. machine = self._global_container_stack.getBottom() - extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains") + extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains", { }) for _,extruder_train_id in extruder_train_ids.items(): extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. if not extruder_definitions: #Empty list or error. From 357997c984793edcb06881c29047854154c30823 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 09:40:20 +0200 Subject: [PATCH 135/182] Add user profile to container registry This will allow it to be saved when restarting Cura and such. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index f27cd061bd..1e701f9eaa 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -76,6 +76,7 @@ class Extruder: self._user_profile = UM.Settings.InstanceContainer(self._name + "_current_settings") self._user_profile.addMetaDataEntry("type", "user") self._container_stack.addContainer(self._user_profile) + container_registry.addContainer(self._user_profile) self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) From bfc880b61a42026e78b4afbca2e3937b00d8dbd6 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 10:20:59 +0200 Subject: [PATCH 136/182] Add extruder container stack to registry Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index 1e701f9eaa..bfda6db27a 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -27,6 +27,7 @@ class Extruder: #Create a container stack for this extruder. self._name = self._uniqueName(self._definition) self._container_stack = UM.Settings.ContainerStack(self._name) + container_registry.addContainer(self._container_stack) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) From 79c37d667e50d3dd730ade079dfb245a3c614079 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 10:22:47 +0200 Subject: [PATCH 137/182] Add extruder stack only when it's completely built Probably better for concurrency reasons, though that is not a problem yet at this moment. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index bfda6db27a..6418f008c4 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -27,7 +27,6 @@ class Extruder: #Create a container stack for this extruder. self._name = self._uniqueName(self._definition) self._container_stack = UM.Settings.ContainerStack(self._name) - container_registry.addContainer(self._container_stack) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) @@ -81,6 +80,8 @@ class Extruder: self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + container_registry.addContainer(self._container_stack) + definition_changed = UM.Signal() material_changed = UM.Signal() name_changed = UM.Signal() From 927d33145f227d04fbfce393213e0878bae87cd5 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 13:41:49 +0200 Subject: [PATCH 138/182] Move creating extruder manager logic to ExtruderManager This logic was both in Extruder.py and in MachineManagerModel.py due to a planning mishap. Contributes to issues CURA-1278 and CURA-340. --- cura/CuraApplication.py | 3 + cura/Extruder.py | 211 ------------------------- cura/ExtruderManager.py | 139 ++++++++++++---- cura/MachineManagerModel.py | 31 ---- resources/qml/Settings/SettingView.qml | 2 +- resources/qml/SidebarHeader.qml | 2 +- 6 files changed, 109 insertions(+), 279 deletions(-) delete mode 100644 cura/Extruder.py diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 4f02d2dab5..126d8b2864 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -31,6 +31,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog +from . import ExtruderManager from . import ExtrudersModel from . import PlatformPhysics from . import BuildVolume @@ -352,6 +353,8 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) + qmlRegisterSingletonType(ExtruderManager.ExtruderManager, "Cura", 1, 0, "ExtruderManager", + ExtruderManager.createExtruderManager) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) diff --git a/cura/Extruder.py b/cura/Extruder.py deleted file mode 100644 index 6418f008c4..0000000000 --- a/cura/Extruder.py +++ /dev/null @@ -1,211 +0,0 @@ -# Copyright (c) 2016 Ultimaker B.V. -# Cura is released under the terms of the AGPLv3 or higher. - -import re #To parse container registry names to increment the duplicates-resolving number. - -import UM.Application #To link the stack to the global container stack. -import UM.Logger -import UM.Settings.ContainerRegistry #To search for nozzles, materials, etc. -import UM.Settings.ContainerStack #To create a container stack for this extruder. -import UM.Signal #To notify people of changing extruder stacks. - -class Extruder: - ## Creates a new extruder from the specified definition container. - # - # \param definition The definition container defining this extruder. - def __init__(self, definition): - self._definition = definition - - container_registry = UM.Settings.ContainerRegistry.getInstance() - - #Find the nozzles that fit on this extruder. - self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + self._definition.getId() + ",*") #Extruder needs to be delimited by either a comma or the end of string. - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + self._definition.getId()) - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId() + ",*") - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) - - #Create a container stack for this extruder. - self._name = self._uniqueName(self._definition) - self._container_stack = UM.Settings.ContainerStack(self._name) - self._container_stack.addMetaDataEntry("type", "extruder_train") - self._container_stack.addContainer(self._definition) - - #Find the nozzle to use for this extruder. - self._nozzle = container_registry.getEmptyInstanceContainer() - if self._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 = self._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. - self._user_profile = UM.Settings.InstanceContainer(self._name + "_current_settings") - self._user_profile.addMetaDataEntry("type", "user") - self._container_stack.addContainer(self._user_profile) - container_registry.addContainer(self._user_profile) - - self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) - - container_registry.addContainer(self._container_stack) - - definition_changed = UM.Signal() - material_changed = UM.Signal() - name_changed = UM.Signal() - nozzle_changed = UM.Signal() - quality_changed = UM.Signal() - - ## Gets the definition container of this extruder. - # - # \return The definition container of this extruder. - @property - def definition(self): - return self._definition - - ## Changes the definition container of this extruder. - # - # \param value The new definition for this extruder. - @definition.setter - def definition(self, value): - try: - position = self._container_stack.index(self._definition) - except ValueError: #Definition is not in the list. Big trouble! - UM.Logger.log("e", "I've lost my old extruder definition, so I can't find where to insert the new definition.") - return - self._container_stack.replaceContainer(position, value) - self._definition = value - self.definition_changed.emit() - - ## Gets the currently active material on this extruder. - # - # \return The currently active material on this extruder. - @property - def material(self): - return self._material - - ## Changes the currently active material in this extruder. - # - # \param value The new material to extrude through this extruder. - @material.setter - def material(self, value): - try: - position = self._container_stack.index(self._material) - except ValueError: #Material is not in the list. - UM.Logger.log("e", "I've lost my old material, so I can't find where to insert the new material.") - return - self._container_stack.replaceContainer(position, value) - self._material = value - self.material_changed.emit() - - ## Gets the name of this extruder. - # - # \return The name of this extruder. - @property - def name(self): - return self._name - - ## Changes the name of this extruder. - # - # \param value The new name for this extruder. - @name.setter - def name(self, value): - self._name = value - self._container_stack.setName(value) #Also update in container stack, being defensive. - self.name_changed.emit() - - ## Gets the currently active nozzle on this extruder. - # - # \return The currently active nozzle on this extruder. - @property - def nozzle(self): - return self._nozzle - - ## Changes the currently active nozzle on this extruder. - # - # \param value The new nozzle to use with this extruder. - @nozzle.setter - def nozzle(self, value): - try: - position = self._container_stack.index(self._nozzle) - except ValueError: #Nozzle is not in the list. - UM.Logger.log("e", "I've lost my old nozzle, so I can't find where to insert the new nozzle.") - return - self._container_stack.replaceContainer(position, value) - self._nozzle = value - self.nozzle_changed.emit() - - ## Gets the currently active quality on this extruder. - # - # \return The currently active quality on this extruder. - @property - def quality(self): - return self._quality - - ## Changes the currently active quality to use with this extruder. - # - # \param value The new quality to use with this extruder. - @quality.setter - def quality(self, value): - try: - position = self._container_stack.index(self._quality) - except ValueError: #Quality is not in the list. - UM.Logger.log("e", "I've lost my old quality, so I can't find where to insert the new quality.") - return - self._container_stack.replaceContainer(position, value) - self._quality = value - self.quality_changed.emit() - - ## Finds a unique name for an extruder stack. - # - # \param extruder An extruder definition 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 = UM.Settings.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/ExtruderManager.py b/cura/ExtruderManager.py index 7222a1c0f8..4f23a01808 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -1,7 +1,8 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from cura.Extruder import Extruder #The individual extruders managed by this manager. +from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject + 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. @@ -13,21 +14,24 @@ import UM.Signal #To notify other components of changes in the extruders. # 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 ExtruderManager: +class ExtruderManager(QObject): ## The singleton instance of this manager. __instance = None ## Signal to notify other components when the list of extruders changes. extrudersChanged = UM.Signal() - ## Registers listeners and such to listen to changes to the extruders. - def __init__(self): - self._extruders = [] #Extruders for the current machine. - self._global_container_stack = None - self._next_item = 0 #For when you use this class as iterator. + ## Notify when the user switches the currently active extruder. + activeExtruderChanged = pyqtSignal() - UM.Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. - self._reconnectExtruderReload() + ## 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._next_item = 0 #For when you use this class as iterator. + self._active_extruder_index = 0 + + self._repopulate() ## Gets an instance of this extruder manager. # @@ -45,34 +49,99 @@ class ExtruderManager: def __iter__(self): return iter(self._extruders) - ## When the global container stack changes, this reconnects to the new - # signal for containers changing. - def _reconnectExtruderReload(self): - if self._global_container_stack: - self._global_container_stack.containersChanged.disconnect(self._reloadExtruders) #Disconnect from the old global container stack. - self._global_container_stack = UM.Application.getInstance().getGlobalContainerStack() - self._global_container_stack.containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. - self._reloadExtruders() + @pyqtProperty(str, notify = activeExtruderChanged) + def activeExtruderStackId(self): + if UM.Application.getInstance().getGlobalContainerStack(): + try: + return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)] + except KeyError: + pass - ## (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 extruders for that machine and loads each of them in a - # list of extruders. - def _reloadExtruders(self, *args): - self._extruders = [] - if not self._global_container_stack: #No machine has been added yet. + @pyqtSlot(int) + def setActiveExtruderIndex(self, index): + self._active_extruder_index = index + self.activeExtruderChanged.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! - #Get the extruder definitions belonging to the current machine. - machine = self._global_container_stack.getBottom() - extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains", { }) - for _,extruder_train_id in extruder_train_ids.items(): - extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. - if not extruder_definitions: #Empty list or error. - UM.Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) + 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 - for extruder_definition in extruder_definitions: - self._extruders.append(Extruder(extruder_definition)) - self.extrudersChanged.emit() \ No newline at end of file + 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, definition, extruder_id): + container_registry = UM.Settings.ContainerRegistry.getInstance() + + #Create a container stack for this extruder. + name = self._uniqueName(extruder_id) + container_stack = UM.Settings.ContainerStack(name) + container_stack.addMetaDataEntry("type", "extruder_train") + container_stack.addContainer(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(name + "_current_settings") + user_profile.addMetaDataEntry("type", "user") + container_stack.addContainer(user_profile) + container_registry.addContainer(user_profile) + + container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + + container_registry.addContainer(container_stack) + +def createExtruderManager(engine, script_engine): + return ExtruderManager() \ No newline at end of file diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3a584a2797..3515d613bd 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -46,20 +46,9 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() - activeExtruderChanged = pyqtSignal() - globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed. globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed. - @pyqtProperty(str, notify=activeExtruderChanged) - def activeExtruderStackId(self): - return self.extrudersIds[str(self._active_extruder_index)] - - @pyqtSlot(int) - def setActiveExtruderIndex(self, index): - self._active_extruder_index = index - self.activeExtruderChanged.emit() - @pyqtProperty("QVariantMap", notify = globalContainerChanged) def extrudersIds(self): ## Find all extruders that reference the new stack @@ -145,26 +134,6 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(current_settings_instance_container) ## Check if the machine has extruder trains - extruder_trains = definition.getMetaDataEntry("machine_extruder_trains", {}) - for extruder in extruder_trains: - extruder_train_stack = UM.Settings.ContainerStack(name + "_extruder_" + extruder) - extruder_train_stack.addMetaDataEntry("type", "extruder") - extruder_train_stack.addMetaDataEntry("machine", name) # What global stack is this extruder linked with? - extruder_train_stack.addMetaDataEntry("position", extruder) # What is the position of the extruder (as defined by machine definition) - extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=extruder_trains[extruder]) - if extruder_definitions: - extruder_train_stack.addContainer(extruder_definitions[0]) - current_settings_container_extruder = UM.Settings.InstanceContainer(extruder_train_stack.getName() + "_current_settings") - current_settings_container_extruder.addMetaDataEntry("machine", name) - current_settings_container_extruder.addMetaDataEntry("type", "user") - current_settings_container_extruder.setDefinition(definition) - UM.Settings.ContainerRegistry.getInstance().addContainer(current_settings_container_extruder) - extruder_train_stack.addContainer(current_settings_container_extruder) - extruder_train_stack.setNextStack(new_global_stack) - UM.Settings.ContainerRegistry.getInstance().addContainer(extruder_train_stack) - else: - Logger.log("W", "Unable to find definition for extruder") - Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 0eb13d668c..2e62280865 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -79,7 +79,7 @@ ScrollView { id: provider - containerStackId: Cura.MachineManager.activeMachineId + containerStackId: Cura.ExtruderManager.activeExtruderStackId ? Cura.ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId key: model.key watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 61ccbb998d..b38f65772d 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -111,7 +111,7 @@ Item onClicked: { base.currentExtruderIndex = index - Cura.MachineManager.setActiveExtruderIndex(index) + Cura.ExtruderManager.setActiveExtruderIndex(index) } style: ButtonStyle { From d1be5b6c029d5764436226b53461b1ef600cda46 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:17:00 +0200 Subject: [PATCH 139/182] Create extruder train for each train in a machine We had the functionality, but this function was not yet called! Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 5 +++-- cura/MachineManagerModel.py | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 4f23a01808..ccf8a3ad40 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -79,14 +79,14 @@ class ExtruderManager(QObject): self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() self.extrudersChanged.emit() - def createExtruderTrain(self, definition, extruder_id): + def createExtruderTrain(self, extruder_definition, machine_definition, extruder_id): container_registry = UM.Settings.ContainerRegistry.getInstance() #Create a container stack for this extruder. name = self._uniqueName(extruder_id) container_stack = UM.Settings.ContainerStack(name) container_stack.addMetaDataEntry("type", "extruder_train") - container_stack.addContainer(definition) + container_stack.addContainer(extruder_definition) """ Yes, I'm committing this code which needs to be transformed to work later. @@ -136,6 +136,7 @@ class ExtruderManager(QObject): #Add an empty user profile. user_profile = UM.Settings.InstanceContainer(name + "_current_settings") user_profile.addMetaDataEntry("type", "user") + user_profile.setDefinition(machine_definition) container_stack.addContainer(user_profile) container_registry.addContainer(user_profile) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3515d613bd..5e811e603d 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -9,7 +9,7 @@ from UM.Logger import Logger import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer - +from . import ExtruderManager class MachineManagerModel(QObject): def __init__(self, parent = None): @@ -133,7 +133,15 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) - ## Check if the machine has extruder trains + for position, extruder_train_id in definitions.getMetaDataEntry("machine_extruder_trains", default = {}).items(): + extruder_definition = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) + if extruder_definition: + extruder_definition = extruder_definition[0] + else: + Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", definition.getName(), extruder_train_id) + continue + ExtruderManager.getInstance().createExtruderTrain(extruder_definition, definition, extruder_train_id) + Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique From 70e6c8093ed56db8bcb50b40a140d7ffe5e4d0da Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:19:18 +0200 Subject: [PATCH 140/182] Explicitly return None if no global container stack That's what it does. This is more clear than doing 'pass' or something. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index ccf8a3ad40..ff29165df5 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -51,11 +51,12 @@ class ExtruderManager(QObject): @pyqtProperty(str, notify = activeExtruderChanged) def activeExtruderStackId(self): - if UM.Application.getInstance().getGlobalContainerStack(): - try: - return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)] - except KeyError: - pass + if not UM.Application.getInstance().getGlobalContainerStack(): + return None #Whatta ya gonna do? + try: + return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)] + except KeyError: + return None @pyqtSlot(int) def setActiveExtruderIndex(self, index): From 7950dfaa072bf9208b5c25551e46bac7bb29e011 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:31:02 +0200 Subject: [PATCH 141/182] Document activeExtruderStackId Contributes to issues CURA-340, CURA-351 and CURA-1278. --- cura/ExtruderManager.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index ff29165df5..369eb33d51 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -49,13 +49,19 @@ class ExtruderManager(QObject): def __iter__(self): return iter(self._extruders) + ## 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 #Whatta ya gonna do? + 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: + 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 @pyqtSlot(int) From 77c918a0a7c92a98e499fb0dba22a4e193fac16f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:32:20 +0200 Subject: [PATCH 142/182] Remove superfluous singleton pattern The qmlRegisterSingletonType function already makes sure it is a singleton. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 369eb33d51..9785c51c2c 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -15,9 +15,6 @@ import UM.Signal #To notify other components of changes in the extruders. # 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 ExtruderManager(QObject): - ## The singleton instance of this manager. - __instance = None - ## Signal to notify other components when the list of extruders changes. extrudersChanged = UM.Signal() @@ -33,16 +30,6 @@ class ExtruderManager(QObject): self._repopulate() - ## Gets an instance of this extruder manager. - # - # If an instance was already created, the old instance is returned. This - # implements the singleton pattern. - @classmethod - def getInstance(cls): - if not cls.__instance: - cls.__instance = ExtruderManager() - return cls.__instance - ## Creates an iterator over the extruders in this manager. # # \return An iterator over the extruders in this manager. From 64c92caa58b410ab39c9306747d004568ad5ed5f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:48:55 +0200 Subject: [PATCH 143/182] Update documentation of ExtruderManager class Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 9785c51c2c..11cd6d70cc 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -9,11 +9,9 @@ import UM.Settings.ContainerRegistry #Finding containers by ID. import UM.Signal #To notify other components of changes in the extruders. -## Class that handles the current extruder stack. +## Manages all existing extruder stacks. # -# 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. +# 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 = UM.Signal() From 84a91662417dfb38323d878f5cfc4b15cfed1b28 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 15:06:36 +0200 Subject: [PATCH 144/182] Make extrudersChanged into a pyqtSignal This way we can listen for it on the cute side. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 11cd6d70cc..b35243df05 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -1,12 +1,11 @@ # 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 +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. -import UM.Signal #To notify other components of changes in the extruders. ## Manages all existing extruder stacks. @@ -14,7 +13,7 @@ import UM.Signal #To notify other components of changes in the extruders. # 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 = UM.Signal() + extrudersChanged = pyqtSignal() ## Notify when the user switches the currently active extruder. activeExtruderChanged = pyqtSignal() From 0b57728d9d7042fff3b5d694732b09a697564779 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 15:55:14 +0200 Subject: [PATCH 145/182] Fix creating a unique name for profiles CURA-1585 --- cura/MachineManagerModel.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 6e1a6185e7..4deea99afc 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -9,7 +9,8 @@ from UM.Logger import Logger import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer - +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") class MachineManagerModel(QObject): def __init__(self, parent = None): @@ -118,7 +119,7 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._createUniqueStackName(name, definition.getName()) + name = self._createUniqueName("machine", name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) new_global_stack.addMetaDataEntry("type", "machine") @@ -168,7 +169,7 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique - def _createUniqueStackName(self, name, fallback_name): + def _createUniqueName(self, object_type, name, fallback_name): name = name.strip() num_check = re.compile("(.*?)\s*#\d$").match(name) if(num_check): @@ -179,10 +180,16 @@ class MachineManagerModel(QObject): i = 1 # 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().findContainerStacks(id = unique_name, type = "machine") or \ - UM.Settings.ContainerRegistry.getInstance().findContainerStacks(name = unique_name, type = "machine"): - i += 1 - unique_name = "%s #%d" % (name, i) + if object_type == "machine": + while UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = unique_name, type = "machine") or \ + UM.Settings.ContainerRegistry.getInstance().findContainerStacks(name = unique_name, type = "machine"): + i += 1 + unique_name = "%s #%d" % (name, i) + else: + while UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = unique_name, type = object_type) or \ + UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = unique_name, type = object_type): + i += 1 + unique_name = "%s #%d" % (name, i) return unique_name @@ -282,7 +289,7 @@ class MachineManagerModel(QObject): if not self._global_container_stack: return - name = self._createUniqueStackName("Custom profile", "") + name = self._createUniqueName("quality", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) user_settings = self._global_container_stack.getTop() new_quality_container = InstanceContainer("") @@ -311,7 +318,7 @@ class MachineManagerModel(QObject): return containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) if containers: - new_name = self._createUniqueStackName(containers[0].getName(), "") + new_name = self._createUniqueName("quality", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) new_container = InstanceContainer("") @@ -424,7 +431,7 @@ class MachineManagerModel(QObject): def renameMachine(self, machine_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) if containers: - new_name = self._createUniqueStackName(new_name, containers[0].getBottom().getName()) + new_name = self._createUniqueName("machine", new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) self.globalContainerChanged.emit() From df71269f8244ed4c3e15b32a20af241df4463384 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 15:56:45 +0200 Subject: [PATCH 146/182] Mark custom profiles as not read-only CURA-1585 --- cura/MachineManagerModel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 4deea99afc..ad7669b43a 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -303,7 +303,8 @@ class MachineManagerModel(QObject): 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("type", "quality") + new_quality_container.setMetaDataEntry("read_only", False) new_quality_container.setName(name) new_quality_container._id = name From 03914674c7f105be37a3a7dc222a9659c3d741f4 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Mon, 6 Jun 2016 16:03:16 +0200 Subject: [PATCH 147/182] Cache all of the settings list items instead of recreating them all the time. Fixes CURA-1630 Settings disappear after selecting all options of Experimental Modes --- resources/qml/Settings/SettingView.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 0eb13d668c..ba7b5e32a9 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -24,6 +24,7 @@ ScrollView { id: contents spacing: UM.Theme.getSize("default_lining").height; + cacheBuffer: 1000000; // A huge to cache to effectively cache everything. model: UM.SettingDefinitionsModel { id: definitionsModel; From a2def606c68b1d91fbe15c0dca8ff4fdd3968424 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 17:10:56 +0200 Subject: [PATCH 148/182] Fix Profile (application-)menu and add separators to profiles dropdown CURA-1585 --- resources/qml/Cura.qml | 43 ++++++++++++++++++++-------------- resources/qml/ProfileSetup.qml | 18 ++++---------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 851e7c984f..46ebc25369 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -226,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 { @@ -239,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: { @@ -269,20 +288,10 @@ 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) } } diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml index 3175a4e2b3..c6291c8c85 100644 --- a/resources/qml/ProfileSetup.qml +++ b/resources/qml/ProfileSetup.qml @@ -88,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: { @@ -117,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) } } From 5235f74adfc68420587a3e0d570a3ff3bc66ec5a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 17:47:33 +0200 Subject: [PATCH 149/182] Prevent unique names like "profile #10 #2" CURA-1606, CURA-1585 --- cura/MachineManagerModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e57294d871..6d6ff10a4b 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -149,7 +149,7 @@ class MachineManagerModel(QObject): # Create a name that is not empty and unique def _createUniqueName(self, object_type, name, fallback_name): name = name.strip() - num_check = re.compile("(.*?)\s*#\d$").match(name) + num_check = re.compile("(.*?)\s*#\d+$").match(name) if(num_check): name = num_check.group(1) if name == "": From efe3f5e4ee08c3dea2104dc35b29c0b7bc408d4a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 17:53:34 +0200 Subject: [PATCH 150/182] Remove dependency on QtQml.Models CURA-1278 --- resources/qml/GeneralPage.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 } } } From 35706734e696ca0c360c4f607b81be21ea6736d3 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 23:13:25 +0200 Subject: [PATCH 151/182] Show settings on Profile page CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index f5d3169508..52ab10cfd6 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -144,7 +144,7 @@ UM.ManagementPage Repeater { model: base.currentItem ? base.currentItem.settings : null Label { - text: modelData.name.toString(); + text: modelData.label elide: Text.ElideMiddle; } } From 05643eca11e8c4cd58645d519db67ad90a4bf4e7 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 08:11:53 +0200 Subject: [PATCH 152/182] Fix renaming profiles from the Profiles page CURA-1585 --- cura/MachineManagerModel.py | 9 +++++++++ resources/qml/Preferences/ProfilesPage.qml | 14 +++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 6d6ff10a4b..6e0e0a6127 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -312,6 +312,15 @@ class MachineManagerModel(QObject): 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("machine", new_name, catalog.i18nc("@label", "Custom profile")) + containers[0].setName(new_name) + UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) + + @pyqtSlot(str) def removeQualityContainer(self, container_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 52ab10cfd6..c031ed9f20 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -184,19 +184,19 @@ UM.ManagementPage UM.ConfirmRemoveDialog { - id: confirmDialog; - object: base.currentItem != null ? base.currentItem.name : ""; - onYes: Cura.MachineManager.removeQualityContainer(base.currentItem.id); + 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.rename(base.currentItem.id, 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) } } } From 0a84867132f899288be59a72ba17b810e81fce87 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 09:33:29 +0200 Subject: [PATCH 153/182] Fixed multiple typos / missing things in extrudermanager --- cura/ExtruderManager.py | 28 ++++++++++++++++++++++++++++ cura/MachineManagerModel.py | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index b35243df05..aae90afdc5 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -6,6 +6,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For commun 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. +import re ## Manages all existing extruder stacks. @@ -48,6 +49,13 @@ class ExtruderManager(QObject): 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 @@ -135,5 +143,25 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) + + def _uniqueName(self, extruder): + container_registry = UM.Settings.ContainerRegistry.getInstance() + + name = extruder.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 + + def createExtruderManager(engine, script_engine): return ExtruderManager() \ No newline at end of file diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 6d6ff10a4b..e2c097daf5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -135,14 +135,14 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) - for position, extruder_train_id in definitions.getMetaDataEntry("machine_extruder_trains", default = {}).items(): + for position, extruder_train_id in definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): extruder_definition = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) if extruder_definition: extruder_definition = extruder_definition[0] else: Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", definition.getName(), extruder_train_id) continue - ExtruderManager.getInstance().createExtruderTrain(extruder_definition, definition, extruder_train_id) + ExtruderManager.ExtruderManager.getInstance().createExtruderTrain(extruder_definition, definition, extruder_train_id) Application.getInstance().setGlobalContainerStack(new_global_stack) From a6870b555b644f2fa91ea313f010551d4f64b61a Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Tue, 7 Jun 2016 10:34:08 +0200 Subject: [PATCH 154/182] Fix up my comment, make it clearer. Fixes CURA-1630 Settings disappear after selecting all options of Experimental Modes --- resources/qml/Settings/SettingView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index ed66661a8e..7191bff3ef 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -24,7 +24,7 @@ ScrollView { id: contents spacing: UM.Theme.getSize("default_lining").height; - cacheBuffer: 1000000; // A huge to cache to effectively cache everything. + cacheBuffer: 1000000; // Set a large cache to effectively just cache every list item. model: UM.SettingDefinitionsModel { id: definitionsModel; From ce388c4b231aaedc8377668b6c27cdc9d7ed96d8 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 11:18:09 +0200 Subject: [PATCH 155/182] Show settings in profile as a sorted list with section headers CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 103 ++++++++++----------- 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index c031ed9f20..28248b23f4 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -91,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 = 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() + 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: Cura.MachineManager.hasUserSettings - onClicked: Cura.MachineManager.clearUserSettings(); + 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 ? Cura.MachineManager.activeQualityName: - base.currentItem.metadata.read_only ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") - } - - Column { - Repeater { - model: base.currentItem ? base.currentItem.settings : null - Label { - text: modelData.label - 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 } } } From 890303da146a77d6be6be51bb1eda1104930f556 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 11:33:10 +0200 Subject: [PATCH 156/182] Add function to add all extruder trains of a machine This function only adds extruder trains if they have not been added already. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 41 +++++++++++++++++++++++++++++++++---- cura/MachineManagerModel.py | 9 +------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index aae90afdc5..8c467ede00 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -61,6 +61,38 @@ class ExtruderManager(QObject): 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 not self._extruder_trains[machine_id]: + 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 position, extruder_definition_id in machine_definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): + extruder_definition = container_registry.findDefinitionContainers(id = extruder_definition_id) + if extruder_definition: + extruder_definition = extruder_definition[0] + else: + Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) + continue + name = self._uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. + if not container_registry.findContainerStacks(id = name): #Doesn't exist yet. + 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 = { } @@ -78,13 +110,14 @@ class ExtruderManager(QObject): self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() self.extrudersChanged.emit() - def createExtruderTrain(self, extruder_definition, machine_definition, extruder_id): + def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position): container_registry = UM.Settings.ContainerRegistry.getInstance() #Create a container stack for this extruder. - name = self._uniqueName(extruder_id) - container_stack = UM.Settings.ContainerStack(name) + 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) """ @@ -133,7 +166,7 @@ class ExtruderManager(QObject): """ #Add an empty user profile. - user_profile = UM.Settings.InstanceContainer(name + "_current_settings") + 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) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 576cf1acc0..86e74e8302 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -135,14 +135,7 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) - for position, extruder_train_id in definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): - extruder_definition = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) - if extruder_definition: - extruder_definition = extruder_definition[0] - else: - Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", definition.getName(), extruder_train_id) - continue - ExtruderManager.ExtruderManager.getInstance().createExtruderTrain(extruder_definition, definition, extruder_train_id) + ExtruderManager.ExtruderManager.getInstance().addMachineExtruders(definition) Application.getInstance().setGlobalContainerStack(new_global_stack) From 9fe543596316fb11c5478b750465f958228983a9 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 11:34:00 +0200 Subject: [PATCH 157/182] Rename parameter in _uniqueName Original means the original name. That's better. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 8c467ede00..15fbbe2a1c 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -177,10 +177,10 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) - def _uniqueName(self, extruder): + def _uniqueName(self, original): container_registry = UM.Settings.ContainerRegistry.getInstance() - name = extruder.strip() + name = original.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. From dff94b4559e558aeadea7a8694393557b838c3f5 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 11:54:16 +0200 Subject: [PATCH 158/182] Make ExtruderManager a QML context item There were two singletons of this manager: One created by QML and managed by QML, and one created by us and managed by our own singleton pattern. That won't work! So we now manage just our own singleton type, and make it a context item for QML so it can use the manager too. Contributes to issues CURA-340 and CURA-1278. --- cura/CuraApplication.py | 7 +++++-- cura/ExtruderManager.py | 6 +----- resources/qml/Settings/SettingView.qml | 2 +- resources/qml/SidebarHeader.qml | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 126d8b2864..7edb0bf8bd 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -353,8 +353,6 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) - qmlRegisterSingletonType(ExtruderManager.ExtruderManager, "Cura", 1, 0, "ExtruderManager", - ExtruderManager.createExtruderManager) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) @@ -386,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() @@ -399,6 +400,8 @@ class CuraApplication(QtApplication): 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"): diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 15fbbe2a1c..4f8c58be07 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -76,7 +76,7 @@ class ExtruderManager(QObject): #Add the extruder trains that don't exist yet. for position, extruder_definition_id in machine_definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): - extruder_definition = container_registry.findDefinitionContainers(id = extruder_definition_id) + extruder_definition = container_registry.findDefinitionContainers(machine = machine_definition.getId()) if extruder_definition: extruder_definition = extruder_definition[0] else: @@ -194,7 +194,3 @@ class ExtruderManager(QObject): i += 1 # Try next numbering. unique_name = "%s #%d" % (name, i) # Fill name like this: "Extruder #2". return unique_name - - -def createExtruderManager(engine, script_engine): - return ExtruderManager() \ No newline at end of file diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 7191bff3ef..6261496c84 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -80,7 +80,7 @@ ScrollView { id: provider - containerStackId: Cura.ExtruderManager.activeExtruderStackId ? Cura.ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId + containerStackId: ExtruderManager.activeExtruderStackId ? ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId key: model.key watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index b38f65772d..237746ac0d 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -111,7 +111,7 @@ Item onClicked: { base.currentExtruderIndex = index - Cura.ExtruderManager.setActiveExtruderIndex(index) + ExtruderManager.setActiveExtruderIndex(index) } style: ButtonStyle { From 66bf0831f310e7f56090843d31db0ba057218903 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 11:55:07 +0200 Subject: [PATCH 159/182] Document _uniqueName This function should really just be moved to ContainerRegistry... I'll do that later. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 4f8c58be07..f8bcd75151 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -176,7 +176,14 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) - + ## Creates a new unique name for a container that doesn't exist yet. + # + # It tries if the original name you provide exists, and if it doesn't + # it'll add a " #1" or " #2" after the name to make it unique. + # + # \param original The original name that may not be unique. + # \return A unique name that looks a lot like the original but may have + # a number behind it to make it unique. def _uniqueName(self, original): container_registry = UM.Settings.ContainerRegistry.getInstance() @@ -189,8 +196,7 @@ class ExtruderManager(QObject): 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. + 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 From 4fb66afe069ba9f6b7dff397448d6f659232cb79 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 11:58:44 +0200 Subject: [PATCH 160/182] Mark duplicated profiles as non-read-only CURA-1585 --- cura/MachineManagerModel.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 576cf1acc0..e179eb2ebd 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -304,6 +304,7 @@ class MachineManagerModel(QObject): ## 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) From 68837a089ad46ca990969188169bcd0b69de6e06 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 12:50:57 +0200 Subject: [PATCH 161/182] Moved some properties to bindings due to bug in qt 5.5.1 CURA-1494 --- resources/qml/Settings/SettingItem.qml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index f476349c42..e4edc267ef 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -22,6 +22,10 @@ Item { 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(); @@ -128,7 +132,7 @@ Item { { id: revertButton; - visible: propertyProvider.stackLevel == 0 && base.showRevertButton + visible: base.stackLevel == 0 && base.showRevertButton height: parent.height; width: height; @@ -155,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 && base.showInheritButton + 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"); From ca1b199c7e4d57e4ef071b64add53ad2d895be3d Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 7 Jun 2016 13:17:35 +0200 Subject: [PATCH 162/182] Fix PerObjectSettings to use the right objects when instantiating setting items Contributes to CURA-1592 --- .../PerObjectSettingsPanel.qml | 62 ++++++++++++++++--- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 8ab05e90c1..c89485517e 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -64,24 +64,26 @@ Item { settingLoader.item.doDepthIdentation = false } - source: + 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 } } } @@ -257,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 { } + } } From 227c0f9f8c9d71d264f1959c18b2fdf550f05a5b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 12:01:12 +0200 Subject: [PATCH 163/182] Move _uniqueName to ContainerRegistry It's not specific to any type of container and we might re-use this anyway. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index f8bcd75151..31943be747 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -26,8 +26,6 @@ class ExtruderManager(QObject): self._next_item = 0 #For when you use this class as iterator. self._active_extruder_index = 0 - self._repopulate() - ## Creates an iterator over the extruders in this manager. # # \return An iterator over the extruders in this manager. @@ -82,7 +80,7 @@ class ExtruderManager(QObject): else: Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) continue - name = self._uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. + name = container_registry.uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. if not container_registry.findContainerStacks(id = name): #Doesn't exist yet. self.createExtruderTrain(extruder_definition, machine_definition, name, position) @@ -175,28 +173,3 @@ class ExtruderManager(QObject): container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) container_registry.addContainer(container_stack) - - ## Creates a new unique name for a container that doesn't exist yet. - # - # It tries if the original name you provide exists, and if it doesn't - # it'll add a " #1" or " #2" after the name to make it unique. - # - # \param original The original name that may not be unique. - # \return A unique name that looks a lot like the original but may have - # a number behind it to make it unique. - def _uniqueName(self, original): - container_registry = UM.Settings.ContainerRegistry.getInstance() - - name = original.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 From c5b07debdcf5583de189c13beeb6bcf333eae252 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:22:47 +0200 Subject: [PATCH 164/182] Remove iterability from ExtruderManager This is no longer used. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 31943be747..a1f901ce54 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -23,15 +23,8 @@ class ExtruderManager(QObject): def __init__(self, parent = None): super().__init__(parent) self._extruder_trains = { } #Extruders for the current machine. - self._next_item = 0 #For when you use this class as iterator. self._active_extruder_index = 0 - ## Creates an iterator over the extruders in this manager. - # - # \return An iterator over the extruders in this manager. - def __iter__(self): - return iter(self._extruders) - ## Gets the unique identifier of the currently active extruder stack. # # The currently active extruder stack is the stack that is currently being From 253061cfa492adeb628e9f7fa4929c43df0fafd6 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:24:03 +0200 Subject: [PATCH 165/182] Remove unused import The _uniqueName function was using this but it was moved to ContainerRegistry. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index a1f901ce54..d157cbb08e 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -6,7 +6,6 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For commun 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. -import re ## Manages all existing extruder stacks. From b991743053edf2778a2395dc9ede7007b99386eb Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 13:30:13 +0200 Subject: [PATCH 166/182] Fix ExtruderManager.py --- cura/ExtruderManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index d157cbb08e..b2c3b47e8e 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -4,7 +4,7 @@ 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 +from UM.Logger import Logger import UM.Settings.ContainerRegistry #Finding containers by ID. @@ -57,7 +57,7 @@ class ExtruderManager(QObject): # \param machine_definition The machine to add the extruders for. def addMachineExtruders(self, machine_definition): machine_id = machine_definition.getId() - if not self._extruder_trains[machine_id]: + if machine_id not in self._extruder_trains: self._extruder_trains[machine_id] = { } container_registry = UM.Settings.ContainerRegistry.getInstance() From 4695862b491dc0edd2560b89f689b170f385e391 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 13:33:19 +0200 Subject: [PATCH 167/182] Added deepcopy function to settingOverrideDecorator CURA-1636 --- cura/SettingOverrideDecorator.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index e212d93dac..04e77b0d3f 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. @@ -25,6 +25,15 @@ class SettingOverrideDecorator(SceneNodeDecorator): Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) self._onGlobalContainerStackChanged() + def __deepcopy__(self, memo): + ## Create a fresh decorator object + deep_copy = SettingOverrideDecorator() + ## Copy the stack + deep_copy._stack = copy.deepcopy(self._stack, memo) + ## Ensure that the id is unique. + deep_copy._stack._id = id(deep_copy) + return deep_copy + def _onSettingChanged(self, instance, property): if property == "value": # Only reslice if the value has changed. Application.getInstance().getBackend().forceSlice() From 08d116590d2aac424be9f222b171a9ada751eabf Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:32:36 +0200 Subject: [PATCH 168/182] Revert "Fix ExtruderManager.py" That is not a fix. That is a patch. This reverts commit b991743053edf2778a2395dc9ede7007b99386eb. --- cura/ExtruderManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index b2c3b47e8e..d157cbb08e 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -4,7 +4,7 @@ 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. -from UM.Logger import Logger +import UM.Logger import UM.Settings.ContainerRegistry #Finding containers by ID. @@ -57,7 +57,7 @@ class ExtruderManager(QObject): # \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: + if not self._extruder_trains[machine_id]: self._extruder_trains[machine_id] = { } container_registry = UM.Settings.ContainerRegistry.getInstance() From 8feed746bf82d7fccaf5c6966685aba49c96b8ac Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:40:49 +0200 Subject: [PATCH 169/182] Re-apply part of b991743053edf2778a2395dc9ede7007b99386eb that worked This was indeed a mistake. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index d157cbb08e..9fbfc8eb84 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -57,7 +57,7 @@ class ExtruderManager(QObject): # \param machine_definition The machine to add the extruders for. def addMachineExtruders(self, machine_definition): machine_id = machine_definition.getId() - if not self._extruder_trains[machine_id]: + if machine_id not in self._extruder_trains: self._extruder_trains[machine_id] = { } container_registry = UM.Settings.ContainerRegistry.getInstance() From a9376cffd1b19c43ecc068e8c579b6ab96d1e3d0 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:41:28 +0200 Subject: [PATCH 170/182] Fix logging Specify the fully qualified name. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 9fbfc8eb84..9ec17c1abd 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -70,7 +70,7 @@ class ExtruderManager(QObject): if extruder_definition: extruder_definition = extruder_definition[0] else: - Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) + UM.Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) continue name = container_registry.uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. if not container_registry.findContainerStacks(id = name): #Doesn't exist yet. From 499a0557bd55492871a0160f7cd6f9b61fe1d0cb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:59:58 +0200 Subject: [PATCH 171/182] Fix checking if an extruder train already exists Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 9ec17c1abd..df31cbacdf 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -65,15 +65,12 @@ class ExtruderManager(QObject): return #Add the extruder trains that don't exist yet. - for position, extruder_definition_id in machine_definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): - extruder_definition = container_registry.findDefinitionContainers(machine = machine_definition.getId()) - if extruder_definition: - extruder_definition = extruder_definition[0] - else: - UM.Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) - continue - name = container_registry.uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. - if not container_registry.findContainerStacks(id = name): #Doesn'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. From d2405a24d26f0c23b1be3349438232142234e842 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 14:56:29 +0200 Subject: [PATCH 172/182] Perobject stacks are no longer saved CURA-1278 --- cura/SettingOverrideDecorator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 04e77b0d3f..10a14007f3 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -15,6 +15,7 @@ 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) From 5761307b336c5dcdea2c8d162a78d04f4ac39863 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 15:45:51 +0200 Subject: [PATCH 173/182] Updated deepcopy to correctly copy the instance container CURA-1636 --- cura/SettingOverrideDecorator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 10a14007f3..f9878e436c 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -29,10 +29,10 @@ class SettingOverrideDecorator(SceneNodeDecorator): def __deepcopy__(self, memo): ## Create a fresh decorator object deep_copy = SettingOverrideDecorator() - ## Copy the stack - deep_copy._stack = copy.deepcopy(self._stack, memo) - ## Ensure that the id is unique. - deep_copy._stack._id = id(deep_copy) + ## 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): From 9a14a3e8b755bb9f85015670d0fb85bf2c90f50f Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 15:46:37 +0200 Subject: [PATCH 174/182] Per object settings no longer watches "state" property CURA-1278 --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index c89485517e..9565b0e345 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -120,7 +120,7 @@ Item { containerStackId: UM.ActiveTool.properties.getValue("ContainerID") key: model.key - watchedProperties: [ "value", "enabled", "state", "validationState" ] + watchedProperties: [ "value", "enabled", "validationState" ] storeIndex: 0 } } From b2782ced0a088274b2f483cc7502fc53abc70ab2 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 15:56:59 +0200 Subject: [PATCH 175/182] Fix "renaming" profiles/machines to their current name without adding an increment CURA-1585 --- cura/MachineManagerModel.py | 66 ++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c764296a68..7d8403afdd 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -9,6 +9,7 @@ from UM.Logger import Logger import UM.Settings 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") @@ -109,7 +110,7 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._createUniqueName("machine", name, definition.getName()) + name = self._createUniqueName(containers[0], "machine", name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) new_global_stack.addMetaDataEntry("type", "machine") @@ -139,31 +140,42 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) - # Create a name that is not empty and unique - def _createUniqueName(self, object_type, 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{} container to create a unique name for + # \param container_type \type{string} Type of the container (machine, quality, ...) + # \param new_name \type{string} Name 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, object_type, 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 - if object_type == "machine": - while UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = unique_name, type = "machine") or \ - UM.Settings.ContainerRegistry.getInstance().findContainerStacks(name = unique_name, type = "machine"): - i += 1 - unique_name = "%s #%d" % (name, i) - else: - while UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = unique_name, type = object_type) or \ - UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = unique_name, type = object_type): - i += 1 - unique_name = "%s #%d" % (name, i) + unique_name = new_name + i = 1 + while self._containerWithIdOrNameExists(unique_name, object_type, container): + 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 + def _containerWithIdOrNameExists(self, id_or_name, container_type, exclude_container = None): + container_class = ContainerStack if container_type == "machine" else InstanceContainer + + containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = id_or_name, type = container_type) + if containers and containers[0] != exclude_container: + return True + containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = id_or_name, type = container_type) + if containers and containers[0] != exclude_container: + return True + + return False + ## Convenience function to check if a stack has errors. def _checkStackForErrors(self, stack): if stack is None: @@ -260,9 +272,9 @@ class MachineManagerModel(QObject): if not self._global_container_stack: return - name = self._createUniqueName("quality", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) - user_settings = self._global_container_stack.getTop() new_quality_container = InstanceContainer("") + name = self._createUniqueName(new_quality_container, "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()) @@ -290,7 +302,7 @@ class MachineManagerModel(QObject): 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_name = self._createUniqueName(containers[0], "quality", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) new_container = InstanceContainer("") @@ -310,7 +322,7 @@ class MachineManagerModel(QObject): def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: - new_name = self._createUniqueName("machine", new_name, catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName(containers[0], "quality", new_name, catalog.i18nc("@label", "Custom profile")) containers[0].setName(new_name) UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) @@ -413,7 +425,7 @@ class MachineManagerModel(QObject): def renameMachine(self, machine_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) if containers: - new_name = self._createUniqueName("machine", new_name, containers[0].getBottom().getName()) + new_name = self._createUniqueName(containers[0], "machine", new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) self.globalContainerChanged.emit() From 44d9fefd5d622bc5a3edaeb553173627fb9705f4 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Tue, 7 Jun 2016 16:11:44 +0200 Subject: [PATCH 176/182] Profile export from the Profiles window. Contributed to CURA-1667 Profile import/export --- resources/qml/Preferences/ProfilesPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 28248b23f4..ed9c20f65f 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -237,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 From cca432742b124f3103cad5fd8b52cf077a67050b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 17:01:08 +0200 Subject: [PATCH 177/182] Fix creating a name for a new MachineManagerModel CURA-1585 --- cura/MachineManagerModel.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 7d8403afdd..c0ac74abe4 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -110,9 +110,10 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._createUniqueName(containers[0], "machine", name, definition.getName()) - new_global_stack = UM.Settings.ContainerStack(name) + name = self._createUniqueName(new_global_stack, "machine", name, definition.getName()) + new_global_stack._id = name + new_global_stack.setName(name) new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) From e33eb52e936dab1cffa98e6568a41ca0dea3782a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 17:32:28 +0200 Subject: [PATCH 178/182] Hide Support Extruder in advanced mode when support is disabled CURA-1663 --- resources/definitions/fdmprinter.def.json | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ec27abd9f5..79bdf4399a 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2139,6 +2139,7 @@ "default_value": 0, "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", + "enabled": "support_enable", "global_only": "True", "children": { "support_infill_extruder_nr": From 4d0bb217af1d7f35c75576e44b1b4e0d61967fb9 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 18:13:19 +0200 Subject: [PATCH 179/182] Fix crash when enabling setting visibility for adhesion_extruder_nr or support_extruder_nr The fix is likely not what was intended by the author of the offending code (and does not seem to be functional), but at least it fixes the hard crash outlined in CURA-1666 --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index eb63bc4257..7e00611742 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -46,7 +46,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def _updateExtruders(self): self.clear() manager = cura.ExtruderManager.ExtruderManager.getInstance() - for index, extruder in enumerate(manager): + 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"), From 21b1891c0ee72afa44a6d606fe40ff5a11bc8776 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 18:55:27 +0200 Subject: [PATCH 180/182] Make unique name generation more robust and simpler CURA-1585 --- cura/MachineManagerModel.py | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c0ac74abe4..202ca3611c 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -106,14 +106,12 @@ 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._createUniqueName("machine", "", name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) - name = self._createUniqueName(new_global_stack, "machine", name, definition.getName()) - new_global_stack._id = name - new_global_stack.setName(name) new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) @@ -142,12 +140,12 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) ## Create a name that is not empty and unique - # \param container \type{} container to create a unique name for # \param container_type \type{string} Type of the container (machine, quality, ...) - # \param new_name \type{string} Name base name, which may not be unique + # \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, object_type, new_name, fallback_name): + 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: @@ -157,7 +155,8 @@ class MachineManagerModel(QObject): unique_name = new_name i = 1 - while self._containerWithIdOrNameExists(unique_name, object_type, container): + # 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) @@ -165,17 +164,13 @@ class MachineManagerModel(QObject): ## 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 - def _containerWithIdOrNameExists(self, id_or_name, container_type, exclude_container = None): + # \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 - containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = id_or_name, type = container_type) - if containers and containers[0] != exclude_container: - return True - containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = id_or_name, type = container_type) - if containers and containers[0] != exclude_container: - return True - - return False + 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): @@ -274,7 +269,7 @@ class MachineManagerModel(QObject): return new_quality_container = InstanceContainer("") - name = self._createUniqueName(new_quality_container, "quality", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) + name = self._createUniqueName("quality", "", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) user_settings = self._global_container_stack.getTop() ## Copy all values @@ -303,7 +298,7 @@ class MachineManagerModel(QObject): return containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) if containers: - new_name = self._createUniqueName(containers[0], "quality", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) new_container = InstanceContainer("") @@ -323,7 +318,7 @@ class MachineManagerModel(QObject): def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: - new_name = self._createUniqueName(containers[0], "quality", new_name, catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) containers[0].setName(new_name) UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) @@ -426,7 +421,7 @@ class MachineManagerModel(QObject): def renameMachine(self, machine_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) if containers: - new_name = self._createUniqueName(containers[0], "machine", 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() From f7480baca2c7f1648571fbf8bb9d1e9a892cddc1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 19:25:12 +0200 Subject: [PATCH 181/182] Fix selecting another quality when the currently active quality is removed CURA-1585 --- cura/MachineManagerModel.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 202ca3611c..5f3ca0b7af 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -335,11 +335,11 @@ class MachineManagerModel(QObject): UM.Settings.ContainerRegistry.getInstance().removeContainer(container_id) if activate_new_container: - old_container = self._global_container_stack.findInstanceContainers({"type": "quality"}) - containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = container_type) - if containers and old_container: - container_index = self._global_container_stack.getContainerIndex(old_container) - self._global_container_stack.replaceContainer(container_index, containers[0]) + 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() From b452af5dbf5997c92e47ea09a4366d7f876c538d Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 19:31:35 +0200 Subject: [PATCH 182/182] Update Profile dropdown when renaming a quality profile CURA-1585 --- cura/MachineManagerModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 5f3ca0b7af..02d8db8290 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -320,7 +320,7 @@ class MachineManagerModel(QObject): if containers: new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) containers[0].setName(new_name) - UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) + self.activeQualityChanged.emit() @pyqtSlot(str)