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 }