ProfilesPage.qml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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. property var extrudersModel: CuraApplication.getExtrudersModel()
  13. property var qualityManagementModel: CuraApplication.getQualityManagementModel()
  14. property bool hasCurrentItem: base.currentItem != null
  15. property var currentItem: objectList.currentIndex == -1 ? null : base.qualityManagementModel.getItem(objectList.currentIndex)
  16. property string currentItemName: hasCurrentItem ? base.currentItem.name : ""
  17. property string currentItemDisplayName: hasCurrentItem ? base.qualityManagementModel.getQualityItemDisplayName(base.currentItem) : ""
  18. property bool isCurrentItemActivated:
  19. {
  20. if (!base.currentItem)
  21. {
  22. return false;
  23. }
  24. if (base.currentItem.is_read_only)
  25. {
  26. return (base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName) && (base.currentItem.intent_category == Cura.MachineManager.activeIntentCategory);
  27. }
  28. else
  29. {
  30. return base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName;
  31. }
  32. }
  33. property bool canCreateProfile: Cura.MachineManager.hasUserSettings
  34. signal createProfile() // Click create profile from ... in Profile context menu
  35. property string newQualityNameToSelect: ""
  36. property bool toActivateNewQuality: false
  37. onHamburgeButtonClicked: menu.popup(content_item, content_item.width - menu.width, hamburger_button.height)
  38. onCreateProfile:
  39. {
  40. createQualityDialog.object = Cura.ContainerManager.makeUniqueName(Cura.MachineManager.activeQualityOrQualityChangesName);
  41. createQualityDialog.open();
  42. createQualityDialog.selectText();
  43. }
  44. title: catalog.i18nc("@title:tab", "Profiles")
  45. scrollviewCaption: catalog.i18nc("@label", "Profiles compatible with active printer:") + "<br><b>" + Cura.MachineManager.activeMachine.name + "</b>"
  46. hamburgerButtonVisible: hasCurrentItem
  47. sectionRole: "section_name"
  48. model: qualityManagementModel
  49. buttons: [
  50. Cura.SecondaryButton
  51. {
  52. text: catalog.i18nc("@action:button", "Import")
  53. onClicked:importDialog.open()
  54. },
  55. Cura.SecondaryButton
  56. {
  57. id: createMenuButton
  58. text: catalog.i18nc("@action:button", "Create new")
  59. enabled: !Cura.MachineManager.stacksHaveErrors
  60. visible: base.canCreateProfile
  61. onClicked:
  62. {
  63. createQualityDialog.object = Cura.ContainerManager.makeUniqueName(base.currentItem.name)
  64. createQualityDialog.open()
  65. createQualityDialog.selectText()
  66. }
  67. }
  68. ]
  69. Item
  70. {
  71. id: content_item
  72. anchors.fill: parent
  73. // This connection makes sure that we will switch to the correct quality after the model gets updated
  74. Connections
  75. {
  76. target: base.qualityManagementModel
  77. function onItemsChanged()
  78. {
  79. var toSelectItemName = base.currentItem == null ? "" : base.currentItem.name;
  80. if (newQualityNameToSelect != "")
  81. {
  82. toSelectItemName = newQualityNameToSelect;
  83. }
  84. var newIdx = -1; // Default to nothing if nothing can be found
  85. if (toSelectItemName != "")
  86. {
  87. // Select the required quality name if given
  88. for (var idx = 0; idx < base.qualityManagementModel.count; ++idx)
  89. {
  90. var item = base.qualityManagementModel.getItem(idx);
  91. if (item && item.name == toSelectItemName)
  92. {
  93. // Switch to the newly created profile if needed
  94. newIdx = idx;
  95. if (base.toActivateNewQuality)
  96. {
  97. // Activate this custom quality if required
  98. if(item.quality_changes_group)
  99. {
  100. Cura.MachineManager.setQualityChangesGroup(item.quality_changes_group);
  101. }
  102. }
  103. break;
  104. }
  105. }
  106. }
  107. objectList.currentIndex = newIdx;
  108. // Reset states
  109. base.newQualityNameToSelect = "";
  110. base.toActivateNewQuality = false;
  111. }
  112. }
  113. Cura.MessageDialog
  114. {
  115. id: messageDialog
  116. standardButtons: Dialog.Ok
  117. }
  118. // Dialog to request a name when creating a new profile
  119. Cura.RenameDialog
  120. {
  121. id: createQualityDialog
  122. title: catalog.i18nc("@title:window", "Create Profile")
  123. object: "<new name>"
  124. explanation: catalog.i18nc("@info", "Please provide a name for this profile.")
  125. onAccepted:
  126. {
  127. base.newQualityNameToSelect = newName; // We want to switch to the new profile once it's created
  128. base.toActivateNewQuality = true;
  129. base.qualityManagementModel.createQualityChanges(newName);
  130. }
  131. }
  132. Cura.Menu
  133. {
  134. id: menu
  135. Cura.MenuItem
  136. {
  137. text: catalog.i18nc("@action:button", "Activate")
  138. enabled: !isCurrentItemActivated && base.currentItem
  139. onTriggered:
  140. {
  141. if(base.currentItem.is_read_only)
  142. {
  143. Cura.IntentManager.selectIntent(base.currentItem.intent_category, base.currentItem.quality_type)
  144. }
  145. else
  146. {
  147. Cura.MachineManager.setQualityChangesGroup(base.currentItem.quality_changes_group)
  148. }
  149. }
  150. }
  151. Cura.MenuItem
  152. {
  153. text: catalog.i18nc("@action:button", "Duplicate")
  154. enabled: base.hasCurrentItem
  155. onTriggered:
  156. {
  157. forceActiveFocus()
  158. duplicateQualityDialog.open()
  159. }
  160. }
  161. Cura.MenuItem
  162. {
  163. text: catalog.i18nc("@action:button", "Remove")
  164. enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated
  165. onTriggered:
  166. {
  167. forceActiveFocus()
  168. confirmRemoveQualityDialog.open()
  169. }
  170. }
  171. Cura.MenuItem
  172. {
  173. text: catalog.i18nc("@action:button", "Rename")
  174. enabled: base.hasCurrentItem && !base.currentItem.is_read_only
  175. onTriggered:
  176. {
  177. renameQualityDialog.object = base.currentItem.name
  178. renameQualityDialog.open()
  179. renameQualityDialog.selectText()
  180. }
  181. }
  182. Cura.MenuItem
  183. {
  184. text: catalog.i18nc("@action:button", "Export")
  185. enabled: base.hasCurrentItem && !base.currentItem.is_read_only
  186. onTriggered: exportDialog.open()
  187. }
  188. }
  189. // Dialog for exporting a quality profile
  190. FileDialog
  191. {
  192. id: exportDialog
  193. title: catalog.i18nc("@title:window", "Export Profile")
  194. selectExisting: false
  195. nameFilters: base.qualityManagementModel.getFileNameFilters("profile_writer")
  196. folder: CuraApplication.getDefaultPath("dialog_profile_path")
  197. onAccepted:
  198. {
  199. var result = Cura.ContainerManager.exportQualityChangesGroup(base.currentItem.quality_changes_group,
  200. fileUrl, selectedNameFilter);
  201. if (result && result.status == "error")
  202. {
  203. messageDialog.title = catalog.i18nc("@title:window", "Export Profile")
  204. messageDialog.text = result.message;
  205. messageDialog.open();
  206. }
  207. // else pop-up Message thing from python code
  208. CuraApplication.setDefaultPath("dialog_profile_path", folder);
  209. }
  210. }
  211. // Dialog to request a name when duplicating a new profile
  212. Cura.RenameDialog
  213. {
  214. id: duplicateQualityDialog
  215. title: catalog.i18nc("@title:window", "Duplicate Profile")
  216. object: "<new name>"
  217. onAccepted: base.qualityManagementModel.duplicateQualityChanges(newName, base.currentItem)
  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. }