ProfilesPage.qml 14 KB

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