JobItem.qml 8.97 KB
Newer Older
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright 2019 Kai Uwe Broulik <kde@privat.broulik.de>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 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 14 of version 3 of the license.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

import QtQuick 2.8
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1

import org.kde.plasma.core 2.0 as PlasmaCore
26
import org.kde.plasma.components 3.0 as PlasmaComponents3
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
27
28

import org.kde.notificationmanager 1.0 as NotificationManager
29

30
import org.kde.plasma.private.notifications 2.0 as Notifications
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
31
32
33
34
35

ColumnLayout {
    id: jobItem

    property int jobState
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
36
    property int jobError
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
37
38
39
40
41
42
43
44

    property alias percentage: progressBar.value
    property alias suspendable: suspendButton.visible
    property alias killable: killButton.visible

    property bool hovered
    property QtObject jobDetails

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
    readonly property int totalFiles: jobItem.jobDetails && jobItem.jobDetails.totalFiles || 0
    readonly property var url: {
       if (jobItem.jobState !== NotificationManager.Notifications.JobStateStopped
               || jobItem.jobError
               || totalFiles <= 0) {
           return null;
       }

       // For a single file show actions for it
       if (totalFiles === 1) {
           return jobItem.jobDetails.descriptionUrl;
       // Otherwise the destination folder all of them were copied into
       } else {
           return jobItem.jobDetails.destUrl;
       }
   }

    property alias iconContainerItem: jobDragIcon.parent

    readonly property alias dragging: jobDragArea.dragging
65
66
    readonly property alias menuOpen: otherFileActionsMenu.visible

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
67
68
69
70
    signal suspendJobClicked
    signal resumeJobClicked
    signal killJobClicked

71
    signal openUrl(string url)
72
    signal fileActionInvoked
73

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
74
75
    spacing: 0

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    // This item is parented to the NotificationItem iconContainer
    PlasmaCore.IconItem {
        id: jobDragIcon
        width: parent ? parent.width : 0
        height: parent ? parent.height : 0
        usesPlasmaTheme: false
        visible: valid
        active: jobDragArea.containsMouse
        source: jobItem.totalFiles === 1 && jobItem.url ? plasmoid.nativeInterface.iconNameForUrl(jobItem.url) : ""

        Binding {
            target: jobDragIcon.parent
            property: "visible"
            value: true
            when: jobDragIcon.valid
        }

        DraggableFileArea {
            id: jobDragArea
            anchors.fill: parent

            hoverEnabled: true
            dragParent: jobDragIcon
            dragUrl: jobItem.url || ""
            dragPixmap: jobDragIcon.source

            onActivated: jobItem.openUrl(jobItem.url)
            onContextMenuRequested: {
                // avoid menu button glowing if we didn't actually press it
                otherFileActionsButton.checked = false;

                otherFileActionsMenu.visualParent = this;
                otherFileActionsMenu.open(x, y);
            }
        }
    }

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
113
    RowLayout {
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
114
        id: progressRow
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
115
116
117
        Layout.fillWidth: true
        spacing: units.smallSpacing

118
        PlasmaComponents3.ProgressBar {
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
119
120
            id: progressBar
            Layout.fillWidth: true
121
122
            from: 0
            to: 100
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
123
124
125
126
127
128
129
130
131
132
133
134
            // TODO do we actually need the window visible check? perhaps I do because it can be in popup or expanded plasmoid
            indeterminate: visible && Window.window && Window.window.visible && percentage < 1
                           && jobItem.jobState === NotificationManager.Notifications.JobStateRunning
                           // is this too annoying?
                           && (jobItem.jobDetails.processedBytes === 0 || jobItem.jobDetails.totalBytes === 0)
                           && jobItem.jobDetails.processedFiles === 0
                           //&& jobItem.jobDetails.processedDirectories === 0
        }

        RowLayout {
            spacing: 0

135
            PlasmaComponents3.ToolButton {
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
136
                id: suspendButton
137
                icon.name: "media-playback-pause"
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
138
139
                onClicked: jobItem.jobState === NotificationManager.Notifications.JobStateSuspended ? jobItem.resumeJobClicked()
                                                                                                    : jobItem.suspendJobClicked()
140
141
142
143

                PlasmaComponents3.ToolTip {
                    text: i18ndc("plasma_applet_org.kde.plasma.notifications", "Pause running job", "Pause")
                }
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
144
145
            }

146
            PlasmaComponents3.ToolButton {
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
147
                id: killButton
148
                icon.name: "media-playback-stop"
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
149
                onClicked: jobItem.killJobClicked()
150
151
152
153

                PlasmaComponents3.ToolTip {
                    text: i18ndc("plasma_applet_org.kde.plasma.notifications", "Cancel running job", "Cancel")
                }
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
154
155
            }

156
            PlasmaComponents3.ToolButton {
157
                id: expandButton
158
                icon.name: checked ? "arrow-down" : (LayoutMirroring.enabled ? "arrow-left" : "arrow-right")
159
                checkable: true
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
160
                enabled: jobItem.jobDetails && jobItem.jobDetails.hasDetails
161
162

                PlasmaComponents3.ToolTip {
163
                    text: expandButton.checked ? i18ndc("plasma_applet_org.kde.plasma.notifications", "A button tooltip; hides item details", "Hide Details")
164
165
                                  : i18ndc("plasma_applet_org.kde.plasma.notifications", "A button tooltip; expands the item to show details", "Show Details")
                }
166
            }
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
167
168
169
170
171
172
173
174
175
176
177
178
179
        }
    }

    Loader {
        Layout.fillWidth: true
        active: expandButton.checked
        // Loader doesn't reset its height when unloaded, just hide it altogether
        visible: active
        sourceComponent: JobDetails {
            jobDetails: jobItem.jobDetails
        }
    }

180
    Flow { // it's a Flow so it can wrap if too long
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
181
182
        Layout.fillWidth: true
        spacing: units.smallSpacing
183
184
        // We want the actions to be right-aligned but Flow also reverses
        // the order of items, so we put them in reverse order
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
185
        layoutDirection: Qt.RightToLeft
186
187
        visible: url && url.toString() !== ""

188
        PlasmaComponents3.Button {
189
            id: otherFileActionsButton
190
            height: Math.max(implicitHeight, openButton.implicitHeight)
191
            icon.name: "application-menu"
192
193
194
195
196
197
            checkable: true
            onPressedChanged: {
                if (pressed) {
                    checked = Qt.binding(function() {
                        return otherFileActionsMenu.visible;
                    });
198
199
                    otherFileActionsMenu.visualParent = this;
                    // -1 tells it to "align bottom left of visualParent (this)"
200
201
202
                    otherFileActionsMenu.open(-1, -1);
                }
            }
203

204
205
206
207
            PlasmaComponents3.ToolTip {
                text: i18nd("plasma_applet_org.kde.plasma.notifications", "More Options...")
            }

208
209
            Notifications.FileMenu {
                id: otherFileActionsMenu
210
                url: jobItem.url || ""
211
                onActionTriggered: jobItem.fileActionInvoked()
212
            }
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
213
214
        }

215
        PlasmaComponents3.Button {
216
217
            id: openButton
            height: Math.max(implicitHeight, otherFileActionsButton.implicitHeight)
218
            // would be nice to have the file icon here?
219
220
221
            text: jobItem.jobDetails && jobItem.jobDetails.totalFiles > 1
                    ? i18nd("plasma_applet_org.kde.plasma.notifications", "Open Containing Folder")
                    : i18nd("plasma_applet_org.kde.plasma.notifications", "Open")
222
            onClicked: jobItem.openUrl(jobItem.url)
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
223
        }
224
    }
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
225
226
227
228
229
230

    states: [
        State {
            when: jobItem.jobState === NotificationManager.Notifications.JobStateSuspended
            PropertyChanges {
                target: suspendButton
231
                tooltip: i18ndc("plasma_applet_org.kde.plasma.notifications", "Resume paused job", "Resume")
232
                checked: true
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
233
234
235
236
237
238
239
240
241
            }
            PropertyChanges {
                target: progressBar
                enabled: false
            }
        },
        State {
            when: jobItem.jobState === NotificationManager.Notifications.JobStateStopped
            PropertyChanges {
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
242
                target: progressRow
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
243
244
245
246
247
248
249
250
251
                visible: false
            }
            PropertyChanges {
                target: expandButton
                checked: false
            }
        }
    ]
}