DiscoverUM3Action.qml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. // Copyright (c) 2019 Ultimaker B.V.
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import UM 1.2 as UM
  4. import Cura 1.5 as Cura
  5. import QtQuick 2.2
  6. import QtQuick.Controls 1.1
  7. import QtQuick.Layouts 1.1
  8. import QtQuick.Window 2.1
  9. import QtQuick.Dialogs 1.2
  10. Cura.MachineAction
  11. {
  12. id: base
  13. anchors.fill: parent;
  14. property alias currentItemIndex: listview.currentIndex
  15. property var selectedDevice: null
  16. property bool completeProperties: true
  17. // For validating IP addresses
  18. property var networkingUtil: Cura.NetworkingUtil {}
  19. function connectToPrinter()
  20. {
  21. if (base.selectedDevice && base.completeProperties)
  22. {
  23. manager.associateActiveMachineWithPrinterDevice(base.selectedDevice)
  24. completed()
  25. }
  26. }
  27. Column
  28. {
  29. anchors.fill: parent;
  30. id: discoverUM3Action
  31. spacing: UM.Theme.getSize("default_margin").height
  32. SystemPalette { id: palette }
  33. UM.I18nCatalog { id: catalog; name:"cura" }
  34. Label
  35. {
  36. id: pageTitle
  37. width: parent.width
  38. text: catalog.i18nc("@title:window", "Connect to Networked Printer")
  39. wrapMode: Text.WordWrap
  40. renderType: Text.NativeRendering
  41. font.pointSize: 18
  42. }
  43. Label
  44. {
  45. id: pageDescription
  46. width: parent.width
  47. wrapMode: Text.WordWrap
  48. renderType: Text.NativeRendering
  49. text: catalog.i18nc("@label", "To print directly to your printer over the network, please make sure your printer is connected to the network using a network cable or by connecting your printer to your WIFI network. If you don't connect Cura with your printer, you can still use a USB drive to transfer g-code files to your printer.") + "\n\n" + catalog.i18nc("@label", "Select your printer from the list below:")
  50. }
  51. Row
  52. {
  53. spacing: UM.Theme.getSize("default_lining").width
  54. Button
  55. {
  56. id: addButton
  57. text: catalog.i18nc("@action:button", "Add");
  58. onClicked:
  59. {
  60. manualPrinterDialog.showDialog("", "");
  61. }
  62. }
  63. Button
  64. {
  65. id: editButton
  66. text: catalog.i18nc("@action:button", "Edit")
  67. enabled: base.selectedDevice != null && base.selectedDevice.getProperty("manual") == "true"
  68. onClicked:
  69. {
  70. manualPrinterDialog.showDialog(base.selectedDevice.key, base.selectedDevice.ipAddress);
  71. }
  72. }
  73. Button
  74. {
  75. id: removeButton
  76. text: catalog.i18nc("@action:button", "Remove")
  77. enabled: base.selectedDevice != null && base.selectedDevice.getProperty("manual") == "true"
  78. onClicked: manager.removeManualDevice(base.selectedDevice.key, base.selectedDevice.ipAddress)
  79. }
  80. Button
  81. {
  82. id: rediscoverButton
  83. text: catalog.i18nc("@action:button", "Refresh")
  84. onClicked: manager.restartDiscovery()
  85. }
  86. }
  87. Row
  88. {
  89. id: contentRow
  90. width: parent.width
  91. spacing: UM.Theme.getSize("default_margin").width
  92. Column
  93. {
  94. width: Math.round(parent.width * 0.5)
  95. spacing: UM.Theme.getSize("default_margin").height
  96. ScrollView
  97. {
  98. id: objectListContainer
  99. frameVisible: true
  100. width: parent.width
  101. height: base.height - contentRow.y - discoveryTip.height
  102. Rectangle
  103. {
  104. parent: viewport
  105. anchors.fill: parent
  106. color: palette.light
  107. }
  108. ListView
  109. {
  110. id: listview
  111. model: manager.foundDevices
  112. width: parent.width
  113. currentIndex: -1
  114. onCurrentIndexChanged:
  115. {
  116. base.selectedDevice = listview.model[currentIndex];
  117. // Only allow connecting if the printer has responded to API query since the last refresh
  118. base.completeProperties = base.selectedDevice != null && base.selectedDevice.getProperty("incomplete") != "true";
  119. }
  120. Component.onCompleted: manager.startDiscovery()
  121. delegate: Rectangle
  122. {
  123. height: childrenRect.height
  124. color: ListView.isCurrentItem ? palette.highlight : index % 2 ? palette.base : palette.alternateBase
  125. width: parent.width
  126. Label
  127. {
  128. anchors.left: parent.left
  129. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  130. anchors.right: parent.right
  131. text: listview.model[index].name
  132. color: parent.ListView.isCurrentItem ? palette.highlightedText : palette.text
  133. elide: Text.ElideRight
  134. renderType: Text.NativeRendering
  135. }
  136. MouseArea
  137. {
  138. anchors.fill: parent;
  139. onClicked:
  140. {
  141. if(!parent.ListView.isCurrentItem)
  142. {
  143. parent.ListView.view.currentIndex = index;
  144. }
  145. }
  146. }
  147. }
  148. }
  149. }
  150. Label
  151. {
  152. id: discoveryTip
  153. anchors.left: parent.left
  154. anchors.right: parent.right
  155. wrapMode: Text.WordWrap
  156. renderType: Text.NativeRendering
  157. text: catalog.i18nc("@label", "If your printer is not listed, read the <a href='%1'>network printing troubleshooting guide</a>").arg("https://support.ultimaker.com/hc/en-us/articles/360012795419");
  158. onLinkActivated: Qt.openUrlExternally(link)
  159. }
  160. }
  161. Column
  162. {
  163. width: Math.round(parent.width * 0.5)
  164. visible: base.selectedDevice ? true : false
  165. spacing: UM.Theme.getSize("default_margin").height
  166. Label
  167. {
  168. width: parent.width
  169. wrapMode: Text.WordWrap
  170. text: base.selectedDevice ? base.selectedDevice.name : ""
  171. font: UM.Theme.getFont("large_bold")
  172. elide: Text.ElideRight
  173. renderType: Text.NativeRendering
  174. }
  175. Grid
  176. {
  177. visible: base.completeProperties
  178. width: parent.width
  179. columns: 2
  180. Label
  181. {
  182. width: Math.round(parent.width * 0.5)
  183. wrapMode: Text.WordWrap
  184. renderType: Text.NativeRendering
  185. text: catalog.i18nc("@label", "Type")
  186. }
  187. Label
  188. {
  189. width: Math.round(parent.width * 0.5)
  190. wrapMode: Text.WordWrap
  191. renderType: Text.NativeRendering
  192. text:
  193. {
  194. if (base.selectedDevice) {
  195. return base.selectedDevice.printerTypeName
  196. }
  197. return ""
  198. }
  199. }
  200. Label
  201. {
  202. width: Math.round(parent.width * 0.5)
  203. wrapMode: Text.WordWrap
  204. renderType: Text.NativeRendering
  205. text: catalog.i18nc("@label", "Firmware version")
  206. }
  207. Label
  208. {
  209. width: Math.round(parent.width * 0.5)
  210. wrapMode: Text.WordWrap
  211. renderType: Text.NativeRendering
  212. text: base.selectedDevice ? base.selectedDevice.firmwareVersion : ""
  213. }
  214. Label
  215. {
  216. width: Math.round(parent.width * 0.5)
  217. wrapMode: Text.WordWrap
  218. renderType: Text.NativeRendering
  219. text: catalog.i18nc("@label", "Address")
  220. }
  221. Label
  222. {
  223. width: Math.round(parent.width * 0.5)
  224. wrapMode: Text.WordWrap
  225. renderType: Text.NativeRendering
  226. text: base.selectedDevice ? base.selectedDevice.ipAddress : ""
  227. }
  228. }
  229. Label
  230. {
  231. width: parent.width
  232. wrapMode: Text.WordWrap
  233. renderType: Text.NativeRendering
  234. text:{
  235. // The property cluster size does not exist for older UM3 devices.
  236. if(!base.selectedDevice || base.selectedDevice.clusterSize == null || base.selectedDevice.clusterSize == 1)
  237. {
  238. return "";
  239. }
  240. else if (base.selectedDevice.clusterSize === 0)
  241. {
  242. return catalog.i18nc("@label", "This printer is not set up to host a group of printers.");
  243. }
  244. else
  245. {
  246. return catalog.i18nc("@label", "This printer is the host for a group of %1 printers.".arg(base.selectedDevice.clusterSize));
  247. }
  248. }
  249. }
  250. Label
  251. {
  252. width: parent.width
  253. wrapMode: Text.WordWrap
  254. renderType: Text.NativeRendering
  255. visible: base.selectedDevice != null && !base.completeProperties
  256. text: catalog.i18nc("@label", "The printer at this address has not yet responded." )
  257. }
  258. Button
  259. {
  260. text: catalog.i18nc("@action:button", "Connect")
  261. enabled: (base.selectedDevice && base.completeProperties && base.selectedDevice.clusterSize > 0) ? true : false
  262. onClicked: connectToPrinter()
  263. }
  264. }
  265. }
  266. }
  267. MessageDialog
  268. {
  269. id: invalidIPAddressMessageDialog
  270. x: parent ? (parent.x + (parent.width) / 2) : 0
  271. y: parent ? (parent.y + (parent.height) / 2) : 0
  272. title: catalog.i18nc("@title:window", "Invalid IP address")
  273. text: catalog.i18nc("@text", "Please enter a valid IP address.")
  274. icon: StandardIcon.Warning
  275. standardButtons: StandardButton.Ok
  276. }
  277. UM.Dialog
  278. {
  279. id: manualPrinterDialog
  280. property string printerKey
  281. property alias addressText: addressField.text
  282. title: catalog.i18nc("@title:window", "Printer Address")
  283. minimumWidth: 400 * screenScaleFactor
  284. minimumHeight: 130 * screenScaleFactor
  285. width: minimumWidth
  286. height: minimumHeight
  287. signal showDialog(string key, string address)
  288. onShowDialog:
  289. {
  290. printerKey = key;
  291. addressText = address;
  292. manualPrinterDialog.show();
  293. addressField.selectAll();
  294. addressField.focus = true;
  295. }
  296. Column {
  297. anchors.fill: parent
  298. spacing: UM.Theme.getSize("default_margin").height
  299. Label
  300. {
  301. text: catalog.i18nc("@label", "Enter the IP address of your printer on the network.")
  302. width: parent.width
  303. wrapMode: Text.WordWrap
  304. renderType: Text.NativeRendering
  305. }
  306. TextField
  307. {
  308. id: addressField
  309. width: parent.width
  310. validator: RegExpValidator
  311. {
  312. regExp: /[a-zA-Z0-9\.\-\_]*/
  313. }
  314. onAccepted: btnOk.clicked()
  315. }
  316. }
  317. rightButtons: [
  318. Button {
  319. text: catalog.i18nc("@action:button","Cancel")
  320. onClicked:
  321. {
  322. manualPrinterDialog.reject()
  323. manualPrinterDialog.hide()
  324. }
  325. },
  326. Button {
  327. id: btnOk
  328. text: catalog.i18nc("@action:button", "OK")
  329. onClicked:
  330. {
  331. // Validate the input first
  332. if (!networkingUtil.isValidIP(manualPrinterDialog.addressText))
  333. {
  334. invalidIPAddressMessageDialog.open()
  335. return
  336. }
  337. // if the entered IP address has already been discovered, switch the current item to that item
  338. // and do nothing else.
  339. for (var i = 0; i < manager.foundDevices.length; i++)
  340. {
  341. var device = manager.foundDevices[i]
  342. if (device.address == manualPrinterDialog.addressText)
  343. {
  344. currentItemIndex = i
  345. manualPrinterDialog.hide()
  346. return
  347. }
  348. }
  349. manager.setManualDevice(manualPrinterDialog.printerKey, manualPrinterDialog.addressText)
  350. manualPrinterDialog.hide()
  351. }
  352. enabled: manualPrinterDialog.addressText.trim() != ""
  353. isDefault: true
  354. }
  355. ]
  356. }
  357. }