MaterialsSyncDialog.qml 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  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
  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. elide: Text.ElideRight
  209. visible: text !== ""
  210. font: UM.Theme.getFont("medium")
  211. }
  212. Cura.TertiaryButton
  213. {
  214. id: troubleshootingLink
  215. anchors.right: parent.right
  216. text: catalog.i18nc("@button", "Troubleshooting")
  217. visible: typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "error"
  218. iconSource: UM.Theme.getIcon("LinkExternal")
  219. 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")
  220. }
  221. }
  222. ListView
  223. {
  224. id: printerList
  225. Layout.fillWidth: true
  226. Layout.fillHeight: true
  227. clip: true
  228. ScrollBar.vertical: UM.ScrollBar
  229. {
  230. id: printerListScrollBar
  231. }
  232. spacing: UM.Theme.getSize("default_margin").height
  233. model: cloudPrinterList
  234. delegate: Rectangle
  235. {
  236. id: delegateContainer
  237. color: "transparent"
  238. border.color: UM.Theme.getColor("lining")
  239. border.width: UM.Theme.getSize("default_lining").width
  240. width: printerList.width - printerListScrollBar.width
  241. height: UM.Theme.getSize("machine_selector_icon").height + 2 * UM.Theme.getSize("default_margin").height
  242. property string syncStatus:
  243. {
  244. var printer_id = model.metadata["host_guid"]
  245. if(syncModel.printerStatus[printer_id] === undefined) //No status information available. Could be added after we started syncing.
  246. {
  247. return "idle";
  248. }
  249. return syncModel.printerStatus[printer_id];
  250. }
  251. Cura.IconWithText
  252. {
  253. anchors
  254. {
  255. verticalCenter: parent.verticalCenter
  256. left: parent.left
  257. leftMargin: Math.round(parent.height - height) / 2 //Equal margin on the left as above and below.
  258. right: parent.right
  259. rightMargin: Math.round(parent.height - height) / 2
  260. }
  261. text: model.name
  262. font: UM.Theme.getFont("medium")
  263. source: UM.Theme.getIcon("Printer", "medium")
  264. iconColor: UM.Theme.getColor("machine_selector_printer_icon")
  265. iconSize: UM.Theme.getSize("machine_selector_icon").width
  266. //Printer status badge (always cloud, but whether it's online or offline).
  267. UM.ColorImage
  268. {
  269. width: UM.Theme.getSize("printer_status_icon").width
  270. height: UM.Theme.getSize("printer_status_icon").height
  271. anchors
  272. {
  273. bottom: parent.bottom
  274. bottomMargin: -Math.round(height / 6)
  275. left: parent.left
  276. leftMargin: parent.iconSize - Math.round(width * 5 / 6)
  277. }
  278. source: UM.Theme.getIcon("CloudBadge", "low")
  279. color: UM.Theme.getColor("primary")
  280. //Make a themeable circle in the background so we can change it in other themes.
  281. Rectangle
  282. {
  283. anchors.centerIn: parent
  284. 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.
  285. height: parent.height - 1.5
  286. radius: width / 2
  287. color: UM.Theme.getColor("connection_badge_background")
  288. z: parent.z - 1
  289. }
  290. }
  291. }
  292. UM.ColorImage
  293. {
  294. id: printerSpinner
  295. width: UM.Theme.getSize("section_icon").width
  296. height: width
  297. anchors.verticalCenter: parent.verticalCenter
  298. anchors.right: parent.right
  299. anchors.rightMargin: Math.round((parent.height - height) / 2) //Same margin on the right as above and below.
  300. visible: delegateContainer.syncStatus === "uploading"
  301. source: UM.Theme.getIcon("ArrowDoubleCircleRight")
  302. color: UM.Theme.getColor("primary")
  303. RotationAnimator
  304. {
  305. target: printerSpinner
  306. from: 0
  307. to: 360
  308. duration: 1000
  309. loops: Animation.Infinite
  310. running: true
  311. }
  312. }
  313. UM.StatusIcon
  314. {
  315. width: UM.Theme.getSize("section_icon").width
  316. height: width
  317. anchors.verticalCenter: parent.verticalCenter
  318. anchors.right: parent.right
  319. anchors.rightMargin: Math.round((parent.height - height) / 2) //Same margin on the right as above and below.
  320. visible: delegateContainer.syncStatus === "failed" || delegateContainer.syncStatus === "success"
  321. status: delegateContainer.syncStatus === "success" ? UM.StatusIcon.Status.POSITIVE : UM.StatusIcon.Status.ERROR
  322. }
  323. }
  324. footer: Item
  325. {
  326. width: printerList.width - printerListScrollBar.width
  327. height: childrenRect.height + UM.Theme.getSize("default_margin").height
  328. visible: includeOfflinePrinterList.count - cloudPrinterList.count > 0 && typeof syncModel !== "undefined" && syncModel.exportUploadStatus === "idle"
  329. Rectangle
  330. {
  331. anchors.top: parent.top
  332. anchors.left: parent.left
  333. anchors.right: parent.right
  334. border.color: UM.Theme.getColor("lining")
  335. border.width: UM.Theme.getSize("default_lining").width
  336. anchors.topMargin: UM.Theme.getSize("default_margin").height
  337. height: childrenRect.height + 2 * UM.Theme.getSize("thick_margin").height
  338. color: "transparent"
  339. GridLayout
  340. {
  341. columns: 3
  342. rows: 2
  343. anchors.top: parent.top
  344. anchors.left: parent.left
  345. anchors.right: parent.right
  346. anchors.leftMargin: UM.Theme.getSize("thick_margin").width
  347. anchors.rightMargin: UM.Theme.getSize("thick_margin").width
  348. anchors.topMargin: UM.Theme.getSize("thick_margin").height
  349. anchors.bottomMargin: UM.Theme.getSize("thick_margin").height
  350. columnSpacing: UM.Theme.getSize("default_margin").width
  351. rowSpacing: UM.Theme.getSize("default_margin").height
  352. UM.StatusIcon
  353. {
  354. Layout.preferredWidth: UM.Theme.getSize("section_icon").width
  355. Layout.preferredHeight: UM.Theme.getSize("section_icon").height
  356. status: UM.StatusIcon.Status.WARNING
  357. }
  358. UM.Label
  359. {
  360. Layout.fillWidth: true
  361. Layout.alignment: Qt.AlignVCenter
  362. text: catalog.i18nc("@text Asking the user whether printers are missing in a list.", "Printers missing?")
  363. + "\n"
  364. + catalog.i18nc("@text", "Make sure all your printers are turned ON and connected to Digital Factory.")
  365. font: UM.Theme.getFont("medium")
  366. elide: Text.ElideRight
  367. }
  368. Cura.SecondaryButton
  369. {
  370. id: refreshListButton
  371. Layout.alignment: Qt.AlignVCenter
  372. text: catalog.i18nc("@button", "Refresh List")
  373. iconSource: UM.Theme.getIcon("ArrowDoubleCircleRight")
  374. onClicked: Cura.API.account.sync(true)
  375. }
  376. Cura.TertiaryButton
  377. {
  378. id: printerListTroubleshooting
  379. Layout.column: 1
  380. Layout.row: 1
  381. Layout.fillWidth: true
  382. leftPadding: 0
  383. text: catalog.i18nc("@button", "Troubleshooting")
  384. iconSource: UM.Theme.getIcon("LinkExternal")
  385. 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")
  386. }
  387. }
  388. }
  389. }
  390. }
  391. Item
  392. {
  393. Layout.fillWidth: true
  394. Layout.preferredHeight: childrenRect.height
  395. Layout.alignment: Qt.AlignBottom
  396. Cura.SecondaryButton
  397. {
  398. anchors.left: parent.left
  399. text: catalog.i18nc("@button", "Sync materials with USB")
  400. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  401. }
  402. Cura.PrimaryButton
  403. {
  404. id: syncButton
  405. anchors.right: parent.right
  406. text:
  407. {
  408. if(typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "error")
  409. {
  410. return catalog.i18nc("@button", "Try again");
  411. }
  412. if(typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "success")
  413. {
  414. return catalog.i18nc("@button", "Done");
  415. }
  416. return catalog.i18nc("@button", "Sync");
  417. }
  418. onClicked:
  419. {
  420. if(typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "success")
  421. {
  422. materialsSyncDialog.close();
  423. }
  424. else
  425. {
  426. syncModel.exportUpload();
  427. }
  428. }
  429. visible:
  430. {
  431. if(!syncModel) //When the dialog is created, this is not set yet.
  432. {
  433. return true;
  434. }
  435. return syncModel.exportUploadStatus != "uploading";
  436. }
  437. }
  438. Item
  439. {
  440. anchors.right: parent.right
  441. width: childrenRect.width
  442. height: syncButton.height
  443. visible: !syncButton.visible
  444. UM.ColorImage
  445. {
  446. id: syncingIcon
  447. height: UM.Theme.getSize("action_button_icon").height
  448. width: height
  449. anchors.verticalCenter: syncingLabel.verticalCenter
  450. source: UM.Theme.getIcon("ArrowDoubleCircleRight")
  451. color: UM.Theme.getColor("primary")
  452. RotationAnimator
  453. {
  454. target: syncingIcon
  455. from: 0
  456. to: 360
  457. duration: 1000
  458. loops: Animation.Infinite
  459. running: true
  460. }
  461. }
  462. UM.Label
  463. {
  464. id: syncingLabel
  465. anchors.left: syncingIcon.right
  466. anchors.leftMargin: UM.Theme.getSize("narrow_margin").width
  467. text: catalog.i18nc("@button", "Syncing")
  468. color: UM.Theme.getColor("primary")
  469. font: UM.Theme.getFont("medium")
  470. }
  471. }
  472. }
  473. }
  474. // Placeholder for when the user has no cloud printers.
  475. ColumnLayout
  476. {
  477. spacing: UM.Theme.getSize("default_margin").height
  478. anchors.fill: parent
  479. anchors.margins: UM.Theme.getSize("default_margin").width
  480. visible: cloudPrinterList.count == 0
  481. UM.Label
  482. {
  483. text: catalog.i18nc("@title:header", "No printers found")
  484. font: UM.Theme.getFont("large_bold")
  485. Layout.fillWidth: true
  486. }
  487. Item
  488. {
  489. Layout.fillWidth: true
  490. Layout.fillHeight: true
  491. Image
  492. {
  493. anchors.fill: parent
  494. source: UM.Theme.getImage("3d_printer_faded")
  495. sourceSize.width: width
  496. fillMode: Image.PreserveAspectFit
  497. }
  498. }
  499. UM.Label
  500. {
  501. 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.")
  502. Layout.fillWidth: true
  503. horizontalAlignment: Text.AlignHCenter
  504. }
  505. Item
  506. {
  507. Layout.fillWidth: true
  508. Layout.preferredHeight: parent.height / 4
  509. Cura.TertiaryButton
  510. {
  511. text: catalog.i18nc("@button", "Learn how to connect your printer to Digital Factory")
  512. iconSource: UM.Theme.getIcon("LinkExternal")
  513. 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")
  514. anchors.horizontalCenter: parent.horizontalCenter
  515. maximumWidth: parent.width
  516. }
  517. }
  518. Item
  519. {
  520. Layout.preferredHeight: childrenRect.height
  521. Layout.alignment: Qt.AlignBottom
  522. Layout.fillWidth: true
  523. Cura.SecondaryButton
  524. {
  525. anchors.left: parent.left
  526. text: catalog.i18nc("@button", "Sync materials with USB")
  527. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  528. }
  529. RowLayout
  530. {
  531. anchors.right: parent.right
  532. spacing: UM.Theme.getSize("default_margin").width
  533. Cura.SecondaryButton
  534. {
  535. text: catalog.i18nc("@button", "Refresh")
  536. iconSource: UM.Theme.getIcon("ArrowDoubleCircleRight")
  537. outlineColor: "transparent"
  538. onClicked: Cura.API.account.sync(true)
  539. }
  540. Cura.PrimaryButton
  541. {
  542. id: disabledSyncButton
  543. text: catalog.i18nc("@button", "Sync")
  544. enabled: false // If there are no printers, always disable this button.
  545. }
  546. }
  547. }
  548. }
  549. }
  550. Item
  551. {
  552. id: removableDriveSyncPage
  553. ColumnLayout
  554. {
  555. spacing: UM.Theme.getSize("default_margin").height
  556. anchors.fill: parent
  557. anchors.margins: UM.Theme.getSize("default_margin").width
  558. UM.Label
  559. {
  560. text: catalog.i18nc("@title:header", "Sync material profiles via USB")
  561. font: UM.Theme.getFont("large_bold")
  562. Layout.fillWidth: true
  563. }
  564. UM.Label
  565. {
  566. 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.")
  567. font: UM.Theme.getFont("medium")
  568. Layout.fillWidth: true
  569. }
  570. RowLayout
  571. {
  572. Layout.fillWidth: true
  573. Layout.fillHeight: true
  574. spacing: UM.Theme.getSize("default_margin").width
  575. Item
  576. {
  577. Layout.preferredWidth: parent.width / 3
  578. Layout.fillHeight: true
  579. Image
  580. {
  581. anchors.fill: parent
  582. source: UM.Theme.getImage("insert_usb")
  583. verticalAlignment: Image.AlignVCenter
  584. horizontalAlignment: Image.AlignHCenter
  585. fillMode: Image.PreserveAspectFit
  586. sourceSize.width: width
  587. }
  588. }
  589. UM.Label
  590. {
  591. Layout.alignment: Qt.AlignCenter
  592. Layout.fillWidth: true
  593. text: "1. " + catalog.i18nc("@text", "Click the export material archive button.")
  594. + "\n2. " + catalog.i18nc("@text", "Save the .umm file on a USB stick.")
  595. + "\n3. " + catalog.i18nc("@text", "Insert the USB stick into your printer and launch the procedure to load new material profiles.")
  596. font: UM.Theme.getFont("medium")
  597. }
  598. }
  599. Cura.TertiaryButton
  600. {
  601. Layout.fillWidth: true
  602. text: catalog.i18nc("@button", "How to load new material profiles to my printer")
  603. iconSource: UM.Theme.getIcon("LinkExternal")
  604. 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")
  605. }
  606. Item
  607. {
  608. Layout.preferredHeight: childrenRect.height
  609. Layout.alignment: Qt.AlignBottom
  610. Layout.fillWidth: true
  611. Cura.SecondaryButton
  612. {
  613. anchors.left: parent.left
  614. text: catalog.i18nc("@button", "Back")
  615. onClicked: swipeView.currentIndex = 0 //Reset to first page.
  616. }
  617. Cura.PrimaryButton
  618. {
  619. id: exportUsbButton
  620. anchors.right: parent.right
  621. property bool hasExported: false
  622. text: materialsSyncDialog.hasExportedUsb ? catalog.i18nc("@button", "Done") : catalog.i18nc("@button", "Export material archive")
  623. onClicked:
  624. {
  625. if(!materialsSyncDialog.hasExportedUsb)
  626. {
  627. exportUsbDialog.currentFolder = syncModel.getPreferredExportAllPath();
  628. exportUsbDialog.open();
  629. }
  630. else
  631. {
  632. materialsSyncDialog.close();
  633. }
  634. }
  635. }
  636. }
  637. }
  638. }
  639. }
  640. property variant cloudPrinterList: Cura.GlobalStacksModel
  641. {
  642. filterConnectionType: 3 //Only show cloud connections.
  643. filterOnlineOnly: true //Only show printers that are online.
  644. filterCapabilities: ["import_material"] //Only show printers that can receive the material profiles.
  645. }
  646. property variant includeOfflinePrinterList: Cura.GlobalStacksModel
  647. {
  648. //In order to show a refresh button only when there are offline cloud printers, we need to know if there are any offline printers.
  649. //A global stacks model without the filter for online-only printers allows this.
  650. filterConnectionType: 3 //Still only show cloud connections.
  651. }
  652. property variant exportUsbDialog: FileDialog
  653. {
  654. title: catalog.i18nc("@title:window", "Export All Materials")
  655. nameFilters: ["Material archives (*.umm)", "All files (*)"]
  656. fileMode: FileDialog.SaveFile
  657. onAccepted:
  658. {
  659. syncModel.exportAll(selectedFile);
  660. CuraApplication.setDefaultPath("dialog_material_path", folder);
  661. materialsSyncDialog.hasExportedUsb = true;
  662. }
  663. }
  664. }