ProfilesPage.qml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. //Copyright (c) 2022 Ultimaker B.V.
  2. //Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.7
  4. import QtQuick.Controls 2.15
  5. import QtQuick.Layouts 1.3
  6. import QtQuick.Dialogs 1.2
  7. import UM 1.5 as UM
  8. import Cura 1.6 as Cura
  9. UM.ManagementPage
  10. {
  11. id: base
  12. title: catalog.i18nc("@title:tab", "Profiles")
  13. property var extrudersModel: CuraApplication.getExtrudersModel()
  14. property var qualityManagementModel: CuraApplication.getQualityManagementModel()
  15. scrollviewCaption: catalog.i18nc("@label", "Profiles compatible with active printer:") + "<b>" + Cura.MachineManager.activeMachine.name + "</b>"
  16. onHamburgeButtonClicked: menu.popup(content_item, content_item.width - menu.width, hamburger_button.height)
  17. property var hasCurrentItem: base.currentItem != null
  18. sectionRole: "section_name"
  19. property var currentItem:
  20. {
  21. var current_index = objectList.currentIndex;
  22. return (current_index == -1) ? null : base.qualityManagementModel.getItem(current_index);
  23. }
  24. property var currentItemName: hasCurrentItem ? base.currentItem.name : ""
  25. property var currentItemDisplayName: hasCurrentItem ? base.qualityManagementModel.getQualityItemDisplayName(base.currentItem) : ""
  26. property var isCurrentItemActivated:
  27. {
  28. if (!base.currentItem)
  29. {
  30. return false;
  31. }
  32. if (base.currentItem.is_read_only)
  33. {
  34. return (base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName) && (base.currentItem.intent_category == Cura.MachineManager.activeIntentCategory);
  35. }
  36. else
  37. {
  38. return base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName;
  39. }
  40. }
  41. property var canCreateProfile:
  42. {
  43. return isCurrentItemActivated && Cura.MachineManager.hasUserSettings;
  44. }
  45. model: qualityManagementModel
  46. buttons: [
  47. Cura.SecondaryButton
  48. {
  49. text: catalog.i18nc("@action:button", "Import")
  50. onClicked:importDialog.open()
  51. },
  52. Cura.SecondaryButton
  53. {
  54. id: createMenuButton
  55. text: catalog.i18nc("@action:button", "Create new")
  56. enabled: !Cura.MachineManager.stacksHaveErrors
  57. visible: base.canCreateProfile
  58. onClicked:
  59. {
  60. createQualityDialog.object = Cura.ContainerManager.makeUniqueName(base.currentItem.name)
  61. createQualityDialog.open()
  62. createQualityDialog.selectText()
  63. }
  64. }
  65. ]
  66. // Click create profile from ... in Profile context menu
  67. signal createProfile()
  68. onCreateProfile:
  69. {
  70. createQualityDialog.object = Cura.ContainerManager.makeUniqueName(Cura.MachineManager.activeQualityOrQualityChangesName);
  71. createQualityDialog.open();
  72. createQualityDialog.selectText();
  73. }
  74. property string newQualityNameToSelect: ""
  75. property bool toActivateNewQuality: false
  76. Item
  77. {
  78. id: content_item
  79. anchors.fill: parent
  80. // This connection makes sure that we will switch to the correct quality after the model gets updated
  81. Connections
  82. {
  83. target: base.qualityManagementModel
  84. function onItemsChanged()
  85. {
  86. var toSelectItemName = base.currentItem == null ? "" : base.currentItem.name;
  87. if (newQualityNameToSelect != "")
  88. {
  89. toSelectItemName = newQualityNameToSelect;
  90. }
  91. var newIdx = -1; // Default to nothing if nothing can be found
  92. if (toSelectItemName != "")
  93. {
  94. // Select the required quality name if given
  95. for (var idx = 0; idx < base.qualityManagementModel.count; ++idx)
  96. {
  97. var item = base.qualityManagementModel.getItem(idx);
  98. if (item && item.name == toSelectItemName)
  99. {
  100. // Switch to the newly created profile if needed
  101. newIdx = idx;
  102. if (base.toActivateNewQuality)
  103. {
  104. // Activate this custom quality if required
  105. if(item.quality_changes_group)
  106. {
  107. Cura.MachineManager.setQualityChangesGroup(item.quality_changes_group);
  108. }
  109. }
  110. break;
  111. }
  112. }
  113. }
  114. objectList.currentIndex = newIdx;
  115. // Reset states
  116. base.newQualityNameToSelect = "";
  117. base.toActivateNewQuality = false;
  118. }
  119. }
  120. Cura.MessageDialog
  121. {
  122. id: messageDialog
  123. standardButtons: Dialog.Ok
  124. }
  125. // Dialog to request a name when creating a new profile
  126. Cura.RenameDialog
  127. {
  128. id: createQualityDialog
  129. title: catalog.i18nc("@title:window", "Create Profile")
  130. object: "<new name>"
  131. explanation: catalog.i18nc("@info", "Please provide a name for this profile.")
  132. onAccepted:
  133. {
  134. base.newQualityNameToSelect = newName; // We want to switch to the new profile once it's created
  135. base.toActivateNewQuality = true;
  136. base.qualityManagementModel.createQualityChanges(newName);
  137. }
  138. }
  139. Cura.Menu
  140. {
  141. id: menu
  142. Cura.MenuItem
  143. {
  144. text: catalog.i18nc("@action:button", "Activate")
  145. enabled: !isCurrentItemActivated && base.currentItem
  146. onTriggered:
  147. {
  148. if(base.currentItem.is_read_only)
  149. {
  150. Cura.IntentManager.selectIntent(base.currentItem.intent_category, base.currentItem.quality_type)
  151. }
  152. else
  153. {
  154. Cura.MachineManager.setQualityChangesGroup(base.currentItem.quality_changes_group)
  155. }
  156. }
  157. }
  158. Cura.MenuItem
  159. {
  160. text: catalog.i18nc("@action:button", "Remove")
  161. enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated
  162. onTriggered:
  163. {
  164. forceActiveFocus()
  165. confirmRemoveQualityDialog.open()
  166. }
  167. }
  168. Cura.MenuItem
  169. {
  170. text: catalog.i18nc("@action:button", "Rename")
  171. enabled: base.hasCurrentItem && !base.currentItem.is_read_only
  172. onTriggered:
  173. {
  174. renameQualityDialog.object = base.currentItem.name
  175. renameQualityDialog.open()
  176. renameQualityDialog.selectText()
  177. }
  178. }
  179. Cura.MenuItem
  180. {
  181. text: catalog.i18nc("@action:button", "Export")
  182. enabled: base.hasCurrentItem && !base.currentItem.is_read_only
  183. onTriggered: exportDialog.open()
  184. }
  185. }
  186. // Dialog for exporting a quality profile
  187. FileDialog
  188. {
  189. id: exportDialog
  190. title: catalog.i18nc("@title:window", "Export Profile")
  191. selectExisting: false
  192. nameFilters: base.qualityManagementModel.getFileNameFilters("profile_writer")
  193. folder: CuraApplication.getDefaultPath("dialog_profile_path")
  194. onAccepted:
  195. {
  196. var result = Cura.ContainerManager.exportQualityChangesGroup(base.currentItem.quality_changes_group,
  197. fileUrl, selectedNameFilter);
  198. if (result && result.status == "error")
  199. {
  200. messageDialog.title = catalog.i18nc("@title:window", "Export Profile")
  201. messageDialog.text = result.message;
  202. messageDialog.open();
  203. }
  204. // else pop-up Message thing from python code
  205. CuraApplication.setDefaultPath("dialog_profile_path", folder);
  206. }
  207. }
  208. // Dialog to request a name when duplicating a new profile
  209. Cura.RenameDialog
  210. {
  211. id: duplicateQualityDialog
  212. title: catalog.i18nc("@title:window", "Duplicate Profile")
  213. object: "<new name>"
  214. onAccepted:
  215. {
  216. base.qualityManagementModel.duplicateQualityChanges(newName, base.currentItem);
  217. }
  218. }
  219. // Confirmation dialog for removing a profile
  220. Cura.MessageDialog
  221. {
  222. id: confirmRemoveQualityDialog
  223. title: catalog.i18nc("@title:window", "Confirm Remove")
  224. text: catalog.i18nc("@label (%1 is object name)", "Are you sure you wish to remove %1? This cannot be undone!").arg(base.currentItemName)
  225. standardButtons: StandardButton.Yes | StandardButton.No
  226. modal: true
  227. onAccepted:
  228. {
  229. base.qualityManagementModel.removeQualityChangesGroup(base.currentItem.quality_changes_group);
  230. // reset current item to the first if available
  231. qualityListView.currentIndex = -1; // Reset selection.
  232. }
  233. }
  234. // Dialog to rename a quality profile
  235. Cura.RenameDialog
  236. {
  237. id: renameQualityDialog
  238. title: catalog.i18nc("@title:window", "Rename Profile")
  239. object: "<new name>"
  240. onAccepted:
  241. {
  242. var actualNewName = base.qualityManagementModel.renameQualityChangesGroup(base.currentItem.quality_changes_group, newName);
  243. base.newQualityNameToSelect = actualNewName; // Select the new name after the model gets updated
  244. }
  245. }
  246. // Dialog for importing a quality profile
  247. FileDialog
  248. {
  249. id: importDialog
  250. title: catalog.i18nc("@title:window", "Import Profile")
  251. selectExisting: true
  252. nameFilters: base.qualityManagementModel.getFileNameFilters("profile_reader")
  253. folder: CuraApplication.getDefaultPath("dialog_profile_path")
  254. onAccepted:
  255. {
  256. var result = Cura.ContainerManager.importProfile(fileUrl);
  257. messageDialog.title = catalog.i18nc("@title:window", "Import Profile")
  258. messageDialog.text = result.message;
  259. messageDialog.open();
  260. CuraApplication.setDefaultPath("dialog_profile_path", folder);
  261. }
  262. }
  263. Column
  264. {
  265. id: detailsPanelHeaderColumn
  266. anchors
  267. {
  268. left: parent.left
  269. right: parent.right
  270. top: parent.top
  271. }
  272. spacing: UM.Theme.getSize("default_margin").height
  273. visible: base.currentItem != null
  274. UM.Label
  275. {
  276. anchors.left: parent.left
  277. anchors.right: parent.right
  278. text: base.currentItemDisplayName
  279. font: UM.Theme.getFont("large_bold")
  280. elide: Text.ElideRight
  281. }
  282. Flow
  283. {
  284. id: currentSettingsActions
  285. width: parent.width
  286. visible: base.hasCurrentItem && base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName && base.currentItem.intent_category == Cura.MachineManager.activeIntentCategory
  287. Cura.SecondaryButton
  288. {
  289. text: catalog.i18nc("@action:button", "Update profile with current settings/overrides")
  290. enabled: Cura.MachineManager.hasUserSettings && objectList.currentIndex && !objectList.currentIndex.is_read_only
  291. onClicked: Cura.ContainerManager.updateQualityChanges()
  292. }
  293. Cura.SecondaryButton
  294. {
  295. text: catalog.i18nc("@action:button", "Discard current changes");
  296. enabled: Cura.MachineManager.hasUserSettings
  297. onClicked: Cura.ContainerManager.clearUserContainers();
  298. }
  299. }
  300. UM.Label
  301. {
  302. id: defaultsMessage
  303. visible: false
  304. text: catalog.i18nc("@action:label", "This profile uses the defaults specified by the printer, so it has no settings/overrides in the list below.")
  305. width: parent.width
  306. }
  307. UM.Label
  308. {
  309. id: noCurrentSettingsMessage
  310. visible: base.isCurrentItemActivated && !Cura.MachineManager.hasUserSettings
  311. text: catalog.i18nc("@action:label", "Your current settings match the selected profile.")
  312. width: parent.width
  313. }
  314. UM.TabRow
  315. {
  316. id: profileExtruderTabs
  317. UM.TabRowButton //One extra tab for the global settings.
  318. {
  319. text: catalog.i18nc("@title:tab", "Global Settings")
  320. }
  321. Repeater
  322. {
  323. model: base.extrudersModel
  324. UM.TabRowButton
  325. {
  326. text: model.name
  327. }
  328. }
  329. }
  330. }
  331. Rectangle
  332. {
  333. color: UM.Theme.getColor("main_background")
  334. anchors
  335. {
  336. top: detailsPanelHeaderColumn.bottom
  337. topMargin: -UM.Theme.getSize("default_lining").width
  338. left: parent.left
  339. right: parent.right
  340. bottom: parent.bottom
  341. }
  342. border.width: UM.Theme.getSize("default_lining").width
  343. border.color: UM.Theme.getColor("thick_lining")
  344. visible: base.hasCurrentItem
  345. }
  346. Cura.ProfileOverview
  347. {
  348. anchors
  349. {
  350. top: detailsPanelHeaderColumn.bottom
  351. margins: UM.Theme.getSize("default_margin").height
  352. left: parent.left
  353. right: parent.right
  354. bottom: parent.bottom
  355. }
  356. visible: detailsPanelHeaderColumn.visible
  357. qualityItem: base.currentItem
  358. extruderPosition: profileExtruderTabs.currentIndex - 1
  359. }
  360. }
  361. }