diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index bfe342d1e4..dc3d777c2f 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -193,7 +193,17 @@ class CuraApplication(QtApplication): ## Cura has multiple locations where instance containers need to be saved, so we need to handle this differently. def _onExit(self): for instance in ContainerRegistry.getInstance().findInstanceContainers(): - data = instance.serialize() + if not instance.isDirty(): + continue + + try: + data = instance.serialize() + except NotImplementedError: + continue + except Exception: + Logger.logException("e", "An exception occurred when serializing container %s", instance.getId()) + continue + file_name = urllib.parse.quote_plus(instance.getId()) + ".inst.cfg" instance_type = instance.getMetaDataEntry("type") path = None @@ -211,7 +221,17 @@ class CuraApplication(QtApplication): f.write(data) for stack in ContainerRegistry.getInstance().findContainerStacks(): - data = stack.serialize() + if not stack.isDirty(): + continue + + try: + data = stack.serialize() + except NotImplementedError: + continue + except Exception: + Logger.logException("e", "An exception occurred when serializing container %s", instance.getId()) + 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: diff --git a/plugins/LayerView/__init__.py b/plugins/LayerView/__init__.py index 3d43532126..67750fb562 100644 --- a/plugins/LayerView/__init__.py +++ b/plugins/LayerView/__init__.py @@ -14,7 +14,7 @@ def getMetaData(): "author": "Ultimaker", "version": "1.0", "description": catalog.i18nc("@info:whatsthis", "Provides the Layer view."), - "api": 2 + "api": 3 }, "view": { "name": catalog.i18nc("@item:inlistbox", "Layers"), diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index b03c5ed06a..733def1b81 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -549,9 +549,11 @@ UM.MainWindow //: View preferences page title insertPage(1, catalog.i18nc("@title:tab","View"), Qt.resolvedUrl("ViewPage.qml")); - insertPage(2, catalog.i18nc("@title:tab", "Printers"), Qt.resolvedUrl("MachinesPage.qml")); + insertPage(3, catalog.i18nc("@title:tab", "Printers"), Qt.resolvedUrl("MachinesPage.qml")); - insertPage(3, catalog.i18nc("@title:tab", "Materials"), Qt.resolvedUrl("Preferences/MaterialsPage.qml")) + insertPage(4, catalog.i18nc("@title:tab", "Materials"), Qt.resolvedUrl("Preferences/MaterialsPage.qml")); + + insertPage(5, catalog.i18nc("@title:tab", "Profiles"), Qt.resolvedUrl("Preferences/ProfilesPage.qml")); //Force refresh setPage(0); diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml new file mode 100644 index 0000000000..6e5d39cb49 --- /dev/null +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -0,0 +1,222 @@ +// 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.Dialogs 1.2 + +import UM 1.2 as UM + +UM.ManagementPage +{ + id: base; + + title: catalog.i18nc("@title:tab", "Profiles"); + addText: catalog.i18nc("@label", "Duplicate") + + model: UM.InstanceContainersModel { filter: { "type": "quality" } } + + onAddObject: { + var selectedProfile; + if (objectList.currentIndex == 0) { + // Current settings + selectedProfile = UM.MachineManager.createProfile(); + } else { + selectedProfile = UM.MachineManager.duplicateProfile(currentItem.name); + } + base.selectProfile(selectedProfile); + + renameDialog.removeWhenRejected = true; + renameDialog.open(); + renameDialog.selectText(); + } + onRemoveObject: confirmDialog.open(); + onRenameObject: { renameDialog.removeWhenRejected = false; renameDialog.open(); renameDialog.selectText(); } + + addEnabled: currentItem != null; + removeEnabled: currentItem != null ? !currentItem.readOnly : false; + renameEnabled: currentItem != null ? !currentItem.readOnly : false; + + scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(UM.MachineManager.activeMachineInstance) + + signal selectProfile(string name) + onSelectProfile: { + objectList.currentIndex = objectList.model.find("name", name); + } + + Item { + visible: base.currentItem != null + anchors.fill: parent + + Label { + id: profileName + text: base.currentItem ? base.currentItem.name : "" + font: UM.Theme.getFont("large") + width: parent.width + elide: Text.ElideRight + } + + ScrollView { + anchors.left: parent.left + anchors.top: 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 || base.currentItem.active + Button + { + text: { + var profileName = UM.MachineManager.activeProfile; + profileName = (profileName.length > 20) ? profileName.substring(0, 20) + '...' : profileName; + return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName)); + } + enabled: UM.ActiveProfile.hasCustomisedValues && !UM.ActiveProfile.readOnly + onClicked: UM.ActiveProfile.updateProfile() + } + + Button + { + text: catalog.i18nc("@action:button", "Discard changes"); + enabled: UM.ActiveProfile.hasCustomisedValues + onClicked: UM.ActiveProfile.discardChanges() + } + } + + Grid + { + id: containerGrid + columns: 2 + spacing: UM.Theme.getSize("default_margin").width + + Label { + text: base.currentItem == null ? "" : + base.currentItem.id == -1 ? catalog.i18nc("@label", "Based on") : catalog.i18nc("@label", "Profile type") + } + Label { + text: base.currentItem == null ? "" : + base.currentItem.id == -1 ? UM.MachineManager.activeProfile : + base.currentItem.readOnly ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") + } + + Column { + Repeater { + model: base.currentItem ? base.currentItem.settings : null + Label { + text: modelData.name.toString(); + elide: Text.ElideMiddle; + } + } + } + Column { + Repeater { + model: base.currentItem ? base.currentItem.settings : null + Label { text: modelData.value.toString(); } + } + } + } + } + } + } + + buttons: Row { + + Button + { + text: catalog.i18nc("@action:button", "Import"); + iconName: "document-import"; + onClicked: importDialog.open(); + } + + Button + { + text: catalog.i18nc("@action:button", "Export"); + iconName: "document-export"; + onClicked: exportDialog.open(); + } + } + + Item + { + UM.I18nCatalog { id: catalog; name: "uranium"; } + + UM.ConfirmRemoveDialog + { + id: confirmDialog; + object: base.currentItem != null ? base.currentItem.name : ""; + onYes: base.model.removeProfile(base.currentItem.name); + } + UM.RenameDialog + { + id: renameDialog; + object: base.currentItem != null ? base.currentItem.name : ""; + property bool removeWhenRejected: false; + onAccepted: base.model.renameProfile(base.currentItem.name, newName.trim()); + onRejected: { + if(removeWhenRejected) { + base.model.removeProfile(base.currentItem.name) + } + } + } + MessageDialog + { + id: messageDialog + title: catalog.i18nc("@window:title", "Import Profile"); + standardButtons: StandardButton.Ok + modality: Qt.ApplicationModal + } + + FileDialog + { + id: importDialog; + title: catalog.i18nc("@title:window", "Import Profile"); + selectExisting: true; + nameFilters: base.model.getFileNameFiltersRead() + folder: base.model.getDefaultPath() + onAccepted: + { + var result = base.model.importProfile(fileUrl) + messageDialog.text = result.message + if(result.status == "ok") + { + messageDialog.icon = StandardIcon.Information + } + else if(result.status == "duplicate") + { + messageDialog.icon = StandardIcon.Warning + } + else + { + messageDialog.icon = StandardIcon.Critical + } + messageDialog.open() + } + } + + FileDialog + { + id: exportDialog; + title: catalog.i18nc("@title:window", "Export Profile"); + selectExisting: false; + nameFilters: base.model.getFileNameFiltersWrite() + folder: base.model.getDefaultPath() + onAccepted: + { + var result = base.model.exportProfile(base.currentItem.id, base.currentItem.name, fileUrl, selectedNameFilter) + if(result && result.status == "error") + { + messageDialog.icon = StandardIcon.Critical + messageDialog.text = result.message + messageDialog.open() + } + // else pop-up Message thing from python code + } + } + } +} diff --git a/resources/variants/ultimaker2_extended_plus_0.25.cfg b/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg similarity index 84% rename from resources/variants/ultimaker2_extended_plus_0.25.cfg rename to resources/variants/ultimaker2_extended_plus_0.25.inst.cfg index 2bc14d7588..0c0154c03b 100644 --- a/resources/variants/ultimaker2_extended_plus_0.25.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg @@ -5,6 +5,7 @@ definition = ultimaker2_extended_plus [metadata] author = Ultimaker +type = variant [values] machine_nozzle_size = 0.25 @@ -13,4 +14,4 @@ coasting_volume = 0.1 coasting_min_volume = 0.17 speed_wall = round(speed_print / 1.2, 1) speed_wall_0 = 1 if speed_wall < 5 else (speed_wall - 5) -speed_topbottom = round(speed_print / 1.5, 1) \ No newline at end of file +speed_topbottom = round(speed_print / 1.5, 1) diff --git a/resources/variants/ultimaker2_extended_plus_0.4.cfg b/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg similarity index 82% rename from resources/variants/ultimaker2_extended_plus_0.4.cfg rename to resources/variants/ultimaker2_extended_plus_0.4.inst.cfg index a0de0ad2d7..87b74b2572 100644 --- a/resources/variants/ultimaker2_extended_plus_0.4.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg @@ -5,10 +5,11 @@ definition = ultimaker2_extended_plus [metadata] author = Ultimaker +type = variant [values] machine_nozzle_size = 0.4 machine_nozzle_tip_outer_diameter = 1.05 speed_wall = round(speed_print / 1.25, 1) speed_wall_0 = 1 if speed_wall < 10 else (speed_wall - 10) -speed_topbottom = round(speed_print / 2.25, 1) \ No newline at end of file +speed_topbottom = round(speed_print / 2.25, 1) diff --git a/resources/variants/ultimaker2_extended_plus_0.6.cfg b/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg similarity index 83% rename from resources/variants/ultimaker2_extended_plus_0.6.cfg rename to resources/variants/ultimaker2_extended_plus_0.6.inst.cfg index 10fa9dd4de..343b2d85e5 100644 --- a/resources/variants/ultimaker2_extended_plus_0.6.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg @@ -5,6 +5,7 @@ definition = ultimaker2_extended_plus [metadata] author = Ultimaker +type = variant [values] machine_nozzle_size = 0.6 @@ -12,4 +13,4 @@ machine_nozzle_tip_outer_diameter = 1.25 coasting_volume = 1.36 speed_wall = round(speed_print * 4 / 3, 1) speed_wall_0 = 1 if speed_wall < 10 else (speed_wall - 10) -speed_topbottom = round(speed_print / 2, 1) \ No newline at end of file +speed_topbottom = round(speed_print / 2, 1) diff --git a/resources/variants/ultimaker2_extended_plus_0.8.cfg b/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg similarity index 83% rename from resources/variants/ultimaker2_extended_plus_0.8.cfg rename to resources/variants/ultimaker2_extended_plus_0.8.inst.cfg index 2980215ebd..c1bb4555c1 100644 --- a/resources/variants/ultimaker2_extended_plus_0.8.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg @@ -5,6 +5,7 @@ definition = ultimaker2_extended_plus [metadata] author = Ultimaker +type = variant [values] machine_nozzle_size = 0.8 @@ -12,4 +13,4 @@ machine_nozzle_tip_outer_diameter = 1.35 coasting_volume = 3.22 speed_wall = round(speed_print * 4 / 3, 1) speed_wall_0 = 1 if speed_wall < 10 else (speed_wall - 10) -speed_topbottom = round(speed_print / 2, 1) \ No newline at end of file +speed_topbottom = round(speed_print / 2, 1) diff --git a/resources/variants/ultimaker2_plus_0.25.cfg b/resources/variants/ultimaker2_plus_0.25.inst.cfg similarity index 84% rename from resources/variants/ultimaker2_plus_0.25.cfg rename to resources/variants/ultimaker2_plus_0.25.inst.cfg index 18839a8871..51a4b44a4a 100644 --- a/resources/variants/ultimaker2_plus_0.25.cfg +++ b/resources/variants/ultimaker2_plus_0.25.inst.cfg @@ -5,6 +5,7 @@ definition = ultimaker2_plus [metadata] author = Ultimaker +type = variant [values] machine_nozzle_size = 0.25 @@ -13,4 +14,4 @@ coasting_volume = 0.1 coasting_min_volume = 0.17 speed_wall = round(speed_print / 1.2, 1) speed_wall_0 = 1 if speed_wall < 5 else (speed_wall - 5) -speed_topbottom = round(speed_print / 1.5, 1) \ No newline at end of file +speed_topbottom = round(speed_print / 1.5, 1) diff --git a/resources/variants/ultimaker2_plus_0.4.cfg b/resources/variants/ultimaker2_plus_0.4.inst.cfg similarity index 81% rename from resources/variants/ultimaker2_plus_0.4.cfg rename to resources/variants/ultimaker2_plus_0.4.inst.cfg index b7dc47ea6e..aaea23a8df 100644 --- a/resources/variants/ultimaker2_plus_0.4.cfg +++ b/resources/variants/ultimaker2_plus_0.4.inst.cfg @@ -5,10 +5,11 @@ definition = ultimaker2_plus [metadata] author = Ultimaker +type = variant [values] machine_nozzle_size = 0.4 machine_nozzle_tip_outer_diameter = 1.05 speed_wall = round(speed_print / 1.25, 1) speed_wall_0 = 1 if speed_wall < 10 else (speed_wall - 10) -speed_topbottom = round(speed_print / 2.25, 1) \ No newline at end of file +speed_topbottom = round(speed_print / 2.25, 1) diff --git a/resources/variants/ultimaker2_plus_0.6.cfg b/resources/variants/ultimaker2_plus_0.6.inst.cfg similarity index 83% rename from resources/variants/ultimaker2_plus_0.6.cfg rename to resources/variants/ultimaker2_plus_0.6.inst.cfg index d6a7da7437..c416b2ec3c 100644 --- a/resources/variants/ultimaker2_plus_0.6.cfg +++ b/resources/variants/ultimaker2_plus_0.6.inst.cfg @@ -5,6 +5,7 @@ definition = ultimaker2_plus [metadata] author = Ultimaker +type = variant [values] machine_nozzle_size = 0.6 @@ -12,4 +13,4 @@ machine_nozzle_tip_outer_diameter = 1.25 coasting_volume = 1.36 speed_wall = round(speed_print * 4 / 3, 1) speed_wall_0 = 1 if speed_wall < 10 else (speed_wall - 10) -speed_topbottom = round(speed_print / 2, 1) \ No newline at end of file +speed_topbottom = round(speed_print / 2, 1) diff --git a/resources/variants/ultimaker2_plus_0.8.cfg b/resources/variants/ultimaker2_plus_0.8.inst.cfg similarity index 83% rename from resources/variants/ultimaker2_plus_0.8.cfg rename to resources/variants/ultimaker2_plus_0.8.inst.cfg index cb97151642..3b577384ec 100644 --- a/resources/variants/ultimaker2_plus_0.8.cfg +++ b/resources/variants/ultimaker2_plus_0.8.inst.cfg @@ -5,6 +5,7 @@ definition = ultimaker2_plus [metadata] author = Ultimaker +type = variant [values] machine_nozzle_size = 0.8 @@ -12,4 +13,4 @@ machine_nozzle_tip_outer_diameter = 1.35 coasting_volume = 3.22 speed_wall = round(speed_print * 4 / 3, 1) speed_wall_0 = 1 if speed_wall < 10 else (speed_wall - 10) -speed_topbottom = round(speed_print / 2, 1) \ No newline at end of file +speed_topbottom = round(speed_print / 2, 1)