Cura.qml 32 KB

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