MaterialsPage.qml 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. // Copyright (c) 2018 Ultimaker B.V.
  2. // Uranium is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.8
  4. import QtQuick.Controls 1.4
  5. import QtQuick.Layouts 1.3
  6. import QtQuick.Dialogs 1.2
  7. import UM 1.2 as UM
  8. import Cura 1.0 as Cura
  9. Item
  10. {
  11. id: base
  12. property QtObject materialManager: CuraApplication.getMaterialManager()
  13. property var resetEnabled: false // Keep PreferencesDialog happy
  14. UM.I18nCatalog { id: catalog; name: "cura"; }
  15. Cura.MaterialManagementModel {
  16. id: materialsModel
  17. }
  18. Label {
  19. id: titleLabel
  20. anchors {
  21. top: parent.top
  22. left: parent.left
  23. right: parent.right
  24. margins: 5 * screenScaleFactor
  25. }
  26. font.pointSize: 18
  27. text: catalog.i18nc("@title:tab", "Materials")
  28. }
  29. property var hasCurrentItem: materialListView.currentItem != null
  30. property var currentItem: { // is soon to be overwritten
  31. var current_index = materialListView.currentIndex;
  32. return materialsModel.getItem(current_index);
  33. }
  34. property var isCurrentItemActivated: {
  35. const extruder_position = Cura.ExtruderManager.activeExtruderIndex;
  36. const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position];
  37. return base.currentItem.root_material_id == root_material_id;
  38. }
  39. Row // Button Row
  40. {
  41. id: buttonRow
  42. anchors {
  43. left: parent.left
  44. right: parent.right
  45. top: titleLabel.bottom
  46. }
  47. height: childrenRect.height
  48. // Activate button
  49. Button {
  50. text: catalog.i18nc("@action:button", "Activate")
  51. iconName: "list-activate"
  52. enabled: !isCurrentItemActivated
  53. onClicked: {
  54. forceActiveFocus()
  55. const extruder_position = Cura.ExtruderManager.activeExtruderIndex;
  56. Cura.MachineManager.setMaterial(extruder_position, base.currentItem.container_node);
  57. }
  58. }
  59. // Create button
  60. Button {
  61. text: catalog.i18nc("@action:button", "Create")
  62. iconName: "list-add"
  63. onClicked: {
  64. forceActiveFocus();
  65. base.newRootMaterialIdToSwitchTo = Cura.ContainerManager.createMaterial();
  66. base.toActivateNewMaterial = true;
  67. }
  68. }
  69. // Duplicate button
  70. Button {
  71. text: catalog.i18nc("@action:button", "Duplicate");
  72. iconName: "list-add"
  73. enabled: base.hasCurrentItem
  74. onClicked: {
  75. forceActiveFocus();
  76. base.newRootMaterialIdToSwitchTo = base.materialManager.duplicateMaterial(base.currentItem.container_node);
  77. base.toActivateNewMaterial = true;
  78. }
  79. }
  80. // Remove button
  81. Button {
  82. text: catalog.i18nc("@action:button", "Remove")
  83. iconName: "list-remove"
  84. enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated
  85. onClicked: {
  86. forceActiveFocus();
  87. confirmRemoveMaterialDialog.open();
  88. }
  89. }
  90. // Import button
  91. Button {
  92. text: catalog.i18nc("@action:button", "Import")
  93. iconName: "document-import"
  94. onClicked: {
  95. forceActiveFocus();
  96. importMaterialDialog.open();
  97. }
  98. visible: true
  99. }
  100. // Export button
  101. Button {
  102. text: catalog.i18nc("@action:button", "Export")
  103. iconName: "document-export"
  104. onClicked: {
  105. forceActiveFocus();
  106. exportMaterialDialog.open();
  107. }
  108. enabled: currentItem != null
  109. }
  110. }
  111. property string newRootMaterialIdToSwitchTo: ""
  112. property bool toActivateNewMaterial: false
  113. // This connection makes sure that we will switch to the new
  114. Connections
  115. {
  116. target: materialsModel
  117. onItemsChanged: {
  118. var currentItemId = base.currentItem == null ? "" : base.currentItem.root_material_id;
  119. var position = Cura.ExtruderManager.activeExtruderIndex;
  120. // try to pick the currently selected item; it may have been moved
  121. if (base.newRootMaterialIdToSwitchTo == "") {
  122. base.newRootMaterialIdToSwitchTo = currentItemId;
  123. }
  124. for (var idx = 0; idx < materialsModel.rowCount(); ++idx) {
  125. var item = materialsModel.getItem(idx);
  126. if (item.root_material_id == base.newRootMaterialIdToSwitchTo) {
  127. // Switch to the newly created profile if needed
  128. materialListView.currentIndex = idx;
  129. materialListView.activateDetailsWithIndex(materialListView.currentIndex);
  130. if (base.toActivateNewMaterial) {
  131. Cura.MachineManager.setMaterial(position, item.container_node);
  132. }
  133. base.newRootMaterialIdToSwitchTo = "";
  134. base.toActivateNewMaterial = false;
  135. return
  136. }
  137. }
  138. materialListView.currentIndex = 0;
  139. materialListView.activateDetailsWithIndex(materialListView.currentIndex);
  140. if (base.toActivateNewMaterial) {
  141. Cura.MachineManager.setMaterial(position, materialsModel.getItem(0).container_node);
  142. }
  143. base.newRootMaterialIdToSwitchTo = "";
  144. base.toActivateNewMaterial = false;
  145. }
  146. }
  147. MessageDialog
  148. {
  149. id: confirmRemoveMaterialDialog
  150. icon: StandardIcon.Question;
  151. title: catalog.i18nc("@title:window", "Confirm Remove")
  152. text: catalog.i18nc("@label (%1 is object name)", "Are you sure you wish to remove %1? This cannot be undone!").arg(base.currentItem.name)
  153. standardButtons: StandardButton.Yes | StandardButton.No
  154. modality: Qt.ApplicationModal
  155. onYes:
  156. {
  157. base.materialManager.removeMaterial(base.currentItem.container_node);
  158. }
  159. }
  160. FileDialog
  161. {
  162. id: importMaterialDialog
  163. title: catalog.i18nc("@title:window", "Import Material")
  164. selectExisting: true
  165. nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
  166. folder: CuraApplication.getDefaultPath("dialog_material_path")
  167. onAccepted:
  168. {
  169. var result = Cura.ContainerManager.importMaterialContainer(fileUrl);
  170. messageDialog.title = catalog.i18nc("@title:window", "Import Material");
  171. 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(fileUrl).arg(result.message);
  172. if (result.status == "success") {
  173. messageDialog.icon = StandardIcon.Information;
  174. messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tag <filename>!", "Successfully imported material <filename>%1</filename>").arg(fileUrl);
  175. }
  176. else if (result.status == "duplicate") {
  177. messageDialog.icon = StandardIcon.Warning;
  178. }
  179. else {
  180. messageDialog.icon = StandardIcon.Critical;
  181. }
  182. messageDialog.open();
  183. CuraApplication.setDefaultPath("dialog_material_path", folder);
  184. }
  185. }
  186. FileDialog
  187. {
  188. id: exportMaterialDialog
  189. title: catalog.i18nc("@title:window", "Export Material")
  190. selectExisting: false
  191. nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
  192. folder: CuraApplication.getDefaultPath("dialog_material_path")
  193. onAccepted:
  194. {
  195. var result = Cura.ContainerManager.exportContainer(base.currentItem.root_material_id, selectedNameFilter, fileUrl);
  196. messageDialog.title = catalog.i18nc("@title:window", "Export Material");
  197. if (result.status == "error") {
  198. messageDialog.icon = StandardIcon.Critical;
  199. 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(fileUrl).arg(result.message);
  200. messageDialog.open();
  201. }
  202. else if (result.status == "success") {
  203. messageDialog.icon = StandardIcon.Information;
  204. messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tag <filename>!", "Successfully exported material to <filename>%1</filename>").arg(result.path);
  205. messageDialog.open();
  206. }
  207. CuraApplication.setDefaultPath("dialog_material_path", folder);
  208. }
  209. }
  210. MessageDialog
  211. {
  212. id: messageDialog
  213. }
  214. Item {
  215. id: contentsItem
  216. anchors {
  217. top: titleLabel.bottom
  218. left: parent.left
  219. right: parent.right
  220. bottom: parent.bottom
  221. margins: 5 * screenScaleFactor
  222. bottomMargin: 0
  223. }
  224. clip: true
  225. }
  226. Item
  227. {
  228. anchors {
  229. top: buttonRow.bottom
  230. topMargin: UM.Theme.getSize("default_margin").height
  231. left: parent.left
  232. right: parent.right
  233. bottom: parent.bottom
  234. }
  235. SystemPalette { id: palette }
  236. Label
  237. {
  238. id: captionLabel
  239. anchors {
  240. top: parent.top
  241. left: parent.left
  242. }
  243. visible: text != ""
  244. text: {
  245. // OLD STUFF
  246. var caption = catalog.i18nc("@action:label", "Printer") + ": " + Cura.MachineManager.activeMachineName;
  247. if (Cura.MachineManager.hasVariants)
  248. {
  249. caption += ", " + Cura.MachineManager.activeDefinitionVariantsName + ": " + Cura.MachineManager.activeVariantName;
  250. }
  251. return caption;
  252. }
  253. width: materialScrollView.width
  254. elide: Text.ElideRight
  255. }
  256. ScrollView
  257. {
  258. id: materialScrollView
  259. anchors {
  260. top: captionLabel.visible ? captionLabel.bottom : parent.top
  261. topMargin: captionLabel.visible ? UM.Theme.getSize("default_margin").height : 0
  262. bottom: parent.bottom
  263. left: parent.left
  264. }
  265. Rectangle {
  266. parent: viewport
  267. anchors.fill: parent
  268. color: palette.light
  269. }
  270. width: true ? (parent.width * 0.4) | 0 : parent.width
  271. ListView
  272. {
  273. id: materialListView
  274. model: materialsModel
  275. section.property: "brand"
  276. section.criteria: ViewSection.FullString
  277. section.delegate: Rectangle
  278. {
  279. width: materialScrollView.width
  280. height: childrenRect.height
  281. color: palette.light
  282. Label
  283. {
  284. anchors.left: parent.left
  285. anchors.leftMargin: UM.Theme.getSize("default_lining").width
  286. text: section
  287. font.bold: true
  288. color: palette.text
  289. }
  290. }
  291. delegate: Rectangle
  292. {
  293. width: materialScrollView.width
  294. height: childrenRect.height
  295. color: ListView.isCurrentItem ? palette.highlight : (model.index % 2) ? palette.base : palette.alternateBase
  296. Row
  297. {
  298. spacing: (UM.Theme.getSize("default_margin").width / 2) | 0
  299. anchors.left: parent.left
  300. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  301. anchors.right: parent.right
  302. Rectangle
  303. {
  304. width: Math.floor(parent.height * 0.8)
  305. height: Math.floor(parent.height * 0.8)
  306. color: model.color_code
  307. border.color: parent.ListView.isCurrentItem ? palette.highlightedText : palette.text;
  308. anchors.verticalCenter: parent.verticalCenter
  309. }
  310. Label
  311. {
  312. width: Math.floor((parent.width * 0.3))
  313. text: model.material
  314. elide: Text.ElideRight
  315. font.italic: { // TODO: make it easier
  316. const extruder_position = Cura.ExtruderManager.activeExtruderIndex;
  317. const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position];
  318. return model.root_material_id == root_material_id
  319. }
  320. color: parent.ListView.isCurrentItem ? palette.highlightedText : palette.text;
  321. }
  322. Label
  323. {
  324. text: (model.name != model.material) ? model.name : ""
  325. elide: Text.ElideRight
  326. font.italic: { // TODO: make it easier
  327. const extruder_position = Cura.ExtruderManager.activeExtruderIndex;
  328. const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position];
  329. return model.root_material_id == root_material_id;
  330. }
  331. color: parent.ListView.isCurrentItem ? palette.highlightedText : palette.text;
  332. }
  333. }
  334. MouseArea
  335. {
  336. anchors.fill: parent
  337. onClicked: {
  338. parent.ListView.view.currentIndex = model.index;
  339. }
  340. }
  341. }
  342. function activateDetailsWithIndex(index) {
  343. var model = materialsModel.getItem(index);
  344. base.currentItem = model;
  345. materialDetailsView.containerId = model.container_id;
  346. materialDetailsView.currentMaterialNode = model.container_node;
  347. detailsPanel.updateMaterialPropertiesObject();
  348. }
  349. onCurrentIndexChanged:
  350. {
  351. forceActiveFocus(); // causes the changed fields to be saved
  352. activateDetailsWithIndex(currentIndex);
  353. }
  354. }
  355. }
  356. Item
  357. {
  358. id: detailsPanel
  359. anchors {
  360. left: materialScrollView.right
  361. leftMargin: UM.Theme.getSize("default_margin").width
  362. top: parent.top
  363. bottom: parent.bottom
  364. right: parent.right
  365. }
  366. function updateMaterialPropertiesObject()
  367. {
  368. var currentItem = materialsModel.getItem(materialListView.currentIndex);
  369. materialProperties.name = currentItem.name;
  370. materialProperties.guid = currentItem.guid;
  371. materialProperties.brand = currentItem.brand ? currentItem.brand : "Unknown";
  372. materialProperties.material = currentItem.material ? currentItem.material : "Unknown";
  373. materialProperties.color_name = currentItem.color_name ? currentItem.color_name : "Yellow";
  374. materialProperties.color_code = currentItem.color_code ? currentItem.color_code : "yellow";
  375. materialProperties.description = currentItem.description ? currentItem.description : "";
  376. materialProperties.adhesion_info = currentItem.adhesion_info ? currentItem.adhesion_info : "";
  377. materialProperties.density = currentItem.density ? currentItem.density : 0.0;
  378. materialProperties.diameter = currentItem.diameter ? currentItem.diameter : 0.0;
  379. materialProperties.approximate_diameter = currentItem.approximate_diameter ? currentItem.approximate_diameter : "0";
  380. }
  381. Item
  382. {
  383. anchors.fill: parent
  384. Item // Material title Label
  385. {
  386. id: profileName
  387. width: parent.width
  388. height: childrenRect.height
  389. Label {
  390. text: materialProperties.name
  391. font: UM.Theme.getFont("large")
  392. }
  393. }
  394. MaterialView // Material detailed information view below the title Label
  395. {
  396. id: materialDetailsView
  397. anchors
  398. {
  399. left: parent.left
  400. right: parent.right
  401. top: profileName.bottom
  402. topMargin: UM.Theme.getSize("default_margin").height
  403. bottom: parent.bottom
  404. }
  405. editingEnabled: base.currentItem != null && !base.currentItem.is_read_only
  406. properties: materialProperties
  407. containerId: base.currentItem != null ? base.currentItem.container_id : ""
  408. currentMaterialNode: base.currentItem.container_node
  409. property alias pane: base
  410. }
  411. QtObject
  412. {
  413. id: materialProperties
  414. property string guid: "00000000-0000-0000-0000-000000000000"
  415. property string name: "Unknown";
  416. property string profile_type: "Unknown";
  417. property string brand: "Unknown";
  418. property string material: "Unknown"; // This needs to be named as "material" to be consistent with
  419. // the material container's metadata entry
  420. property string color_name: "Yellow";
  421. property color color_code: "yellow";
  422. property real density: 0.0;
  423. property real diameter: 0.0;
  424. property string approximate_diameter: "0";
  425. property real spool_cost: 0.0;
  426. property real spool_weight: 0.0;
  427. property real spool_length: 0.0;
  428. property real cost_per_meter: 0.0;
  429. property string description: "";
  430. property string adhesion_info: "";
  431. }
  432. }
  433. }
  434. }
  435. }