Cura.qml 30 KB

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