Warning, /plasma/drkonqi/src/qml/DeveloperPage.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0002 // SPDX-FileCopyrightText: 2021-2022 Harald Sitter <sitter@kde.org>
0003
0004 import QtQuick 2.15
0005 import QtQuick.Layouts 1.15
0006 import QtQuick.Controls 2.15 as QQC2
0007 import org.kde.kirigami 2.19 as Kirigami
0008 import org.kde.syntaxhighlighting 1.0
0009
0010 import org.kde.drkonqi 1.0
0011
0012 Kirigami.ScrollablePage {
0013 id: page
0014
0015 property alias reportActionVisible: reportAction.visible
0016 property string trace: ""
0017 property bool basic: false
0018 property alias usefulness: ratingItem.usefulness
0019 property alias footerActionsLeft: footerBarLeft.actions
0020 property alias footerActionsRight: footerBarRight.actions
0021
0022 padding: 0
0023 bottomPadding: 0
0024
0025 title: i18nc("@title:window", "Developer Information")
0026
0027 actions: [
0028 Kirigami.Action {
0029 id: reportAction
0030 enabled: Kirigami.Settings.isMobile ? true : canReport
0031 visible: Kirigami.Settings.isMobile ? canReport : true
0032 icon.name: "story-editor-symbolic"
0033 text: i18nc("@action Report the bug on this domain", "Report on %1", Globals.bugzillaShortUrl)
0034 // TODO: could give context on why the button is disabled when canReport is false
0035 tooltip: i18nc("@info:tooltip", "Starts the bug report assistant.")
0036 onTriggered: pageStack.push("qrc:/ui/WelcomePage.qml")
0037 },
0038
0039 Kirigami.Action {
0040 id: installButton
0041 visible: false
0042 text: i18nc("@action:button", "Install Debug Symbols")
0043 onTriggered: {
0044 if (debugPackageInstaller.canInstallDebugPackages) { // prefer the installer when available over dynamic resolution
0045 debugPackageInstaller.installDebugPackages()
0046 } else if (BacktraceGenerator.supportsSymbolResolution) {
0047 traceArea.text = ""
0048 BacktraceGenerator.symbolResolution = true
0049 BacktraceGenerator.start()
0050 } else {
0051 console.warn("Unexpected install button state :O")
0052 }
0053 }
0054 icon.name: "install"
0055 tooltip: i18nc("@info:tooltip", "Use this button to install the missing debug symbols packages.")
0056 },
0057
0058 Kirigami.Action {
0059 id: reloadAction
0060 enabled: BacktraceGenerator.state !== BacktraceGenerator.Loading
0061 icon.name: "view-refresh"
0062 text: i18nc("@action:button", "Reload")
0063 tooltip: xi18nc("@info:tooltip",
0064 `Use this button to reload the crash information (backtrace). This is useful when you have
0065 installed the proper debug symbol packages and you want to obtain a better backtrace.`)
0066 onTriggered: {
0067 traceArea.text = ""
0068 BacktraceGenerator.start()
0069 }
0070 },
0071
0072 Kirigami.Action {
0073 icon.name: "edit-copy"
0074 text: i18nc("@action:button", "Copy")
0075 tooltip: i18nc("@info:tooltip", "Use this button to copy the crash information (backtrace) to the clipboard.")
0076 onTriggered: DrKonqi.copyToClipboard(traceArea.text)
0077 },
0078
0079 Kirigami.Action {
0080 icon.name: "document-save"
0081 text: i18nc("@action:button", "Save")
0082 tooltip: xi18nc("@info:tooltip",
0083 `Use this button to save the crash information (backtrace) to a file. This is useful if you want to take a look at it or to report the bug later.`)
0084 onTriggered: DrKonqi.saveReport(traceArea.text)
0085 }
0086 ]
0087
0088 header: QQC2.ToolBar {
0089 RatingItem {
0090 id: ratingItem
0091 anchors.fill: parent
0092 failed: BacktraceGenerator.state === BacktraceGenerator.Failed || BacktraceGenerator.state === BacktraceGenerator.FailedToStart
0093 loading: BacktraceGenerator.state === BacktraceGenerator.Loading
0094 }
0095 }
0096
0097 ColumnLayout {
0098 spacing: 0
0099
0100 DebugPackageInstaller { // not in global scope because it messes up scrollbars
0101 id: debugPackageInstaller
0102 onPackagesInstalled: reloadAction.trigger()
0103 onError: appWindow.showPassiveNotification(i18nc("@title:window", "Error during the installation of debug symbols"), "long")
0104 }
0105
0106 RowLayout {
0107 visible: page.basic
0108 spacing: Kirigami.Units.smallSpacing
0109 Layout.fillHeight: true
0110 Kirigami.Icon {
0111 source: "help-hint"
0112 width: Kirigami.Units.iconSizes.enormous
0113 height: width
0114 }
0115 QQC2.Label {
0116 Layout.fillHeight: true
0117 Layout.fillWidth: true
0118 wrapMode: Text.Wrap
0119 text: xi18nc("@info",
0120 `<subtitle>What is a "backtrace" ?</subtitle><para>A backtrace basically describes what was
0121 happening inside the application when it crashed, so the developers may track
0122 down where the mess started. They may look meaningless to you, but they might
0123 actually contain a wealth of useful information.<nl />Backtraces are commonly
0124 used during interactive and post-mortem debugging.</para>`)
0125 }
0126 }
0127 QQC2.TextArea {
0128 id: traceArea
0129 Layout.fillWidth: true
0130 Layout.fillHeight: true
0131 visible: text !== "" && !page.basic
0132
0133 // text: output.text
0134 font.family: "monospace"
0135 wrapMode: TextEdit.Wrap
0136 textFormat: TextEdit.PlainText
0137 readOnly: true
0138 selectByMouse: Kirigami.Settings.isMobile ? false : true
0139
0140 SyntaxHighlighter {
0141 textEdit: BacktraceGenerator.debuggerIsGDB() ? traceArea : undefined
0142 definition: "GDB Backtrace"
0143 }
0144
0145 function ensureVisible(r) {
0146 if (flickable.contentX >= r.x) {
0147 flickable.contentX = r.x;
0148 } else if (flickable.contentX + flickable.width <= r.x + r.width) {
0149 flickable.contentX = r.x + r.width - flickable.width;
0150 }
0151 if (flickable.contentY >= r.y) {
0152 flickable.contentY = r.y;
0153 } else if (flickable.contentY + flickable.height <= r.y + r.height) {
0154 flickable.contentY = r.y + r.height - flickable.height;
0155 }
0156 }
0157
0158 Connections {
0159 id: generatorConnections
0160 target: BacktraceGenerator
0161 function onNewLine(line) { traceArea.text += line }
0162 function onStateChanged() {
0163 console.log(BacktraceGenerator.state)
0164 console.log(BacktraceGenerator.Loaded)
0165
0166 const state = BacktraceGenerator.state
0167 page.state = state
0168
0169 installButton.visible = false
0170
0171 const parser = BacktraceGenerator.parser();
0172 usefulness = parser.backtraceUsefulness()
0173 // ratingItem.usefulness = usefulness
0174 if (state == BacktraceGenerator.Loaded) {
0175 traceArea.text = BacktraceGenerator.backtrace()
0176 // Kinda hacky. Scroll all the way down, then scroll up until the handler is visible.
0177 // This should bring the most relevant frames into the viewport.
0178 traceArea.cursorPosition = traceArea.length - 1
0179 traceArea.ensureVisible(traceArea.cursorRectangle)
0180 traceArea.cursorPosition = traceArea.text.indexOf("[KCrash Handler]")
0181 traceArea.ensureVisible(traceArea.cursorRectangle)
0182 trace = traceArea.text // FIXME ensure this doesn't result in a binding
0183
0184 if (usefulness != BacktraceParser.ReallyUseful) {
0185 if (debugPackageInstaller.canInstallDebugPackages || BacktraceGenerator.supportsSymbolResolution) {
0186 detailsLabel.text = xi18nc("@info/rich",
0187 `You can click the <interface>Install Debug Symbols</interface> button in order to automatically install the missing debugging information packages. If this method
0188 does not work: please read <link url='%1'>How to create useful crash reports</link> to learn how to get a useful
0189 backtrace; install the needed packages (<link url='%2'>list of files</link>) and click the <interface>Reload</interface> button.`,
0190 Globals.techbaseHowtoDoc, '#missingDebugPackages')
0191 installButton.visible = true
0192 debugPackageInstaller.setMissingLibraries(parser.librariesWithMissingDebugSymbols())
0193 } else {
0194 detailsLabel.text = xi18nc("@info/rich",
0195 `Please read <link url='%1'>How to create useful crash reports</link> to learn how to get a useful backtrace; install the needed packages
0196 (<link url='%2'>list of files</link>) and click the <interface>Reload</interface> button.`,
0197 Globals.techbaseHowtoDoc, '#missingDebugPackages')
0198 }
0199 }
0200 } else if (state == BacktraceGenerator.Failed) {
0201 traceArea.text = i18nc("@info:status", "The crash information could not be generated.")
0202 detailsLabel.text = xi18nc("@info/rich", `You could try to regenerate the backtrace by clicking the <interface>Reload</interface> button.`)
0203 } else if (state == BacktraceGenerator.FailedToStart) {
0204 // FIXME dupe from failed
0205 traceArea.text = i18nc("@info:status", "The crash information could not be generated.")
0206 detailsLabel.text = xi18nc("@info/rich",
0207 `<emphasis strong='true'>You need to first install the debugger application (%1) then click the <interface>Reload</interface> button.</emphasis>`,
0208 BacktraceGenerator.debuggerName())
0209 }
0210 }
0211 }
0212 }
0213 }
0214
0215 footer: ColumnLayout {
0216 QQC2.Control { // Get standard padding so it doesn't stick to the edges, Label has none by default cause it isn't a Control
0217 Layout.fillWidth: true
0218 background: null
0219
0220 Kirigami.PromptDialog {
0221 id: filesDialog
0222 title: i18nc("@title", "Not Sufficiently Useful")
0223 function reload() {
0224 const parser = BacktraceGenerator.parser()
0225 let missingDbgForFiles = parser.librariesWithMissingDebugSymbols()
0226 missingDbgForFiles.unshift(CrashedApplication.exectuableAbsoluteFilePath)
0227 // TODO should maybe prepend DrKonqi::crashedApplication()->executable().absoluteFilePath()
0228 // NB: cannot use xi18nc here because that'd close the html tag but we need to append an unordered list of paths
0229 let message = "<html>" + i18n("The packages containing debug information for the following application and libraries are missing:") + "<br /><ul>";
0230 for (const i in missingDbgForFiles) {
0231 message += "<li>" + missingDbgForFiles[i] + "</li>";
0232 }
0233 message += "</ul></html>"
0234 subtitle = message
0235 }
0236
0237 showCloseButton: true
0238 }
0239
0240 contentItem: QQC2.Label {
0241 id: detailsLabel
0242 wrapMode: Text.Wrap
0243 onLinkActivated: link => {
0244 if (link[0] == "#") { // in-page reference
0245 filesDialog.reload()
0246 filesDialog.open()
0247 } else {
0248 Qt.openUrlExternally(link)
0249 }
0250 }
0251 textFormat: Text.RichText
0252 }
0253 }
0254 RowLayout {
0255 spacing: Kirigami.Units.smallSpacing
0256 // Two bars because of https://bugs.kde.org/show_bug.cgi?id=451026
0257 // Awkard though, maybe we should just live with everything being right aligned
0258 FooterActionBar {
0259 padding: 0
0260 id: footerBarLeft
0261 alignment: Qt.AlignLeft
0262 visible: actions.length > 0
0263 }
0264 FooterActionBar {
0265 padding: 0
0266 id: footerBarRight
0267 visible: actions.length > 0
0268 }
0269 }
0270 }
0271
0272 Component.onCompleted: {
0273 if (BacktraceGenerator.state === BacktraceGenerator.NotLoaded) {
0274 reloadAction.trigger()
0275 } else {
0276 // ensure our current state is the state of the backend. this is important in case the developer page
0277 // was used before the report workflow (i.e. the data was generated but from a different view)
0278 generatorConnections.onStateChanged()
0279 }
0280 }
0281 }