6import QGroundControl.Controls
8/// Left panel for the Log Viewer charting tab.
9/// Shows log stats and the grouped fields list.
13 required property var logParser
14 required property var logViewerController
16 signal clearSelectedRequested
18 property bool xAxisShowLocalTime: QGroundControl.settingsManager.logViewerSettings.xAxisShowLocalTime.rawValue
20 color: qgcPal.windowShade
21 radius: ScreenTools.defaultFontPixelWidth * 0.5
22 Layout.preferredWidth: mainLayout.implicitWidth + (mainLayout.anchors.margins * 2)
24 // -------------------------------------------------------------------------
26 // -------------------------------------------------------------------------
27 property string _fieldSearchText: ""
28 property var _filteredFieldRows: []
29 property real _maxFieldRowWidth: _minFieldRowWidth
31 readonly property real _minFieldRowWidth: ScreenTools.defaultFontPixelWidth
32 readonly property bool _isFirmwareLog: logViewerController.sourceType === LogViewerController.Bin
33 || logViewerController.sourceType === LogViewerController.ULog
35 QGCPalette { id: qgcPal }
37 // -------------------------------------------------------------------------
39 // -------------------------------------------------------------------------
41 /// Called by the parent after a log finishes loading.
42 function rebuildGroupedFields() {
43 _maxFieldRowWidth = _minFieldRowWidth
44 logViewerController.setPlottableFields(logParser.plottableFields)
48 // -------------------------------------------------------------------------
50 // -------------------------------------------------------------------------
52 function _applyFieldFilter() {
53 const query = String(_fieldSearchText).trim().toLowerCase()
54 if (query.length === 0) {
55 _filteredFieldRows = logViewerController.fieldRows
60 const fields = logParser.plottableFields
61 for (let i = 0; i < fields.length; i++) {
62 const fullName = String(fields[i])
63 const splitIndex = fullName.indexOf(".")
64 const groupName = splitIndex > 0 ? fullName.substring(0, splitIndex) : qsTr("Other")
65 const shortName = splitIndex > 0 ? fullName.substring(splitIndex + 1) : fullName
66 const haystack = (fullName + " " + groupName + " " + shortName).toLowerCase()
67 if (haystack.indexOf(query) === -1) {
70 if (!groupedMap[groupName]) {
71 groupedMap[groupName] = []
73 groupedMap[groupName].push({ fullName: fullName, shortName: shortName })
76 const groups = Object.keys(groupedMap).sort()
78 for (let g = 0; g < groups.length; g++) {
79 const groupName = groups[g]
80 rows.push({ rowType: "group", group: groupName })
81 groupedMap[groupName].sort((a, b) => String(a.shortName).localeCompare(String(b.shortName)))
82 for (let s = 0; s < groupedMap[groupName].length; s++) {
86 fullName: groupedMap[groupName][s].fullName,
87 shortName: groupedMap[groupName][s].shortName
91 _filteredFieldRows = rows
94 function _isGroupExpanded(groupName) {
95 return logViewerController.isGroupExpanded(groupName)
98 function _toggleGroupExpanded(groupName) {
99 if (String(_fieldSearchText).trim().length > 0) {
102 logViewerController.toggleGroupExpanded(groupName)
106 // -------------------------------------------------------------------------
108 // -------------------------------------------------------------------------
111 target: logViewerController
112 function onFieldRowsChanged() {
113 const savedY = _fieldsListView.contentY
115 Qt.callLater(() => { _fieldsListView.contentY = savedY })
119 // -------------------------------------------------------------------------
121 // -------------------------------------------------------------------------
124 id: _groupRowComponent
127 width: _maxFieldRowWidth
128 implicitWidth: _groupLayout.implicitWidth
129 implicitHeight: _groupLayout.implicitHeight
131 Component.onCompleted: _maxFieldRowWidth = Math.max(_maxFieldRowWidth, implicitWidth)
135 spacing: ScreenTools.defaultFontPixelWidth / 2
138 Layout.preferredWidth: _groupLabel.height * 0.5
139 Layout.preferredHeight: _groupLabel.height * 0.5
140 source: "/qmlimages/arrow-down.png"
142 fillMode: Image.PreserveAspectFit
143 rotation: (String(control._fieldSearchText).trim().length > 0 || control._isGroupExpanded(rowData.group)) ? 0 : -90
155 onClicked: control._toggleGroupExpanded(rowData.group)
161 id: _fieldRowComponent
165 width: _maxFieldRowWidth
166 checked: logViewerController.selectedFields.indexOf(rowData.fullName) !== -1
167 text: rowData.shortName ? " " + String(rowData.shortName) : ""
168 onClicked: logViewerController.setFieldSelected(rowData.fullName, checked)
170 Component.onCompleted: _maxFieldRowWidth = Math.max(_maxFieldRowWidth, implicitWidth)
176 anchors.top: parent.top
177 anchors.bottom: parent.bottom
178 anchors.left: parent.left
179 anchors.margins: ScreenTools.defaultFontPixelWidth / 2
180 spacing: ScreenTools.defaultFontPixelHeight * 0.5
183 visible: _isFirmwareLog
184 text: qsTr("Fields: %1 Parameters: %2 Events: %3")
185 .arg(logParser.plottableFields.length)
186 .arg(logParser.parameters.length)
187 .arg(logParser.events.length)
191 visible: _isFirmwareLog
192 && logParser.startTime
193 && !isNaN(logParser.startTime.getTime())
194 && logParser.startTime.getTime() > 0
195 spacing: ScreenTools.defaultFontPixelWidth
197 QGCLabel { text: qsTr("X axis:") }
199 ButtonGroup { id: _xAxisButtonGroup }
202 text: qsTr("Elapsed")
203 checked: !control.xAxisShowLocalTime
204 ButtonGroup.group: _xAxisButtonGroup
205 onClicked: QGroundControl.settingsManager.logViewerSettings.xAxisShowLocalTime.rawValue = false
209 text: qsTr("Local time")
210 checked: control.xAxisShowLocalTime
211 ButtonGroup.group: _xAxisButtonGroup
212 onClicked: QGroundControl.settingsManager.logViewerSettings.xAxisShowLocalTime.rawValue = true
217 visible: _isFirmwareLog
218 spacing: ScreenTools.defaultFontPixelWidth * 0.5
226 id: _fieldSearchField
227 Layout.fillWidth: true
228 textColor: qgcPal.textFieldText
229 placeholderTextColor: Qt.rgba(qgcPal.textFieldText.r, qgcPal.textFieldText.g, qgcPal.textFieldText.b, 0.7)
230 placeholderText: qsTr("Search fields")
233 control._fieldSearchText = text
234 if (text.trim().length === 0) {
235 _fieldSearchTimer.stop()
236 control._applyFieldFilter()
238 _fieldSearchTimer.restart()
243 control._fieldSearchText = text
244 _fieldSearchTimer.stop()
245 control._applyFieldFilter()
250 text: qsTr("Clear Selected")
251 enabled: logViewerController.selectedFields.length > 0
254 logViewerController.clearSelection()
255 control._applyFieldFilter()
256 control.clearSelectedRequested()
263 Layout.fillHeight: true
264 Layout.preferredWidth: _maxFieldRowWidth + ScreenTools.defaultFontPixelWidth
265 visible: _isFirmwareLog
266 model: _filteredFieldRows
267 spacing: ScreenTools.defaultFontPixelHeight * 0.25
270 sourceComponent: modelData.rowType === "group" ? _groupRowComponent : _fieldRowComponent
271 property var rowData: modelData
277 id: _fieldSearchTimer
280 onTriggered: control._applyFieldFilter()