ProfilesPage.qml 15 KB

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