Warning, /plasma/plasma-desktop/containments/desktop/package/contents/ui/FolderItemDelegate.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 import QtQuick 2.15
0008 import QtQuick.Window 2.15
0009 import Qt5Compat.GraphicalEffects
0010 
0011 import org.kde.plasma.plasmoid 2.0
0012 import org.kde.plasma.core as PlasmaCore
0013 import org.kde.plasma.extras as PlasmaExtras
0014 
0015 import org.kde.kirigami 2.20 as Kirigami
0016 import org.kde.ksvg 1.0 as KSvg
0017 import org.kde.kquickcontrolsaddons 2.0
0018 
0019 Item {
0020     id: main
0021 
0022     property int index:          model.index
0023     property string name:        model.blank ? "" : model.display
0024     property string nameWrapped: model.blank ? "" : model.displayWrapped
0025     property bool blank:         model.blank
0026     property bool isDir:           loader.item ? loader.item.isDir : false
0027     property QtObject popupDialog: loader.item ? loader.item.popupDialog    : null
0028     property Item iconArea:        loader.item ? loader.item.iconArea       : null
0029     property Item label:           loader.item ? loader.item.label          : null
0030     property Item labelArea:       loader.item ? loader.item.labelArea      : null
0031     property Item actionsOverlay:  loader.item ? loader.item.actionsOverlay : null
0032     property Item hoverArea:       loader.item ? loader.item.hoverArea      : null
0033     property Item frame:           loader.item ? loader.item.frame          : null
0034     property Item toolTip:         loader.item ? loader.item.toolTip        : null
0035     Accessible.name: name
0036     Accessible.role: Accessible.Canvas
0037 
0038     // This MouseArea exists to intercept press and hold; preventing edit mode
0039     // from being triggered when pressing and holding on an icon (if there is one).
0040     MouseArea {
0041         anchors.fill: parent
0042         visible: !main.blank
0043     }
0044 
0045     function openPopup() {
0046         if (isDir) {
0047             loader.item.openPopup();
0048         }
0049     }
0050 
0051     function closePopup() {
0052         if (popupDialog) {
0053             popupDialog.requestDestroy();
0054             loader.item.popupDialog = null;
0055         }
0056     }
0057 
0058     Loader {
0059         id: loader
0060 
0061         // On the desktop we pad our cellSize to avoid a gap at the right/bottom of the screen.
0062         // The padding per item is quite small and causes the delegate to be positioned on fractional pixels
0063         // leading to blurry rendering. The Loader is offset to account for this.
0064         x: -main.x % 1
0065         y: -main.y % 1
0066         width: parent.width
0067         height: parent.height
0068 
0069         visible: status === Loader.Ready
0070 
0071         active: !model.blank
0072 
0073         sourceComponent: delegateImplementation
0074 
0075         asynchronous: true
0076     }
0077 
0078     Component {
0079         id: delegateImplementation
0080 
0081         Item {
0082             id: impl
0083 
0084             anchors.fill: parent
0085 
0086             property bool blank: model.blank
0087             property bool selected: model.blank ? false : model.selected
0088             property bool isDir: model.blank ? false : model.isDir
0089             property bool hovered: (main.GridView.view.hoveredItem === main)
0090             property QtObject popupDialog: null
0091             property Item iconArea: icon
0092             property Item label: label
0093             property Item labelArea: label
0094             property Item actionsOverlay: actions
0095             property Item hoverArea: toolTip
0096             property Item frame: frameLoader
0097             property Item toolTip: toolTip
0098             property Item selectionButton: null
0099             property Item popupButton: null
0100 
0101             readonly property bool iconAndLabelsShouldlookSelected: impl.hovered
0102 
0103             // When a drop happens, a new item is created, and is set to selected
0104             // grabToImagebefore it gets the final width, making grabToImage fail because it's still 0x0
0105             onSelectedChanged: Qt.callLater(updateDragImage)
0106             function updateDragImage() {
0107                 if (selected && !blank) {
0108                     frameLoader.grabToImage(result => {
0109                         dir.addItemDragImage(positioner.map(index), main.x + frameLoader.x, main.y + frameLoader.y, frameLoader.width, frameLoader.height, result.image);
0110                     });
0111                 }
0112             }
0113 
0114             Connections {
0115                 target: model
0116 
0117                 function onSelectedChanged() {
0118                     if (dir.usedByContainment && model.selected) {
0119                         gridView.currentIndex = model.index;
0120                     }
0121                 }
0122             }
0123 
0124             onHoveredChanged: {
0125                 if (hovered) {
0126                     // In list view, it behaves more like a menu, and menus always activate their items on a single click
0127                     if (Plasmoid.configuration.selectionMarkers && (Qt.styleHints.singleClickActivation || root.useListViewMode)) {
0128                         selectionButton = selectionButtonComponent.createObject(actions);
0129                     }
0130 
0131                     if (model.isDir) {
0132                         if (!main.GridView.view.isRootView || root.containsDrag) {
0133                             hoverActivateTimer.restart();
0134                         }
0135 
0136                         if (Plasmoid.configuration.popups && !root.useListViewMode) {
0137                             popupButton = popupButtonComponent.createObject(actions);
0138                         }
0139                     }
0140                 } else if (!hovered) {
0141                     if (popupDialog != null) {
0142                         closePopup();
0143                     }
0144 
0145                     if (selectionButton) {
0146                         selectionButton.destroy();
0147                         selectionButton = null;
0148                     }
0149 
0150                     if (popupButton) {
0151                         popupButton.destroy();
0152                         popupButton = null;
0153                     }
0154                 }
0155             }
0156 
0157             function openPopup() {
0158                 if (folderViewDialogComponent.status === Component.Ready) {
0159                     impl.popupDialog = folderViewDialogComponent.createObject(impl);
0160                     impl.popupDialog.visualParent = icon;
0161                     impl.popupDialog.url = model.linkDestinationUrl;
0162                     impl.popupDialog.visible = true;
0163                 }
0164             }
0165 
0166             PlasmaCore.ToolTipArea {
0167                 id: toolTip
0168 
0169                 active: (Plasmoid.configuration.toolTips || label.truncated)
0170                         && popupDialog === null
0171                         && !model.blank
0172                 interactive: false
0173                 location: root.useListViewMode ? (Plasmoid.location === PlasmaCore.Types.LeftEdge ? PlasmaCore.Types.LeftEdge : PlasmaCore.Types.RightEdge) : Plasmoid.location
0174 
0175                 onContainsMouseChanged:  {
0176                     if (containsMouse && !model.blank) {
0177                         if (toolTip.active) {
0178                             toolTip.icon = model.decoration;
0179                             toolTip.mainText = model.display;
0180 
0181                             if (model.size !== undefined) {
0182                                 toolTip.subText = model.type + "\n" + model.size;
0183                             } else {
0184                                 toolTip.subText = model.type;
0185                             }
0186                         }
0187 
0188                         main.GridView.view.hoveredItem = main;
0189                     }
0190                 }
0191 
0192                 states: [
0193                     State { // icon view
0194                         when: !root.useListViewMode
0195 
0196                         AnchorChanges {
0197                             target: toolTip
0198                             anchors.horizontalCenter: parent.horizontalCenter
0199                         }
0200 
0201                         PropertyChanges {
0202                             target: toolTip
0203                             y: frameLoader.y + icon.y
0204                             width: Math.max(icon.paintedWidth, label.paintedWidth)
0205                             height: (label.y + label.paintedHeight) - y
0206                         }
0207                     },
0208                     State { // list view
0209                         when: root.useListViewMode
0210 
0211                         AnchorChanges {
0212                             target: toolTip
0213                             anchors.horizontalCenter: undefined
0214                         }
0215 
0216                         PropertyChanges {
0217                             target: toolTip
0218                             x: frameLoader.x
0219                             y: frameLoader.y
0220                             width: frameLoader.width
0221                             height: frameLoader.height
0222                         }
0223                     }
0224                 ]
0225             }
0226 
0227             Loader {
0228                 id: frameLoader
0229 
0230                 x: root.useListViewMode ? 0 : Kirigami.Units.smallSpacing
0231                 y: root.useListViewMode ? 0 : Kirigami.Units.smallSpacing
0232 
0233                 property Item iconShadow: null
0234                 property string prefix: ""
0235 
0236                 sourceComponent: frameComponent
0237                 active: impl.iconAndLabelsShouldlookSelected || model.selected
0238                 asynchronous: true
0239 
0240                 width: {
0241                     if (root.useListViewMode) {
0242                         if (main.GridView.view.overflowing) {
0243                             return parent.width - Kirigami.Units.smallSpacing;
0244                         } else {
0245                             return parent.width;
0246                         }
0247                     }
0248 
0249                     return parent.width - (Kirigami.Units.smallSpacing * 2);
0250                 }
0251 
0252                 height: root.useListViewMode
0253                                 ? parent.height
0254                                 // the smallSpacings are for padding
0255                                 : icon.height + (Kirigami.Units.gridUnit * label.lineCount) + (Kirigami.Units.smallSpacing * 3)
0256 
0257                 Kirigami.Icon {
0258                     id: icon
0259 
0260                     z: 2
0261 
0262                     states: [
0263                         State { // icon view
0264                             when: !root.useListViewMode
0265 
0266                             AnchorChanges {
0267                                 target: icon
0268                                 anchors.top: parent.top
0269                                 anchors.horizontalCenter: parent.horizontalCenter
0270                             }
0271                         },
0272                         State { // list view
0273                             when: root.useListViewMode
0274 
0275                             AnchorChanges {
0276                                 target: icon
0277                                 anchors.left: parent.left
0278                                 anchors.verticalCenter: parent.verticalCenter
0279                             }
0280                         }
0281                     ]
0282 
0283                     anchors {
0284                         topMargin: Kirigami.Units.smallSpacing
0285                         leftMargin: Kirigami.Units.smallSpacing
0286                     }
0287 
0288                     width: root.useListViewMode ? main.GridView.view.iconSize : (parent.width - 2 * Kirigami.Units.smallSpacing)
0289                     height: main.GridView.view.iconSize
0290 
0291                     opacity: {
0292                         if (root.useListViewMode && selectionButton) {
0293                             return 0.3;
0294                         }
0295 
0296                         if (model.isHidden) {
0297                             return 0.6;
0298                         }
0299 
0300                         return 1.0;
0301                     }
0302 
0303                     animated: false
0304 
0305                     source: model.decoration
0306                 }
0307 
0308                 PlasmaExtras.ShadowedLabel {
0309                     id: label
0310 
0311                     z: 2 // So it's always above the highlight effect
0312 
0313                     states: [
0314                         State { // icon view
0315                             when: !root.useListViewMode
0316 
0317                             AnchorChanges {
0318                                 target: label
0319                                 anchors.top: icon.bottom
0320                                 anchors.horizontalCenter: parent.horizontalCenter
0321                             }
0322                             PropertyChanges {
0323                                 target: label
0324                                 anchors.topMargin: Kirigami.Units.smallSpacing
0325                                 width: parent.width - Kirigami.Units.smallSpacing
0326                                 maximumLineCount: Plasmoid.configuration.textLines
0327                                 horizontalAlignment: Text.AlignHCenter
0328                             }
0329                         },
0330                         State { // list view
0331                             when: root.useListViewMode
0332 
0333                             AnchorChanges {
0334                                 target: label
0335                                 anchors.left: icon.right
0336                                 anchors.verticalCenter: parent.verticalCenter
0337                             }
0338                             PropertyChanges {
0339                                 target: label
0340                                 anchors.leftMargin: Kirigami.Units.smallSpacing * 2
0341                                 anchors.rightMargin: Kirigami.Units.smallSpacing * 2
0342                                 width: parent.width - icon.width - (Kirigami.Units.smallSpacing * 4)
0343                                 maximumLineCount: 1
0344                                 horizontalAlignment: Text.AlignLeft
0345                             }
0346                         }
0347                     ]
0348 
0349                     color: {
0350                         if (!root.useListViewMode) {
0351                             // In this situation there's a shadow or a background rect, both of which are always black
0352                             return "white";
0353                         }
0354 
0355                         if (model.selected) {
0356                             return Kirigami.Theme.highlightedTextColor;
0357                         }
0358 
0359                         return Kirigami.Theme.textColor;
0360 
0361                     }
0362                     renderShadow: (!editor || editor.targetItem !== main) && !root.useListViewMode
0363                     opacity: model.isHidden ? 0.6 : 1
0364 
0365                     text: main.nameWrapped
0366                     font.italic: model.isLink
0367                     wrapMode: (maximumLineCount === 1) ? Text.NoWrap : Text.Wrap
0368                     horizontalAlignment: Text.AlignHCenter
0369                 }
0370 
0371                 Component {
0372                     id: frameComponent
0373 
0374                     PlasmaExtras.Highlight {
0375                         // Workaround for a bug where the frameComponent does not
0376                         // get unloaded when items are dragged to a different
0377                         // place on the desktop.
0378                         visible: this === frameLoader.item
0379                         hovered: impl.iconAndLabelsShouldlookSelected
0380                         pressed: model.selected
0381                         active: Window.active
0382                     }
0383                 }
0384 
0385                 Component {
0386                     id: selectionButtonComponent
0387 
0388                     FolderItemActionButton {
0389                         element: model.selected ? "remove" : "add"
0390 
0391                         onClicked: {
0392                             dir.toggleSelected(positioner.map(index));
0393                             main.GridView.view.currentIndex = index;
0394                         }
0395                     }
0396                 }
0397 
0398                 Component {
0399                     id: popupButtonComponent
0400 
0401                     FolderItemActionButton {
0402                         visible: main.GridView.view.isRootView && (popupDialog == null)
0403 
0404                         element: "open"
0405 
0406                         onClicked: {
0407                             dir.setSelected(positioner.map(index));
0408                             main.GridView.view.currentIndex = index;
0409                             openPopup();
0410                         }
0411                     }
0412                 }
0413 
0414                 Component {
0415                     id: iconShadowComponent
0416 
0417                     DropShadow {
0418                         anchors.fill: icon
0419 
0420                         z: 1
0421 
0422                         verticalOffset: 1
0423 
0424                         radius: 5.0
0425                         samples: radius * 2 + 1
0426                         spread: 0.05
0427 
0428                         color: "black"
0429 
0430                         opacity: model.isHidden ? 0.3 : 0.6
0431 
0432                         source: icon
0433                     }
0434                 }
0435             }
0436 
0437             Column {
0438                 id: actions
0439 
0440                 visible: {
0441                     if (main.GridView.view.isRootView && root.containsDrag) {
0442                         return false;
0443                     }
0444 
0445                     if (!main.GridView.view.isRootView && main.GridView.view.dialog && main.GridView.view.dialog.containsDrag) {
0446                         return false;
0447                     }
0448 
0449                     if (popupDialog) {
0450                         return false;
0451                     }
0452 
0453                     return true;
0454                 }
0455 
0456                 anchors {
0457                     left: frameLoader.left
0458                     top: frameLoader.top
0459                     leftMargin: root.useListViewMode ? (icon.x + (icon.width / 2)) - (width / 2) : 0
0460                     topMargin: root.useListViewMode ? (icon.y + (icon.height / 2)) - (height / 2) : 0
0461                 }
0462 
0463                 width: implicitWidth
0464                 height: implicitHeight
0465             }
0466 
0467             Component.onCompleted: {
0468                 if (Plasmoid.isContainment && main.GridView.view.isRootView && root.GraphicsInfo.api === GraphicsInfo.OpenGL) {
0469                     frameLoader.iconShadow = iconShadowComponent.createObject(frameLoader);
0470                 }
0471             }
0472         }
0473     }
0474 }