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