// Copyright (c) 2018 Ultimaker B.V. // Uranium is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import QtQuick.Dialogs 1.2 import UM 1.2 as UM import Cura 1.0 as Cura Item { id: base property QtObject qualityManager: CuraApplication.getQualityManager() property var resetEnabled: false // Keep PreferencesDialog happy property var extrudersModel: CuraApplication.getExtrudersModel() UM.I18nCatalog { id: catalog; name: "cura"; } Cura.QualityManagementModel { id: qualitiesModel } Label { id: titleLabel anchors { top: parent.top left: parent.left right: parent.right margins: 5 * screenScaleFactor } font.pointSize: 18 text: catalog.i18nc("@title:tab", "Profiles") } property var hasCurrentItem: base.currentItem != null property var currentItem: { var current_index = qualityListView.currentIndex; return (current_index == -1) ? null : qualitiesModel.getItem(current_index); } property var currentItemName: hasCurrentItem ? base.currentItem.name : "" property var isCurrentItemActivated: { if (!base.currentItem) { return false; } return base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName; } property var canCreateProfile: { return isCurrentItemActivated && Cura.MachineManager.hasUserSettings; } Row // Button Row { id: buttonRow anchors { left: parent.left right: parent.right top: titleLabel.bottom } height: childrenRect.height // Activate button Button { text: catalog.i18nc("@action:button", "Activate") iconName: "list-activate" enabled: !isCurrentItemActivated onClicked: { if (base.currentItem.is_read_only) { Cura.MachineManager.setQualityGroup(base.currentItem.quality_group); } else { Cura.MachineManager.setQualityChangesGroup(base.currentItem.quality_changes_group); } } } // Create button Button { text: catalog.i18nc("@label", "Create") iconName: "list-add" enabled: base.canCreateProfile && !Cura.MachineManager.stacksHaveErrors visible: base.canCreateProfile onClicked: { createQualityDialog.object = Cura.ContainerManager.makeUniqueName(base.currentItem.name); createQualityDialog.open(); createQualityDialog.selectText(); } } // Duplicate button Button { text: catalog.i18nc("@label", "Duplicate") iconName: "list-add" enabled: !base.canCreateProfile visible: !base.canCreateProfile onClicked: { duplicateQualityDialog.object = Cura.ContainerManager.makeUniqueName(base.currentItem.name); duplicateQualityDialog.open(); duplicateQualityDialog.selectText(); } } // Remove button Button { text: catalog.i18nc("@action:button", "Remove") iconName: "list-remove" enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated onClicked: { forceActiveFocus(); confirmRemoveQualityDialog.open(); } } // Rename button Button { text: catalog.i18nc("@action:button", "Rename") iconName: "edit-rename" enabled: base.hasCurrentItem && !base.currentItem.is_read_only onClicked: { renameQualityDialog.object = base.currentItem.name; renameQualityDialog.open(); renameQualityDialog.selectText(); } } // Import button Button { text: catalog.i18nc("@action:button", "Import") iconName: "document-import" onClicked: { importDialog.open(); } } // Export button Button { text: catalog.i18nc("@action:button", "Export") iconName: "document-export" enabled: base.hasCurrentItem && !base.currentItem.is_read_only onClicked: { exportDialog.open(); } } } // Click create profile from ... in Profile context menu signal createProfile() onCreateProfile: { createQualityDialog.object = Cura.ContainerManager.makeUniqueName(Cura.MachineManager.activeQualityOrQualityChangesName); createQualityDialog.open(); createQualityDialog.selectText(); } // Dialog to request a name when creating a new profile UM.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.qualityManager.createQualityChanges(newName); } } property string newQualityNameToSelect: "" property bool toActivateNewQuality: false // This connection makes sure that we will switch to the correct quality after the model gets updated Connections { target: qualitiesModel 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 < qualitiesModel.count; ++idx) { var item = qualitiesModel.getItem(idx); if (item.name == toSelectItemName) { // Switch to the newly created profile if needed newIdx = idx; if (base.toActivateNewQuality) { // Activate this custom quality if required Cura.MachineManager.setQualityChangesGroup(item.quality_changes_group); } break; } } } qualityListView.currentIndex = newIdx; // Reset states base.newQualityNameToSelect = ""; base.toActivateNewQuality = false; } } // Dialog to request a name when duplicating a new profile UM.RenameDialog { id: duplicateQualityDialog title: catalog.i18nc("@title:window", "Duplicate Profile") object: "" onAccepted: { base.qualityManager.duplicateQualityChanges(newName, base.currentItem); } } // Confirmation dialog for removing a profile MessageDialog { id: confirmRemoveQualityDialog icon: StandardIcon.Question; 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: StandardButton.Yes | StandardButton.No modality: Qt.ApplicationModal onYes: { base.qualityManager.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 UM.RenameDialog { id: renameQualityDialog title: catalog.i18nc("@title:window", "Rename Profile") object: "" onAccepted: { var actualNewName = base.qualityManager.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") selectExisting: true nameFilters: qualitiesModel.getFileNameFilters("profile_reader") folder: CuraApplication.getDefaultPath("dialog_profile_path") onAccepted: { var result = Cura.ContainerManager.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(); CuraApplication.setDefaultPath("dialog_profile_path", folder); } } // Dialog for exporting a quality profile FileDialog { id: exportDialog title: catalog.i18nc("@title:window", "Export Profile") selectExisting: false nameFilters: qualitiesModel.getFileNameFilters("profile_writer") folder: CuraApplication.getDefaultPath("dialog_profile_path") onAccepted: { var result = Cura.ContainerManager.exportQualityChangesGroup(base.currentItem.quality_changes_group, 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 CuraApplication.setDefaultPath("dialog_profile_path", folder); } } Item { id: contentsItem anchors { top: titleLabel.bottom left: parent.left right: parent.right bottom: parent.bottom margins: 5 * screenScaleFactor bottomMargin: 0 } clip: true } Item { anchors { top: buttonRow.bottom topMargin: UM.Theme.getSize("default_margin").height left: parent.left right: parent.right bottom: parent.bottom } SystemPalette { id: palette } Label { id: captionLabel anchors { top: parent.top left: parent.left } visible: text != "" text: catalog.i18nc("@label %1 is printer name", "Printer: %1").arg(Cura.MachineManager.activeMachineName) width: profileScrollView.width elide: Text.ElideRight } ScrollView { id: profileScrollView anchors { top: captionLabel.visible ? captionLabel.bottom : parent.top topMargin: captionLabel.visible ? UM.Theme.getSize("default_margin").height : 0 bottom: parent.bottom left: parent.left } Rectangle { parent: viewport anchors.fill: parent color: palette.light } width: true ? (parent.width * 0.4) | 0 : parent.width frameVisible: true clip: true ListView { id: qualityListView model: qualitiesModel Component.onCompleted: { var selectedItemName = Cura.MachineManager.activeQualityOrQualityChangesName; // Select the required quality name if given for (var idx = 0; idx < qualitiesModel.count; idx++) { var item = qualitiesModel.getItem(idx); if (item.name == selectedItemName) { currentIndex = idx; break; } } } section.property: "is_read_only" section.delegate: Rectangle { height: childrenRect.height Label { anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_lining").width text: section == "true" ? catalog.i18nc("@label", "Default profiles") : catalog.i18nc("@label", "Custom profiles") font.bold: true } } delegate: Rectangle { width: profileScrollView.width height: childrenRect.height property bool isCurrentItem: ListView.isCurrentItem color: isCurrentItem ? palette.highlight : (model.index % 2) ? palette.base : palette.alternateBase Label { anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.right: parent.right width: Math.floor((parent.width * 0.8)) text: model.name elide: Text.ElideRight font.italic: model.name == Cura.MachineManager.activeQualityOrQualityChangesName color: parent.isCurrentItem ? palette.highlightedText : palette.text } MouseArea { anchors.fill: parent onClicked: { parent.ListView.view.currentIndex = model.index; } } } } } // details panel on the right Item { id: detailsPanel anchors { left: profileScrollView.right leftMargin: UM.Theme.getSize("default_margin").width top: parent.top bottom: parent.bottom right: parent.right } Item { anchors.fill: parent visible: base.currentItem != null Item // Profile title Label { id: profileName width: parent.width height: childrenRect.height Label { text: base.currentItemName font: UM.Theme.getFont("large_bold") } } Flow { id: currentSettingsActions visible: base.hasCurrentItem && base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName anchors.left: parent.left anchors.right: parent.right anchors.top: profileName.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height Button { text: catalog.i18nc("@action:button", "Update profile with current settings/overrides") enabled: Cura.MachineManager.hasUserSettings && !base.currentItem.is_read_only onClicked: Cura.ContainerManager.updateQualityChanges() } Button { text: catalog.i18nc("@action:button", "Discard current changes"); enabled: Cura.MachineManager.hasUserSettings onClicked: Cura.ContainerManager.clearUserContainers(); } } Column { id: profileNotices anchors.top: currentSettingsActions.visible ? currentSettingsActions.bottom : currentSettingsActions.anchors.top anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.left: parent.left anchors.right: parent.right spacing: UM.Theme.getSize("default_margin").height 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.") wrapMode: Text.WordWrap width: parent.width } Label { id: noCurrentSettingsMessage visible: base.isCurrentItemActivated && !Cura.MachineManager.hasUserSettings text: catalog.i18nc("@action:label", "Your current settings match the selected profile.") wrapMode: Text.WordWrap width: parent.width } } TabView { anchors.left: parent.left anchors.top: profileNotices.visible ? profileNotices.bottom : profileNotices.anchors.top anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.right: parent.right anchors.bottom: parent.bottom currentIndex: 0 ProfileTab { title: catalog.i18nc("@title:tab", "Global Settings") qualityItem: base.currentItem } Repeater { model: base.extrudersModel ProfileTab { title: model.name extruderPosition: model.index qualityItem: base.currentItem } } } } } } }