ProfilesPage.qml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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.")
  290. enabled: Cura.MachineManager.hasUserSettings && objectList.currentIndex && !objectList.currentIndex.is_read_only
  291. onClicked: Cura.ContainerManager.updateQualityChanges()
  292. tooltip: catalog.i18nc("@action:tooltip", "Update profile with current settings/overrides")
  293. }
  294. Cura.SecondaryButton
  295. {
  296. text: catalog.i18nc("@action:button", "Discard current changes")
  297. enabled: Cura.MachineManager.hasUserSettings
  298. onClicked: Cura.ContainerManager.clearUserContainers()
  299. }
  300. }
  301. UM.Label
  302. {
  303. id: defaultsMessage
  304. visible: false
  305. text: catalog.i18nc("@action:label", "This profile uses the defaults specified by the printer, so it has no settings/overrides in the list below.")
  306. width: parent.width
  307. }
  308. UM.Label
  309. {
  310. id: noCurrentSettingsMessage
  311. visible: base.isCurrentItemActivated && !Cura.MachineManager.hasUserSettings
  312. text: catalog.i18nc("@action:label", "Your current settings match the selected profile.")
  313. width: parent.width
  314. }
  315. UM.TabRow
  316. {
  317. id: profileExtruderTabs
  318. UM.TabRowButton // One extra tab for the global settings.
  319. {
  320. text: catalog.i18nc("@title:tab", "Global Settings")
  321. }
  322. Repeater
  323. {
  324. model: base.extrudersModel
  325. UM.TabRowButton
  326. {
  327. text: model.name
  328. }
  329. }
  330. }
  331. }
  332. Rectangle
  333. {
  334. color: UM.Theme.getColor("main_background")
  335. anchors
  336. {
  337. top: detailsPanelHeaderColumn.bottom
  338. topMargin: -UM.Theme.getSize("default_lining").width
  339. left: parent.left
  340. right: parent.right
  341. bottom: parent.bottom
  342. }
  343. border.width: UM.Theme.getSize("default_lining").width
  344. border.color: UM.Theme.getColor("thick_lining")
  345. visible: base.hasCurrentItem
  346. }
  347. Cura.ProfileOverview
  348. {
  349. anchors
  350. {
  351. top: detailsPanelHeaderColumn.bottom
  352. margins: UM.Theme.getSize("default_margin").height
  353. left: parent.left
  354. right: parent.right
  355. bottom: parent.bottom
  356. }
  357. visible: detailsPanelHeaderColumn.visible
  358. qualityItem: base.currentItem
  359. extruderPosition: profileExtruderTabs.currentIndex - 1
  360. }
  361. }
  362. }