Cura.qml 33 KB

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