Cura.qml 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  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_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+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_mimetypes": "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_mimetypes": "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:settings", "&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 Only show in dev mode. Remove check when feature ready
  199. BuildplateMenu { title: catalog.i18nc("@title:menu", "&Build plate"); visible: CuraSDKVersion == "dev" ? Cura.MachineManager.hasVariantBuildplates : false }
  200. ProfileMenu { title: catalog.i18nc("@title:settings", "&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. containerStack: Cura.MachineManager.activeMachine
  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/Materials/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. onVisibilityChanged:
  617. {
  618. if (!visible)
  619. {
  620. // reset the text to default because other modules may change the message text.
  621. text = catalog.i18nc("@label", "Are you sure you want to exit Cura?");
  622. }
  623. }
  624. }
  625. Connections
  626. {
  627. target: CuraApplication
  628. onShowConfirmExitDialog:
  629. {
  630. exitConfirmationDialog.text = message;
  631. exitConfirmationDialog.open();
  632. }
  633. }
  634. Connections
  635. {
  636. target: Cura.Actions.quit
  637. onTriggered: CuraApplication.checkAndExitApplication();
  638. }
  639. Connections
  640. {
  641. target: Cura.Actions.toggleFullScreen
  642. onTriggered: base.toggleFullscreen();
  643. }
  644. FileDialog
  645. {
  646. id: openDialog;
  647. //: File open dialog title
  648. title: catalog.i18nc("@title:window","Open file(s)")
  649. modality: UM.Application.platform == "linux" ? Qt.NonModal : Qt.WindowModal;
  650. selectMultiple: true
  651. nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
  652. folder: CuraApplication.getDefaultPath("dialog_load_path")
  653. onAccepted:
  654. {
  655. // Because several implementations of the file dialog only update the folder
  656. // when it is explicitly set.
  657. var f = folder;
  658. folder = f;
  659. CuraApplication.setDefaultPath("dialog_load_path", folder);
  660. handleOpenFileUrls(fileUrls);
  661. }
  662. // Yeah... I know... it is a mess to put all those things here.
  663. // There are lots of user interactions in this part of the logic, such as showing a warning dialog here and there,
  664. // etc. This means it will come back and forth from time to time between QML and Python. So, separating the logic
  665. // and view here may require more effort but make things more difficult to understand.
  666. function handleOpenFileUrls(fileUrlList)
  667. {
  668. // look for valid project files
  669. var projectFileUrlList = [];
  670. var hasGcode = false;
  671. var nonGcodeFileList = [];
  672. for (var i in fileUrlList)
  673. {
  674. var endsWithG = /\.g$/;
  675. var endsWithGcode = /\.gcode$/;
  676. if (endsWithG.test(fileUrlList[i]) || endsWithGcode.test(fileUrlList[i]))
  677. {
  678. continue;
  679. }
  680. else if (CuraApplication.checkIsValidProjectFile(fileUrlList[i]))
  681. {
  682. projectFileUrlList.push(fileUrlList[i]);
  683. }
  684. nonGcodeFileList.push(fileUrlList[i]);
  685. }
  686. hasGcode = nonGcodeFileList.length < fileUrlList.length;
  687. // show a warning if selected multiple files together with Gcode
  688. var hasProjectFile = projectFileUrlList.length > 0;
  689. var selectedMultipleFiles = fileUrlList.length > 1;
  690. if (selectedMultipleFiles && hasGcode)
  691. {
  692. infoMultipleFilesWithGcodeDialog.selectedMultipleFiles = selectedMultipleFiles;
  693. infoMultipleFilesWithGcodeDialog.hasProjectFile = hasProjectFile;
  694. infoMultipleFilesWithGcodeDialog.fileUrls = nonGcodeFileList.slice();
  695. infoMultipleFilesWithGcodeDialog.projectFileUrlList = projectFileUrlList.slice();
  696. infoMultipleFilesWithGcodeDialog.open();
  697. }
  698. else
  699. {
  700. handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList);
  701. }
  702. }
  703. function handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList)
  704. {
  705. // we only allow opening one project file
  706. if (selectedMultipleFiles && hasProjectFile)
  707. {
  708. openFilesIncludingProjectsDialog.fileUrls = fileUrlList.slice();
  709. openFilesIncludingProjectsDialog.show();
  710. return;
  711. }
  712. if (hasProjectFile)
  713. {
  714. var projectFile = projectFileUrlList[0];
  715. // check preference
  716. var choice = UM.Preferences.getValue("cura/choice_on_open_project");
  717. if (choice == "open_as_project")
  718. {
  719. openFilesIncludingProjectsDialog.loadProjectFile(projectFile);
  720. }
  721. else if (choice == "open_as_model")
  722. {
  723. openFilesIncludingProjectsDialog.loadModelFiles([projectFile].slice());
  724. }
  725. else // always ask
  726. {
  727. // ask whether to open as project or as models
  728. askOpenAsProjectOrModelsDialog.fileUrl = projectFile;
  729. askOpenAsProjectOrModelsDialog.show();
  730. }
  731. }
  732. else
  733. {
  734. openFilesIncludingProjectsDialog.loadModelFiles(fileUrlList.slice());
  735. }
  736. }
  737. }
  738. MessageDialog
  739. {
  740. id: packageInstallDialog
  741. title: catalog.i18nc("@window:title", "Install Package");
  742. standardButtons: StandardButton.Ok
  743. modality: Qt.ApplicationModal
  744. }
  745. MessageDialog {
  746. id: infoMultipleFilesWithGcodeDialog
  747. title: catalog.i18nc("@title:window", "Open File(s)")
  748. icon: StandardIcon.Information
  749. standardButtons: StandardButton.Ok
  750. 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.")
  751. property var selectedMultipleFiles
  752. property var hasProjectFile
  753. property var fileUrls
  754. property var projectFileUrlList
  755. onAccepted:
  756. {
  757. openDialog.handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrls, projectFileUrlList);
  758. }
  759. }
  760. Connections
  761. {
  762. target: Cura.Actions.open
  763. onTriggered: openDialog.open()
  764. }
  765. OpenFilesIncludingProjectsDialog
  766. {
  767. id: openFilesIncludingProjectsDialog
  768. }
  769. AskOpenAsProjectOrModelsDialog
  770. {
  771. id: askOpenAsProjectOrModelsDialog
  772. }
  773. Connections
  774. {
  775. target: CuraApplication
  776. onOpenProjectFile:
  777. {
  778. askOpenAsProjectOrModelsDialog.fileUrl = project_file;
  779. askOpenAsProjectOrModelsDialog.show();
  780. }
  781. }
  782. EngineLog
  783. {
  784. id: engineLog;
  785. }
  786. Connections
  787. {
  788. target: Cura.Actions.showProfileFolder
  789. onTriggered:
  790. {
  791. var path = UM.Resources.getPath(UM.Resources.Preferences, "");
  792. if(Qt.platform.os == "windows") {
  793. path = path.replace(/\\/g,"/");
  794. }
  795. Qt.openUrlExternally(path);
  796. if(Qt.platform.os == "linux") {
  797. Qt.openUrlExternally(UM.Resources.getPath(UM.Resources.Resources, ""));
  798. }
  799. }
  800. }
  801. AddMachineDialog
  802. {
  803. id: addMachineDialog
  804. onMachineAdded:
  805. {
  806. machineActionsWizard.firstRun = addMachineDialog.firstRun
  807. machineActionsWizard.start(id)
  808. }
  809. }
  810. // Dialog to handle first run machine actions
  811. UM.Wizard
  812. {
  813. id: machineActionsWizard;
  814. title: catalog.i18nc("@title:window", "Add Printer")
  815. property var machine;
  816. function start(id)
  817. {
  818. var actions = Cura.MachineActionManager.getFirstStartActions(id)
  819. resetPages() // Remove previous pages
  820. for (var i = 0; i < actions.length; i++)
  821. {
  822. actions[i].displayItem.reset()
  823. machineActionsWizard.appendPage(actions[i].displayItem, catalog.i18nc("@title", actions[i].label));
  824. }
  825. //Only start if there are actions to perform.
  826. if (actions.length > 0)
  827. {
  828. machineActionsWizard.currentPage = 0;
  829. show()
  830. }
  831. }
  832. }
  833. MessageDialog
  834. {
  835. id: messageDialog
  836. modality: Qt.ApplicationModal
  837. onAccepted: CuraApplication.messageBoxClosed(clickedButton)
  838. onApply: CuraApplication.messageBoxClosed(clickedButton)
  839. onDiscard: CuraApplication.messageBoxClosed(clickedButton)
  840. onHelp: CuraApplication.messageBoxClosed(clickedButton)
  841. onNo: CuraApplication.messageBoxClosed(clickedButton)
  842. onRejected: CuraApplication.messageBoxClosed(clickedButton)
  843. onReset: CuraApplication.messageBoxClosed(clickedButton)
  844. onYes: CuraApplication.messageBoxClosed(clickedButton)
  845. }
  846. Connections
  847. {
  848. target: CuraApplication
  849. onShowMessageBox:
  850. {
  851. messageDialog.title = title
  852. messageDialog.text = text
  853. messageDialog.informativeText = informativeText
  854. messageDialog.detailedText = detailedText
  855. messageDialog.standardButtons = buttons
  856. messageDialog.icon = icon
  857. messageDialog.visible = true
  858. }
  859. }
  860. DiscardOrKeepProfileChangesDialog
  861. {
  862. id: discardOrKeepProfileChangesDialog
  863. }
  864. Connections
  865. {
  866. target: CuraApplication
  867. onShowDiscardOrKeepProfileChanges:
  868. {
  869. discardOrKeepProfileChangesDialog.show()
  870. }
  871. }
  872. Connections
  873. {
  874. target: Cura.Actions.addMachine
  875. onTriggered: addMachineDialog.visible = true;
  876. }
  877. AboutDialog
  878. {
  879. id: aboutDialog
  880. }
  881. Connections
  882. {
  883. target: Cura.Actions.about
  884. onTriggered: aboutDialog.visible = true;
  885. }
  886. Connections
  887. {
  888. target: CuraApplication
  889. onRequestAddPrinter:
  890. {
  891. addMachineDialog.visible = true
  892. addMachineDialog.firstRun = false
  893. }
  894. }
  895. Timer
  896. {
  897. id: startupTimer;
  898. interval: 100;
  899. repeat: false;
  900. running: true;
  901. onTriggered:
  902. {
  903. if(!base.visible)
  904. {
  905. base.visible = true;
  906. }
  907. // check later if the user agreement dialog has been closed
  908. if (CuraApplication.needToShowUserAgreement)
  909. {
  910. restart();
  911. }
  912. else if(Cura.MachineManager.activeMachine == null)
  913. {
  914. addMachineDialog.open();
  915. }
  916. }
  917. }
  918. }