Cura.qml 27 KB

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