MaterialsPage.qml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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.Dialogs
  6. import UM 1.5 as UM
  7. import Cura 1.5 as Cura
  8. UM.ManagementPage
  9. {
  10. id: base
  11. Item { enabled: false; UM.I18nCatalog { id: catalog; name: "cura"} }
  12. // Keep PreferencesDialog happy
  13. property var resetEnabled: false
  14. property var currentItem: null
  15. property var materialManagementModel: CuraApplication.getMaterialManagementModel()
  16. property var hasCurrentItem: base.currentItem != null
  17. property var isCurrentItemActivated:
  18. {
  19. if (!hasCurrentItem)
  20. {
  21. return false
  22. }
  23. const extruder_position = Cura.ExtruderManager.activeExtruderIndex
  24. const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position]
  25. return base.currentItem.root_material_id == root_material_id
  26. }
  27. property string newRootMaterialIdToSwitchTo: ""
  28. property bool toActivateNewMaterial: false
  29. property var extruder_position: Cura.ExtruderManager.activeExtruderIndex
  30. property var active_root_material_id: Cura.MachineManager.currentRootMaterialId[extruder_position]
  31. function resetExpandedActiveMaterial()
  32. {
  33. materialListView.expandActiveMaterial(active_root_material_id)
  34. }
  35. function setExpandedActiveMaterial(root_material_id)
  36. {
  37. materialListView.expandActiveMaterial(root_material_id)
  38. }
  39. // When loaded, try to select the active material in the tree
  40. Component.onCompleted:
  41. {
  42. resetExpandedActiveMaterial()
  43. base.newRootMaterialIdToSwitchTo = active_root_material_id
  44. }
  45. // Every time the selected item has changed, notify to the details panel
  46. onCurrentItemChanged:
  47. {
  48. forceActiveFocus()
  49. if(materialDetailsPanel.currentItem != currentItem)
  50. {
  51. materialDetailsPanel.currentItem = currentItem
  52. // CURA-6679 If the current item is gone after the model update, reset the current item to the active material.
  53. if (currentItem == null)
  54. {
  55. resetExpandedActiveMaterial()
  56. }
  57. }
  58. }
  59. title: catalog.i18nc("@title:tab", "Materials")
  60. detailsPlaneCaption: currentItem ? currentItem.name: ""
  61. scrollviewCaption: catalog.i18nc("@label", "Materials compatible with active printer:") + `<br /><b>${Cura.MachineManager.activeMachine.name}</b>`
  62. buttons: [
  63. Cura.SecondaryButton
  64. {
  65. id: createMenuButton
  66. text: catalog.i18nc("@action:button", "Create new")
  67. enabled: Cura.MachineManager.activeMachine.hasMaterials
  68. onClicked:
  69. {
  70. forceActiveFocus();
  71. base.newRootMaterialIdToSwitchTo = base.materialManagementModel.createMaterial();
  72. base.toActivateNewMaterial = true;
  73. }
  74. },
  75. Cura.SecondaryButton
  76. {
  77. id: importMenuButton
  78. text: catalog.i18nc("@action:button", "Import")
  79. onClicked:
  80. {
  81. forceActiveFocus();
  82. importMaterialDialog.open();
  83. }
  84. enabled: Cura.MachineManager.activeMachine.hasMaterials
  85. },
  86. Cura.SecondaryButton
  87. {
  88. id: syncMaterialsButton
  89. text: catalog.i18nc("@action:button", "Sync with Printers")
  90. onClicked:
  91. {
  92. forceActiveFocus();
  93. base.materialManagementModel.openSyncAllWindow();
  94. }
  95. visible: Cura.MachineManager.activeMachine.supportsMaterialExport
  96. }
  97. ]
  98. onHamburgeButtonClicked: {
  99. const hamburerButtonHeight = hamburger_button.height;
  100. menu.popup(hamburger_button, -menu.width + hamburger_button.width / 2, hamburger_button.height);
  101. // for some reason the height of the hamburger changes when opening the popup
  102. // reset height to initial heigt
  103. hamburger_button.height = hamburerButtonHeight;
  104. }
  105. listContent: ScrollView
  106. {
  107. id: materialScrollView
  108. anchors.fill: parent
  109. anchors.margins: parent.border.width
  110. width: (parent.width * 0.4) | 0
  111. clip: true
  112. ScrollBar.vertical: UM.ScrollBar
  113. {
  114. id: materialScrollBar
  115. parent: materialScrollView.parent
  116. anchors
  117. {
  118. top: parent.top
  119. right: parent.right
  120. bottom: parent.bottom
  121. }
  122. }
  123. contentHeight: materialListView.height //For some reason, this is not determined automatically with this ScrollView. Very weird!
  124. MaterialsList
  125. {
  126. id: materialListView
  127. width: materialScrollView.width - materialScrollBar.width
  128. }
  129. }
  130. MaterialsDetailsPanel
  131. {
  132. id: materialDetailsPanel
  133. anchors.fill: parent
  134. }
  135. Item
  136. {
  137. Cura.Menu
  138. {
  139. id: menu
  140. Cura.MenuItem
  141. {
  142. id: activateMenuButton
  143. text: catalog.i18nc("@action:button", "Activate")
  144. onClicked:
  145. {
  146. forceActiveFocus()
  147. // Set the current material as the one to be activated (needed to force the UI update)
  148. base.newRootMaterialIdToSwitchTo = base.currentItem.root_material_id
  149. const extruder_position = Cura.ExtruderManager.activeExtruderIndex
  150. Cura.MachineManager.setMaterial(extruder_position, base.currentItem.container_node)
  151. }
  152. }
  153. Cura.MenuItem
  154. {
  155. id: duplicateMenuButton
  156. text: catalog.i18nc("@action:button", "Duplicate");
  157. enabled: base.hasCurrentItem
  158. onClicked:
  159. {
  160. forceActiveFocus();
  161. base.newRootMaterialIdToSwitchTo = base.materialManagementModel.duplicateMaterial(base.currentItem.container_node);
  162. base.toActivateNewMaterial = true;
  163. }
  164. }
  165. Cura.MenuItem
  166. {
  167. id: removeMenuButton
  168. text: catalog.i18nc("@action:button", "Remove")
  169. enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated && base.materialManagementModel.canMaterialBeRemoved(base.currentItem.container_node)
  170. onClicked:
  171. {
  172. forceActiveFocus();
  173. confirmRemoveMaterialDialog.open();
  174. }
  175. }
  176. Cura.MenuItem
  177. {
  178. id: exportMenuButton
  179. text: catalog.i18nc("@action:button", "Export")
  180. onClicked:
  181. {
  182. forceActiveFocus();
  183. exportMaterialDialog.open();
  184. }
  185. enabled: base.hasCurrentItem
  186. }
  187. }
  188. // Dialogs
  189. Cura.MessageDialog
  190. {
  191. id: confirmRemoveMaterialDialog
  192. title: catalog.i18nc("@title:window", "Confirm Remove")
  193. property string materialName: base.currentItem !== null ? base.currentItem.name : ""
  194. text: catalog.i18nc("@label (%1 is object name)", "Are you sure you wish to remove %1? This cannot be undone!").arg(materialName)
  195. standardButtons: Dialog.Yes | Dialog.No
  196. onAccepted:
  197. {
  198. // Set the active material as the fallback. It will be selected when the current material is deleted
  199. base.newRootMaterialIdToSwitchTo = base.active_root_material_id
  200. base.materialManagementModel.removeMaterial(base.currentItem.container_node);
  201. }
  202. }
  203. FileDialog
  204. {
  205. id: importMaterialDialog
  206. title: catalog.i18nc("@title:window", "Import Material")
  207. fileMode: FileDialog.OpenFile
  208. nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
  209. currentFolder: CuraApplication.getDefaultPath("dialog_material_path")
  210. onAccepted:
  211. {
  212. const result = Cura.ContainerManager.importMaterialContainer(selectedFile);
  213. const messageDialog = Qt.createQmlObject("import Cura 1.5 as Cura; Cura.MessageDialog { onClosed: destroy() }", base);
  214. messageDialog.standardButtons = Dialog.Ok;
  215. messageDialog.title = catalog.i18nc("@title:window", "Import Material");
  216. switch (result.status)
  217. {
  218. case "success":
  219. messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tag <filename>!", "Successfully imported material <filename>%1</filename>").arg(selectedFile);
  220. break;
  221. default:
  222. messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Could not import material <filename>%1</filename>: <message>%2</message>").arg(selectedFile).arg(result.message);
  223. break;
  224. }
  225. messageDialog.open();
  226. CuraApplication.setDefaultPath("dialog_material_path", currentFolder);
  227. }
  228. }
  229. FileDialog
  230. {
  231. id: exportMaterialDialog
  232. title: catalog.i18nc("@title:window", "Export Material")
  233. fileMode: FileDialog.SaveFile
  234. nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
  235. currentFolder: CuraApplication.getDefaultPath("dialog_material_path")
  236. onAccepted:
  237. {
  238. const nameFilterString = selectedNameFilter.index >= 0 ? nameFilters[selectedNameFilter.index] : nameFilters[0];
  239. const result = Cura.ContainerManager.exportContainer(base.currentItem.root_material_id, nameFilterString, selectedFile);
  240. const messageDialog = Qt.createQmlObject("import Cura 1.5 as Cura; Cura.MessageDialog { onClosed: destroy() }", base);
  241. messageDialog.title = catalog.i18nc("@title:window", "Export Material");
  242. messageDialog.standardButtons = Dialog.Ok;
  243. switch (result.status)
  244. {
  245. case "error":
  246. messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tags <filename> and <message>!", "Failed to export material to <filename>%1</filename>: <message>%2</message>").arg(selectedFile).arg(result.message);
  247. break;
  248. case "success":
  249. messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tag <filename>!", "Successfully exported material to <filename>%1</filename>").arg(result.path);
  250. break;
  251. }
  252. messageDialog.open();
  253. CuraApplication.setDefaultPath("dialog_material_path", currentFolder);
  254. }
  255. }
  256. }
  257. }