MaterialsPage.qml 19 KB

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