Cura.qml 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. // Copyright (c) 2015 Ultimaker B.V.
  2. // Cura is released under the terms of the AGPLv3 or higher.
  3. import QtQuick 2.2
  4. import QtQuick.Controls 1.1
  5. import QtQuick.Controls.Styles 1.1
  6. import QtQuick.Layouts 1.1
  7. import QtQuick.Dialogs 1.1
  8. import UM 1.3 as UM
  9. import Cura 1.0 as Cura
  10. import "Menus"
  11. UM.MainWindow
  12. {
  13. id: base
  14. //: Cura application window title
  15. title: catalog.i18nc("@title:window","Cura");
  16. viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0)
  17. property bool monitoringPrint: false
  18. Component.onCompleted:
  19. {
  20. CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
  21. // Workaround silly issues with QML Action's shortcut property.
  22. //
  23. // Currently, there is no way to define shortcuts as "Application Shortcut".
  24. // This means that all Actions are "Window Shortcuts". The code for this
  25. // implements a rather naive check that just checks if any of the action's parents
  26. // are a window. Since the "Actions" object is a singleton it has no parent by
  27. // default. If we set its parent to something contained in this window, the
  28. // shortcut will activate properly because one of its parents is a window.
  29. //
  30. // This has been fixed for QtQuick Controls 2 since the Shortcut item has a context property.
  31. Cura.Actions.parent = backgroundItem
  32. }
  33. Item
  34. {
  35. id: backgroundItem;
  36. anchors.fill: parent;
  37. UM.I18nCatalog{id: catalog; name:"cura"}
  38. signal hasMesh(string name) //this signal sends the filebase name so it can be used for the JobSpecs.qml
  39. function getMeshName(path){
  40. //takes the path the complete path of the meshname and returns only the filebase
  41. var fileName = path.slice(path.lastIndexOf("/") + 1)
  42. var fileBase = fileName.slice(0, fileName.indexOf("."))
  43. return fileBase
  44. }
  45. //DeleteSelection on the keypress backspace event
  46. Keys.onPressed: {
  47. if (event.key == Qt.Key_Backspace)
  48. {
  49. Cura.Actions.deleteSelection.trigger()
  50. }
  51. }
  52. UM.ApplicationMenu
  53. {
  54. id: menu
  55. window: base
  56. Menu
  57. {
  58. id: fileMenu
  59. title: catalog.i18nc("@title:menu menubar:toplevel","&File");
  60. MenuItem
  61. {
  62. action: Cura.Actions.newProject;
  63. }
  64. MenuItem
  65. {
  66. action: Cura.Actions.open;
  67. }
  68. RecentFilesMenu { }
  69. MenuSeparator { }
  70. MenuItem
  71. {
  72. text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File");
  73. enabled: UM.Selection.hasSelection;
  74. iconName: "document-save-as";
  75. onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetype": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"});
  76. }
  77. MenuItem
  78. {
  79. id: saveAsMenu
  80. text: catalog.i18nc("@title:menu menubar:file", "Save &As...")
  81. onTriggered:
  82. {
  83. var localDeviceId = "local_file";
  84. UM.OutputDeviceManager.requestWriteToDevice(localDeviceId, PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetype": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"});
  85. }
  86. }
  87. MenuItem
  88. {
  89. id: saveWorkspaceMenu
  90. text: catalog.i18nc("@title:menu menubar:file","Save project")
  91. onTriggered:
  92. {
  93. if(UM.Preferences.getValue("cura/dialog_on_project_save"))
  94. {
  95. saveWorkspaceDialog.open()
  96. }
  97. else
  98. {
  99. UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "file_type": "workspace" })
  100. }
  101. }
  102. }
  103. MenuItem { action: Cura.Actions.reloadAll; }
  104. MenuSeparator { }
  105. MenuItem { action: Cura.Actions.quit; }
  106. }
  107. Menu
  108. {
  109. title: catalog.i18nc("@title:menu menubar:toplevel","&Edit");
  110. MenuItem { action: Cura.Actions.undo; }
  111. MenuItem { action: Cura.Actions.redo; }
  112. MenuSeparator { }
  113. MenuItem { action: Cura.Actions.selectAll; }
  114. MenuItem { action: Cura.Actions.arrangeAll; }
  115. MenuItem { action: Cura.Actions.deleteSelection; }
  116. MenuItem { action: Cura.Actions.deleteAll; }
  117. MenuItem { action: Cura.Actions.resetAllTranslation; }
  118. MenuItem { action: Cura.Actions.resetAll; }
  119. MenuSeparator { }
  120. MenuItem { action: Cura.Actions.groupObjects;}
  121. MenuItem { action: Cura.Actions.mergeObjects;}
  122. MenuItem { action: Cura.Actions.unGroupObjects;}
  123. }
  124. ViewMenu { title: catalog.i18nc("@title:menu", "&View") }
  125. Menu
  126. {
  127. id: settingsMenu
  128. title: catalog.i18nc("@title:menu", "&Settings")
  129. PrinterMenu { title: catalog.i18nc("@title:menu menubar:toplevel", "&Printer") }
  130. Instantiator
  131. {
  132. model: Cura.ExtrudersModel { simpleNames: true }
  133. Menu {
  134. title: model.name
  135. visible: machineExtruderCount.properties.value > 1
  136. NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.hasVariants; extruderIndex: index }
  137. MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials; extruderIndex: index }
  138. ProfileMenu { title: catalog.i18nc("@title:menu", "&Profile"); }
  139. MenuSeparator { }
  140. MenuItem { text: catalog.i18nc("@action:inmenu", "Set as Active Extruder"); onTriggered: ExtruderManager.setActiveExtruderIndex(model.index) }
  141. }
  142. onObjectAdded: settingsMenu.insertItem(index, object)
  143. onObjectRemoved: settingsMenu.removeItem(object)
  144. }
  145. NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: machineExtruderCount.properties.value <= 1 && Cura.MachineManager.hasVariants }
  146. MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: machineExtruderCount.properties.value <= 1 && Cura.MachineManager.hasMaterials }
  147. ProfileMenu { title: catalog.i18nc("@title:menu", "&Profile"); visible: machineExtruderCount.properties.value <= 1 }
  148. MenuSeparator { }
  149. MenuItem { action: Cura.Actions.configureSettingVisibility }
  150. }
  151. Menu
  152. {
  153. id: extension_menu
  154. title: catalog.i18nc("@title:menu menubar:toplevel","E&xtensions");
  155. Instantiator
  156. {
  157. id: extensions
  158. model: UM.ExtensionModel { }
  159. Menu
  160. {
  161. id: sub_menu
  162. title: model.name;
  163. visible: actions != null
  164. enabled:actions != null
  165. Instantiator
  166. {
  167. model: actions
  168. MenuItem
  169. {
  170. text: model.text
  171. onTriggered: extensions.model.subMenuTriggered(name, model.text)
  172. }
  173. onObjectAdded: sub_menu.insertItem(index, object)
  174. onObjectRemoved: sub_menu.removeItem(object)
  175. }
  176. }
  177. onObjectAdded: extension_menu.insertItem(index, object)
  178. onObjectRemoved: extension_menu.removeItem(object)
  179. }
  180. }
  181. Menu
  182. {
  183. title: catalog.i18nc("@title:menu menubar:toplevel","P&references");
  184. MenuItem { action: Cura.Actions.preferences; }
  185. }
  186. Menu
  187. {
  188. //: Help menu
  189. title: catalog.i18nc("@title:menu menubar:toplevel","&Help");
  190. MenuItem { action: Cura.Actions.showProfileFolder; }
  191. MenuItem { action: Cura.Actions.documentation; }
  192. MenuItem { action: Cura.Actions.reportBug; }
  193. MenuSeparator { }
  194. MenuItem { action: Cura.Actions.about; }
  195. }
  196. }
  197. UM.SettingPropertyProvider
  198. {
  199. id: machineExtruderCount
  200. containerStackId: Cura.MachineManager.activeMachineId
  201. key: "machine_extruder_count"
  202. watchedProperties: [ "value" ]
  203. storeIndex: 0
  204. }
  205. Item
  206. {
  207. id: contentItem;
  208. y: menu.height
  209. width: parent.width;
  210. height: parent.height - menu.height;
  211. Keys.forwardTo: menu
  212. DropArea
  213. {
  214. anchors.fill: parent;
  215. onDropped:
  216. {
  217. if (drop.urls.length > 0)
  218. {
  219. openDialog.handleOpenFileUrls(drop.urls);
  220. }
  221. }
  222. }
  223. JobSpecs
  224. {
  225. id: jobSpecs
  226. anchors
  227. {
  228. bottom: parent.bottom;
  229. right: sidebar.left;
  230. bottomMargin: UM.Theme.getSize("default_margin").height;
  231. rightMargin: UM.Theme.getSize("default_margin").width;
  232. }
  233. }
  234. Loader
  235. {
  236. id: view_panel
  237. anchors.top: viewModeButton.bottom
  238. anchors.topMargin: UM.Theme.getSize("default_margin").height;
  239. anchors.left: viewModeButton.left;
  240. height: childrenRect.height;
  241. source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : "";
  242. }
  243. Button
  244. {
  245. id: openFileButton;
  246. text: catalog.i18nc("@action:button","Open File");
  247. iconSource: UM.Theme.getIcon("load")
  248. style: UM.Theme.styles.tool_button
  249. tooltip: '';
  250. anchors
  251. {
  252. top: parent.top;
  253. left: parent.left;
  254. }
  255. action: Cura.Actions.open;
  256. }
  257. Image
  258. {
  259. id: logo
  260. anchors
  261. {
  262. left: parent.left
  263. leftMargin: UM.Theme.getSize("default_margin").width;
  264. bottom: parent.bottom
  265. bottomMargin: UM.Theme.getSize("default_margin").height;
  266. }
  267. source: UM.Theme.getImage("logo");
  268. width: UM.Theme.getSize("logo").width;
  269. height: UM.Theme.getSize("logo").height;
  270. z: -1;
  271. sourceSize.width: width;
  272. sourceSize.height: height;
  273. }
  274. Toolbar
  275. {
  276. id: toolbar;
  277. property int mouseX: base.mouseX
  278. property int mouseY: base.mouseY
  279. anchors {
  280. top: openFileButton.bottom;
  281. topMargin: UM.Theme.getSize("window_margin").height;
  282. left: parent.left;
  283. }
  284. }
  285. Sidebar
  286. {
  287. id: sidebar;
  288. anchors
  289. {
  290. top: parent.top;
  291. bottom: parent.bottom;
  292. right: parent.right;
  293. }
  294. z: 1
  295. onMonitoringPrintChanged: base.monitoringPrint = monitoringPrint
  296. width: UM.Theme.getSize("sidebar").width;
  297. }
  298. Button
  299. {
  300. id: viewModeButton
  301. anchors
  302. {
  303. top: toolbar.bottom;
  304. topMargin: UM.Theme.getSize("window_margin").height;
  305. left: parent.left;
  306. }
  307. text: catalog.i18nc("@action:button","View Mode");
  308. iconSource: UM.Theme.getIcon("viewmode");
  309. style: UM.Theme.styles.tool_button;
  310. tooltip: "";
  311. enabled: !PrintInformation.preSliced
  312. menu: ViewMenu { }
  313. }
  314. Rectangle
  315. {
  316. id: viewportOverlay
  317. color: UM.Theme.getColor("viewport_overlay")
  318. anchors
  319. {
  320. top: parent.top
  321. bottom: parent.bottom
  322. left:parent.left
  323. right: sidebar.left
  324. }
  325. visible: opacity > 0
  326. opacity: base.monitoringPrint ? 0.75 : 0
  327. Behavior on opacity { NumberAnimation { duration: 100; } }
  328. MouseArea {
  329. anchors.fill: parent
  330. acceptedButtons: Qt.AllButtons
  331. onWheel: wheel.accepted = true
  332. }
  333. }
  334. Image
  335. {
  336. id: cameraImage
  337. width: Math.min(viewportOverlay.width, sourceSize.width)
  338. height: sourceSize.height * width / sourceSize.width
  339. anchors.horizontalCenter: parent.horizontalCenter
  340. anchors.verticalCenter: parent.verticalCenter
  341. anchors.horizontalCenterOffset: - UM.Theme.getSize("sidebar").width / 2
  342. visible: base.monitoringPrint
  343. onVisibleChanged:
  344. {
  345. if(Cura.MachineManager.printerOutputDevices.length == 0 )
  346. {
  347. return;
  348. }
  349. if(visible)
  350. {
  351. Cura.MachineManager.printerOutputDevices[0].startCamera()
  352. } else
  353. {
  354. Cura.MachineManager.printerOutputDevices[0].stopCamera()
  355. }
  356. }
  357. source:
  358. {
  359. if(!base.monitoringPrint)
  360. {
  361. return "";
  362. }
  363. if(Cura.MachineManager.printerOutputDevices.length > 0 && Cura.MachineManager.printerOutputDevices[0].cameraImage)
  364. {
  365. return Cura.MachineManager.printerOutputDevices[0].cameraImage;
  366. }
  367. return "";
  368. }
  369. }
  370. UM.MessageStack
  371. {
  372. anchors
  373. {
  374. horizontalCenter: parent.horizontalCenter
  375. horizontalCenterOffset: -(UM.Theme.getSize("sidebar").width/ 2)
  376. top: parent.verticalCenter;
  377. bottom: parent.bottom;
  378. }
  379. }
  380. }
  381. }
  382. UM.PreferencesDialog
  383. {
  384. id: preferences
  385. Component.onCompleted:
  386. {
  387. //; Remove & re-add the general page as we want to use our own instead of uranium standard.
  388. removePage(0);
  389. insertPage(0, catalog.i18nc("@title:tab","General"), Qt.resolvedUrl("Preferences/GeneralPage.qml"));
  390. removePage(1);
  391. insertPage(1, catalog.i18nc("@title:tab","Settings"), Qt.resolvedUrl("Preferences/SettingVisibilityPage.qml"));
  392. insertPage(2, catalog.i18nc("@title:tab", "Printers"), Qt.resolvedUrl("Preferences/MachinesPage.qml"));
  393. insertPage(3, catalog.i18nc("@title:tab", "Materials"), Qt.resolvedUrl("Preferences/MaterialsPage.qml"));
  394. insertPage(4, catalog.i18nc("@title:tab", "Profiles"), Qt.resolvedUrl("Preferences/ProfilesPage.qml"));
  395. //Force refresh
  396. setPage(0);
  397. }
  398. onVisibleChanged:
  399. {
  400. // When the dialog closes, switch to the General page.
  401. // This prevents us from having a heavy page like Setting Visiblity active in the background.
  402. setPage(0);
  403. }
  404. }
  405. WorkspaceSummaryDialog
  406. {
  407. id: saveWorkspaceDialog
  408. onYes: UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "file_type": "workspace" })
  409. }
  410. Connections
  411. {
  412. target: Cura.Actions.preferences
  413. onTriggered: preferences.visible = true
  414. }
  415. MessageDialog
  416. {
  417. id: newProjectDialog
  418. modality: Qt.ApplicationModal
  419. title: catalog.i18nc("@title:window", "New project")
  420. text: catalog.i18nc("@info:question", "Are you sure you want to start a new project? This will clear the build plate and any unsaved settings.")
  421. standardButtons: StandardButton.Yes | StandardButton.No
  422. icon: StandardIcon.Question
  423. onYes:
  424. {
  425. CuraApplication.deleteAll();
  426. Cura.Actions.resetProfile.trigger();
  427. }
  428. }
  429. Connections
  430. {
  431. target: Cura.Actions.newProject
  432. onTriggered:
  433. {
  434. if(Printer.platformActivity || Cura.MachineManager.hasUserSettings)
  435. {
  436. newProjectDialog.visible = true
  437. }
  438. }
  439. }
  440. Connections
  441. {
  442. target: Cura.Actions.addProfile
  443. onTriggered:
  444. {
  445. preferences.show();
  446. preferences.setPage(4);
  447. // Create a new profile after a very short delay so the preference page has time to initiate
  448. createProfileTimer.start();
  449. }
  450. }
  451. Connections
  452. {
  453. target: Cura.Actions.configureMachines
  454. onTriggered:
  455. {
  456. preferences.visible = true;
  457. preferences.setPage(2);
  458. }
  459. }
  460. Connections
  461. {
  462. target: Cura.Actions.manageProfiles
  463. onTriggered:
  464. {
  465. preferences.visible = true;
  466. preferences.setPage(4);
  467. }
  468. }
  469. Connections
  470. {
  471. target: Cura.Actions.manageMaterials
  472. onTriggered:
  473. {
  474. preferences.visible = true;
  475. preferences.setPage(3)
  476. }
  477. }
  478. Connections
  479. {
  480. target: Cura.Actions.configureSettingVisibility
  481. onTriggered:
  482. {
  483. preferences.visible = true;
  484. preferences.setPage(1);
  485. preferences.getCurrentItem().scrollToSection(source.key);
  486. }
  487. }
  488. Timer
  489. {
  490. id: createProfileTimer
  491. repeat: false
  492. interval: 1
  493. onTriggered: preferences.getCurrentItem().createProfile()
  494. }
  495. // BlurSettings is a way to force the focus away from any of the setting items.
  496. // We need to do this in order to keep the bindings intact.
  497. Connections
  498. {
  499. target: Cura.MachineManager
  500. onBlurSettings:
  501. {
  502. contentItem.forceActiveFocus()
  503. }
  504. }
  505. Menu
  506. {
  507. id: objectContextMenu;
  508. property variant objectId: -1;
  509. MenuItem { action: Cura.Actions.centerObject; }
  510. MenuItem { action: Cura.Actions.deleteObject; }
  511. MenuItem { action: Cura.Actions.multiplyObject; }
  512. MenuSeparator { }
  513. MenuItem { action: Cura.Actions.selectAll; }
  514. MenuItem { action: Cura.Actions.arrangeAll; }
  515. MenuItem { action: Cura.Actions.deleteAll; }
  516. MenuItem { action: Cura.Actions.reloadAll; }
  517. MenuItem { action: Cura.Actions.resetAllTranslation; }
  518. MenuItem { action: Cura.Actions.resetAll; }
  519. MenuSeparator { }
  520. MenuItem { action: Cura.Actions.groupObjects; }
  521. MenuItem { action: Cura.Actions.mergeObjects; }
  522. MenuItem { action: Cura.Actions.unGroupObjects; }
  523. Connections
  524. {
  525. target: Cura.Actions.deleteObject
  526. onTriggered:
  527. {
  528. if(objectContextMenu.objectId != 0)
  529. {
  530. CuraApplication.deleteObject(objectContextMenu.objectId);
  531. objectContextMenu.objectId = 0;
  532. }
  533. }
  534. }
  535. MultiplyObjectOptions
  536. {
  537. id: multiplyObjectOptions
  538. }
  539. Connections
  540. {
  541. target: Cura.Actions.multiplyObject
  542. onTriggered:
  543. {
  544. if(objectContextMenu.objectId != 0)
  545. {
  546. multiplyObjectOptions.objectId = objectContextMenu.objectId;
  547. multiplyObjectOptions.visible = true;
  548. multiplyObjectOptions.reset();
  549. objectContextMenu.objectId = 0;
  550. }
  551. }
  552. }
  553. Connections
  554. {
  555. target: Cura.Actions.centerObject
  556. onTriggered:
  557. {
  558. if(objectContextMenu.objectId != 0)
  559. {
  560. CuraApplication.centerObject(objectContextMenu.objectId);
  561. objectContextMenu.objectId = 0;
  562. }
  563. }
  564. }
  565. }
  566. Menu
  567. {
  568. id: contextMenu;
  569. MenuItem { action: Cura.Actions.selectAll; }
  570. MenuItem { action: Cura.Actions.arrangeAll; }
  571. MenuItem { action: Cura.Actions.deleteAll; }
  572. MenuItem { action: Cura.Actions.reloadAll; }
  573. MenuItem { action: Cura.Actions.resetAllTranslation; }
  574. MenuItem { action: Cura.Actions.resetAll; }
  575. MenuSeparator { }
  576. MenuItem { action: Cura.Actions.groupObjects; }
  577. MenuItem { action: Cura.Actions.mergeObjects; }
  578. MenuItem { action: Cura.Actions.unGroupObjects; }
  579. }
  580. Connections
  581. {
  582. target: UM.Controller
  583. onContextMenuRequested:
  584. {
  585. if(objectId == 0)
  586. {
  587. contextMenu.popup();
  588. } else
  589. {
  590. objectContextMenu.objectId = objectId;
  591. objectContextMenu.popup();
  592. }
  593. }
  594. }
  595. Connections
  596. {
  597. target: Cura.Actions.quit
  598. onTriggered: base.visible = false;
  599. }
  600. Connections
  601. {
  602. target: Cura.Actions.toggleFullScreen
  603. onTriggered: base.toggleFullscreen();
  604. }
  605. FileDialog
  606. {
  607. id: openDialog;
  608. //: File open dialog title
  609. title: catalog.i18nc("@title:window","Open file(s)")
  610. modality: UM.Application.platform == "linux" ? Qt.NonModal : Qt.WindowModal;
  611. selectMultiple: true
  612. nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
  613. folder: CuraApplication.getDefaultPath("dialog_load_path")
  614. onAccepted:
  615. {
  616. // Because several implementations of the file dialog only update the folder
  617. // when it is explicitly set.
  618. var f = folder;
  619. folder = f;
  620. CuraApplication.setDefaultPath("dialog_load_path", folder);
  621. handleOpenFileUrls(fileUrls);
  622. }
  623. // Yeah... I know... it is a mess to put all those things here.
  624. // There are lots of user interactions in this part of the logic, such as showing a warning dialog here and there,
  625. // etc. This means it will come back and forth from time to time between QML and Python. So, separating the logic
  626. // and view here may require more effort but make things more difficult to understand.
  627. function handleOpenFileUrls(fileUrlList)
  628. {
  629. // look for valid project files
  630. var projectFileUrlList = [];
  631. var hasGcode = false;
  632. var nonGcodeFileList = [];
  633. for (var i in fileUrlList)
  634. {
  635. var endsWithG = /\.g$/;
  636. var endsWithGcode = /\.gcode$/;
  637. if (endsWithG.test(fileUrlList[i]) || endsWithGcode.test(fileUrlList[i]))
  638. {
  639. continue;
  640. }
  641. else if (CuraApplication.checkIsValidProjectFile(fileUrlList[i]))
  642. {
  643. projectFileUrlList.push(fileUrlList[i]);
  644. }
  645. nonGcodeFileList.push(fileUrlList[i]);
  646. }
  647. hasGcode = nonGcodeFileList.length < fileUrlList.length;
  648. // show a warning if selected multiple files together with Gcode
  649. var hasProjectFile = projectFileUrlList.length > 0;
  650. var selectedMultipleFiles = fileUrlList.length > 1;
  651. if (selectedMultipleFiles && hasGcode)
  652. {
  653. infoMultipleFilesWithGcodeDialog.selectedMultipleFiles = selectedMultipleFiles;
  654. infoMultipleFilesWithGcodeDialog.hasProjectFile = hasProjectFile;
  655. infoMultipleFilesWithGcodeDialog.fileUrls = nonGcodeFileList.slice();
  656. infoMultipleFilesWithGcodeDialog.projectFileUrlList = projectFileUrlList.slice();
  657. infoMultipleFilesWithGcodeDialog.open();
  658. }
  659. else
  660. {
  661. handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList);
  662. }
  663. }
  664. function handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList)
  665. {
  666. // we only allow opening one project file
  667. if (selectedMultipleFiles && hasProjectFile)
  668. {
  669. openFilesIncludingProjectsDialog.fileUrls = fileUrlList.slice();
  670. openFilesIncludingProjectsDialog.show();
  671. return;
  672. }
  673. if (hasProjectFile)
  674. {
  675. var projectFile = projectFileUrlList[0];
  676. // check preference
  677. var choice = UM.Preferences.getValue("cura/choice_on_open_project");
  678. if (choice == "open_as_project")
  679. {
  680. openFilesIncludingProjectsDialog.loadProjectFile(projectFile);
  681. }
  682. else if (choice == "open_as_model")
  683. {
  684. openFilesIncludingProjectsDialog.loadModelFiles([projectFile].slice());
  685. }
  686. else // always ask
  687. {
  688. // ask whether to open as project or as models
  689. askOpenAsProjectOrModelsDialog.fileUrl = projectFile;
  690. askOpenAsProjectOrModelsDialog.show();
  691. }
  692. }
  693. else
  694. {
  695. openFilesIncludingProjectsDialog.loadModelFiles(fileUrlList.slice());
  696. }
  697. }
  698. }
  699. MessageDialog {
  700. id: infoMultipleFilesWithGcodeDialog
  701. title: catalog.i18nc("@title:window", "Open File(s)")
  702. icon: StandardIcon.Information
  703. standardButtons: StandardButton.Ok
  704. text: catalog.i18nc("@text:window", "We have found one or more G-Code files within the files you have selected. You can only open one G-Code file at a time. If you want to open a G-Code file, please just select only one.")
  705. property var selectedMultipleFiles
  706. property var hasProjectFile
  707. property var fileUrls
  708. property var projectFileUrlList
  709. onAccepted:
  710. {
  711. openDialog.handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrls, projectFileUrlList);
  712. }
  713. }
  714. Connections
  715. {
  716. target: Cura.Actions.open
  717. onTriggered: openDialog.open()
  718. }
  719. OpenFilesIncludingProjectsDialog
  720. {
  721. id: openFilesIncludingProjectsDialog
  722. }
  723. AskOpenAsProjectOrModelsDialog
  724. {
  725. id: askOpenAsProjectOrModelsDialog
  726. }
  727. EngineLog
  728. {
  729. id: engineLog;
  730. }
  731. Connections
  732. {
  733. target: Cura.Actions.showProfileFolder
  734. onTriggered:
  735. {
  736. var path = UM.Resources.getPath(UM.Resources.Preferences, "");
  737. if(Qt.platform.os == "windows") {
  738. path = path.replace(/\\/g,"/");
  739. }
  740. Qt.openUrlExternally(path);
  741. }
  742. }
  743. AddMachineDialog
  744. {
  745. id: addMachineDialog
  746. onMachineAdded:
  747. {
  748. machineActionsWizard.firstRun = addMachineDialog.firstRun
  749. machineActionsWizard.start(id)
  750. }
  751. }
  752. // Dialog to handle first run machine actions
  753. UM.Wizard
  754. {
  755. id: machineActionsWizard;
  756. title: catalog.i18nc("@title:window", "Add Printer")
  757. property var machine;
  758. function start(id)
  759. {
  760. var actions = Cura.MachineActionManager.getFirstStartActions(id)
  761. resetPages() // Remove previous pages
  762. for (var i = 0; i < actions.length; i++)
  763. {
  764. actions[i].displayItem.reset()
  765. machineActionsWizard.appendPage(actions[i].displayItem, catalog.i18nc("@title", actions[i].label));
  766. }
  767. //Only start if there are actions to perform.
  768. if (actions.length > 0)
  769. {
  770. machineActionsWizard.currentPage = 0;
  771. show()
  772. }
  773. }
  774. }
  775. MessageDialog
  776. {
  777. id: messageDialog
  778. modality: Qt.ApplicationModal
  779. onAccepted: CuraApplication.messageBoxClosed(clickedButton)
  780. onApply: CuraApplication.messageBoxClosed(clickedButton)
  781. onDiscard: CuraApplication.messageBoxClosed(clickedButton)
  782. onHelp: CuraApplication.messageBoxClosed(clickedButton)
  783. onNo: CuraApplication.messageBoxClosed(clickedButton)
  784. onRejected: CuraApplication.messageBoxClosed(clickedButton)
  785. onReset: CuraApplication.messageBoxClosed(clickedButton)
  786. onYes: CuraApplication.messageBoxClosed(clickedButton)
  787. }
  788. Connections
  789. {
  790. target: Printer
  791. onShowMessageBox:
  792. {
  793. messageDialog.title = title
  794. messageDialog.text = text
  795. messageDialog.informativeText = informativeText
  796. messageDialog.detailedText = detailedText
  797. messageDialog.standardButtons = buttons
  798. messageDialog.icon = icon
  799. messageDialog.visible = true
  800. }
  801. }
  802. DiscardOrKeepProfileChangesDialog
  803. {
  804. id: discardOrKeepProfileChangesDialog
  805. }
  806. Connections
  807. {
  808. target: Printer
  809. onShowDiscardOrKeepProfileChanges:
  810. {
  811. discardOrKeepProfileChangesDialog.show()
  812. }
  813. }
  814. Connections
  815. {
  816. target: Cura.Actions.addMachine
  817. onTriggered: addMachineDialog.visible = true;
  818. }
  819. AboutDialog
  820. {
  821. id: aboutDialog
  822. }
  823. Connections
  824. {
  825. target: Cura.Actions.about
  826. onTriggered: aboutDialog.visible = true;
  827. }
  828. Connections
  829. {
  830. target: Printer
  831. onRequestAddPrinter:
  832. {
  833. addMachineDialog.visible = true
  834. addMachineDialog.firstRun = false
  835. }
  836. }
  837. Timer
  838. {
  839. id: startupTimer;
  840. interval: 100;
  841. repeat: false;
  842. running: true;
  843. onTriggered:
  844. {
  845. if(!base.visible)
  846. {
  847. base.visible = true;
  848. restart();
  849. }
  850. else if(Cura.MachineManager.activeMachineId == null || Cura.MachineManager.activeMachineId == "")
  851. {
  852. addMachineDialog.open();
  853. }
  854. }
  855. }
  856. }