Cura.qml 29 KB

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