Cura.qml 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. // Copyright (c) 2021 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.Layouts 1.1
  6. import QtQuick.Dialogs 1.2
  7. import QtGraphicalEffects 1.0
  8. import QtQuick.Controls 2.15 as NewControls
  9. import UM 1.5 as UM
  10. import Cura 1.1 as Cura
  11. import "Dialogs"
  12. import "Menus"
  13. import "MainWindow"
  14. import "WelcomePages"
  15. UM.MainWindow
  16. {
  17. id: base
  18. // Cura application window title
  19. title:
  20. {
  21. let result = "";
  22. if(PrintInformation !== null && PrintInformation.jobName != "")
  23. {
  24. result += PrintInformation.jobName + " - ";
  25. }
  26. result += CuraApplication.applicationDisplayName;
  27. return result;
  28. }
  29. backgroundColor: UM.Theme.getColor("viewport_background")
  30. UM.I18nCatalog
  31. {
  32. id: catalog
  33. name: "cura"
  34. }
  35. function showTooltip(item, position, text)
  36. {
  37. tooltip.text = text;
  38. position = item.mapToItem(backgroundItem, position.x - UM.Theme.getSize("default_arrow").width, position.y);
  39. tooltip.show(position);
  40. }
  41. function hideTooltip()
  42. {
  43. tooltip.hide();
  44. }
  45. Rectangle
  46. {
  47. id: greyOutBackground
  48. anchors.fill: parent
  49. visible: welcomeDialogItem.visible
  50. color: UM.Theme.getColor("window_disabled_background")
  51. opacity: 0.7
  52. z: stageMenu.z + 1
  53. MouseArea
  54. {
  55. // Prevent all mouse events from passing through.
  56. enabled: parent.visible
  57. anchors.fill: parent
  58. hoverEnabled: true
  59. acceptedButtons: Qt.AllButtons
  60. }
  61. }
  62. WelcomeDialogItem
  63. {
  64. id: welcomeDialogItem
  65. visible: false
  66. z: greyOutBackground.z + 1
  67. }
  68. Component.onCompleted:
  69. {
  70. CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
  71. CuraApplication.purgeWindows()
  72. }
  73. Connections
  74. {
  75. // This connection is used when there is no ActiveMachine and the user is logged in
  76. target: CuraApplication
  77. function onShowAddPrintersUncancellableDialog()
  78. {
  79. Cura.Actions.parent = backgroundItem
  80. // Reuse the welcome dialog item to show "Add a printer" only.
  81. welcomeDialogItem.model = CuraApplication.getAddPrinterPagesModelWithoutCancel()
  82. welcomeDialogItem.progressBarVisible = false
  83. welcomeDialogItem.visible = true
  84. }
  85. }
  86. Connections
  87. {
  88. target: CuraApplication
  89. function onInitializationFinished()
  90. {
  91. // Workaround silly issues with QML Action's shortcut property.
  92. //
  93. // Currently, there is no way to define shortcuts as "Application Shortcut".
  94. // This means that all Actions are "Window Shortcuts". The code for this
  95. // implements a rather naive check that just checks if any of the action's parents
  96. // are a window. Since the "Actions" object is a singleton it has no parent by
  97. // default. If we set its parent to something contained in this window, the
  98. // shortcut will activate properly because one of its parents is a window.
  99. //
  100. // This has been fixed for QtQuick Controls 2 since the Shortcut item has a context property.
  101. Cura.Actions.parent = backgroundItem
  102. if (CuraApplication.shouldShowWelcomeDialog())
  103. {
  104. welcomeDialogItem.visible = true
  105. }
  106. else
  107. {
  108. welcomeDialogItem.visible = false
  109. }
  110. // Reuse the welcome dialog item to show "What's New" only.
  111. if (CuraApplication.shouldShowWhatsNewDialog())
  112. {
  113. welcomeDialogItem.model = CuraApplication.getWhatsNewPagesModel()
  114. welcomeDialogItem.progressBarVisible = false
  115. welcomeDialogItem.visible = true
  116. }
  117. // Reuse the welcome dialog item to show the "Add printers" dialog. Triggered when there is no active
  118. // machine and the user is logged in.
  119. if (!Cura.MachineManager.activeMachine && Cura.API.account.isLoggedIn)
  120. {
  121. welcomeDialogItem.model = CuraApplication.getAddPrinterPagesModelWithoutCancel()
  122. welcomeDialogItem.progressBarVisible = false
  123. welcomeDialogItem.visible = true
  124. }
  125. }
  126. }
  127. Item
  128. {
  129. id: backgroundItem
  130. anchors.fill: parent
  131. //DeleteSelection on the keypress backspace event
  132. Keys.onPressed:
  133. {
  134. if (event.key == Qt.Key_Backspace)
  135. {
  136. Cura.Actions.deleteSelection.trigger()
  137. }
  138. }
  139. ApplicationMenu
  140. {
  141. id: applicationMenu
  142. }
  143. Item
  144. {
  145. id: headerBackground
  146. anchors
  147. {
  148. top: applicationMenu.bottom
  149. left: parent.left
  150. right: parent.right
  151. }
  152. height: stageMenu.source != "" ? Math.round(mainWindowHeader.height + stageMenu.height / 2) : mainWindowHeader.height
  153. LinearGradient
  154. {
  155. anchors.fill: parent
  156. start: Qt.point(0, 0)
  157. end: Qt.point(parent.width, 0)
  158. gradient: Gradient
  159. {
  160. GradientStop
  161. {
  162. position: 0.0
  163. color: UM.Theme.getColor("main_window_header_background")
  164. }
  165. GradientStop
  166. {
  167. position: 0.5
  168. color: UM.Theme.getColor("main_window_header_background_gradient")
  169. }
  170. GradientStop
  171. {
  172. position: 1.0
  173. color: UM.Theme.getColor("main_window_header_background")
  174. }
  175. }
  176. }
  177. // This is a placeholder for adding a pattern in the header
  178. Image
  179. {
  180. id: backgroundPattern
  181. anchors.fill: parent
  182. fillMode: Image.Tile
  183. source: UM.Theme.getImage("header_pattern")
  184. horizontalAlignment: Image.AlignLeft
  185. verticalAlignment: Image.AlignTop
  186. }
  187. }
  188. MainWindowHeader
  189. {
  190. id: mainWindowHeader
  191. anchors
  192. {
  193. left: parent.left
  194. right: parent.right
  195. top: applicationMenu.bottom
  196. }
  197. }
  198. Item
  199. {
  200. id: contentItem
  201. anchors
  202. {
  203. top: mainWindowHeader.bottom
  204. bottom: parent.bottom
  205. left: parent.left
  206. right: parent.right
  207. }
  208. Keys.forwardTo: applicationMenu
  209. DropArea
  210. {
  211. // The drop area is here to handle files being dropped onto Cura.
  212. anchors.fill: parent
  213. onDropped:
  214. {
  215. if (drop.urls.length > 0)
  216. {
  217. var nonPackages = [];
  218. for (var i = 0; i < drop.urls.length; i++)
  219. {
  220. var filename = drop.urls[i];
  221. if (filename.toLowerCase().endsWith(".curapackage"))
  222. {
  223. // Try to install plugin & close.
  224. CuraApplication.installPackageViaDragAndDrop(filename);
  225. packageInstallDialog.text = catalog.i18nc("@label", "This package will be installed after restarting.");
  226. packageInstallDialog.icon = StandardIcon.Information;
  227. packageInstallDialog.open();
  228. }
  229. else
  230. {
  231. nonPackages.push(filename);
  232. }
  233. }
  234. openDialog.handleOpenFileUrls(nonPackages);
  235. }
  236. }
  237. }
  238. ObjectSelector
  239. {
  240. id: objectSelector
  241. visible: CuraApplication.platformActivity
  242. anchors
  243. {
  244. bottom: jobSpecs.top
  245. left: toolbar.right
  246. leftMargin: UM.Theme.getSize("default_margin").width
  247. rightMargin: UM.Theme.getSize("default_margin").width
  248. bottomMargin: UM.Theme.getSize("narrow_margin").height
  249. }
  250. }
  251. JobSpecs
  252. {
  253. id: jobSpecs
  254. visible: CuraApplication.platformActivity
  255. anchors
  256. {
  257. left: toolbar.right
  258. bottom: viewOrientationControls.top
  259. leftMargin: UM.Theme.getSize("default_margin").width
  260. rightMargin: UM.Theme.getSize("default_margin").width
  261. bottomMargin: UM.Theme.getSize("thin_margin").width
  262. topMargin: UM.Theme.getSize("thin_margin").width
  263. }
  264. }
  265. ViewOrientationControls
  266. {
  267. id: viewOrientationControls
  268. anchors
  269. {
  270. left: toolbar.right
  271. bottom: parent.bottom
  272. margins: UM.Theme.getSize("default_margin").width
  273. }
  274. }
  275. Toolbar
  276. {
  277. // The toolbar is the left bar that is populated by all the tools
  278. // (which are dynamically populated by plugins)
  279. id: toolbar
  280. property int mouseX: base.mouseX
  281. property int mouseY: base.mouseY
  282. anchors
  283. {
  284. verticalCenter: parent.verticalCenter
  285. left: parent.left
  286. }
  287. visible: CuraApplication.platformActivity && !PrintInformation.preSliced
  288. }
  289. // A hint for the loaded content view. Overlay items / controls can safely be placed in this area
  290. Item {
  291. id: mainSafeArea
  292. anchors.left: viewOrientationControls.right
  293. anchors.right: main.right
  294. anchors.top: main.top
  295. anchors.bottom: main.bottom
  296. }
  297. Loader
  298. {
  299. // A stage can control this area. If nothing is set, it will therefore show the 3D view.
  300. id: main
  301. anchors
  302. {
  303. // Align to the top of the stageMenu since the stageMenu may not exist
  304. top: stageMenu.source ? stageMenu.verticalCenter : parent.top
  305. left: parent.left
  306. right: parent.right
  307. bottom: parent.bottom
  308. }
  309. source: UM.Controller.activeStage != null ? UM.Controller.activeStage.mainComponent : ""
  310. onLoaded: {
  311. if (main.item.safeArea !== undefined){
  312. main.item.safeArea = Qt.binding(function() { return mainSafeArea });
  313. }
  314. }
  315. }
  316. Loader
  317. {
  318. // The stage menu is, as the name implies, a menu that is defined by the active stage.
  319. // Note that this menu does not need to be set at all! It's perfectly acceptable to have a stage
  320. // without this menu!
  321. id: stageMenu
  322. anchors
  323. {
  324. left: parent.left
  325. right: parent.right
  326. top: parent.top
  327. }
  328. height: UM.Theme.getSize("stage_menu").height
  329. source: UM.Controller.activeStage != null ? UM.Controller.activeStage.stageMenuComponent : ""
  330. // HACK: This is to ensure that the parent never gets set to null, as this wreaks havoc on the focus.
  331. function onParentDestroyed()
  332. {
  333. printSetupSelector.parent = stageMenu
  334. printSetupSelector.visible = false
  335. }
  336. property Item oldParent: null
  337. // The printSetupSelector is defined here so that the setting list doesn't need to get re-instantiated
  338. // Every time the stage is changed.
  339. property var printSetupSelector: Cura.PrintSetupSelector
  340. {
  341. width: UM.Theme.getSize("print_setup_widget").width
  342. height: UM.Theme.getSize("stage_menu").height
  343. headerCornerSide: RoundedRectangle.Direction.Right
  344. onParentChanged:
  345. {
  346. if(stageMenu.oldParent !=null)
  347. {
  348. stageMenu.oldParent.Component.destruction.disconnect(stageMenu.onParentDestroyed)
  349. }
  350. stageMenu.oldParent = parent
  351. visible = parent != stageMenu
  352. parent.Component.destruction.connect(stageMenu.onParentDestroyed)
  353. }
  354. }
  355. }
  356. UM.MessageStack
  357. {
  358. anchors
  359. {
  360. horizontalCenter: parent.horizontalCenter
  361. top: parent.verticalCenter
  362. bottom: parent.bottom
  363. bottomMargin: UM.Theme.getSize("default_margin").height
  364. }
  365. primaryButton: Component
  366. {
  367. Cura.PrimaryButton
  368. {
  369. text: model.name
  370. iconSource: UM.Theme.getIcon(model.icon)
  371. height: UM.Theme.getSize("message_action_button").height
  372. }
  373. }
  374. secondaryButton: Component
  375. {
  376. Cura.SecondaryButton
  377. {
  378. text: model.name
  379. iconSource: UM.Theme.getIcon(model.icon)
  380. height: UM.Theme.getSize("message_action_button").height
  381. }
  382. }
  383. link: Component
  384. {
  385. Cura.TertiaryButton
  386. {
  387. text: model.name
  388. iconSource:
  389. {
  390. if (model.icon == null || model.icon == "")
  391. {
  392. return UM.Theme.getIcon("LinkExternal")
  393. }
  394. return UM.Theme.getIcon(model.icon)
  395. }
  396. height: UM.Theme.getSize("message_action_button").height
  397. }
  398. }
  399. }
  400. }
  401. PrintSetupTooltip
  402. {
  403. id: tooltip
  404. sourceWidth: UM.Theme.getSize("print_setup_widget").width
  405. }
  406. }
  407. UM.PreferencesDialog
  408. {
  409. id: preferences
  410. Component.onCompleted:
  411. {
  412. //; Remove & re-add the general page as we want to use our own instead of uranium standard.
  413. removePage(0);
  414. insertPage(0, catalog.i18nc("@title:tab","General"), Qt.resolvedUrl("Preferences/GeneralPage.qml"));
  415. removePage(1);
  416. insertPage(1, catalog.i18nc("@title:tab","Settings"), Qt.resolvedUrl("Preferences/SettingVisibilityPage.qml"));
  417. insertPage(2, catalog.i18nc("@title:tab", "Printers"), Qt.resolvedUrl("Preferences/MachinesPage.qml"));
  418. insertPage(3, catalog.i18nc("@title:tab", "Materials"), Qt.resolvedUrl("Preferences/Materials/MaterialsPage.qml"));
  419. insertPage(4, catalog.i18nc("@title:tab", "Profiles"), Qt.resolvedUrl("Preferences/ProfilesPage.qml"));
  420. currentPage = 0;
  421. }
  422. onVisibleChanged:
  423. {
  424. // When the dialog closes, switch to the General page.
  425. // This prevents us from having a heavy page like Setting Visibility active in the background.
  426. setPage(0);
  427. }
  428. }
  429. Connections
  430. {
  431. target: Cura.Actions.preferences
  432. function onTriggered() { preferences.visible = true }
  433. }
  434. Connections
  435. {
  436. target: CuraApplication
  437. function onShowPreferencesWindow() { preferences.visible = true }
  438. }
  439. Connections
  440. {
  441. target: Cura.Actions.addProfile
  442. function onTriggered()
  443. {
  444. preferences.show();
  445. preferences.setPage(4);
  446. // Create a new profile after a very short delay so the preference page has time to initiate
  447. createProfileTimer.start();
  448. }
  449. }
  450. Connections
  451. {
  452. target: Cura.Actions.configureMachines
  453. function onTriggered()
  454. {
  455. preferences.visible = true;
  456. preferences.setPage(2);
  457. }
  458. }
  459. Connections
  460. {
  461. target: Cura.Actions.manageProfiles
  462. function onTriggered()
  463. {
  464. preferences.visible = true;
  465. preferences.setPage(4);
  466. }
  467. }
  468. Connections
  469. {
  470. target: Cura.Actions.manageMaterials
  471. function onTriggered()
  472. {
  473. preferences.visible = true;
  474. preferences.setPage(3)
  475. }
  476. }
  477. Connections
  478. {
  479. target: Cura.Actions.configureSettingVisibility
  480. function onTriggered(source)
  481. {
  482. preferences.visible = true;
  483. preferences.setPage(1);
  484. if(source && source.key)
  485. {
  486. preferences.getCurrentItem().scrollToSection(source.key);
  487. }
  488. }
  489. }
  490. Timer
  491. {
  492. id: createProfileTimer
  493. repeat: false
  494. interval: 1
  495. onTriggered: preferences.getCurrentItem().createProfile()
  496. }
  497. // BlurSettings is a way to force the focus away from any of the setting items.
  498. // We need to do this in order to keep the bindings intact.
  499. Connections
  500. {
  501. target: Cura.MachineManager
  502. function onBlurSettings()
  503. {
  504. contentItem.forceActiveFocus()
  505. }
  506. }
  507. ContextMenu
  508. {
  509. id: contextMenu
  510. }
  511. onPreClosing:
  512. {
  513. close.accepted = CuraApplication.getIsAllChecksPassed();
  514. if (!close.accepted)
  515. {
  516. CuraApplication.checkAndExitApplication();
  517. }
  518. }
  519. MessageDialog
  520. {
  521. id: exitConfirmationDialog
  522. title: catalog.i18nc("@title:window %1 is the application name", "Closing %1").arg(CuraApplication.applicationDisplayName)
  523. text: catalog.i18nc("@label %1 is the application name", "Are you sure you want to exit %1?").arg(CuraApplication.applicationDisplayName)
  524. icon: StandardIcon.Question
  525. modality: Qt.ApplicationModal
  526. standardButtons: StandardButton.Yes | StandardButton.No
  527. onYes: CuraApplication.callConfirmExitDialogCallback(true)
  528. onNo: CuraApplication.callConfirmExitDialogCallback(false)
  529. onRejected: CuraApplication.callConfirmExitDialogCallback(false)
  530. onVisibilityChanged:
  531. {
  532. if (!visible)
  533. {
  534. // reset the text to default because other modules may change the message text.
  535. text = catalog.i18nc("@label %1 is the application name", "Are you sure you want to exit %1?").arg(CuraApplication.applicationDisplayName);
  536. }
  537. }
  538. }
  539. Connections
  540. {
  541. target: CuraApplication
  542. function onShowConfirmExitDialog(message)
  543. {
  544. exitConfirmationDialog.text = message;
  545. exitConfirmationDialog.open();
  546. }
  547. }
  548. Connections
  549. {
  550. target: Cura.Actions.quit
  551. function onTriggered() { CuraApplication.checkAndExitApplication(); }
  552. }
  553. Connections
  554. {
  555. target: Cura.Actions.toggleFullScreen
  556. function onTriggered() { base.toggleFullscreen() }
  557. }
  558. Connections
  559. {
  560. target: Cura.Actions.exitFullScreen
  561. function onTriggered() { base.exitFullscreen() }
  562. }
  563. FileDialog
  564. {
  565. id: openDialog;
  566. //: File open dialog title
  567. title: catalog.i18nc("@title:window","Open file(s)")
  568. modality: Qt.WindowModal
  569. selectMultiple: true
  570. nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
  571. folder:
  572. {
  573. //Because several implementations of the file dialog only update the folder when it is explicitly set.
  574. folder = CuraApplication.getDefaultPath("dialog_load_path");
  575. return CuraApplication.getDefaultPath("dialog_load_path");
  576. }
  577. onAccepted:
  578. {
  579. // Because several implementations of the file dialog only update the folder
  580. // when it is explicitly set.
  581. var f = folder;
  582. folder = f;
  583. CuraApplication.setDefaultPath("dialog_load_path", folder);
  584. handleOpenFileUrls(fileUrls);
  585. }
  586. // Yeah... I know... it is a mess to put all those things here.
  587. // There are lots of user interactions in this part of the logic, such as showing a warning dialog here and there,
  588. // etc. This means it will come back and forth from time to time between QML and Python. So, separating the logic
  589. // and view here may require more effort but make things more difficult to understand.
  590. function handleOpenFileUrls(fileUrlList)
  591. {
  592. // look for valid project files
  593. var projectFileUrlList = [];
  594. var hasGcode = false;
  595. var nonGcodeFileList = [];
  596. for (var i in fileUrlList)
  597. {
  598. var endsWithG = /\.g$/;
  599. var endsWithGcode = /\.gcode$/;
  600. if (endsWithG.test(fileUrlList[i]) || endsWithGcode.test(fileUrlList[i]))
  601. {
  602. continue;
  603. }
  604. else if (CuraApplication.checkIsValidProjectFile(fileUrlList[i]))
  605. {
  606. projectFileUrlList.push(fileUrlList[i]);
  607. }
  608. nonGcodeFileList.push(fileUrlList[i]);
  609. }
  610. hasGcode = nonGcodeFileList.length < fileUrlList.length;
  611. // show a warning if selected multiple files together with Gcode
  612. var hasProjectFile = projectFileUrlList.length > 0;
  613. var selectedMultipleFiles = fileUrlList.length > 1;
  614. if (selectedMultipleFiles && hasGcode)
  615. {
  616. infoMultipleFilesWithGcodeDialog.selectedMultipleFiles = selectedMultipleFiles;
  617. infoMultipleFilesWithGcodeDialog.hasProjectFile = hasProjectFile;
  618. infoMultipleFilesWithGcodeDialog.fileUrls = nonGcodeFileList.slice();
  619. infoMultipleFilesWithGcodeDialog.projectFileUrlList = projectFileUrlList.slice();
  620. infoMultipleFilesWithGcodeDialog.open();
  621. }
  622. else
  623. {
  624. handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList);
  625. }
  626. }
  627. function handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList)
  628. {
  629. // Make sure the files opened through the openFilesIncludingProjectDialog are added to the recent files list
  630. openFilesIncludingProjectsDialog.addToRecent = true;
  631. // we only allow opening one project file
  632. if (selectedMultipleFiles && hasProjectFile)
  633. {
  634. openFilesIncludingProjectsDialog.fileUrls = fileUrlList.slice();
  635. openFilesIncludingProjectsDialog.show();
  636. return;
  637. }
  638. if (hasProjectFile)
  639. {
  640. var projectFile = projectFileUrlList[0];
  641. // check preference
  642. var choice = UM.Preferences.getValue("cura/choice_on_open_project");
  643. if (choice == "open_as_project")
  644. {
  645. openFilesIncludingProjectsDialog.loadProjectFile(projectFile);
  646. }
  647. else if (choice == "open_as_model")
  648. {
  649. openFilesIncludingProjectsDialog.loadModelFiles([projectFile].slice());
  650. }
  651. else // always ask
  652. {
  653. // ask whether to open as project or as models
  654. askOpenAsProjectOrModelsDialog.fileUrl = projectFile;
  655. askOpenAsProjectOrModelsDialog.addToRecent = true;
  656. askOpenAsProjectOrModelsDialog.show();
  657. }
  658. }
  659. else
  660. {
  661. openFilesIncludingProjectsDialog.loadModelFiles(fileUrlList.slice());
  662. }
  663. }
  664. }
  665. MessageDialog
  666. {
  667. id: packageInstallDialog
  668. title: catalog.i18nc("@window:title", "Install Package");
  669. standardButtons: StandardButton.Ok
  670. modality: Qt.ApplicationModal
  671. }
  672. MessageDialog
  673. {
  674. id: infoMultipleFilesWithGcodeDialog
  675. title: catalog.i18nc("@title:window", "Open File(s)")
  676. icon: StandardIcon.Information
  677. standardButtons: StandardButton.Ok
  678. 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.")
  679. property var selectedMultipleFiles
  680. property var hasProjectFile
  681. property var fileUrls
  682. property var projectFileUrlList
  683. onAccepted:
  684. {
  685. openDialog.handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrls, projectFileUrlList);
  686. }
  687. }
  688. Connections
  689. {
  690. target: Cura.Actions.open
  691. function onTriggered() { openDialog.open() }
  692. }
  693. OpenFilesIncludingProjectsDialog
  694. {
  695. id: openFilesIncludingProjectsDialog
  696. }
  697. AskOpenAsProjectOrModelsDialog
  698. {
  699. id: askOpenAsProjectOrModelsDialog
  700. }
  701. Connections
  702. {
  703. target: CuraApplication
  704. function onOpenProjectFile(project_file, add_to_recent_files)
  705. {
  706. askOpenAsProjectOrModelsDialog.fileUrl = project_file;
  707. askOpenAsProjectOrModelsDialog.addToRecent = add_to_recent_files;
  708. askOpenAsProjectOrModelsDialog.show();
  709. }
  710. }
  711. Connections
  712. {
  713. target: Cura.Actions.showProfileFolder
  714. function onTriggered()
  715. {
  716. var path = UM.Resources.getPath(UM.Resources.Preferences, "");
  717. if(Qt.platform.os == "windows")
  718. {
  719. path = path.replace(/\\/g,"/");
  720. }
  721. Qt.openUrlExternally(path);
  722. if(Qt.platform.os == "linux")
  723. {
  724. Qt.openUrlExternally(UM.Resources.getPath(UM.Resources.Resources, ""));
  725. }
  726. }
  727. }
  728. MessageDialog
  729. {
  730. id: messageDialog
  731. modality: Qt.ApplicationModal
  732. onAccepted: CuraApplication.messageBoxClosed(clickedButton)
  733. onApply: CuraApplication.messageBoxClosed(clickedButton)
  734. onDiscard: CuraApplication.messageBoxClosed(clickedButton)
  735. onHelp: CuraApplication.messageBoxClosed(clickedButton)
  736. onNo: CuraApplication.messageBoxClosed(clickedButton)
  737. onRejected: CuraApplication.messageBoxClosed(clickedButton)
  738. onReset: CuraApplication.messageBoxClosed(clickedButton)
  739. onYes: CuraApplication.messageBoxClosed(clickedButton)
  740. }
  741. Connections
  742. {
  743. target: CuraApplication
  744. function onShowMessageBox(title, text, informativeText, detailedText, buttons, icon)
  745. {
  746. messageDialog.title = title
  747. messageDialog.text = text
  748. messageDialog.informativeText = informativeText
  749. messageDialog.detailedText = detailedText
  750. messageDialog.standardButtons = buttons
  751. messageDialog.icon = icon
  752. messageDialog.visible = true
  753. }
  754. }
  755. Component
  756. {
  757. id: discardOrKeepProfileChangesDialogComponent
  758. DiscardOrKeepProfileChangesDialog { }
  759. }
  760. Loader
  761. {
  762. id: discardOrKeepProfileChangesDialogLoader
  763. }
  764. Connections
  765. {
  766. target: CuraApplication
  767. function onShowDiscardOrKeepProfileChanges()
  768. {
  769. discardOrKeepProfileChangesDialogLoader.sourceComponent = discardOrKeepProfileChangesDialogComponent
  770. discardOrKeepProfileChangesDialogLoader.item.show()
  771. }
  772. }
  773. Cura.WizardDialog
  774. {
  775. id: addMachineDialog
  776. title: catalog.i18nc("@title:window", "Add Printer")
  777. model: CuraApplication.getAddPrinterPagesModel()
  778. progressBarVisible: false
  779. }
  780. Cura.WizardDialog
  781. {
  782. id: whatsNewDialog
  783. title: catalog.i18nc("@title:window", "What's New")
  784. minimumWidth: UM.Theme.getSize("welcome_wizard_window").width
  785. minimumHeight: UM.Theme.getSize("welcome_wizard_window").height
  786. model: CuraApplication.getWhatsNewPagesModel()
  787. progressBarVisible: false
  788. visible: false
  789. }
  790. Connections
  791. {
  792. target: Cura.Actions.whatsNew
  793. function onTriggered() { whatsNewDialog.show() }
  794. }
  795. Connections
  796. {
  797. target: Cura.Actions.addMachine
  798. function onTriggered()
  799. {
  800. // Make sure to show from the first page when the dialog shows up.
  801. addMachineDialog.resetModelState()
  802. addMachineDialog.show()
  803. }
  804. }
  805. AboutDialog
  806. {
  807. id: aboutDialog
  808. }
  809. Connections
  810. {
  811. target: Cura.Actions.about
  812. function onTriggered() { aboutDialog.visible = true; }
  813. }
  814. Timer
  815. {
  816. id: startupTimer
  817. interval: 100
  818. repeat: false
  819. running: true
  820. onTriggered:
  821. {
  822. if (!base.visible)
  823. {
  824. base.visible = true
  825. }
  826. }
  827. }
  828. /**
  829. * Function to check whether a QML object has a certain type.
  830. * Taken from StackOverflow: https://stackoverflow.com/a/28384228 and
  831. * adapted to our code style.
  832. * Licensed under CC BY-SA 3.0.
  833. * \param obj The QtObject to get the name of.
  834. * \param class_name (str) The name of the class to check against. Has to be
  835. * the QtObject class name, not the QML entity name.
  836. */
  837. function qmlTypeOf(obj, class_name)
  838. {
  839. //className plus "(" is the class instance without modification.
  840. //className plus "_QML" is the class instance with user-defined properties.
  841. var str = obj.toString();
  842. return str.indexOf(class_name + "(") == 0 || str.indexOf(class_name + "_QML") == 0;
  843. }
  844. }