Cura.qml 34 KB

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