Changeset View
Changeset View
Standalone View
Standalone View
applets/systemtray/package/contents/ui/main.qml
1 | /* | 1 | /* | ||
---|---|---|---|---|---|
2 | * Copyright 2011 Marco Martin <mart@kde.org> | 2 | * Copyright 2011 Marco Martin <mart@kde.org> | ||
3 | * Copyright 2019 ivan tkachenko <ratijastk@kde.org> | ||||
3 | * | 4 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU Library General Public License as | 6 | * it under the terms of the GNU Library General Public License as | ||
6 | * published by the Free Software Foundation; either version 2, or | 7 | * published by the Free Software Foundation; either version 2, or | ||
7 | * (at your option) any later version. | 8 | * (at your option) any later version. | ||
8 | * | 9 | * | ||
9 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
Show All 12 Lines | |||||
23 | import org.kde.plasma.plasmoid 2.0 | 24 | import org.kde.plasma.plasmoid 2.0 | ||
24 | import org.kde.draganddrop 2.0 as DnD | 25 | import org.kde.draganddrop 2.0 as DnD | ||
25 | 26 | | |||
26 | import "items" | 27 | import "items" | ||
27 | 28 | | |||
28 | MouseArea { | 29 | MouseArea { | ||
29 | id: root | 30 | id: root | ||
30 | 31 | | |||
31 | Layout.minimumWidth: vertical ? units.iconSizes.small : tasksRow.implicitWidth + (expander.visible ? expander.implicitWidth : 0) + units.smallSpacing | 32 | Layout.fillWidth: vertical | ||
32 | 33 | Layout.fillHeight: !vertical | |||
33 | Layout.minimumHeight: vertical ? tasksRow.implicitHeight + (expander.visible ? expander.implicitHeight : 0) + units.smallSpacing : units.smallSpacing | 34 | Layout.minimumWidth: vertical ? 0 : mainLayout.implicitWidth | ||
34 | 35 | Layout.minimumHeight: !vertical ? 0 : mainLayout.implicitHeight | |||
35 | Layout.preferredHeight: Layout.minimumHeight | | |||
36 | LayoutMirroring.enabled: !vertical && Qt.application.layoutDirection === Qt.RightToLeft | 36 | LayoutMirroring.enabled: !vertical && Qt.application.layoutDirection === Qt.RightToLeft | ||
37 | LayoutMirroring.childrenInherit: true | 37 | LayoutMirroring.childrenInherit: true | ||
38 | 38 | | |||
39 | property var iconSizes: ["small", "smallMedium", "medium", "large", "huge", "enormous"]; | 39 | property var iconSizes: ["small", "smallMedium", "medium", "large", "huge", "enormous"]; | ||
40 | 40 | | |||
41 | property bool vertical: plasmoid.formFactor === PlasmaCore.Types.Vertical | 41 | property bool vertical: plasmoid.formFactor === PlasmaCore.Types.Vertical | ||
42 | property int itemSize: units.roundToIconSize(Math.min(Math.min(width, height), units.iconSizes[iconSizes[plasmoid.configuration.iconSize]])) | 42 | property int itemSize: units.roundToIconSize(Math.min(width, height, units.iconSizes[iconSizes[plasmoid.configuration.iconSize]])) | ||
43 | property int hiddenItemSize: units.iconSizes.smallMedium | 43 | property int hiddenItemSize: units.iconSizes.smallMedium | ||
44 | property alias expanded: dialog.visible | 44 | property alias expanded: dialog.visible | ||
45 | property Item activeApplet | 45 | property Item activeApplet | ||
46 | property Item activeAppletItem: findParentNamed(activeApplet, "abstractItem") | ||||
47 | property Item activeAppletContainer: activeAppletItem ? activeAppletItem.parent : null | ||||
48 | | ||||
46 | property int status: dialog.visible ? PlasmaCore.Types.RequiresAttentionStatus : PlasmaCore.Types.PassiveStatus | 49 | property int status: dialog.visible ? PlasmaCore.Types.RequiresAttentionStatus : PlasmaCore.Types.PassiveStatus | ||
47 | 50 | | |||
48 | property alias visibleLayout: tasksRow | 51 | property alias visibleLayout: tasksLayout | ||
49 | property alias hiddenLayout: expandedRepresentation.hiddenLayout | 52 | property alias hiddenLayout: expandedRepresentation.hiddenLayout | ||
50 | 53 | | |||
51 | property alias statusNotifierModel: statusNotifierModel | 54 | property alias statusNotifierModel: statusNotifierModel | ||
52 | 55 | | |||
53 | // workaround https://bugreports.qt.io/browse/QTBUG-71238 / https://bugreports.qt.io/browse/QTBUG-72004 | 56 | // workaround https://bugreports.qt.io/browse/QTBUG-71238 / https://bugreports.qt.io/browse/QTBUG-72004 | ||
54 | property Component plasmoidItemComponent: Qt.createComponent("items/PlasmoidItem.qml") | 57 | property Component plasmoidItemComponent: Qt.createComponent("items/PlasmoidItem.qml") | ||
55 | 58 | | |||
56 | Plasmoid.onExpandedChanged: { | 59 | Plasmoid.onExpandedChanged: { | ||
57 | if (!plasmoid.expanded) { | 60 | if (!plasmoid.expanded) { | ||
58 | dialog.visible = plasmoid.expanded; | 61 | dialog.visible = plasmoid.expanded; | ||
62 | root.activeApplet = null; | ||||
63 | } | ||||
64 | } | ||||
65 | | ||||
66 | // Shouldn't it be part of Qt? | ||||
davidedmundson: Not really.
Using objectNames is a bit of an anti pattern, especially when QML has so the built… | |||||
Pattern or not — Qt provides us with this objectName property so we can do stuff. But Qt itself is not engaged in providing further support for it. That's frustrating. ratijas: Pattern or not — Qt provides us with this `objectName` property so we can do stuff. But Qt… | |||||
67 | function findParentNamed(object, objectName) { | ||||
68 | if (object) { | ||||
69 | while (object = object.parent) { | ||||
70 | if (object.objectName === objectName) { | ||||
71 | return object; | ||||
72 | } | ||||
59 | } | 73 | } | ||
60 | } | 74 | } | ||
75 | return null; | ||||
76 | } | ||||
61 | 77 | | |||
62 | function updateItemVisibility(item) { | 78 | function updateItemVisibility(item) { | ||
63 | switch (item.effectiveStatus) { | 79 | switch (item.effectiveStatus) { | ||
64 | case PlasmaCore.Types.HiddenStatus: | 80 | case PlasmaCore.Types.HiddenStatus: | ||
65 | if (item.parent === invisibleEntriesContainer) { | 81 | if (item.parent !== invisibleEntriesContainer) { | ||
66 | return; | | |||
67 | } | | |||
68 | | ||||
69 | item.parent = invisibleEntriesContainer; | 82 | item.parent = invisibleEntriesContainer; | ||
83 | } | ||||
70 | break; | 84 | break; | ||
71 | 85 | | |||
72 | case PlasmaCore.Types.ActiveStatus: | 86 | case PlasmaCore.Types.ActiveStatus: | ||
73 | if (visibleLayout.children.length === 0) { | 87 | if (visibleLayout.children.length === 0) { | ||
74 | item.parent = visibleLayout; | 88 | item.parent = visibleLayout; | ||
75 | //notifications is always the first | 89 | //notifications is always the first | ||
76 | } else if (visibleLayout.children[0].itemId === "org.kde.plasma.notifications" && | 90 | } else if (visibleLayout.children[0].itemId === "org.kde.plasma.notifications" && | ||
77 | item.itemId !== "org.kde.plasma.notifications") { | 91 | item.itemId !== "org.kde.plasma.notifications") { | ||
Show All 9 Lines | 100 | if (hiddenLayout.children.length === 0) { | |||
87 | item.parent = hiddenLayout; | 101 | item.parent = hiddenLayout; | ||
88 | //notifications is always the first | 102 | //notifications is always the first | ||
89 | } else if (hiddenLayout.children[0].itemId === "org.kde.plasma.notifications" && | 103 | } else if (hiddenLayout.children[0].itemId === "org.kde.plasma.notifications" && | ||
90 | item.itemId !== "org.kde.plasma.notifications") { | 104 | item.itemId !== "org.kde.plasma.notifications") { | ||
91 | plasmoid.nativeInterface.reorderItemAfter(item, hiddenLayout.children[0]); | 105 | plasmoid.nativeInterface.reorderItemAfter(item, hiddenLayout.children[0]); | ||
92 | } else if (hiddenLayout.children[0] !== item) { | 106 | } else if (hiddenLayout.children[0] !== item) { | ||
93 | plasmoid.nativeInterface.reorderItemBefore(item, hiddenLayout.children[0]); | 107 | plasmoid.nativeInterface.reorderItemBefore(item, hiddenLayout.children[0]); | ||
94 | } | 108 | } | ||
95 | item.x = 0; | | |||
96 | break; | 109 | break; | ||
97 | } | 110 | } | ||
98 | } | 111 | } | ||
99 | 112 | | |||
100 | onWheel: { | 113 | onWheel: { | ||
101 | // Don't propagate unhandled wheel events | 114 | // Don't propagate unhandled wheel events | ||
102 | wheel.accepted = true; | 115 | wheel.accepted = true; | ||
103 | } | 116 | } | ||
104 | 117 | | |||
105 | Containment.onAppletAdded: { | 118 | Containment.onAppletAdded: { | ||
106 | //Allow the plasmoid expander to know in what window it will be | 119 | //Allow the plasmoid expander to know in what window it will be | ||
107 | var plasmoidContainer = plasmoidItemComponent.createObject(invisibleEntriesContainer, {"x": x, "y": y, "applet": applet}); | 120 | var plasmoidContainer = plasmoidItemComponent.createObject(invisibleEntriesContainer, {"applet": applet}); | ||
108 | | ||||
109 | applet.parent = plasmoidContainer | | |||
110 | applet.anchors.left = plasmoidContainer.left | | |||
111 | applet.anchors.top = plasmoidContainer.top | | |||
112 | applet.anchors.bottom = plasmoidContainer.bottom | | |||
113 | applet.width = plasmoidContainer.height | | |||
114 | applet.visible = true | 121 | applet.visible = true | ||
115 | plasmoidContainer.visible = true | 122 | plasmoidContainer.visible = true | ||
116 | 123 | | |||
117 | //This is to make preloading effective, minimizes the scene changes | 124 | //This is to make preloading effective, minimizes the scene changes | ||
118 | if (applet.fullRepresentationItem) { | 125 | if (applet.fullRepresentationItem) { | ||
119 | applet.fullRepresentationItem.width = expandedRepresentation.width | 126 | applet.fullRepresentationItem.width = expandedRepresentation.width | ||
120 | applet.fullRepresentationItem.width = expandedRepresentation.height | 127 | applet.fullRepresentationItem.width = expandedRepresentation.height | ||
121 | applet.fullRepresentationItem.parent = preloadedStorage; | 128 | applet.fullRepresentationItem.parent = preloadedStorage; | ||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Line(s) | 167 | function initializePlasmoidList() { | |||
184 | } | 191 | } | ||
185 | if (newKnownItems.length > 0) { | 192 | if (newKnownItems.length > 0) { | ||
186 | plasmoid.configuration.knownItems = plasmoid.configuration.knownItems.slice().concat(newKnownItems); | 193 | plasmoid.configuration.knownItems = plasmoid.configuration.knownItems.slice().concat(newKnownItems); | ||
187 | } | 194 | } | ||
188 | 195 | | |||
189 | return plasmoid.configuration.extraItems; | 196 | return plasmoid.configuration.extraItems; | ||
190 | } | 197 | } | ||
191 | 198 | | |||
192 | PlasmaCore.DataSource { | | |||
193 | id: statusNotifierSource | | |||
194 | engine: "statusnotifieritem" | | |||
195 | interval: 0 | | |||
196 | onSourceAdded: { | | |||
197 | connectSource(source) | | |||
198 | } | | |||
199 | Component.onCompleted: { | | |||
200 | connectedSources = sources | | |||
201 | } | | |||
202 | } | | |||
203 | | ||||
204 | | ||||
205 | //due to the magic of property bindings this function will be | 199 | //due to the magic of property bindings this function will be | ||
206 | //re-executed all the times a setting changes | 200 | //re-executed all the times a setting changes | ||
207 | property var shownCategories: { | 201 | property var shownCategories: { | ||
208 | var array = []; | 202 | var array = []; | ||
209 | if (plasmoid.configuration.applicationStatusShown) { | 203 | if (plasmoid.configuration.applicationStatusShown) { | ||
210 | array.push("ApplicationStatus"); | 204 | array.push("ApplicationStatus"); | ||
211 | } | 205 | } | ||
212 | if (plasmoid.configuration.communicationsShown) { | 206 | if (plasmoid.configuration.communicationsShown) { | ||
Show All 11 Lines | |||||
224 | 218 | | |||
225 | //nothing? make a regexp that matches nothing | 219 | //nothing? make a regexp that matches nothing | ||
226 | if (array.length === 0) { | 220 | if (array.length === 0) { | ||
227 | array.push("$^") | 221 | array.push("$^") | ||
228 | } | 222 | } | ||
229 | return array; | 223 | return array; | ||
230 | } | 224 | } | ||
231 | 225 | | |||
232 | PlasmaCore.SortFilterModel { | 226 | StatusNotifierItemModel { | ||
233 | id: statusNotifierModel | 227 | id: statusNotifierModel | ||
234 | sourceModel: PlasmaCore.DataModel { | | |||
235 | dataSource: statusNotifierSource | | |||
236 | } | | |||
237 | } | 228 | } | ||
238 | 229 | | |||
239 | //This is a dump for items we don't want to be seen or as an incubation, when they are | 230 | //This is a dump for items we don't want to be seen or as an incubation, when they are | ||
240 | //created as a nursery before going in their final place | 231 | //created as a nursery before going in their final place | ||
241 | Item { | 232 | Item { | ||
242 | id: invisibleEntriesContainer | 233 | id: invisibleEntriesContainer | ||
243 | visible: false | 234 | visible: false | ||
244 | Repeater { | 235 | Repeater { | ||
245 | id: tasksRepeater | 236 | id: tasksRepeater | ||
246 | model: statusNotifierModel | 237 | model: statusNotifierModel | ||
247 | 238 | | |||
248 | delegate: StatusNotifierItem {} | 239 | delegate: StatusNotifierItem {} | ||
249 | } | 240 | } | ||
250 | //NOTE: this exists mostly for not causing reference errors | 241 | //NOTE: this exists mostly for not causing reference errors | ||
251 | property QtObject marginHints: QtObject { | 242 | property QtObject marginHints: QtObject { | ||
252 | property int left: 0 | 243 | property int left: 0 | ||
253 | property int top: 0 | 244 | property int top: 0 | ||
254 | property int right: 0 | 245 | property int right: 0 | ||
255 | property int bottom: 0 | 246 | property int bottom: 0 | ||
256 | } | 247 | } | ||
257 | } | 248 | } | ||
258 | 249 | | |||
259 | CurrentItemHighLight { | 250 | CurrentItemHighLight { | ||
260 | visualParent: tasksRow | 251 | visualParent: mainLayout | ||
261 | target: root.activeApplet && root.activeApplet.parent.parent == tasksRow ? root.activeApplet.parent : root | 252 | | ||
253 | target: root.activeAppletContainer === tasksLayout ? root.activeAppletItem : root | ||||
262 | location: plasmoid.location | 254 | location: plasmoid.location | ||
263 | } | 255 | } | ||
264 | 256 | | |||
265 | DnD.DropArea { | 257 | DnD.DropArea { | ||
266 | anchors.fill: parent | 258 | anchors.fill: parent | ||
267 | 259 | | |||
268 | preventStealing: true; | 260 | preventStealing: true; | ||
269 | 261 | | |||
Show All 27 Lines | 282 | onDrop: { | |||
297 | if (plasmoid.configuration.extraItems.indexOf(plasmoidId) < 0) { | 289 | if (plasmoid.configuration.extraItems.indexOf(plasmoidId) < 0) { | ||
298 | var extraItems = plasmoid.configuration.extraItems; | 290 | var extraItems = plasmoid.configuration.extraItems; | ||
299 | extraItems.push(plasmoidId); | 291 | extraItems.push(plasmoidId); | ||
300 | plasmoid.configuration.extraItems = extraItems; | 292 | plasmoid.configuration.extraItems = extraItems; | ||
301 | } | 293 | } | ||
302 | } | 294 | } | ||
303 | } | 295 | } | ||
304 | 296 | | |||
305 | //Main Layout | 297 | // Main layout | ||
306 | Flow { | 298 | GridLayout { | ||
307 | id: tasksRow | 299 | id: mainLayout | ||
308 | spacing: 0 | 300 | | ||
309 | height: parent.height - (vertical && expander.visible ? expander.height : 0) | 301 | rowSpacing: 0 | ||
310 | width: parent.width - (vertical || !expander.visible ? 0 : expander.width) | 302 | columnSpacing: 0 | ||
311 | property string skipItems | 303 | anchors.fill: parent | ||
312 | flow: vertical ? Flow.LeftToRight : Flow.TopToBottom | 304 | | ||
313 | //To make it look centered | 305 | flow: vertical ? GridLayout.TopToBottom : GridLayout.LeftToRight | ||
314 | y: Math.round(height/2 - childrenRect.height/2) | | |||
315 | x: (expander.visible && LayoutMirroring.enabled ? expander.width : 0) + Math.round(width/2 - childrenRect.width/2) | | |||
316 | 306 | | |||
307 | GridLayout { | ||||
308 | id: tasksLayout | ||||
309 | | ||||
310 | rowSpacing: 0 | ||||
311 | columnSpacing: 0 | ||||
312 | Layout.fillWidth: true | ||||
313 | Layout.fillHeight: true | ||||
314 | | ||||
315 | flow: vertical ? GridLayout.TopToBottom : GridLayout.LeftToRight | ||||
316 | rows: vertical ? Math.round(children.length / columns) | ||||
317 | : Math.max(1, Math.floor(root.height / (itemSize + marginHints.top + marginHints.bottom))) | ||||
318 | columns: !vertical ? Math.round(children.length / rows) | ||||
319 | : Math.max(1, Math.floor(root.width / (itemSize + marginHints.left + marginHints.right))) | ||||
317 | 320 | | |||
318 | //Do spacing with margins, to correctly compute the number of lines | 321 | // Do spacing with margins, to correctly compute the number of lines | ||
319 | property QtObject marginHints: QtObject { | 322 | property QtObject marginHints: QtObject { | ||
320 | property int left: Math.round(units.smallSpacing / 2) | 323 | property int left: Math.round(units.smallSpacing / 2) | ||
321 | property int top: Math.round(units.smallSpacing / 2) | 324 | property int top: Math.round(units.smallSpacing / 2) | ||
322 | property int right: Math.round(units.smallSpacing / 2) | 325 | property int right: Math.round(units.smallSpacing / 2) | ||
323 | property int bottom: Math.round(units.smallSpacing / 2) | 326 | property int bottom: Math.round(units.smallSpacing / 2) | ||
324 | } | 327 | } | ||
325 | | ||||
326 | //add doesn't seem to work used in conjunction with stackBefore/stackAfter | | |||
327 | /*add: Transition { | | |||
328 | NumberAnimation { | | |||
329 | property: "scale" | | |||
330 | from: 0 | | |||
331 | to: 1 | | |||
332 | easing.type: Easing.InQuad | | |||
333 | duration: units.longDuration | | |||
334 | } | | |||
335 | } | | |||
336 | move: Transition { | | |||
337 | NumberAnimation { | | |||
338 | properties: "x,y" | | |||
339 | easing.type: Easing.InQuad | | |||
340 | duration: units.longDuration | | |||
341 | } | | |||
342 | }*/ | | |||
343 | } | 328 | } | ||
344 | 329 | | |||
345 | ExpanderArrow { | 330 | ExpanderArrow { | ||
346 | id: expander | 331 | id: expander | ||
347 | anchors { | 332 | Layout.fillWidth: vertical | ||
348 | fill: parent | 333 | Layout.fillHeight: !vertical | ||
349 | leftMargin: vertical ? 0 : parent.width - implicitWidth | | |||
350 | topMargin: vertical ? parent.height - implicitHeight : 0 | | |||
351 | } | 334 | } | ||
352 | } | 335 | } | ||
353 | 336 | | |||
354 | //Main popup | 337 | // Main popup | ||
355 | PlasmaCore.Dialog { | 338 | PlasmaCore.Dialog { | ||
356 | id: dialog | 339 | id: dialog | ||
357 | visualParent: root | 340 | visualParent: root | ||
358 | flags: Qt.WindowStaysOnTopHint | 341 | flags: Qt.WindowStaysOnTopHint | ||
359 | location: plasmoid.location | 342 | location: plasmoid.location | ||
360 | hideOnWindowDeactivate: !plasmoid.configuration.pin | 343 | hideOnWindowDeactivate: !plasmoid.configuration.pin | ||
361 | 344 | | |||
362 | onVisibleChanged: { | 345 | onVisibleChanged: { | ||
Show All 24 Lines |
Not really.
Using objectNames is a bit of an anti pattern, especially when QML has so the built-in component scope hierachy.
We use it in the system tray already, and it's arguably no worse than the existing applet.parent.parent.
So fine here, but only because the system is mad.