/*SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>SPDX-License-Identifier: LGPL-2.0-or-later*/import QtQuickimport QtQuick.Controls as QQC2import org.kde.plasma.components as PC3import org.kde.plasma.core as PlasmaCoreimport org.kde.plasma.extras as PlasmaExtrasimport org.kde.kquickcontrolsaddonsimport org.kde.kwindowsystemimport org.kde.kirigami as Kirigamiimport QtQuick.Windowimport QtQuick.Layoutsimport org.kde.plasma.private.shellPC3.Page {id: mainwidth: Math.max(heading.paintedWidth, Kirigami.Units.iconSizes.enormous * 3 + Kirigami.Units.smallSpacing * 4 + Kirigami.Units.gridUnit * 5)height: 800//Screen.heightopacity: draggingWidget ? 0.3 : 1readonly property int contentMargins: Kirigami.Units.largeSpacingproperty QtObject containmentproperty PlasmaCore.Dialog sidePanel//external drop events can cause a raise event causing us to lose focus and//therefore get deleted whilst we are still in a drag exec()//this is a clue to the owning dialog that hideOnWindowDeactivate should be deleted//See https://bugs.kde.org/show_bug.cgi?id=332733property bool preventWindowHide: draggingWidget || categoriesDialog.status !== PlasmaExtras.Menu.Closed|| getWidgetsDialog.status !== PlasmaExtras.Menu.Closed// We might've lost focus during the widget drag and drop or whilst using// the "get widgets" dialog; however we prevented the sidebar to hide.// This might get the sidebar stuck, since we only hide when losing focus.// To avoid this we reclaim focus as soon as the drag and drop is done,// or the get widgets window is closed.onPreventWindowHideChanged: {if (!preventWindowHide && !sidePanel.active) {sidePanel.requestActivate()}}property bool outputOnly: draggingWidgetproperty Item categoryButtonproperty bool draggingWidget: falsesignal closed()PlasmaCore.EdgeEventForwarder {window: main.Window.windowactiveEdges: Qt.TopEdgemargins.top: Kirigami.Units.gridUnit}onClosed: {// If was called from a panel, open the panel configif (root.widgetExplorer.containment &&root.widgetExplorer.containment.containmentType == 1 &&!root.widgetExplorer.containment.userConfiguring) {root.widgetExplorer.containment.internalAction("configure").trigger()}}onVisibleChanged: {if (!visible) {KWindowSystem.showingDesktop = false}}Component.onCompleted: {if (!root.widgetExplorer) {root.widgetExplorer = widgetExplorerComponent.createObject(root)}root.widgetExplorer.containment = main.containment}Component.onDestruction: {if (pendingUninstallTimer.running) {// we're not being destroyed so at least reset the filterswidgetExplorer.widgetsModel.filterQuery = ""widgetExplorer.widgetsModel.filterType = ""widgetExplorer.widgetsModel.searchTerm = ""} else {root.widgetExplorer.destroy()root.widgetExplorer = null}}function addCurrentApplet() {var pluginName = list.currentItem ? list.currentItem.pluginName : ""if (pluginName) {widgetExplorer.addApplet(pluginName)}}QQC2.Action {shortcut: "Escape"onTriggered: {if (searchInput.length > 0) {searchInput.text = ""} else {main.closed()}}}QQC2.Action {shortcut: "Enter"onTriggered: addCurrentApplet()}QQC2.Action {shortcut: "Return"onTriggered: addCurrentApplet()}Component {id: widgetExplorerComponentWidgetExplorer {//view: desktoponShouldClose: main.closed();}}PlasmaExtras.ModelContextMenu {id: categoriesDialogvisualParent: categoryButton// model set on first invocationonClicked: model => {list.contentX = 0list.contentY = 0categoryButton.text = (model.filterData ? model.display : i18ndc("plasma_shell_org.kde.plasma.desktop", "@action:button like listbox, switches category to all widgets", "All Widgets"))widgetExplorer.widgetsModel.filterQuery = model.filterDatawidgetExplorer.widgetsModel.filterType = model.filterType}}PlasmaExtras.ModelContextMenu {id: getWidgetsDialogvisualParent: getWidgetsButtonplacement: PlasmaExtras.Menu.TopPosedLeftAlignedPopup// model set on first invocationonClicked: model.trigger()}header: PlasmaExtras.PlasmoidHeading {// Subtract page's own margins since we touch the top, left, and righttopPadding: main.contentMargins - main.sidePanel.margins.topleftPadding: main.contentMargins - main.sidePanel.margins.leftrightPadding: main.contentMargins - main.sidePanel.margins.rightbottomPadding: main.contentMarginscontentItem: ColumnLayout {spacing: Kirigami.Units.largeSpacingRowLayout {spacing: Kirigami.Units.smallSpacingKirigami.Heading {id: headinglevel: 1text: i18ndc("plasma_shell_org.kde.plasma.desktop", "@title:group for widget grid", "Widgets")textFormat: Text.PlainTextelide: Text.ElideRightLayout.fillWidth: true}PC3.ToolButton {id: getWidgetsButtonicon.name: "get-hot-new-stuff"text: i18ndc("plasma_shell_org.kde.plasma.desktop", "@action:button The word 'new' refers to widgets", "Get Newβ¦")Accessible.name: i18ndc("plasma_shell_org.kde.plasma.desktop", "@action:button", "Get New Widgetsβ¦")KeyNavigation.right: closeButtonKeyNavigation.down: searchInputonClicked: {getWidgetsDialog.model = widgetExplorer.widgetsMenuActionsgetWidgetsDialog.openRelative()}}PC3.ToolButton {id: closeButtontext: i18nc("@action:button accessible for close button", "Close Widget Explorer")icon.name: "window-close"display: PC3.AbstractButton.IconOnlyKeyNavigation.down: categoryButtononClicked: main.closed()}}RowLayout {spacing: Kirigami.Units.smallSpacingPlasmaExtras.SearchField {id: searchInputLayout.fillWidth: trueAccessible.name: i18nc("@label:textbox accessible", "Search through widgets")KeyNavigation.down: listKeyNavigation.right: categoryButtononTextChanged: {list.positionViewAtBeginning()list.currentIndex = -1widgetExplorer.widgetsModel.searchTerm = text}Component.onCompleted: if (!Kirigami.InputMethod.willShowOnActive) { forceActiveFocus() }}PC3.ToolButton {id: categoryButtontext: i18ndc("plasma_shell_org.kde.plasma.desktop", "@action:button like listbox, switches category to all widgets", "All Widgets")icon.name: "view-filter"Accessible.role: Accessible.ButtonMenudown: categoriesDialog.status == PlasmaExtras.ModelContextMenu.Open || pressedKeyNavigation.down: listonClicked: {categoriesDialog.model = widgetExplorer.filterModelcategoriesDialog.open(0, categoryButton.height)}PC3.ToolTip {text: i18ndc("plasma_shell_org.kde.plasma.desktop", "@action:button tooltip only", "Categories")}}}}}footer: PlasmaExtras.PlasmoidHeading {id: footerContainer// Subtract page's own margins since we touch the left, right, and bottomtopPadding: main.contentMarginsleftPadding: main.contentMargins - main.sidePanel.margins.leftrightPadding: main.contentMargins - main.sidePanel.margins.rightbottomPadding: main.contentMargins - main.sidePanel.margins.bottomposition: PC3.ToolBar.Footervisible: pendingUninstallTimer.applets.length > 0contentItem: PC3.Button {id: uninstallButtonicon.name: "delete"text: i18ndcp("plasma_shell_org.kde.plasma.desktop", "@action:button uninstall widgets in widget explorer", "Uninstall (%1 Widget)", "Uninstall (%1 Widgets)", pendingUninstallTimer.applets.length)onClicked: pendingUninstallTimer.uninstall()}}Timer {id: setModelTimerinterval: 20running: trueonTriggered: list.model = widgetExplorer.widgetsModel}PC3.ScrollView {id: scrollViewanchors {fill: parent// Subtract page's own margins since we touch the left, right, and sometimes bottomtopMargin: -1 // account for PlasmoidHeading's pixelleftMargin: - main.sidePanel.margins.leftrightMargin: - main.sidePanel.margins.rightbottomMargin: footerContainer.visible ? 0 : - main.sidePanel.margins.bottom}// The scrollbar changing visibility can lead to the content size changing due to word wrap// A delayed binding gives some extra time, it'll come to a stop as there's only one scroll barproperty bool scrollBarVisibleBinding on scrollBarVisible {value: list.contentHeight > scrollView.heightdelayed: true}PC3.ScrollBar.horizontal.policy: PC3.ScrollBar.AlwaysOffPC3.ScrollBar.vertical.visible: scrollBarVisible// hide the flickering by fading in nicelyopacity: setModelTimer.running ? 0 : 1Behavior on opacity {OpacityAnimator {duration: Kirigami.Units.longDurationeasing.type: Easing.InOutQuad}}GridView {id: listreadonly property int effectiveWidth: width- leftMargin- rightMargin// model set delayed by Timer abovetopMargin: main.contentMarginsleftMargin: main.contentMarginsrightMargin: main.contentMarginsbottomMargin: main.contentMarginsactiveFocusOnTab: truecellWidth: Math.floor(effectiveWidth / 3)cellHeight: Kirigami.Units.iconSizes.enormous + Kirigami.Units.smallSpacing * 4 + headingFontMetrics.height * 3 * referenceHeading.lineHeight + descriptionFontMetrics.height * 2// This element is used as a reference to size the// cellHeight and should be kept in sync with the// heading within the AppletDelegate.Kirigami.Heading {id: referenceHeadingvisible: falselevel: 4lineHeight: 0.95}FontMetrics {id: headingFontMetricsfont: referenceHeading.font}FontMetrics {id: descriptionFontMetricsfont: Kirigami.Theme.smallFont}delegate: AppletDelegate {}highlight: PlasmaExtras.Highlight {pressed: list.currentItem && list.currentItem.pressed}highlightMoveDuration: 0//highlightResizeDuration: 0//slide in to view from the leftadd: Transition {// Work around https://bugreports.qt.io/browse/QTBUG-127709enabled: Kirigami.Units.shortDuration > 0NumberAnimation {properties: "x"from: -list.widthduration: Kirigami.Units.shortDuration}}//slide out of view to the rightremove: Transition {// Work around https://bugreports.qt.io/browse/QTBUG-127709enabled: Kirigami.Units.shortDuration > 0NumberAnimation {properties: "x"to: list.widthduration: Kirigami.Units.shortDuration}}//if we are adding other items into the view use the same animation as normal adding//this makes everything slide in together//if we make it move everything ends up weirdaddDisplaced: list.add//moved due to filteringdisplaced: Transition {NumberAnimation {properties: "x,y"duration: Kirigami.Units.shortDuration}}KeyNavigation.up: searchInputKeyNavigation.down: uninstallButton}}PlasmaExtras.PlaceholderMessage {anchors.centerIn: parentwidth: parent.width - (Kirigami.Units.gridUnit * 4)iconName: "edit-none"text: searchInput.text.length > 0 ? i18ndc("plasma_shell_org.kde.plasma.desktop", "@info placeholdermessage", "No widgets matched the search terms") : i18ndc("plasma_shell_org.kde.plasma.desktop", "@info placeholdermessage", "No widgets available")visible: list.count == 0 && !setModelTimer.running}}