🏑 index : quine-global-labs/mirror-kde-plasma-desktop.git

/*
    SPDX-FileCopyrightText: 2018 Tomaz Canabrava <tcanabrava@kde.org>

    SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/

import QtCore
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import QtQuick.Dialogs as QtDialogs
import org.kde.baloo.experimental as Baloo
import org.kde.kirigami as Kirigami
import org.kde.kcmutils as KCM

KCM.ScrollViewKCM {
    id: root

    implicitWidth: Kirigami.Units.gridUnit * 42
    implicitHeight: Kirigami.Units.gridUnit * 25

    Baloo.Monitor {
        id: monitor

        readonly property bool currentlyIndexing: switch(state) {
            case Baloo.Global.FirstRun:
            case Baloo.Global.NewFiles:
            case Baloo.Global.ModifiedFiles:
            case Baloo.Global.XAttrFiles:
            case Baloo.Global.ContentIndexing:
            case Baloo.Global.UnindexedFileCheck:
            case Baloo.Global.StaleIndexEntriesClean:
                return true;
            default:
                return false;
        }

        readonly property int completionPercentage: Math.floor(filesIndexed / totalFiles * 100)
    }

    actions: [
        Kirigami.Action {
            icon.name: monitor.state !== Baloo.Global.Suspended ? "media-playback-pause" : "media-playback-start"
            text: monitor.state !== Baloo.Global.Suspended ? i18nc("@action:button", "Pause Indexer") : i18nc("@action:button", "Resume Indexer")
            visible: kcm.balooSettings.indexingEnabled
            displayHint: Kirigami.DisplayHint.KeepVisible
            onTriggered: monitor.toggleSuspendState()
        }
    ]

    headerPaddingEnabled: false // Let the InlineMessages touch the edges
    header: ColumnLayout {
        spacing: Kirigami.Units.smallSpacing

        Kirigami.InlineMessage {
            Layout.fillWidth: true
            visible: fileSearchDisabled.checked && kcm.needsSave
            type: Kirigami.MessageType.Warning
            position: Kirigami.InlineMessage.Position.Header
            showCloseButton: true
            text: i18nc("@info inlinemessage", "This will disable file searching in KRunner and launcher menus, and remove extended metadata display from all KDE applications.");
        }

        Kirigami.InlineMessage {
            id: indexingDisabledWarning
            Layout.fillWidth: true
            visible: !kcm.balooSettings.indexingEnabled && !kcm.needsSave && kcm.rawIndexFileSize() > 0
            type: Kirigami.MessageType.Warning
            position: Kirigami.InlineMessage.Position.Header
            showCloseButton: true
            text: i18nc("@info:inlinemessage", "Do you want to delete the saved index data? %1 of space will be freed, but if indexing is re-enabled later, the entire index will have to be re-created from scratch. This may take some time, depending on the number of files to index.", kcm.prettyIndexFileSize());
            actions: Kirigami.Action {
                text: i18nc("@action:button", "Delete Index Data")
                icon.name: "edit-delete"
                onTriggered: {
                    kcm.deleteIndex();
                    indexingDisabledWarning.visible = false;
                }
            }
        }

        QQC2.Label {
            text: i18nc("@info:usagetip", "File Search helps you quickly locate your files. You can choose which folders and what types of file data are indexed.")
            textFormat: Text.PlainText
            Layout.fillWidth: true
            Layout.maximumWidth: Kirigami.Units.gridUnit * 24
            Layout.alignment: Qt.AlignHCenter
            Layout.topMargin: Kirigami.Units.largeSpacing * 2
            Layout.bottomMargin: Kirigami.Units.largeSpacing
            horizontalAlignment: Text.AlignHCenter
            wrapMode: Text.WordWrap
        }
        // By disabling header margins to make the header banners look correct,
        // we have to re-add some margins for the content area so it doesn't
        // touch the window edges and look ugly. To make it apply to everything,
        // we wrap it all in another ColumnLayout with its own margins.
        Kirigami.Form {
            Layout.bottomMargin: Kirigami.Units.largeSpacing * 2
            Layout.fillWidth: true
            Kirigami.FormGroup {
                Kirigami.FormEntry {
                    title: i18nc("@title:group", "Data to index:")
                    contentItem: QQC2.RadioButton {
                        id: fileSearchDisabled

                        text: i18nc("@option:radio Data to index", "Nothing (disable indexing entirely)")
                        checked: !kcm.balooSettings.indexingEnabled
                        onToggled: kcm.balooSettings.indexingEnabled = false

                        QQC2.ButtonGroup.group: indexingStyleGroup

                        KCM.SettingStateBinding {
                            configObject: kcm.balooSettings
                            settingName: "indexingEnabled"
                        }
                        QQC2.ButtonGroup {
                            id: indexingStyleGroup
                        }
                    }
                }

                Kirigami.FormEntry {
                    contentItem: QQC2.RadioButton {
                        text: i18nc("@option:radio Data to index", "File names only")
                        checked: kcm.balooSettings.indexingEnabled && kcm.balooSettings.onlyBasicIndexing
                        onToggled: {
                            kcm.balooSettings.indexingEnabled = true;
                            kcm.balooSettings.onlyBasicIndexing = true;
                        }

                        QQC2.ButtonGroup.group: indexingStyleGroup

                        KCM.SettingStateBinding {
                            configObject: kcm.balooSettings
                            settingName: "onlyBasicIndexing"
                        }
                    }
                }

                Kirigami.FormEntry {
                    contentItem: QQC2.RadioButton {
                        text: i18nc("@option:radio Data to index", "File names and contents")
                        checked: kcm.balooSettings.indexingEnabled && !kcm.balooSettings.onlyBasicIndexing
                        onToggled: {
                            kcm.balooSettings.indexingEnabled = true;
                            kcm.balooSettings.onlyBasicIndexing = false;
                        }

                        QQC2.ButtonGroup.group: indexingStyleGroup

                        KCM.SettingStateBinding {
                            configObject: kcm.balooSettings
                            settingName: "onlyBasicIndexing"
                        }
                    }
                }


                Kirigami.FormEntry {
                    contentItem: QQC2.CheckBox {
                        id: indexHiddenFolders
                        text: i18nc("@option:check", "Also index hidden files and folders")
                        checked: kcm.balooSettings.indexHiddenFolders
                        onCheckStateChanged: kcm.balooSettings.indexHiddenFolders = checked

                        KCM.SettingStateBinding {
                            configObject: kcm.balooSettings
                            settingName: "indexHiddenFolders"
                            extraEnabledConditions: !fileSearchDisabled.checked
                        }
                    }
                }
            }
        }
    }

    view: ListView {
        id: directoryConfigList
        enabled: !fileSearchDisabled.checked
        clip: true
        currentIndex: -1

        model: kcm.filteredModel
        delegate: directoryConfigDelegate

        headerPositioning: ListView.OverlayHeader
        header: Kirigami.InlineViewHeader {
            width: directoryConfigList.width
            text: i18nc("@title:table Locations to include or exclude from indexing", "Locations")
            actions: [
                Kirigami.Action {
                    text: i18nc("@action:button", "Start Indexing a Folder…")
                    icon.name: "list-add-symbolic"
                    onTriggered: {
                        fileDialogLoader.included = true
                        fileDialogLoader.active = true
                    }
                },
                Kirigami.Action {
                    text: i18nc("@action:button", "Stop Indexing a Folder…")
                    icon.name: "list-remove-symbolic"
                    onTriggered: {
                        fileDialogLoader.included = false
                        fileDialogLoader.active = true
                    }
                }
            ]
        }
    }

    extraFooterTopPadding: true // re-add separator line
    footer: ColumnLayout {
        visible: !fileSearchDisabled.checked
        spacing: Kirigami.Units.smallSpacing

        QQC2.Label {
            Layout.fillWidth: true
            text: i18nc("State and a percentage of progress", "%1, %2% complete", monitor.stateString, monitor.completionPercentage)
            textFormat: Text.PlainText
        }

        Kirigami.SelectableLabel {
            Layout.fillWidth: true
            visible: monitor.currentlyIndexing && monitor.completionPercentage !== 100 && monitor.filePath.length > 0
            text: xi18nc("@info Currently Indexing", "Currently indexing: <filename>%1</filename>", monitor.filePath)
        }
    }

    Component {
        id: directoryConfigDelegate
        QQC2.ItemDelegate {
            id: listItem

            // Store this as a property so we can access it within the combobox,
            // which also has a `model` property
            property var indexingModel: model

            width: directoryConfigList.width

            // There's no need for a list item to ever be selected
            down: false
            highlighted: false
            hoverEnabled: false
            // ... and because of that, use alternating backgrounds to visually
            // connect list items' left and right side content elements
            Kirigami.Theme.useAlternateBackgroundColor: true

            contentItem: RowLayout {
                spacing: Kirigami.Units.smallSpacing

                // The folder's icon
                Kirigami.Icon {
                    source: indexingModel.decoration

                    Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
                    Layout.preferredWidth: Layout.preferredHeight
                }

                // The folder's path
                QQC2.Label {
                    text: indexingModel.folder
                    textFormat: Text.PlainText
                    elide: Text.ElideRight

                    Layout.fillWidth: true
                }

                // What kind of indexing to do for the folder
                QQC2.ComboBox {
                    id: indexingOptionsCombobox

                    property bool indexingDisabled: !indexingModel.enableIndex
                    property bool fullContentIndexing: indexingModel.enableIndex

                    model: [
                        i18nc("@info:status", "Not indexed"),
                        i18nc("@info:status", "Indexed"),
                    ]

                    // Intentionally not a simple ternary to facilitate adding
                    // more conditions in the future
                    currentIndex: {
                        if (indexingDisabled) return 0
                        if (fullContentIndexing) return 1
                    }

                    onActivated: {
                        // New value is "Not indexed"
                        if (indexingOptionsCombobox.currentIndex === 0 && fullContentIndexing) {
                            indexingModel.enableIndex = false
                        // New value is "Full content indexing"
                        } else if (indexingOptionsCombobox.currentIndex === 1 && indexingDisabled) {
                            indexingModel.enableIndex = true
                        }
                    }
                }

                // Delete button to remove this folder entry
                QQC2.Button {
                    enabled: model.deletable

                    icon.name: "edit-delete-remove"
                    text: i18nc("Remove the list item for this filesystem path", "Remove entry")
                    display: QQC2.AbstractButton.IconOnly

                    onClicked: kcm.filteredModel.removeFolder(index)

                    QQC2.ToolTip.text: text
                    QQC2.ToolTip.visible: hovered || activeFocus
                    QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
                }
            }
        }
    }

    Loader {
        id: fileDialogLoader

        property bool included: false

        active: false

        sourceComponent: QtDialogs.FolderDialog {
            title: fileDialogLoader.included ? i18nc("@title:window", "Select a folder to include") : i18nc("@title:window", "Select a folder to exclude")
            currentFolder: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]

            onAccepted: {
                kcm.filteredModel.addFolder(selectedFolder, fileDialogLoader.included)
                fileDialogLoader.active = false
            }

            onRejected: {
                fileDialogLoader.active = false
            }

            Component.onCompleted: open()
        }
    }
}