Cura.qml 26 KB

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