Warning, /plasma/plasma-workspace/applets/systemtray/package/contents/ui/main.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
0003 SPDX-FileCopyrightText: 2020 Konrad Materka <materka@gmail.com>
0004
0005 SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007
0008 import QtQuick 2.5
0009 import QtQuick.Layouts 1.1
0010 import QtQuick.Window 2.15
0011 import org.kde.plasma.core as PlasmaCore
0012 import org.kde.ksvg 1.0 as KSvg
0013 import org.kde.plasma.plasmoid 2.0
0014 import org.kde.draganddrop 2.0 as DnD
0015 import org.kde.kirigami 2.5 as Kirigami // For Settings.tabletMode
0016 import org.kde.kitemmodels 1.0 as KItemModels
0017
0018 import "items"
0019
0020 ContainmentItem {
0021 id: root
0022
0023 readonly property bool vertical: Plasmoid.formFactor === PlasmaCore.Types.Vertical
0024
0025 Layout.minimumWidth: vertical ? Kirigami.Units.iconSizes.small : mainLayout.implicitWidth + Kirigami.Units.smallSpacing
0026 Layout.minimumHeight: vertical ? mainLayout.implicitHeight + Kirigami.Units.smallSpacing : Kirigami.Units.iconSizes.small
0027
0028 LayoutMirroring.enabled: !vertical && Qt.application.layoutDirection === Qt.RightToLeft
0029 LayoutMirroring.childrenInherit: true
0030
0031 readonly property alias systemTrayState: systemTrayState
0032 readonly property alias itemSize: tasksGrid.itemSize
0033 readonly property alias visibleLayout: tasksGrid
0034 readonly property alias hiddenLayout: expandedRepresentation.hiddenLayout
0035 readonly property bool oneRowOrColumn: tasksGrid.rowsOrColumns === 1
0036
0037 MouseArea {
0038 anchors.fill: parent
0039
0040 onWheel: {
0041 // Don't propagate unhandled wheel events
0042 wheel.accepted = true;
0043 }
0044
0045 SystemTrayState {
0046 id: systemTrayState
0047 }
0048
0049 //being there forces the items to fully load, and they will be reparented in the popup one by one, this item is *never* visible
0050 Item {
0051 id: preloadedStorage
0052 visible: false
0053 }
0054
0055 CurrentItemHighLight {
0056 location: Plasmoid.location
0057 parent: root
0058 }
0059
0060 DnD.DropArea {
0061 anchors.fill: parent
0062
0063 preventStealing: true
0064
0065 /** Extracts the name of the system tray applet in the drag data if present
0066 * otherwise returns null*/
0067 function systemTrayAppletName(event) {
0068 if (event.mimeData.formats.indexOf("text/x-plasmoidservicename") < 0) {
0069 return null;
0070 }
0071 const plasmoidId = event.mimeData.getDataAsByteArray("text/x-plasmoidservicename");
0072
0073 if (!Plasmoid.isSystemTrayApplet(plasmoidId)) {
0074 return null;
0075 }
0076 return plasmoidId;
0077 }
0078
0079 onDragEnter: {
0080 if (!systemTrayAppletName(event)) {
0081 event.ignore();
0082 }
0083 }
0084
0085 onDrop: {
0086 const plasmoidId = systemTrayAppletName(event);
0087 if (!plasmoidId) {
0088 event.ignore();
0089 return;
0090 }
0091
0092 if (Plasmoid.configuration.extraItems.indexOf(plasmoidId) < 0) {
0093 const extraItems = Plasmoid.configuration.extraItems;
0094 extraItems.push(plasmoidId);
0095 Plasmoid.configuration.extraItems = extraItems;
0096 }
0097 }
0098 }
0099
0100
0101 //Main Layout
0102 GridLayout {
0103 id: mainLayout
0104
0105 rowSpacing: 0
0106 columnSpacing: 0
0107 anchors.fill: parent
0108
0109 flow: vertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
0110
0111 GridView {
0112 id: tasksGrid
0113
0114 Layout.alignment: Qt.AlignCenter
0115
0116 interactive: false //disable features we don't need
0117 flow: vertical ? GridView.LeftToRight : GridView.TopToBottom
0118
0119 // The icon size to display when not using the auto-scaling setting
0120 readonly property int smallIconSize: Kirigami.Units.iconSizes.smallMedium
0121
0122 // Automatically use autoSize setting when in tablet mode, if it's
0123 // not already being used
0124 readonly property bool autoSize: Plasmoid.configuration.scaleIconsToFit || Kirigami.Settings.tabletMode
0125
0126 readonly property int gridThickness: root.vertical ? root.width : root.height
0127 // Should change to 2 rows/columns on a 56px panel (in standard DPI)
0128 readonly property int rowsOrColumns: autoSize ? 1 : Math.max(1, Math.min(count, Math.floor(gridThickness / (smallIconSize + Kirigami.Units.smallSpacing))))
0129
0130 // Add margins only if the panel is larger than a small icon (to avoid large gaps between tiny icons)
0131 readonly property int cellSpacing: Kirigami.Units.smallSpacing * (Kirigami.Settings.tabletMode ? 6 : Plasmoid.configuration.iconSpacing)
0132 readonly property int smallSizeCellLength: gridThickness < smallIconSize ? smallIconSize : smallIconSize + cellSpacing
0133
0134 cellHeight: {
0135 if (root.vertical) {
0136 return autoSize ? itemSize + (gridThickness < itemSize ? 0 : cellSpacing) : smallSizeCellLength
0137 } else {
0138 return autoSize ? root.height : Math.floor(root.height / rowsOrColumns)
0139 }
0140 }
0141 cellWidth: {
0142 if (root.vertical) {
0143 return autoSize ? root.width : Math.floor(root.width / rowsOrColumns)
0144 } else {
0145 return autoSize ? itemSize + (gridThickness < itemSize ? 0 : cellSpacing) : smallSizeCellLength
0146 }
0147 }
0148
0149 //depending on the form factor, we are calculating only one dimension, second is always the same as root/parent
0150 implicitHeight: root.vertical ? cellHeight * Math.ceil(count / rowsOrColumns) : root.height
0151 implicitWidth: !root.vertical ? cellWidth * Math.ceil(count / rowsOrColumns) : root.width
0152
0153 readonly property int itemSize: {
0154 if (autoSize) {
0155 return Kirigami.Units.iconSizes.roundedIconSize(Math.min(Math.min(root.width, root.height) / rowsOrColumns, Kirigami.Units.iconSizes.enormous))
0156 } else {
0157 return smallIconSize
0158 }
0159 }
0160
0161 model: KItemModels.KSortFilterProxyModel {
0162 sourceModel: Plasmoid.systemTrayModel
0163 filterRoleName: "effectiveStatus"
0164 filterRowCallback: (sourceRow, sourceParent) => {
0165 let value = sourceModel.data(sourceModel.index(sourceRow, 0, sourceParent), filterRole);
0166 return value === PlasmaCore.Types.ActiveStatus;
0167 }
0168 }
0169
0170 delegate: ItemLoader {
0171 id: delegate
0172
0173 width: tasksGrid.cellWidth
0174 height: tasksGrid.cellHeight
0175 minLabelHeight: 0
0176
0177 // We need to recalculate the stacking order of the z values due to how keyboard navigation works
0178 // the tab order depends exclusively from this, so we redo it as the position in the list
0179 // ensuring tab navigation focuses the expected items
0180 Component.onCompleted: {
0181 let item = tasksGrid.itemAtIndex(index - 1);
0182 if (item) {
0183 Plasmoid.stackItemBefore(delegate, item)
0184 } else {
0185 item = tasksGrid.itemAtIndex(index + 1);
0186 }
0187 if (item) {
0188 Plasmoid.stackItemAfter(delegate, item)
0189 }
0190 }
0191 }
0192
0193 add: Transition {
0194 enabled: itemSize > 0 && Component.status == Component.Ready
0195
0196 NumberAnimation {
0197 property: "scale"
0198 from: 0
0199 to: 1
0200 easing.type: Easing.InOutQuad
0201 duration: Kirigami.Units.longDuration
0202 }
0203 }
0204
0205 displaced: Transition {
0206 //ensure scale value returns to 1.0
0207 //https://doc.qt.io/qt-5/qml-qtquick-viewtransition.html#handling-interrupted-animations
0208 enabled: Component.status == Component.Ready
0209 NumberAnimation {
0210 property: "scale"
0211 to: 1
0212 easing.type: Easing.InOutQuad
0213 duration: Kirigami.Units.longDuration
0214 }
0215 }
0216
0217 move: Transition {
0218 NumberAnimation {
0219 properties: "x,y"
0220 easing.type: Easing.InOutQuad
0221 duration: Kirigami.Units.longDuration
0222 }
0223 }
0224 }
0225
0226 ExpanderArrow {
0227 id: expander
0228 Layout.fillWidth: vertical
0229 Layout.fillHeight: !vertical
0230 Layout.alignment: vertical ? Qt.AlignVCenter : Qt.AlignHCenter
0231 iconSize: tasksGrid.itemSize
0232 visible: root.hiddenLayout.itemCount > 0
0233 }
0234 }
0235
0236 Timer {
0237 id: expandedSync
0238 interval: 100
0239 onTriggered: systemTrayState.expanded = dialog.visible;
0240 }
0241
0242 //Main popup
0243 PlasmaCore.AppletPopup {
0244 id: dialog
0245 objectName: "popupWindow"
0246 visualParent: root
0247 popupDirection: switch (Plasmoid.location) {
0248 case PlasmaCore.Types.TopEdge:
0249 return Qt.BottomEdge
0250 case PlasmaCore.Types.LeftEdge:
0251 return Qt.RightEdge
0252 case PlasmaCore.Types.RightEdge:
0253 return Qt.LeftEdge
0254 default:
0255 return Qt.TopEdge
0256 }
0257 margin: (Plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentPrefersFloatingApplets) ? Kirigami.Units.largeSpacing : 0
0258
0259 floating: Plasmoid.location == PlasmaCore.Desktop
0260
0261 removeBorderStrategy: Plasmoid.location === PlasmaCore.Types.Floating
0262 ? PlasmaCore.AppletPopup.AtScreenEdges
0263 : PlasmaCore.AppletPopup.AtScreenEdges | PlasmaCore.AppletPopup.AtPanelEdges
0264
0265
0266 hideOnWindowDeactivate: !Plasmoid.configuration.pin
0267 visible: systemTrayState.expanded
0268 appletInterface: root
0269
0270 backgroundHints: (Plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentPrefersOpaqueBackground) ? PlasmaCore.AppletPopup.SolidBackground : PlasmaCore.AppletPopup.StandardBackground
0271
0272 onVisibleChanged: {
0273 if (!visible) {
0274 expandedSync.restart();
0275 } else {
0276 if (expandedRepresentation.plasmoidContainer.visible) {
0277 expandedRepresentation.plasmoidContainer.forceActiveFocus();
0278 } else if (expandedRepresentation.hiddenLayout.visible) {
0279 expandedRepresentation.hiddenLayout.forceActiveFocus();
0280 }
0281 }
0282 }
0283 mainItem: ExpandedRepresentation {
0284 id: expandedRepresentation
0285
0286 Keys.onEscapePressed: {
0287 systemTrayState.expanded = false
0288 }
0289
0290 // Draws a line between the applet dialog and the panel
0291 KSvg.SvgItem {
0292 id: separator
0293 // Only draw for popups of panel applets, not desktop applets
0294 visible: [PlasmaCore.Types.TopEdge, PlasmaCore.Types.LeftEdge, PlasmaCore.Types.RightEdge, PlasmaCore.Types.BottomEdge]
0295 .includes(Plasmoid.location) && !dialog.margin
0296 anchors {
0297 topMargin: -dialog.topMargin
0298 leftMargin: -dialog.leftMargin
0299 rightMargin: -dialog.rightMargin
0300 bottomMargin: -dialog.bottomMargin
0301 }
0302 z: 999 /* Draw the line on top of the applet */
0303 elementId: (Plasmoid.location === PlasmaCore.Types.TopEdge || Plasmoid.location === PlasmaCore.Types.BottomEdge) ? "horizontal-line" : "vertical-line"
0304 imagePath: "widgets/line"
0305 // Use states instead of bindings to work around https://bugreports.qt.io/browse/QTBUG-120464
0306 states: [
0307 State {
0308 when: Plasmoid.location === PlasmaCore.Types.TopEdge
0309 AnchorChanges {
0310 target: separator
0311 anchors {
0312 top: separator.parent.top
0313 left: separator.parent.left
0314 right: separator.parent.right
0315 }
0316 }
0317 PropertyChanges {
0318 target: separator
0319 height: 1
0320 }
0321 },
0322 State {
0323 when: Plasmoid.location === PlasmaCore.Types.LeftEdge
0324 AnchorChanges {
0325 target: separator
0326 anchors {
0327 left: separator.parent.left
0328 top: separator.parent.top
0329 bottom: separator.parent.bottom
0330 }
0331 }
0332 PropertyChanges {
0333 target: separator
0334 width: 1
0335 }
0336 },
0337 State {
0338 when: Plasmoid.location === PlasmaCore.Types.RightEdge
0339 AnchorChanges {
0340 target: separator
0341 anchors {
0342 top: separator.parent.top
0343 right: separator.parent.right
0344 bottom: separator.parent.bottom
0345 }
0346 }
0347 PropertyChanges {
0348 target: separator
0349 width: 1
0350 }
0351 },
0352 State {
0353 when: Plasmoid.location === PlasmaCore.Types.BottomEdge
0354 AnchorChanges {
0355 target: separator
0356 anchors {
0357 left: separator.parent.left
0358 right: separator.parent.right
0359 bottom: separator.parent.bottom
0360 }
0361 }
0362 PropertyChanges {
0363 target: separator
0364 height: 1
0365 }
0366 }
0367 ]
0368 }
0369
0370 LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
0371 LayoutMirroring.childrenInherit: true
0372 }
0373 }
0374 }
0375 }