ProfilesPage.qml 15 KB

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