Warning, /plasma/discover/discover/qml/DiscoverWindow.qml is written in an unsupported language. File is not indexed.
0001 pragma ComponentBehavior: Bound 0002 0003 import QtQml.Models 0004 import QtQuick 0005 import QtQuick.Controls as QQC2 0006 import QtQuick.Layouts 0007 import org.kde.discover as Discover 0008 import org.kde.discover.app as DiscoverApp 0009 import org.kde.kirigami as Kirigami 0010 0011 Kirigami.ApplicationWindow { 0012 id: window 0013 0014 property string currentTopLevel 0015 0016 readonly property string topBrowsingComp: "BrowsingPage.qml" 0017 readonly property string topInstalledComp: "InstalledPage.qml" 0018 readonly property string topSearchComp: "SearchPage.qml" 0019 readonly property string topUpdateComp: "UpdatesPage.qml" 0020 readonly property string topSourcesComp: "SourcesPage.qml" 0021 readonly property string topAboutComp: "AboutPage.qml" 0022 0023 objectName: "DiscoverMainWindow" 0024 title: leftPage?.title ?? "" 0025 0026 width: app.initialGeometry.width >= 10 ? app.initialGeometry.width : Kirigami.Units.gridUnit * 52 0027 height: app.initialGeometry.height >= 10 ? app.initialGeometry.height : Math.max(Kirigami.Units.gridUnit * 38, window.globalDrawer.contentHeight) 0028 0029 visible: true 0030 0031 minimumWidth: Kirigami.Units.gridUnit * 17 0032 minimumHeight: Kirigami.Units.gridUnit * 17 0033 0034 pageStack.defaultColumnWidth: Math.max(Kirigami.Units.gridUnit * 25, pageStack.width / 4) 0035 pageStack.globalToolBar.style: Kirigami.Settings.isMobile ? Kirigami.ApplicationHeaderStyle.Titles : Kirigami.ApplicationHeaderStyle.Auto 0036 pageStack.globalToolBar.showNavigationButtons: pageStack.currentIndex === 0 ? Kirigami.ApplicationHeaderStyle.None : Kirigami.ApplicationHeaderStyle.ShowBackButton 0037 pageStack.globalToolBar.canContainHandles: true // mobile handles in header 0038 0039 readonly property Item leftPage: window.pageStack.depth > 0 ? window.pageStack.get(0) : null 0040 0041 Component.onCompleted: { 0042 if (app.isRoot) { 0043 messagesSheet.addMessage(i18n("Running as <em>root</em> is discouraged and unnecessary.")); 0044 } 0045 } 0046 0047 // This property is queried from C++, do not remove it 0048 readonly property string describeSources: feedbackLoader.item?.describeDataSources ?? "" 0049 Loader { 0050 id: feedbackLoader 0051 active: typeof DiscoverApp.UserFeedbackSettings !== "undefined" 0052 source: "Feedback.qml" 0053 } 0054 0055 TopLevelPageData { 0056 id: featuredAction 0057 icon.name: "go-home" 0058 text: i18n("&Home") 0059 component: topBrowsingComp 0060 objectName: "discover" 0061 } 0062 0063 TopLevelPageData { 0064 id: searchAction 0065 visible: enabled 0066 enabled: !window.wideScreen 0067 icon.name: "search" 0068 text: i18n("&Search") 0069 component: topSearchComp 0070 objectName: "search" 0071 shortcut: StandardKey.Find 0072 } 0073 TopLevelPageData { 0074 id: installedAction 0075 icon.name: "view-list-details" 0076 text: i18n("&Installed") 0077 component: topInstalledComp 0078 objectName: "installed" 0079 } 0080 TopLevelPageData { 0081 id: updateAction 0082 0083 icon.name: Discover.ResourcesModel.updatesCount <= 0 0084 ? "update-none" 0085 : (Discover.ResourcesModel.hasSecurityUpdates ? "update-high" : "update-low") 0086 0087 text: Discover.ResourcesModel.isFetching ? i18n("Fetching &updates…") : i18np("&Update (%1)", "&Updates (%1)", Discover.ResourcesModel.updatesCount) 0088 0089 component: topUpdateComp 0090 objectName: "update" 0091 } 0092 TopLevelPageData { 0093 id: aboutAction 0094 icon.name: "help-feedback" 0095 text: i18n("&About") 0096 component: topAboutComp 0097 objectName: "about" 0098 shortcut: StandardKey.HelpContents 0099 } 0100 TopLevelPageData { 0101 id: sourcesAction 0102 icon.name: "configure" 0103 text: i18n("S&ettings") 0104 component: topSourcesComp 0105 objectName: "sources" 0106 shortcut: StandardKey.Preferences 0107 } 0108 0109 Kirigami.Action { 0110 id: refreshAction 0111 readonly property Discover.DiscoverAction action: Discover.ResourcesModel.updateAction 0112 text: action.text 0113 icon.name: "view-refresh" 0114 onTriggered: action.trigger() 0115 enabled: action.enabled 0116 // Don't need to show this action in mobile view since you can pull down 0117 // on the view to refresh, and this is the common and expected behavior 0118 //on that platform 0119 visible: window.wideScreen 0120 tooltip: shortcut.nativeText 0121 0122 // Need to define an explicit Shortcut object so we can get its text 0123 // using shortcut.nativeText 0124 shortcut: Shortcut { 0125 sequences: [ StandardKey.Refresh ] 0126 onActivated: refreshAction.trigger() 0127 } 0128 } 0129 0130 Connections { 0131 target: app 0132 0133 function onOpenApplicationInternal(app) { 0134 Navigation.clearStack() 0135 Navigation.openApplication(app) 0136 } 0137 0138 function onListMimeInternal(mime) { 0139 currentTopLevel = topBrowsingComp; 0140 Navigation.openApplicationMime(mime) 0141 } 0142 0143 function onListCategoryInternal(cat) { 0144 currentTopLevel = topBrowsingComp; 0145 Navigation.openCategory(cat) 0146 } 0147 0148 function onOpenSearch(search) { 0149 Navigation.clearStack() 0150 Navigation.openApplicationList({ search }) 0151 } 0152 0153 function onOpenErrorPage(errorMessage, errorExplanation, buttonText, buttonIcon, buttonUrl) { 0154 Navigation.clearStack() 0155 console.warn(`Error: ${errorMessage}\n${errorExplanation}\nPlease visit ${buttonUrl}`) 0156 window.pageStack.push(errorPageComponent, { title: i18n("Error"), errorMessage, errorExplanation, buttonText, buttonIcon, buttonUrl }) 0157 } 0158 0159 function onUnableToFind(resid) { 0160 messagesSheet.addMessage(i18n("Unable to find resource: %1", resid)); 0161 Navigation.openHome() 0162 } 0163 } 0164 0165 Connections { 0166 target: Discover.ResourcesModel 0167 0168 function onSwitchToUpdates() { 0169 window.currentTopLevel = topUpdateComp 0170 } 0171 function onPassiveMessage(message) { 0172 messagesSheet.addMessage(message); 0173 } 0174 } 0175 0176 0177 footer: footerLoader.item 0178 0179 Loader { 0180 id: footerLoader 0181 active: !window.wideScreen 0182 sourceComponent: Kirigami.NavigationTabBar { 0183 actions: [ 0184 featuredAction, 0185 searchAction, 0186 installedAction, 0187 updateAction, 0188 ] 0189 Component.onCompleted: { 0190 // Exclusivity is already handled by the actions. This prevents BUG:448460 0191 tabGroup.exclusive = false 0192 } 0193 } 0194 } 0195 0196 Component { 0197 id: errorPageComponent 0198 Kirigami.Page { 0199 id: page 0200 property string errorMessage: "" 0201 property string errorExplanation: "" 0202 property string buttonText: "" 0203 property string buttonIcon: "" 0204 property string buttonUrl: "" 0205 readonly property bool isHome: true 0206 0207 Kirigami.PlaceholderMessage { 0208 anchors.centerIn: parent 0209 width: parent.width - (Kirigami.Units.largeSpacing * 8) 0210 visible: page.errorMessage !== "" 0211 type: Kirigami.PlaceholderMessage.Type.Actionable // All error messages must be actionable 0212 icon.name: "emblem-warning" 0213 text: page.errorMessage 0214 explanation: page.errorExplanation 0215 helpfulAction: Kirigami.Action { 0216 icon.name: page.buttonIcon 0217 text: page.buttonText 0218 enabled: page.buttonText.length > 0 && page.buttonUrl.length > 0 0219 onTriggered: { 0220 Qt.openUrlExternally(page.buttonUrl) 0221 } 0222 } 0223 onLinkActivated: link => Qt.openUrlExternally(link) 0224 } 0225 } 0226 } 0227 0228 Component { 0229 id: proceedDialog 0230 Kirigami.OverlaySheet { 0231 id: sheet 0232 showCloseButton: false 0233 property QtObject transaction 0234 property alias description: descriptionLabel.text 0235 property bool acted: false 0236 0237 // No need to add our own ScrollView since OverlaySheet includes 0238 // one automatically. 0239 // But we do need to put the label into a Layout of some sort so we 0240 // can limit the width of the sheet. 0241 ColumnLayout { 0242 QQC2.Label { 0243 id: descriptionLabel 0244 0245 Layout.fillWidth: true 0246 Layout.maximumWidth: Kirigami.Units.gridUnit * 20 0247 0248 textFormat: Text.StyledText 0249 wrapMode: Text.WordWrap 0250 } 0251 } 0252 0253 footer: RowLayout { 0254 0255 Item { Layout.fillWidth : true } 0256 0257 QQC2.Button { 0258 text: i18n("Proceed") 0259 icon.name: "dialog-ok" 0260 onClicked: { 0261 transaction.proceed() 0262 sheet.acted = true 0263 sheet.close() 0264 } 0265 Keys.onEnterPressed: clicked() 0266 Keys.onReturnPressed: clicked() 0267 } 0268 0269 QQC2.Button { 0270 Layout.alignment: Qt.AlignRight 0271 text: i18n("Cancel") 0272 icon.name: "dialog-cancel" 0273 onClicked: { 0274 transaction.cancel() 0275 sheet.acted = true 0276 sheet.close() 0277 } 0278 Keys.onEscapePressed: clicked() 0279 } 0280 } 0281 0282 onVisibleChanged: if(!visible) { 0283 sheet.destroy(1000) 0284 if (!sheet.acted) { 0285 transaction.cancel() 0286 } 0287 } 0288 } 0289 } 0290 0291 Component { 0292 id: distroErrorMessageDialog 0293 Kirigami.OverlaySheet { 0294 id: sheet 0295 property alias message: messageLabel.text 0296 0297 // No need to add our own ScrollView since OverlaySheet includes 0298 // one automatically. 0299 // But we do need to put the label into a Layout of some sort so we 0300 // can limit the width of the sheet. 0301 ColumnLayout { 0302 QQC2.Label { 0303 id: messageLabel 0304 0305 Layout.fillWidth: true 0306 Layout.maximumWidth: Kirigami.Units.gridUnit * 20 0307 0308 textFormat: Text.StyledText 0309 wrapMode: Text.WordWrap 0310 } 0311 0312 RowLayout { 0313 Item { Layout.fillWidth: true } 0314 QQC2.Button { 0315 icon.name: "tools-report-bug" 0316 text: i18n("Report this issue") 0317 onClicked: { 0318 Qt.openUrlExternally(Discover.ResourcesModel.distroBugReportUrl()) 0319 } 0320 } 0321 } 0322 } 0323 0324 onVisibleChanged: if (!visible) { 0325 sheet.destroy(1000) 0326 } 0327 } 0328 } 0329 0330 Kirigami.OverlaySheet { 0331 id: messagesSheet 0332 0333 property bool copyButtonEnabled: true 0334 0335 function addMessage(message: string) { 0336 messages.append({ message }); 0337 app.restore() 0338 } 0339 0340 title: messages.count > 1 ? i18n("Error %1 of %2", messagesSheetView.currentIndex + 1, messages.count) : i18n("Error") 0341 0342 // No need to add our own ScrollView since OverlaySheet includes 0343 // one automatically. 0344 // But we do need to put the label into a Layout of some sort so we 0345 // can limit the width of the sheet. 0346 ColumnLayout { 0347 Item { 0348 Layout.fillWidth: true 0349 Layout.maximumWidth: Kirigami.Units.gridUnit * 20 0350 } 0351 0352 StackLayout { 0353 id: messagesSheetView 0354 0355 Layout.fillWidth: true 0356 Layout.bottomMargin: Kirigami.Units.gridUnit 0357 0358 Repeater { 0359 // roles: { 0360 // message: string 0361 // } 0362 model: ListModel { 0363 id: messages 0364 0365 onCountChanged: { 0366 messagesSheet.visible = (count > 0); 0367 0368 if (count > 0 && messagesSheetView.currentIndex === -1) { 0369 messagesSheetView.currentIndex = 0; 0370 } 0371 } 0372 } 0373 0374 delegate: QQC2.Label { 0375 required property string message 0376 0377 Layout.fillWidth: true 0378 0379 text: message 0380 textFormat: Text.StyledText 0381 wrapMode: Text.WordWrap 0382 } 0383 } 0384 } 0385 0386 RowLayout { 0387 Layout.fillWidth: true 0388 0389 QQC2.Button { 0390 text: i18nc("@action:button", "Show Previous") 0391 icon.name: "go-previous" 0392 visible: messages.count > 1 0393 enabled: visible && messagesSheetView.currentIndex > 0 0394 0395 onClicked: { 0396 if (messagesSheetView.currentIndex > 0) { 0397 messagesSheetView.currentIndex--; 0398 } 0399 } 0400 } 0401 0402 QQC2.Button { 0403 text: i18nc("@action:button", "Show Next") 0404 icon.name: "go-next" 0405 visible: messages.count > 1 0406 enabled: visible && messagesSheetView.currentIndex < messages.count - 1 0407 0408 onClicked: { 0409 if (messagesSheetView.currentIndex < messages.count) { 0410 messagesSheetView.currentIndex++; 0411 } 0412 } 0413 } 0414 0415 Item { Layout.fillWidth: true } 0416 0417 QQC2.Button { 0418 Layout.alignment: Qt.AlignRight 0419 text: i18n("Copy to Clipboard") 0420 icon.name: "edit-copy" 0421 0422 onClicked: { 0423 app.copyTextToClipboard(messages.get(messagesSheetView.currentIndex).message); 0424 } 0425 } 0426 } 0427 } 0428 0429 onVisibleChanged: if(!visible) { 0430 messagesSheetView.currentIndex = -1; 0431 messages.clear(); 0432 } 0433 } 0434 0435 Instantiator { 0436 model: Discover.TransactionModel 0437 0438 delegate: Connections { 0439 required property Discover.Transaction transaction 0440 0441 target: transaction 0442 0443 function onProceedRequest(title, description) { 0444 const dialog = proceedDialog.createObject(window, { transaction, title, description }) 0445 dialog.open() 0446 app.restore() 0447 } 0448 0449 function onPassiveMessage(message) { 0450 messagesSheet.addMessage(message); 0451 } 0452 0453 function onDistroErrorMessage(message, actions) { 0454 const dialog = distroErrorMessageDialog.createObject(window, { title: i18n("Error"), transaction, message }) 0455 dialog.open() 0456 app.restore() 0457 } 0458 0459 function onWebflowStarted(url) { 0460 const component = Qt.createComponent("WebflowDialog.qml"); 0461 if (component.status === Component.Error) { 0462 Qt.openUrlExternally(url); 0463 console.error("Webflow Error", component.errorString()) 0464 } else if (component.status === Component.Ready) { 0465 const sheet = component.createObject(window, { transaction, url }); 0466 sheet.open() 0467 } 0468 component.destroy(); 0469 } 0470 } 0471 } 0472 0473 DiscoverApp.PowerManagementInterface { 0474 reason: Discover.TransactionModel.mainTransactionText 0475 preventSleep: Discover.TransactionModel.count > 0 0476 } 0477 0478 contextDrawer: Kirigami.ContextDrawer {} 0479 0480 globalDrawer: DiscoverDrawer { 0481 wideScreen: window.wideScreen 0482 } 0483 0484 onCurrentTopLevelChanged: { 0485 pageStack.clear(); 0486 if (currentTopLevel) { 0487 const pageUrl = Qt.resolvedUrl(currentTopLevel); 0488 pageStack.push(pageUrl); 0489 } 0490 globalDrawer.forceSearchFieldFocus(); 0491 } 0492 0493 DiscoverApp.UnityLauncher { 0494 launcherId: "org.kde.discover.desktop" 0495 progressVisible: Discover.TransactionModel.count > 0 0496 progress: Discover.TransactionModel.progress 0497 } 0498 }