/*SPDX-FileCopyrightText: 2013-2014 Eike Hein <hein@kde.org>SPDX-License-Identifier: GPL-2.0-or-later*/pragma ComponentBehavior: Boundimport QtQuickimport org.kde.kirigami as Kirigamiimport org.kde.kquickcontrolsaddons as KQuickControlsAddonsimport org.kde.plasma.components as PlasmaComponents3import org.kde.plasma.extras as PlasmaExtrasimport org.kde.ksvg as KSvgFocusScope {id: itemListproperty real minimumWidth: Kirigami.Units.gridUnit * 14property real maximumWidth: Math.round(minimumWidth * 1.5)width: minimumWidthimplicitHeight: listView.contentHeightsignal exitedsignal keyNavigationAtListEndsignal navigateLeftRequestedsignal navigateRightRequestedproperty Item focusParent: nullproperty Item mainSearchField: nullproperty QtObject dialog: nullproperty QtObject childDialog: nullproperty bool iconsEnabled: falseproperty int itemHeight: Math.ceil((Math.max(Kirigami.Units.iconSizes.sizeForLabels, Kirigami.Units.iconSizes.small)+ Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom,listItemSvg.margins.top + listItemSvg.margins.bottom)) / 2) * 2property int separatorHeight: showSeparators ? lineMetrics.elementRect.height + (2 * Kirigami.Units.smallSpacing) : 0property alias currentIndex: listView.currentIndexproperty alias currentItem: listView.currentItemproperty alias keyNavigationWraps: listView.keyNavigationWrapsproperty alias showChildDialogs: listView.showChildDialogsproperty alias model: listView.modelproperty alias count: listView.countproperty alias containsMouse: listener.containsMouseproperty alias resetOnExitDelay: resetIndexTimer.intervalproperty alias showSeparators: listView.showSeparatorsproperty alias hoverEnabled: listView.hoverEnabledproperty KSvg.SvgItem lineMetrics: KSvg.SvgItem {imagePath: "widgets/line"elementId: "horizontal-line"}Timer {id: dialogSpawnTimerproperty bool focusOnSpawn: falseinterval: 70repeat: falseonTriggered: {if (!kicker.expanded || itemList.model === undefined || itemList.currentIndex == -1) {return;}if (itemList.childDialog != null) {itemList.childDialog.delayedDestroy();}// Gets reenabled after the dialog spawn causes a focus-in on the dialog window.kicker.hideOnWindowDeactivate = false;itemList.childDialog = itemListDialogComponent.createObject(itemList,{mainSearchField: itemList.mainSearchField,focusParent: itemList,visualParent: listView.currentItem,model: itemList.model.modelForRow(listView.currentIndex),visible: true});itemList.childDialog.LayoutMirroring.enabled = itemList.LayoutMirroring.enabledwindowSystem.forceActive(itemList.childDialog.mainItem);itemList.childDialog.mainItem.focus = true;if (focusOnSpawn) {itemList.childDialog.mainItem.showChildDialogs = false;itemList.childDialog.mainItem.currentIndex = 0;itemList.childDialog.mainItem.showChildDialogs = true;}}}Timer {id: resetIndexTimerinterval: (itemList.dialog != null) ? 50 : 150repeat: falseonTriggered: {if (itemList.focus && (!itemList.childDialog || !itemList.childDialog.mainItem.containsMouse)) {itemList.currentIndex = -1;itemList.exited();}}}Keys.priority: Keys.AfterItemKeys.forwardTo: [itemList.mainSearchField]KQuickControlsAddons.MouseEventListener {id: listeneranchors.fill: parenthoverEnabled: trueonContainsMouseChanged: containsMouseChanged => {listView.eligibleWidth = listView.width;if (containsMouse) {resetIndexTimer.stop();itemList.forceActiveFocus();} else if ((!itemList.childDialog || !itemList.dialog)&& (!itemList.currentItem || !itemList.currentItem.menu.opened)) {resetIndexTimer.start();}}PlasmaComponents3.ScrollView {anchors.fill: parentfocus: trueListView {id: listViewproperty bool showChildDialogs: trueproperty int eligibleWidth: widthproperty bool showSeparators: !model.sorted // separators are mostly useless when sortedproperty bool hoverEnabled: truecurrentIndex: -1focus: trueclip: height < contentHeight + topMargin + bottomMarginboundsBehavior: Flickable.StopAtBoundssnapMode: ListView.SnapToItemspacing: 0keyNavigationEnabled: falsedelegate: ItemListDelegate {showSeparators: listView.showSeparatorsdialogDefaultRight: !itemList.LayoutMirroring.enabledhoverEnabled: listView.hoverEnabledonFullTextWidthChanged: {if (itemList && fullTextWidth > itemList.width) {itemList.width = Math.min(fullTextWidth, itemList.maximumWidth);}}}highlight: PlasmaExtras.Highlight {visible: !listView.currentItem || !listView.currentItem.isSeparatorpressed: listView.currentItem && listView.currentItem.pressed && !listView.currentItem.hasChildrenactive: listView.currentItem && listView.currentItem.hovered}highlightMoveDuration: 0onCountChanged: {if (currentIndex == 0 && !itemList.mainSearchField.activeFocus) {currentItem?.forceActiveFocus();} else {currentIndex = -1;}}onCurrentIndexChanged: {if (currentIndex != -1) {if (itemList.childDialog) {if (currentItem && currentItem.hasChildren) {itemList.childDialog.mainItem.width = itemList.minimumWidth;itemList.childDialog.model = model.modelForRow(currentIndex);itemList.childDialog.visualParent = listView.currentItem;} else {itemList.childDialog.delayedDestroy();}return;}if (currentItem == null || !currentItem.hasChildren || !kicker.expanded) {dialogSpawnTimer.stop();return;}if (showChildDialogs) {dialogSpawnTimer.focusOnSpawn = false;dialogSpawnTimer.restart();}} else if (itemList.childDialog != null) {itemList.childDialog.delayedDestroy();itemList.childDialog = null;}}onCurrentItemChanged: {if (currentItem) {currentItem.menu.closed.connect(resetIndexTimer.restart);}}}Keys.onPressed: event => {let backArrowKey = (event.key === Qt.Key_Left && !itemList.LayoutMirroring.enabled) ||(event.key === Qt.Key_Right && itemList.LayoutMirroring.enabled)let forwardArrowKey = (event.key === Qt.Key_Right && !itemList.LayoutMirroring.enabled) ||(event.key === Qt.Key_Left && itemList.LayoutMirroring.enabled)if (listView.currentItem !== null && listView.currentItem.hasChildren &&(forwardArrowKey || event.key === Qt.Key_Return || event.key === Qt.Key_Enter)) {if (itemList.childDialog === null) {dialogSpawnTimer.focusOnSpawn = true;dialogSpawnTimer.restart();} else {windowSystem.forceActive(itemList.childDialog.mainItem);itemList.childDialog.mainItem.focus = true;itemList.childDialog.mainItem.currentIndex = 0;}} else if (event.key === Qt.Key_Up) {event.accepted = true;if (!listView.keyNavigationWraps && listView.currentIndex == 0) {itemList.keyNavigationAtListEnd();return;}itemList.showChildDialogs = false;listView.decrementCurrentIndex();if (listView.currentItem !== null) {if (listView.currentItem.isSeparator) {listView.decrementCurrentIndex();}listView.currentItem.forceActiveFocus();}itemList.showChildDialogs = true;} else if (event.key === Qt.Key_Down) {event.accepted = true;if (!listView.keyNavigationWraps && listView.currentIndex == listView.count - 1) {itemList.keyNavigationAtListEnd();return;}itemList.showChildDialogs = false;listView.incrementCurrentIndex();if (listView.currentItem !== null) {if (listView.currentItem.isSeparator) {listView.incrementCurrentIndex();}listView.currentItem.forceActiveFocus();}itemList.showChildDialogs = true;} else if (backArrowKey && itemList.dialog != null) {itemList.dialog.destroy();} else if (event.key === Qt.Key_Escape) {kicker.expanded = false;} else if (event.key === Qt.Key_Tab) {//do nothing, and skip appending text} else if (event.text !== "") {if (itemList.mainSearchField) {itemList.mainSearchField.forceActiveFocus();}} else if (backArrowKey) {itemList.navigateLeftRequested();} else if (forwardArrowKey) {itemList.navigateRightRequested();}}}}Component.onCompleted: {windowSystem.monitorWindowFocus(itemList);}}