MaterialsPage.qml 20 KB

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