Warning, /plasma/milou/lib/qml/ResultDelegate.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  * This file is part of the KDE Milou Project
0003  * SPDX-FileCopyrightText: 2013-2014 Vishesh Handa <me@vhanda.in>
0004  * SPDX-FileCopyrightText: 2015-2016 Kai Uwe Broulik <kde@privat.broulik.de>
0005  *
0006  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007  *
0008  */
0009 
0010 import QtQuick
0011 import QtQuick.Layouts
0012 
0013 import org.kde.kirigami as Kirigami
0014 import org.kde.plasma.components as PlasmaComponents3
0015 import org.kde.milou as Milou
0016 import org.kde.ksvg 1.0 as KSvg
0017 
0018 PlasmaComponents3.ItemDelegate {
0019     id: resultDelegate
0020 
0021     implicitHeight: labelWrapper.implicitHeight + Kirigami.Units.mediumSpacing * 2
0022     down: tapHandler.pressed
0023     hoverEnabled: true
0024 
0025     readonly property int indexModifier: reversed ? 0 : 1
0026     readonly property QtObject theModel: model
0027     property bool reversed: false
0028 
0029     readonly property bool isCurrent: ListView.isCurrentItem // cannot properly Connect {} to this
0030     readonly property bool sectionHasChanged: (reversed && ListView.section != ListView.nextSection)
0031                                            || (!reversed && ListView.section != ListView.previousSection)
0032 
0033     property int activeAction: -1
0034 
0035     property string typeText: sectionHasChanged ? ListView.section : ""
0036     property var additionalActions: typeof actions !== "undefined" ? actions : []
0037     property int categoryWidth: Kirigami.Units.gridUnit * 10
0038 
0039     Accessible.role: Accessible.ListItem
0040     Accessible.name: displayLabel.text
0041     Accessible.description: {
0042         var section = ListView.section;
0043         if (!section) {
0044             return "";
0045         }
0046         var subtext = subtextLabel.text;
0047         if (subtext.length > 0) {
0048             return i18nd("milou", "%1, in category %2", subtext, section);
0049         } else {
0050             return i18nd("milou", "in category %1", section);
0051         }
0052     }
0053 
0054     onIsCurrentChanged: {
0055         if (!isCurrent) {
0056             activeAction = -1
0057         }
0058     }
0059 
0060     function activateNextAction() {
0061         if (activeAction === actionsRepeater.count - 1) { // last action, do nothing
0062             return false
0063         }
0064         ++activeAction
0065         return true
0066     }
0067 
0068     function activatePreviousAction() {
0069         if (activeAction < 0) { // no action, do nothing
0070             return false
0071         }
0072         --activeAction
0073         return true
0074     }
0075 
0076     function activateLastAction() {
0077         activeAction = actionsRepeater.count - 1
0078     }
0079 
0080     onClicked: {
0081         resultDelegate.ListView.view.currentIndex = index
0082         resultDelegate.ListView.view.runCurrentIndex()
0083     }
0084 
0085     DragHandler {
0086         id: dragHandler
0087         parent: labelWrapper
0088         target: labelLayout
0089         grabPermissions: PointerHandler.TakeOverForbidden
0090         onActiveChanged: if (active) {
0091             typePixmap.grabToImage((result) => {
0092                 const mimeData = resultDelegate.ListView.view.model.getMimeData(resultDelegate.ListView.view.model.index(index, 0));
0093                 if (!mimeData) {
0094                     return;
0095                 }
0096                 dragHelper.Drag.imageSource = result.url;
0097                 dragHelper.Drag.mimeData = Milou.MouseHelper.generateMimeDataMap(mimeData);
0098                 dragHelper.Drag.active = dragHandler.active;
0099             });
0100         } else {
0101             dragHelper.Drag.active = false;
0102         }
0103     }
0104 
0105     contentItem: Item {
0106         id: labelWrapper
0107         implicitHeight: labelLayout.implicitHeight
0108 
0109         readonly property color dimmedTextColor: {
0110             if (resultDelegate.down) {
0111                 return Qt.tint(Kirigami.Theme.highlightedTextColor, Qt.alpha(Kirigami.Theme.textColor, 0.2));
0112             } else if (resultDelegate.isCurrent) {
0113                 return Qt.tint(Kirigami.Theme.disabledTextColor, Qt.alpha(Kirigami.Theme.textColor, 0.4));
0114             } else {
0115                 return Kirigami.Theme.disabledTextColor;
0116             }
0117         }
0118 
0119         HoverHandler {
0120             enabled: !resultDelegate.isCurrent
0121             onPointChanged: {
0122                 // In case we display the history we have a QML ListView which does not have the moved property
0123                 if (!resultDelegate.ListView.view.hasOwnProperty("moved") || resultDelegate.ListView.view.moved) {
0124                     resultDelegate.ListView.view.currentIndex = index
0125                 } else if (resultDelegate.ListView.view.mouseMovedGlobally()) {
0126                     resultDelegate.ListView.view.moved = true
0127                     resultDelegate.ListView.view.currentIndex = index
0128                 }
0129             }
0130         }
0131 
0132         // QTBUG-63395: DragHandler blocks ItemDelegate's clicked signal
0133         TapHandler {
0134             id: tapHandler
0135             onTapped: resultDelegate.clicked()
0136         }
0137 
0138         KSvg.SvgItem {
0139             width: parent.width
0140             height: 1
0141             anchors.bottom: parent.top
0142             anchors.bottomMargin: Kirigami.Units.smallSpacing
0143             imagePath: "widgets/line"
0144             elementId: "horizontal-line"
0145             visible: resultDelegate.sectionHasChanged
0146                      && !resultDelegate.isCurrent
0147                      && resultDelegate.index !== 0
0148                      && resultDelegate.ListView.view.currentIndex !== (index - indexModifier)
0149             opacity: 0.5
0150         }
0151 
0152         PlasmaComponents3.Label {
0153             id: typeText
0154             anchors {
0155                 left: parent.left
0156                 verticalCenter: labelWrapper.verticalCenter
0157             }
0158             width: resultDelegate.categoryWidth - Kirigami.Units.largeSpacing
0159             color: labelWrapper.dimmedTextColor
0160             elide: Text.ElideRight
0161             text: resultDelegate.typeText
0162             textFormat: Text.PlainText
0163             horizontalAlignment: Text.AlignRight
0164             verticalAlignment: Text.AlignVCenter
0165         }
0166 
0167         RowLayout {
0168             id: labelLayout
0169             anchors {
0170                 left: parent.left
0171                 leftMargin: resultDelegate.categoryWidth
0172                 right: actionsRow.visible ? actionsRow.left : parent.right
0173                 rightMargin: actionsRow.visible ? Kirigami.Units.smallSpacing : 0
0174                 verticalCenter: parent.verticalCenter
0175             }
0176 
0177             Kirigami.Icon {
0178                 id: typePixmap
0179                 Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
0180                 Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
0181                 Layout.rightMargin: Kirigami.Units.smallSpacing
0182                 Layout.alignment: Qt.AlignVCenter
0183                 source: model.decoration
0184                 animated: false
0185                 selected: resultDelegate.down
0186             }
0187 
0188             PlasmaComponents3.Label {
0189                 id: displayLabel
0190                 text: String(typeof modelData !== "undefined" ? modelData : model.display)
0191 
0192                 elide: Text.ElideMiddle
0193                 wrapMode: model.multiLine ? Text.WordWrap : Text.NoWrap
0194                 maximumLineCount: model.multiLine ? Infinity : 1
0195                 verticalAlignment: Text.AlignVCenter
0196                 // For multiLine we offer styled text, otherwise we default to plain text
0197                 textFormat: model.multiLine ? Text.StyledText : Text.PlainText
0198                 color: resultDelegate.down ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor
0199                 // The extra spacing accounts for the right margin so the text doesn't overlap the actions
0200                 Layout.rightMargin: Kirigami.Units.smallSpacing
0201                 Layout.maximumWidth: labelLayout.width - typePixmap.implicitWidth
0202 
0203                 PlasmaComponents3.ToolTip {
0204                     text: displayLabel.text
0205                     visible: displayLabelHoverHandler.hovered && displayLabel.truncated
0206                     timeout: -1
0207                 }
0208 
0209                 HoverHandler {
0210                     id: displayLabelHoverHandler
0211                 }
0212             }
0213 
0214             PlasmaComponents3.Label {
0215                 id: subtextLabel
0216                 Layout.fillWidth: true
0217                 // HACK If displayLabel is too long it will shift this label outside boundaries
0218                 // but still render the text leading to it overlapping the action buttons looking horrible
0219                 opacity: width > 0 ? 1 : 0
0220                 // SourcesModel returns number of duplicates in this property
0221                 // ResultsModel just has it as a boolean as you would expect from the name of the property
0222                 text: model.isDuplicate === true || model.isDuplicate > 1 || resultDelegate.isCurrent ? String(model.subtext || "") : ""
0223 
0224                 color: labelWrapper.dimmedTextColor
0225                 elide: Text.ElideMiddle
0226                 wrapMode: Text.NoWrap
0227                 maximumLineCount: 1
0228                 verticalAlignment: Text.AlignVCenter
0229                 textFormat: Text.PlainText
0230 
0231                 PlasmaComponents3.ToolTip {
0232                     text: subtextLabel.text
0233                     visible: subtextLabelHoverHandler.hovered && subtextLabel.truncated
0234                     timeout: -1
0235                 }
0236 
0237                 HoverHandler {
0238                     id: subtextLabelHoverHandler
0239                 }
0240             }
0241         }
0242 
0243         Row {
0244             id: actionsRow
0245             anchors.right: parent.right
0246             anchors.verticalCenter: labelWrapper.verticalCenter
0247             visible: resultDelegate.isCurrent && actionsRepeater.count > 0
0248 
0249             Repeater {
0250                 id: actionsRepeater
0251                 model: resultDelegate.additionalActions
0252 
0253                 PlasmaComponents3.ToolButton {
0254                     width: height
0255                     height: Kirigami.Units.iconSizes.medium
0256                     visible: modelData.visible || true
0257                     enabled: modelData.enabled || true
0258 
0259                     Accessible.role: Accessible.Button
0260                     Accessible.name: modelData.text
0261                     checkable: checked
0262                     checked: resultDelegate.activeAction === index
0263                     focus: resultDelegate.activeAction === index
0264 
0265                     Kirigami.Icon {
0266                         anchors.centerIn: parent
0267                         implicitWidth: Kirigami.Units.iconSizes.smallMedium
0268                         implicitHeight: Kirigami.Units.iconSizes.smallMedium
0269                         // ToolButton cannot cope with QIcon
0270                         source: modelData.iconSource || ""
0271                         active: parent.hovered || parent.checked
0272                     }
0273 
0274                     PlasmaComponents3.ToolTip {
0275                         text: {
0276                             var text = modelData.text || ""
0277                             if (index === 0) { // Shift+Return will invoke first action
0278                                 text = i18ndc("milou", "placeholder is action e.g. run in terminal, in parenthesis is shortcut", "%1 (Shift+Return)", text)
0279                             }
0280                             return text
0281                         }
0282                     }
0283 
0284                     onClicked: resultDelegate.ListView.view.runAction(index)
0285                 }
0286             }
0287         }
0288     }
0289 }