Cura.qml 29 KB

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