ResultDelegate.qml 9.95 KB
Newer Older
1
2
3
/*
 * This file is part of the KDE Milou Project
 * Copyright (C) 2013-2014 Vishesh Handa <me@vhanda.in>
4
 * Copyright (C) 2015-2016 Kai Uwe Broulik <kde@privat.broulik.de>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) version 3, or any
 * later version accepted by the membership of KDE e.V. (or its
 * successor approved by the membership of KDE e.V.), which shall
 * act as a proxy defined in Section 6 of version 3 of the license.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

24
import QtQuick 2.1
25
import QtQuick.Layouts 1.1
26

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
27
import org.kde.plasma.core 2.0 as PlasmaCore
28
import org.kde.plasma.components 2.0 as PlasmaComponents
29

30
MouseArea {
31
    id: resultDelegate
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
32

33
    property variant theModel: model
34

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
35
    readonly property bool isCurrent: ListView.isCurrentItem // cannot properly Connect {} to this
36
37
38
39
    readonly property bool sectionHasChanged: typeof reversed !== "undefined" && (
                                                  (reversed && ListView.section != ListView.nextSection)
                                                    || (!reversed && ListView.section != ListView.previousSection)
                                                  )
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
40
41
42

    property int activeAction: -1

43
    property string typeText: sectionHasChanged ? ListView.section : ""
44
    property var additionalActions: typeof actions !== "undefined" ? actions : []
45
    property int categoryWidth: units.gridUnit * 10
46

Marco Martin's avatar
Marco Martin committed
47
48
    Accessible.role: Accessible.ListItem
    Accessible.name: displayLabel.text
49
50
51
52
53
54
55
56
57
58
59
60
    Accessible.description: {
        var section = ListView.section;
        if (!section) {
            return "";
        }
        var subtext = subtextLabel.text;
        if (subtext.length > 0) {
            return i18nd("milou", "%1, in category %2", subtext, section);
        } else {
            return i18nd("milou", "in category %1", section);
        }
    }
61

62
63
64
    property bool __pressed: false
    property int __pressX: -1
    property int __pressY: -1
65

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    onIsCurrentChanged: {
        if (!isCurrent) {
            activeAction = -1
        }
    }

    function activateNextAction() {
        if (activeAction === actionsRepeater.count - 1) { // last action, do nothing
            return false
        }
        ++activeAction
        return true
    }

    function activatePreviousAction() {
        if (activeAction < 0) { // no action, do nothing
            return false
        }
        --activeAction
        return true
    }

    function activateLastAction() {
        activeAction = actionsRepeater.count - 1
    }

92
93
94
    width: listItem.implicitWidth
    height: listItem.implicitHeight

95
    acceptedButtons: Qt.LeftButton
96
    hoverEnabled: true
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    onPressed: {
        __pressed = true;
        __pressX = mouse.x;
        __pressY = mouse.y;
    }

    onReleased: {
        if (__pressed) {
            listView.currentIndex = model.index
            listView.runCurrentIndex()
        }

        __pressed = false;
        __pressX = -1;
        __pressY = -1;
    }

    onPositionChanged: {
        if (__pressX != -1 && typeof dragHelper !== "undefined" && dragHelper.isDrag(__pressX, __pressY, mouse.x, mouse.y)) {
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
116
117
            var resultsModel = ListView.view.model;
            var mimeData = resultsModel.getMimeData(resultsModel.index(index, 0));
118
            if (mimeData) {
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
119
                dragHelper.startDrag(resultDelegate, mimeData, model.decoration);
120
121
122
123
124
                __pressed = false;
                __pressX = -1;
                __pressY = -1;
            }
        }
125
126
127
128
129

        if (!listView.moved && listView.mouseMovedGlobally()) {
            listView.moved = true
            listView.currentIndex = index
        }
130
131
132
133
134
135
136
    }

    onContainsMouseChanged: {
        if (!containsMouse) {
            __pressed = false;
            __pressX = -1;
            __pressY = -1;
137
138
139
140
141
142
143
        } else {
            if (listView.moved) {
                listView.currentIndex = index
            } else if (listView.mouseMovedGlobally()) {
                listView.moved = true
                listView.currentIndex = index
            }
144
145
146
        }
    }

Vishesh Handa's avatar
Vishesh Handa committed
147
148
    PlasmaComponents.Label {
        id: typeText
149
        text: resultDelegate.typeText
150
        color: isCurrent ? Qt.tint(theme.disabledTextColor, Qt.rgba(theme.textColor.r, theme.textColor.g, theme.textColor.b, 0.4)) : theme.disabledTextColor
151

Vishesh Handa's avatar
Vishesh Handa committed
152
153
154
        horizontalAlignment: Text.AlignRight
        verticalAlignment: Text.AlignVCenter
        elide: Text.ElideRight
155
        textFormat: Text.PlainText
156

157
        width: resultDelegate.categoryWidth - units.largeSpacing
Vishesh Handa's avatar
Vishesh Handa committed
158
159
160
161
162
        anchors {
            left: parent.left
            verticalCenter: listItem.verticalCenter
        }
    }
163

Eike Hein's avatar
Eike Hein committed
164
165
    PlasmaComponents.ListItem {
        id: listItem
166

Nate Graham's avatar
Nate Graham committed
167
168
        readonly property int indexModifier: reversed ? 0 : 1

169
170
        // fake pressed look
        checked: resultDelegate.pressed
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
171
172
        separatorVisible: resultDelegate.sectionHasChanged
                       && !resultDelegate.isCurrent
Nate Graham's avatar
Nate Graham committed
173
                       && (index === 0 || resultDelegate.ListView.view.currentIndex !== (index - indexModifier))
174

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
175
        Item {
176
            id: labelWrapper
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
177
178
179
            anchors {
                left: parent.left
                right: parent.right
180
                leftMargin: resultDelegate.categoryWidth
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
181
            }
182
            height: Math.max(typePixmap.height, displayLabel.height, subtextLabel.height)
183

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
184
185
186
187
188
189
            RowLayout {
                anchors {
                    left: parent.left
                    right: actionsRow.left
                    rightMargin: units.smallSpacing
                }
Eike Hein's avatar
Eike Hein committed
190

191
                PlasmaCore.IconItem {
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
192
                    id: typePixmap
193
194
                    Layout.preferredWidth: units.iconSizes.small
                    Layout.preferredHeight: units.iconSizes.small
195
196
197
198
                    Layout.fillHeight: true
                    source: model.decoration
                    usesPlasmaTheme: false
                    animated: false
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
199
                }
Eike Hein's avatar
Eike Hein committed
200

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
201
202
203
                PlasmaComponents.Label {
                    id: displayLabel
                    text: String(typeof modelData !== "undefined" ? modelData : model.display)
Eike Hein's avatar
Eike Hein committed
204

205
                    height: undefined
Eike Hein's avatar
Eike Hein committed
206

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
207
                    elide: Text.ElideMiddle
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
208
                    wrapMode: Text.NoWrap
209
                    maximumLineCount: 1
210
                    verticalAlignment: Text.AlignVCenter
211
                    textFormat: Text.PlainText
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
212

213
                    Layout.maximumWidth: labelWrapper.width - typePixmap.width - actionsRow.width
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
214
                }
215

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
216
217
                PlasmaComponents.Label {
                    id: subtextLabel
218
219
220
221

                    // SourcesModel returns number of duplicates in this property
                    // ResultsModel just has it as a boolean as you would expect from the name of the property
                    text: model.isDuplicate === true || model.isDuplicate > 1 || resultDelegate.isCurrent ? String(model.subtext || "") : ""
222

223
224
                    // HACK If displayLabel is too long it will shift this label outside boundaries
                    // but still render the text leading to it overlapping the action buttons looking horrible
225
226
                    opacity: width > 0 ? 1 : 0

227
                    color: isCurrent ? Qt.tint(theme.disabledTextColor, Qt.rgba(theme.textColor.r, theme.textColor.g, theme.textColor.b, 0.4)) : theme.disabledTextColor
228

229
                    height: undefined
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
230

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
231
232
                    elide: Text.ElideMiddle
                    wrapMode: Text.NoWrap
233
                    maximumLineCount: 1
234
                    verticalAlignment: Text.AlignVCenter
235
236
                    textFormat: Text.PlainText

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
237
238
239
                    Layout.fillWidth: true
                }
            }
240

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
241
242
243
244
            Row {
                id: actionsRow
                anchors.right: parent.right
                anchors.verticalCenter: parent.verticalCenter
245
                visible: resultDelegate.isCurrent
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
246
247
248

                Repeater {
                    id: actionsRepeater
249
                    model: resultDelegate.additionalActions
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
250
251
252
253

                    PlasmaComponents.ToolButton {
                        width: height
                        height: listItem.height
254
255
                        visible: modelData.visible || true
                        enabled: modelData.enabled || true
256
257
258
                        tooltip: {
                            var text = modelData.text || ""
                            if (index === 0) { // Shift+Return will invoke first action
Xuetian Weng's avatar
Xuetian Weng committed
259
                                text = i18ndc("milou", "placeholder is action e.g. run in terminal, in parenthesis is shortcut", "%1 (Shift+Return)", text)
260
261
262
                            }
                            return text
                        }
Marco Martin's avatar
Marco Martin committed
263
264
                        Accessible.role: Accessible.Button
                        Accessible.name: modelData.text
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
265
266
                        checkable: checked
                        checked: resultDelegate.activeAction === index
Marco Martin's avatar
Marco Martin committed
267
                        focus: resultDelegate.activeAction === index
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
268
269
270

                        PlasmaCore.IconItem {
                            anchors.centerIn: parent
271
272
                            width: units.iconSizes.small
                            height: units.iconSizes.small
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
273
                            // ToolButton cannot cope with QIcon
274
                            source: modelData.icon || ""
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
275
276
277
                            active: parent.hovered || parent.checked
                        }

278
                        onClicked: resultDelegate.ListView.view.runAction(index)
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
279
280
                    }
                }
281
            }
282
283
        }
    }
284
}