MaterialsSyncDialog.qml 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. //Copyright (c) 2022 Ultimaker B.V.
  2. //Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.15
  4. import QtQuick.Controls 2.15
  5. import QtQuick.Dialogs 1.2
  6. import QtQuick.Layouts 1.15
  7. import QtQuick.Window 2.1
  8. import Cura 1.1 as Cura
  9. import UM 1.5 as UM
  10. Window
  11. {
  12. id: materialsSyncDialog
  13. property variant catalog: UM.I18nCatalog { name: "cura" }
  14. title: catalog.i18nc("@title:window", "Sync materials with printers")
  15. minimumWidth: UM.Theme.getSize("modal_window_minimum").width
  16. minimumHeight: UM.Theme.getSize("modal_window_minimum").height
  17. width: minimumWidth
  18. height: minimumHeight
  19. modality: Qt.ApplicationModal
  20. color: UM.Theme.getColor("main_background")
  21. property variant syncModel
  22. property alias pageIndex: swipeView.currentIndex
  23. property alias syncStatusText: syncStatusLabel.text
  24. property bool hasExportedUsb: false
  25. SwipeView
  26. {
  27. id: swipeView
  28. anchors.fill: parent
  29. interactive: false
  30. Item
  31. {
  32. id: introPage
  33. ColumnLayout
  34. {
  35. spacing: UM.Theme.getSize("default_margin").height
  36. anchors.fill: parent
  37. anchors.margins: UM.Theme.getSize("default_margin").width
  38. UM.Label
  39. {
  40. text: catalog.i18nc("@title:header", "Sync materials with printers")
  41. font: UM.Theme.getFont("large_bold")
  42. Layout.fillWidth: true
  43. }
  44. UM.Label
  45. {
  46. text: catalog.i18nc("@text", "Following a few simple steps, you will be able to synchronize all your material profiles with your printers.")
  47. font: UM.Theme.getFont("medium")
  48. Layout.fillWidth: true
  49. }
  50. Image
  51. {
  52. Layout.fillWidth: true
  53. Layout.fillHeight: true
  54. source: UM.Theme.getImage("material_ecosystem")
  55. fillMode: Image.PreserveAspectFit
  56. sourceSize.width: width
  57. }
  58. Item
  59. {
  60. Layout.preferredHeight: childrenRect.height
  61. Layout.alignment: Qt.AlignBottom
  62. Layout.fillWidth: true
  63. Cura.TertiaryButton
  64. {
  65. text: catalog.i18nc("@button", "Why do I need to sync material profiles?")
  66. iconSource: UM.Theme.getIcon("LinkExternal")
  67. isIconOnRightSide: true
  68. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/360013137919?utm_source=cura&utm_medium=software&utm_campaign=sync-material-printer-why")
  69. }
  70. Cura.PrimaryButton
  71. {
  72. anchors.right: parent.right
  73. text: catalog.i18nc("@button", "Start")
  74. onClicked:
  75. {
  76. if(Cura.API.account.isLoggedIn)
  77. {
  78. swipeView.currentIndex += 2; //Skip sign in page.
  79. }
  80. else
  81. {
  82. swipeView.currentIndex += 1;
  83. }
  84. }
  85. }
  86. }
  87. }
  88. }
  89. Item
  90. {
  91. id: signinPage
  92. // While this page is active, continue to the next page if the user logs in.
  93. Connections
  94. {
  95. target: Cura.API.account
  96. function onLoginStateChanged(is_logged_in)
  97. {
  98. if(is_logged_in && signinPage.SwipeView.isCurrentItem)
  99. {
  100. swipeView.currentIndex += 1;
  101. }
  102. }
  103. }
  104. ColumnLayout
  105. {
  106. spacing: UM.Theme.getSize("default_margin").height
  107. anchors.fill: parent
  108. anchors.margins: UM.Theme.getSize("default_margin").width
  109. UM.Label
  110. {
  111. text: catalog.i18nc("@title:header", "Sign in")
  112. font: UM.Theme.getFont("large_bold")
  113. Layout.fillWidth: true
  114. }
  115. UM.Label
  116. {
  117. text: catalog.i18nc("@text", "To automatically sync the material profiles with all your printers connected to Digital Factory you need to be signed in in Cura.")
  118. font: UM.Theme.getFont("medium")
  119. Layout.fillWidth: true
  120. }
  121. Image
  122. {
  123. Layout.alignment: Qt.AlignCenter
  124. Layout.preferredWidth: parent.width / 2
  125. source: UM.Theme.getImage("first_run_ultimaker_cloud")
  126. Layout.fillHeight: true
  127. sourceSize.width: width
  128. fillMode: Image.PreserveAspectFit
  129. }
  130. Item
  131. {
  132. Layout.preferredHeight: childrenRect.height
  133. Layout.alignment: Qt.AlignBottom
  134. Layout.fillWidth: true
  135. Cura.SecondaryButton
  136. {
  137. anchors.left: parent.left
  138. text: catalog.i18nc("@button", "Sync materials with USB")
  139. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  140. }
  141. Cura.PrimaryButton
  142. {
  143. anchors.right: parent.right
  144. text: catalog.i18nc("@button", "Sign in")
  145. onClicked: Cura.API.account.login()
  146. }
  147. }
  148. }
  149. }
  150. Item
  151. {
  152. id: printerListPage
  153. ColumnLayout
  154. {
  155. spacing: UM.Theme.getSize("default_margin").height
  156. anchors.fill: parent
  157. anchors.margins: UM.Theme.getSize("default_margin").width
  158. visible: cloudPrinterList.count > 0
  159. Row
  160. {
  161. spacing: UM.Theme.getSize("default_margin").width
  162. states: [
  163. State
  164. {
  165. name: "idle"
  166. when: typeof syncModel === "undefined" || syncModel.exportUploadStatus == "idle" || syncModel.exportUploadStatus == "uploading"
  167. PropertyChanges { target: printerListHeader; text: catalog.i18nc("@title:header", "The following printers will receive the new material profiles:") }
  168. PropertyChanges { target: printerListHeaderIcon; status: UM.StatusIcon.Status.NEUTRAL; width: 0 }
  169. },
  170. State
  171. {
  172. name: "error"
  173. when: typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "error"
  174. PropertyChanges { target: printerListHeader; text: catalog.i18nc("@title:header", "Something went wrong when sending the materials to the printers.") }
  175. PropertyChanges { target: printerListHeaderIcon; status: UM.StatusIcon.Status.ERROR }
  176. },
  177. State
  178. {
  179. name: "success"
  180. when: typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "success"
  181. PropertyChanges { target: printerListHeader; text: catalog.i18nc("@title:header", "Material profiles successfully synced with the following printers:") }
  182. PropertyChanges { target: printerListHeaderIcon; status: UM.StatusIcon.Status.POSITIVE }
  183. }
  184. ]
  185. UM.StatusIcon
  186. {
  187. id: printerListHeaderIcon
  188. width: UM.Theme.getSize("section_icon").width
  189. height: UM.Theme.getSize("section_icon").height
  190. anchors.verticalCenter: parent.verticalCenter
  191. }
  192. UM.Label
  193. {
  194. id: printerListHeader
  195. anchors.verticalCenter: parent.verticalCenter
  196. //Text is always defined by the states above.
  197. font: UM.Theme.getFont("large_bold")
  198. }
  199. }
  200. Row
  201. {
  202. Layout.fillWidth: true
  203. Layout.preferredHeight: childrenRect.height
  204. UM.Label
  205. {
  206. id: syncStatusLabel
  207. anchors.left: parent.left
  208. wrapMode: Text.Wrap
  209. elide: Text.ElideRight
  210. visible: text !== ""
  211. font: UM.Theme.getFont("medium")
  212. }
  213. Cura.TertiaryButton
  214. {
  215. id: troubleshootingLink
  216. anchors.right: parent.right
  217. text: catalog.i18nc("@button", "Troubleshooting")
  218. visible: typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "error"
  219. iconSource: UM.Theme.getIcon("LinkExternal")
  220. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/360012019239?utm_source=cura&utm_medium=software&utm_campaign=sync-material-wizard-troubleshoot-cloud-printer")
  221. }
  222. }
  223. ListView
  224. {
  225. id: printerList
  226. Layout.fillWidth: true
  227. Layout.fillHeight: true
  228. clip: true
  229. ScrollBar.vertical: UM.ScrollBar
  230. {
  231. id: printerListScrollBar
  232. }
  233. spacing: UM.Theme.getSize("default_margin").height
  234. model: cloudPrinterList
  235. delegate: Rectangle
  236. {
  237. id: delegateContainer
  238. color: "transparent"
  239. border.color: UM.Theme.getColor("lining")
  240. border.width: UM.Theme.getSize("default_lining").width
  241. width: printerList.width - printerListScrollBar.width
  242. height: UM.Theme.getSize("machine_selector_icon").height + 2 * UM.Theme.getSize("default_margin").height
  243. property string syncStatus:
  244. {
  245. var printer_id = model.metadata["host_guid"]
  246. if(syncModel.printerStatus[printer_id] === undefined) //No status information available. Could be added after we started syncing.
  247. {
  248. return "idle";
  249. }
  250. return syncModel.printerStatus[printer_id];
  251. }
  252. Cura.IconWithText
  253. {
  254. anchors
  255. {
  256. verticalCenter: parent.verticalCenter
  257. left: parent.left
  258. leftMargin: Math.round(parent.height - height) / 2 //Equal margin on the left as above and below.
  259. right: parent.right
  260. rightMargin: Math.round(parent.height - height) / 2
  261. }
  262. text: model.name
  263. font: UM.Theme.getFont("medium")
  264. source: UM.Theme.getIcon("Printer", "medium")
  265. iconColor: UM.Theme.getColor("machine_selector_printer_icon")
  266. iconSize: UM.Theme.getSize("machine_selector_icon").width
  267. //Printer status badge (always cloud, but whether it's online or offline).
  268. UM.RecolorImage
  269. {
  270. width: UM.Theme.getSize("printer_status_icon").width
  271. height: UM.Theme.getSize("printer_status_icon").height
  272. anchors
  273. {
  274. bottom: parent.bottom
  275. bottomMargin: -Math.round(height / 6)
  276. left: parent.left
  277. leftMargin: parent.iconSize - Math.round(width * 5 / 6)
  278. }
  279. source: UM.Theme.getIcon("CloudBadge", "low")
  280. color: UM.Theme.getColor("primary")
  281. //Make a themeable circle in the background so we can change it in other themes.
  282. Rectangle
  283. {
  284. anchors.centerIn: parent
  285. width: parent.width - 1.5 //1.5 pixels smaller (at least sqrt(2), regardless of pixel scale) so that the circle doesn't show up behind the icon due to anti-aliasing.
  286. height: parent.height - 1.5
  287. radius: width / 2
  288. color: UM.Theme.getColor("connection_badge_background")
  289. z: parent.z - 1
  290. }
  291. }
  292. }
  293. UM.RecolorImage
  294. {
  295. id: printerSpinner
  296. width: UM.Theme.getSize("section_icon").width
  297. height: width
  298. anchors.verticalCenter: parent.verticalCenter
  299. anchors.right: parent.right
  300. anchors.rightMargin: Math.round((parent.height - height) / 2) //Same margin on the right as above and below.
  301. visible: delegateContainer.syncStatus === "uploading"
  302. source: UM.Theme.getIcon("ArrowDoubleCircleRight")
  303. color: UM.Theme.getColor("primary")
  304. RotationAnimator
  305. {
  306. target: printerSpinner
  307. from: 0
  308. to: 360
  309. duration: 1000
  310. loops: Animation.Infinite
  311. running: true
  312. }
  313. }
  314. UM.StatusIcon
  315. {
  316. width: UM.Theme.getSize("section_icon").width
  317. height: width
  318. anchors.verticalCenter: parent.verticalCenter
  319. anchors.right: parent.right
  320. anchors.rightMargin: Math.round((parent.height - height) / 2) //Same margin on the right as above and below.
  321. visible: delegateContainer.syncStatus === "failed" || delegateContainer.syncStatus === "success"
  322. status: delegateContainer.syncStatus === "success" ? UM.StatusIcon.Status.POSITIVE : UM.StatusIcon.Status.ERROR
  323. }
  324. }
  325. footer: Item
  326. {
  327. width: printerList.width - printerListScrollBar.width
  328. height: childrenRect.height + UM.Theme.getSize("default_margin").height
  329. visible: includeOfflinePrinterList.count - cloudPrinterList.count > 0 && typeof syncModel !== "undefined" && syncModel.exportUploadStatus === "idle"
  330. Rectangle
  331. {
  332. anchors.top: parent.top
  333. anchors.left: parent.left
  334. anchors.right: parent.right
  335. border.color: UM.Theme.getColor("lining")
  336. border.width: UM.Theme.getSize("default_lining").width
  337. anchors.topMargin: UM.Theme.getSize("default_margin").height
  338. height: childrenRect.height + 2 * UM.Theme.getSize("thick_margin").height
  339. color: "transparent"
  340. GridLayout
  341. {
  342. columns: 3
  343. rows: 2
  344. anchors.top: parent.top
  345. anchors.left: parent.left
  346. anchors.right: parent.right
  347. anchors.leftMargin: UM.Theme.getSize("thick_margin").width
  348. anchors.rightMargin: UM.Theme.getSize("thick_margin").width
  349. anchors.topMargin: UM.Theme.getSize("thick_margin").height
  350. anchors.bottomMargin: UM.Theme.getSize("thick_margin").height
  351. columnSpacing: UM.Theme.getSize("default_margin").width
  352. rowSpacing: UM.Theme.getSize("default_margin").height
  353. UM.StatusIcon
  354. {
  355. Layout.preferredWidth: UM.Theme.getSize("section_icon").width
  356. Layout.preferredHeight: UM.Theme.getSize("section_icon").height
  357. status: UM.StatusIcon.Status.WARNING
  358. }
  359. UM.Label
  360. {
  361. Layout.fillWidth: true
  362. Layout.alignment: Qt.AlignVCenter
  363. text: catalog.i18nc("@text Asking the user whether printers are missing in a list.", "Printers missing?")
  364. + "\n"
  365. + catalog.i18nc("@text", "Make sure all your printers are turned ON and connected to Digital Factory.")
  366. font: UM.Theme.getFont("medium")
  367. elide: Text.ElideRight
  368. }
  369. Cura.SecondaryButton
  370. {
  371. id: refreshListButton
  372. Layout.alignment: Qt.AlignVCenter
  373. text: catalog.i18nc("@button", "Refresh List")
  374. iconSource: UM.Theme.getIcon("ArrowDoubleCircleRight")
  375. onClicked: Cura.API.account.sync(true)
  376. }
  377. Cura.TertiaryButton
  378. {
  379. id: printerListTroubleshooting
  380. Layout.column: 1
  381. Layout.row: 1
  382. Layout.fillWidth: true
  383. leftPadding: 0
  384. text: catalog.i18nc("@button", "Troubleshooting")
  385. iconSource: UM.Theme.getIcon("LinkExternal")
  386. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/360012019239?utm_source=cura&utm_medium=software&utm_campaign=sync-material-wizard-troubleshoot-cloud-printer")
  387. }
  388. }
  389. }
  390. }
  391. }
  392. Item
  393. {
  394. Layout.fillWidth: true
  395. Layout.preferredHeight: childrenRect.height
  396. Layout.alignment: Qt.AlignBottom
  397. Cura.SecondaryButton
  398. {
  399. anchors.left: parent.left
  400. text: catalog.i18nc("@button", "Sync materials with USB")
  401. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  402. }
  403. Cura.PrimaryButton
  404. {
  405. id: syncButton
  406. anchors.right: parent.right
  407. text:
  408. {
  409. if(typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "error")
  410. {
  411. return catalog.i18nc("@button", "Try again");
  412. }
  413. if(typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "success")
  414. {
  415. return catalog.i18nc("@button", "Done");
  416. }
  417. return catalog.i18nc("@button", "Sync");
  418. }
  419. onClicked:
  420. {
  421. if(typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "success")
  422. {
  423. materialsSyncDialog.close();
  424. }
  425. else
  426. {
  427. syncModel.exportUpload();
  428. }
  429. }
  430. visible:
  431. {
  432. if(!syncModel) //When the dialog is created, this is not set yet.
  433. {
  434. return true;
  435. }
  436. return syncModel.exportUploadStatus != "uploading";
  437. }
  438. }
  439. Item
  440. {
  441. anchors.right: parent.right
  442. width: childrenRect.width
  443. height: syncButton.height
  444. visible: !syncButton.visible
  445. UM.RecolorImage
  446. {
  447. id: syncingIcon
  448. height: UM.Theme.getSize("action_button_icon").height
  449. width: height
  450. anchors.verticalCenter: syncingLabel.verticalCenter
  451. source: UM.Theme.getIcon("ArrowDoubleCircleRight")
  452. color: UM.Theme.getColor("primary")
  453. RotationAnimator
  454. {
  455. target: syncingIcon
  456. from: 0
  457. to: 360
  458. duration: 1000
  459. loops: Animation.Infinite
  460. running: true
  461. }
  462. }
  463. UM.Label
  464. {
  465. id: syncingLabel
  466. anchors.left: syncingIcon.right
  467. anchors.leftMargin: UM.Theme.getSize("narrow_margin").width
  468. text: catalog.i18nc("@button", "Syncing")
  469. color: UM.Theme.getColor("primary")
  470. font: UM.Theme.getFont("medium")
  471. }
  472. }
  473. }
  474. }
  475. // Placeholder for when the user has no cloud printers.
  476. ColumnLayout
  477. {
  478. spacing: UM.Theme.getSize("default_margin").height
  479. anchors.fill: parent
  480. anchors.margins: UM.Theme.getSize("default_margin").width
  481. visible: cloudPrinterList.count == 0
  482. UM.Label
  483. {
  484. text: catalog.i18nc("@title:header", "No printers found")
  485. font: UM.Theme.getFont("large_bold")
  486. Layout.fillWidth: true
  487. }
  488. Item
  489. {
  490. Layout.fillWidth: true
  491. Layout.fillHeight: true
  492. Image
  493. {
  494. anchors.fill: parent
  495. source: UM.Theme.getImage("3d_printer_faded")
  496. sourceSize.width: width
  497. fillMode: Image.PreserveAspectFit
  498. }
  499. }
  500. UM.Label
  501. {
  502. text: catalog.i18nc("@text", "It seems like you don't have any compatible printers connected to Digital Factory. Make sure your printer is connected and it's running the latest firmware.")
  503. Layout.fillWidth: true
  504. horizontalAlignment: Text.AlignHCenter
  505. wrapMode: Text.Wrap
  506. }
  507. Item
  508. {
  509. Layout.fillWidth: true
  510. Layout.preferredHeight: parent.height / 4
  511. Cura.TertiaryButton
  512. {
  513. text: catalog.i18nc("@button", "Learn how to connect your printer to Digital Factory")
  514. iconSource: UM.Theme.getIcon("LinkExternal")
  515. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/360012019239?utm_source=cura&utm_medium=software&utm_campaign=sync-material-wizard-add-cloud-printer")
  516. anchors.horizontalCenter: parent.horizontalCenter
  517. maximumWidth: parent.width
  518. }
  519. }
  520. Item
  521. {
  522. Layout.preferredHeight: childrenRect.height
  523. Layout.alignment: Qt.AlignBottom
  524. Layout.fillWidth: true
  525. Cura.SecondaryButton
  526. {
  527. anchors.left: parent.left
  528. text: catalog.i18nc("@button", "Sync materials with USB")
  529. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  530. }
  531. RowLayout
  532. {
  533. anchors.right: parent.right
  534. spacing: UM.Theme.getSize("default_margin").width
  535. Cura.SecondaryButton
  536. {
  537. text: catalog.i18nc("@button", "Refresh")
  538. iconSource: UM.Theme.getIcon("ArrowDoubleCircleRight")
  539. outlineColor: "transparent"
  540. onClicked: Cura.API.account.sync(true)
  541. }
  542. Cura.PrimaryButton
  543. {
  544. id: disabledSyncButton
  545. text: catalog.i18nc("@button", "Sync")
  546. enabled: false // If there are no printers, always disable this button.
  547. }
  548. }
  549. }
  550. }
  551. }
  552. Item
  553. {
  554. id: removableDriveSyncPage
  555. ColumnLayout
  556. {
  557. spacing: UM.Theme.getSize("default_margin").height
  558. anchors.fill: parent
  559. anchors.margins: UM.Theme.getSize("default_margin").width
  560. UM.Label
  561. {
  562. text: catalog.i18nc("@title:header", "Sync material profiles via USB")
  563. font: UM.Theme.getFont("large_bold")
  564. Layout.fillWidth: true
  565. }
  566. UM.Label
  567. {
  568. text: catalog.i18nc("@text In the UI this is followed by a list of steps the user needs to take.", "Follow the following steps to load the new material profiles to your printer.")
  569. font: UM.Theme.getFont("medium")
  570. wrapMode: Text.Wrap
  571. Layout.fillWidth: true
  572. }
  573. RowLayout
  574. {
  575. Layout.fillWidth: true
  576. Layout.fillHeight: true
  577. spacing: UM.Theme.getSize("default_margin").width
  578. Item
  579. {
  580. Layout.preferredWidth: parent.width / 3
  581. Layout.fillHeight: true
  582. Image
  583. {
  584. anchors.fill: parent
  585. source: UM.Theme.getImage("insert_usb")
  586. verticalAlignment: Image.AlignVCenter
  587. horizontalAlignment: Image.AlignHCenter
  588. fillMode: Image.PreserveAspectFit
  589. sourceSize.width: width
  590. }
  591. }
  592. UM.Label
  593. {
  594. Layout.alignment: Qt.AlignCenter
  595. Layout.fillWidth: true
  596. text: "1. " + catalog.i18nc("@text", "Click the export material archive button.")
  597. + "\n2. " + catalog.i18nc("@text", "Save the .umm file on a USB stick.")
  598. + "\n3. " + catalog.i18nc("@text", "Insert the USB stick into your printer and launch the procedure to load new material profiles.")
  599. font: UM.Theme.getFont("medium")
  600. }
  601. }
  602. Cura.TertiaryButton
  603. {
  604. Layout.fillWidth: true
  605. text: catalog.i18nc("@button", "How to load new material profiles to my printer")
  606. iconSource: UM.Theme.getIcon("LinkExternal")
  607. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/4403319801106/?utm_source=cura&utm_medium=software&utm_campaign=add-material-profiles-via-usb")
  608. }
  609. Item
  610. {
  611. Layout.preferredHeight: childrenRect.height
  612. Layout.alignment: Qt.AlignBottom
  613. Layout.fillWidth: true
  614. Cura.SecondaryButton
  615. {
  616. anchors.left: parent.left
  617. text: catalog.i18nc("@button", "Back")
  618. onClicked: swipeView.currentIndex = 0 //Reset to first page.
  619. }
  620. Cura.PrimaryButton
  621. {
  622. id: exportUsbButton
  623. anchors.right: parent.right
  624. property bool hasExported: false
  625. text: materialsSyncDialog.hasExportedUsb ? catalog.i18nc("@button", "Done") : catalog.i18nc("@button", "Export material archive")
  626. onClicked:
  627. {
  628. if(!materialsSyncDialog.hasExportedUsb)
  629. {
  630. exportUsbDialog.folder = syncModel.getPreferredExportAllPath();
  631. exportUsbDialog.open();
  632. }
  633. else
  634. {
  635. materialsSyncDialog.close();
  636. }
  637. }
  638. }
  639. }
  640. }
  641. }
  642. }
  643. property variant cloudPrinterList: Cura.GlobalStacksModel
  644. {
  645. filterConnectionType: 3 //Only show cloud connections.
  646. filterOnlineOnly: true //Only show printers that are online.
  647. filterCapabilities: ["import_material"] //Only show printers that can receive the material profiles.
  648. }
  649. property variant includeOfflinePrinterList: Cura.GlobalStacksModel
  650. {
  651. //In order to show a refresh button only when there are offline cloud printers, we need to know if there are any offline printers.
  652. //A global stacks model without the filter for online-only printers allows this.
  653. filterConnectionType: 3 //Still only show cloud connections.
  654. }
  655. property variant exportUsbDialog: FileDialog
  656. {
  657. title: catalog.i18nc("@title:window", "Export All Materials")
  658. selectExisting: false
  659. nameFilters: ["Material archives (*.umm)", "All files (*)"]
  660. onAccepted:
  661. {
  662. syncModel.exportAll(fileUrl);
  663. CuraApplication.setDefaultPath("dialog_material_path", folder);
  664. materialsSyncDialog.hasExportedUsb = true;
  665. }
  666. }
  667. }