Revision control
Copy as Markdown
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
import QtQuick
import QtQuick.Controls.impl
import QtQuick.Templates as T
import Qt.labs.StyleKit
import Qt.labs.StyleKit.impl
T.TreeViewDelegate {
id: control
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding,
implicitIndicatorHeight + topPadding + bottomPadding)
required property int row
required property var model
readonly property real __indicatorSpace: indicator
? implicitIndicatorWidth + styleReader.indicator.leftMargin + styleReader.indicator.rightMargin
: 0
readonly property real __contentIndent: !isTreeNode
? 0
: depth * indentation + (indicator ? __indicatorSpace + spacing : 0)
highlighted: control.selected || control.current
|| ((control.treeView.selectionBehavior === TableView.SelectRows
|| control.treeView.selectionBehavior === TableView.SelectionDisabled)
&& control.row === control.treeView.currentRow)
indentation: indicator ? __indicatorSpace : 12
leftPadding: !mirrored ? styleReader.leftPadding + __contentIndent : styleReader.rightPadding
rightPadding: !mirrored ? styleReader.rightPadding : styleReader.leftPadding + __contentIndent
topPadding: treeViewLayout.padding.top
bottomPadding: treeViewLayout.padding.bottom
leftInset: styleReader.background.leftMargin
rightInset: styleReader.background.rightMargin
topInset: styleReader.background.topMargin
bottomInset: styleReader.background.bottomMargin
spacing: styleReader.spacing
font: styleReader.font
StyleVariation.controlType: styleReader.controlType
StyleReader {
id: styleReader
controlType: StyleReader.TreeViewDelegate
enabled: control.enabled
// Cell delegates are recycled, so giving one real Qt keyboard focus would
// clash with what "current" means and in practice activeFocus never
// triggers here anyway. We map focused to current instead.
focused: control.current
checked: control.expanded
hovered: control.hovered
pressed: control.pressed
highlighted: control.highlighted
palette: control.palette
}
StyleKitLayout {
id: treeViewLayout
container: control
// Layout only positions the indicator; content padding is computed above
contentMargins {
left: control.mirrored ? styleReader.rightPadding : styleReader.leftPadding + control.depth * control.indentation
right: control.mirrored ? styleReader.leftPadding + control.depth * control.indentation : styleReader.rightPadding
top: styleReader.topPadding
bottom: styleReader.bottomPadding
}
layoutItems: [
// We don't lay out the contentItem here because it occupies the remaining space
// as calculated by control internal logic.
StyleKitLayoutItem {
id: indicatorItem
item: control.indicator
alignment: styleReader.indicator.alignment
margins.left: styleReader.indicator.leftMargin
margins.right: styleReader.indicator.rightMargin
margins.top: styleReader.indicator.topMargin
margins.bottom: styleReader.indicator.bottomMargin
fillWidth: styleReader.indicator.fillWidth
fillHeight: styleReader.indicator.fillHeight
}
]
spacing: styleReader.spacing
mirrored: control.mirrored
}
// Wrap the indicator in an Item, since its visibility is set in two places:
// updateIndicatorVisibility() in QQuickTreeViewDelegate hides it for nodes
// without children, and IndicatorDelegate binds it to the style. With the wrapper,
// the template sets the outer item and the style sets the inner one, so the
// indicator is only visible when both are visible.
indicator: Item {
x: indicatorItem.x
y: indicatorItem.y
width: indicatorItem.width
height: indicatorItem.height
implicitWidth: indicatorDelegate.implicitWidth
implicitHeight: indicatorDelegate.implicitHeight
IndicatorDelegate {
id: indicatorDelegate
quickControl: control
indicatorStyle: styleReader.indicator
width: parent.width
height: parent.height
}
}
contentItem: Label {
clip: false
text: control.model.display
elide: Text.ElideRight
color: styleReader.text.color
font: styleReader.font
visible: !control.editing
horizontalAlignment: styleReader.text.alignment & Qt.AlignHorizontal_Mask
verticalAlignment: styleReader.text.alignment & Qt.AlignVertical_Mask
padding: styleReader.text.padding
leftPadding: styleReader.text.leftPadding
rightPadding: styleReader.text.rightPadding
bottomPadding: styleReader.text.bottomPadding
topPadding: styleReader.text.topPadding
}
// The edit delegate is a separate component, and doesn't need
// to follow the same strict rules that are applied to a control.
// qmllint disable attached-property-reuse
// qmllint disable controls-attached-property-reuse
// qmllint disable QuickControlsSanity.controls-sanity
TableView.editDelegate: FocusScope {
width: parent.width
height: parent.height
readonly property int __role: {
let model = control.treeView.model
let index = control.treeView.index(row, column)
let editText = model.data(index, Qt.EditRole)
return editText !== undefined ? Qt.EditRole : Qt.DisplayRole
}
TextField {
id: textField
x: control.contentItem.x
y: (parent.height - height) / 2
width: control.contentItem.width
text: control.treeView.model.data(control.treeView.index(row, column), __role)
focus: true
}
TableView.onCommit: {
let index = TableView.view.index(row, column)
TableView.view.model.setData(index, textField.text, __role)
}
Component.onCompleted: textField.selectAll()
}
// qmllint enable attached-property-reuse
// qmllint enable controls-attached-property-reuse
// qmllint enable QuickControlsSanity.controls-sanity
background: BackgroundDelegate {
quickControl: control
backgroundStyle: styleReader.background
}
}