Cura.qml 34 KB

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