//Copyright (c) 2022 Ultimaker B.V. //Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.3 import QtQuick.Dialogs import UM 1.5 as UM import Cura 1.6 as Cura UM.ManagementPage { id: base Item { enabled: false; UM.I18nCatalog { id: catalog; name: "cura"} } property var extrudersModel: CuraApplication.getExtrudersModel() property var qualityManagementModel: CuraApplication.getQualityManagementModel() property bool hasCurrentItem: base.currentItem != null property var currentItem: objectList.currentIndex == -1 ? null : base.qualityManagementModel.getItem(objectList.currentIndex) property string currentItemName: hasCurrentItem ? base.currentItem.name : "" property string currentItemDisplayName: hasCurrentItem ? base.qualityManagementModel.getQualityItemDisplayName(base.currentItem) : "" property bool isCurrentItemActivated: { if (!base.currentItem) { return false; } if (base.currentItem.is_read_only) { return (base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName) && (base.currentItem.intent_category == Cura.MachineManager.activeIntentCategory); } else { return base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName; } } property bool canCreateProfile: Cura.MachineManager.hasUserSettings signal createProfile() // Click create profile from ... in Profile context menu property string newQualityNameToSelect: "" property bool toActivateNewQuality: false onCreateProfile: { createQualityDialog.object = Cura.ContainerManager.makeUniqueName(Cura.MachineManager.activeQualityOrQualityChangesName); createQualityDialog.open(); createQualityDialog.selectText(); } title: catalog.i18nc("@title:tab", "Profiles") detailsPlaneCaption: base.currentItemDisplayName scrollviewCaption: catalog.i18nc("@label", "Profiles compatible with active printer:") + "
" + Cura.MachineManager.activeMachine.name + "" hamburgerButtonVisible: hasCurrentItem onHamburgeButtonClicked: (hamburger_button) => { const hamburerButtonHeight = hamburger_button.height; menu.popup(hamburger_button, -menu.width + hamburger_button.width / 2, hamburger_button.height); // for some reason the height of the hamburger changes when opening the popup // reset height to initial heigt hamburger_button.height = hamburerButtonHeight; } isActiveModelFunction: function(model, id) { if (model.is_read_only) { return (model.name == Cura.MachineManager.activeQualityOrQualityChangesName) && (model.intent_category == Cura.MachineManager.activeIntentCategory); } else { return model.name == Cura.MachineManager.activeQualityOrQualityChangesName; } } sectionRole: "section_name" model: qualityManagementModel buttons: [ Cura.SecondaryButton { text: catalog.i18nc("@action:button", "Import") onClicked:importDialog.open() }, Cura.SecondaryButton { id: createMenuButton text: catalog.i18nc("@action:button", "Create new") enabled: !Cura.MachineManager.stacksHaveErrors visible: base.canCreateProfile tooltip: catalog.i18nc("@action:tooltip", "Create new profile from current settings/overrides") onClicked: { createQualityDialog.object = Cura.ContainerManager.makeUniqueName("") createQualityDialog.open() createQualityDialog.selectText() } } ] Column { id: detailsPanelHeaderColumn anchors { left: parent.left right: parent.right top: parent.top } spacing: UM.Theme.getSize("default_margin").height visible: base.currentItem != null UM.Label { anchors.left: parent.left anchors.right: parent.right text: catalog.i18nc("@action:label", "Some settings from current profile were overwritten.") visible: currentSettingsActions.visible } Flow { id: currentSettingsActions width: parent.width visible: base.hasCurrentItem && base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName && base.currentItem.intent_category == Cura.MachineManager.activeIntentCategory spacing: UM.Theme.getSize("default_margin").width Cura.SecondaryButton { text: catalog.i18nc("@action:button", "Update profile.") enabled: Cura.MachineManager.hasUserSettings && objectList.currentIndex && !objectList.currentIndex.is_read_only onClicked: Cura.ContainerManager.updateQualityChanges() tooltip: catalog.i18nc("@action:tooltip", "Update profile with current settings/overrides") } Cura.SecondaryButton { text: catalog.i18nc("@action:button", "Discard current changes") enabled: Cura.MachineManager.hasUserSettings onClicked: Cura.ContainerManager.clearUserContainers() } } UM.Label { id: defaultsMessage visible: false text: catalog.i18nc("@action:label", "This profile uses the defaults specified by the printer, so it has no settings/overrides in the list below.") width: parent.width } UM.Label { id: noCurrentSettingsMessage visible: base.isCurrentItemActivated && !Cura.MachineManager.hasUserSettings text: catalog.i18nc("@action:label", "Your current settings match the selected profile.") width: parent.width } UM.TabRow { id: profileExtruderTabs // One extra tab for the global settings. UM.TabRowButton { text: catalog.i18nc("@title:tab", "Global Settings") } Repeater { model: base.extrudersModel UM.TabRowButton { text: model.name } } } } Rectangle { color: UM.Theme.getColor("main_background") anchors { top: detailsPanelHeaderColumn.bottom topMargin: -UM.Theme.getSize("default_lining").width left: parent.left right: parent.right bottom: parent.bottom } border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("thick_lining") visible: base.hasCurrentItem } Cura.ProfileOverview { anchors { top: detailsPanelHeaderColumn.bottom margins: UM.Theme.getSize("default_margin").height left: parent.left right: parent.right bottom: parent.bottom } visible: detailsPanelHeaderColumn.visible qualityItem: base.currentItem extruderPosition: profileExtruderTabs.currentIndex - 1 } Item { id: content_item anchors.fill: parent // This connection makes sure that we will switch to the correct quality after the model gets updated Connections { target: base.qualityManagementModel function onItemsChanged() { var toSelectItemName = base.currentItem == null ? "" : base.currentItem.name; if (newQualityNameToSelect != "") { toSelectItemName = newQualityNameToSelect; } var newIdx = -1; // Default to nothing if nothing can be found if (toSelectItemName != "") { // Select the required quality name if given for (var idx = 0; idx < base.qualityManagementModel.count; ++idx) { var item = base.qualityManagementModel.getItem(idx); if (item && item.name == toSelectItemName) { // Switch to the newly created profile if needed newIdx = idx; if (base.toActivateNewQuality) { // Activate this custom quality if required if(item.quality_changes_group) { Cura.MachineManager.setQualityChangesGroup(item.quality_changes_group); } } break; } } } objectList.currentIndex = newIdx; // Reset states base.newQualityNameToSelect = ""; base.toActivateNewQuality = false; } } Cura.MessageDialog { id: messageDialog standardButtons: Dialog.Ok } // Dialog to request a name when creating a new profile Cura.RenameDialog { id: createQualityDialog title: catalog.i18nc("@title:window", "Create Profile") object: "" explanation: catalog.i18nc("@info", "Please provide a name for this profile.") onAccepted: { base.newQualityNameToSelect = newName; // We want to switch to the new profile once it's created base.toActivateNewQuality = true; base.qualityManagementModel.createQualityChanges(newName); } } Cura.Menu { id: menu Cura.MenuItem { text: catalog.i18nc("@action:button", "Activate") enabled: !isCurrentItemActivated && base.currentItem onTriggered: { if(base.currentItem.is_read_only) { Cura.IntentManager.selectIntent(base.currentItem.intent_category, base.currentItem.quality_type) } else { Cura.MachineManager.setQualityChangesGroup(base.currentItem.quality_changes_group) } } } Cura.MenuItem { text: catalog.i18nc("@action:button", "Duplicate") enabled: base.hasCurrentItem onTriggered: { forceActiveFocus() duplicateQualityDialog.open() } } Cura.MenuItem { text: catalog.i18nc("@action:button", "Remove") enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated onTriggered: { forceActiveFocus() confirmRemoveQualityDialog.open() } } Cura.MenuItem { text: catalog.i18nc("@action:button", "Rename") enabled: base.hasCurrentItem && !base.currentItem.is_read_only onTriggered: { renameQualityDialog.object = base.currentItem.name renameQualityDialog.open() renameQualityDialog.selectText() } } Cura.MenuItem { text: catalog.i18nc("@action:button", "Export") enabled: base.hasCurrentItem && !base.currentItem.is_read_only onTriggered: exportDialog.open() } } // Dialog for exporting a quality profile FileDialog { id: exportDialog title: catalog.i18nc("@title:window", "Export Profile") fileMode: FileDialog.SaveFile nameFilters: base.qualityManagementModel.getFileNameFilters("profile_writer") currentFolder: CuraApplication.getDefaultPath("dialog_profile_path") onAccepted: { // If nameFilters contains only 1 item, the index of selectedNameFilter will always be -1 // This fetches the nameFilter at index selectedNameFilter.index if it is positive const nameFilterString = selectedNameFilter.index >= 0 ? nameFilters[selectedNameFilter.index] : nameFilters[0]; var result = Cura.ContainerManager.exportQualityChangesGroup(base.currentItem.quality_changes_group, selectedFile, nameFilterString); if (result && result.status == "error") { messageDialog.title = catalog.i18nc("@title:window", "Export Profile") messageDialog.text = result.message; messageDialog.open(); } // else pop-up Message thing from python code CuraApplication.setDefaultPath("dialog_profile_path", currentFolder); } } // Dialog to request a name when duplicating a new profile Cura.RenameDialog { id: duplicateQualityDialog title: catalog.i18nc("@title:window", "Duplicate Profile") object: "" onAccepted: base.qualityManagementModel.duplicateQualityChanges(newName, base.currentItem) } // Confirmation dialog for removing a profile Cura.MessageDialog { id: confirmRemoveQualityDialog title: catalog.i18nc("@title:window", "Confirm Remove") text: catalog.i18nc("@label (%1 is object name)", "Are you sure you wish to remove %1? This cannot be undone!").arg(base.currentItemName) standardButtons: Dialog.Yes | Dialog.No modal: true onAccepted: { base.qualityManagementModel.removeQualityChangesGroup(base.currentItem.quality_changes_group); // reset current item to the first if available qualityListView.currentIndex = -1; // Reset selection. } } // Dialog to rename a quality profile Cura.RenameDialog { id: renameQualityDialog title: catalog.i18nc("@title:window", "Rename Profile") object: "" onAccepted: { var actualNewName = base.qualityManagementModel.renameQualityChangesGroup(base.currentItem.quality_changes_group, newName); base.newQualityNameToSelect = actualNewName; // Select the new name after the model gets updated } } // Dialog for importing a quality profile FileDialog { id: importDialog title: catalog.i18nc("@title:window", "Import Profile") fileMode: FileDialog.OpenFile nameFilters: base.qualityManagementModel.getFileNameFilters("profile_reader") currentFolder: CuraApplication.getDefaultPath("dialog_profile_path") onAccepted: { var result = Cura.ContainerManager.importProfile(selectedFile); messageDialog.title = catalog.i18nc("@title:window", "Import Profile") messageDialog.text = result.message; messageDialog.open(); CuraApplication.setDefaultPath("dialog_profile_path", folder); } } } }