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

0001 /*
0002     SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
0003     SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 import QtQuick 2.15
0009 import QtQuick.Layouts 1.15
0010 import QtQml 2.15
0011 
0012 import org.kde.plasma.plasmoid 2.0
0013 import org.kde.kirigami 2.20 as Kirigami
0014 import org.kde.plasma.components 3.0 as PlasmaComponents
0015 import org.kde.kquickcontrolsaddons 2.0
0016 
0017 import org.kde.private.desktopcontainment.folder 0.1 as Folder
0018 import "code/FolderTools.js" as FolderTools
0019 
0020 FocusScope {
0021     id: main
0022 
0023     signal pressed()
0024 
0025     property QtObject model: dir
0026     property Item rubberBand: null
0027 
0028     property alias view: gridView
0029     property alias isRootView: gridView.isRootView
0030     property alias currentIndex: gridView.currentIndex
0031     property alias url: dir.url
0032     property alias status: dir.status
0033     property alias perStripe: positioner.perStripe
0034     property alias positions: positioner.positions
0035     property alias errorString: dir.errorString
0036     property alias dragging: dir.dragging
0037     property alias dragInProgressAnywhere: dir.dragInProgressAnywhere
0038     property alias locked: dir.locked
0039     property alias sortMode: dir.sortMode
0040     property alias filterMode: dir.filterMode
0041     property alias filterPattern: dir.filterPattern
0042     property alias filterMimeTypes: dir.filterMimeTypes
0043     property alias showHiddenFiles: dir.showHiddenFiles
0044     property alias flow: gridView.flow
0045     property alias layoutDirection: gridView.layoutDirection
0046     property alias cellWidth: gridView.cellWidth
0047     property alias cellHeight: gridView.cellHeight
0048     property alias overflowing: gridView.overflowing
0049     property alias scrollLeft: gridView.scrollLeft
0050     property alias scrollRight: gridView.scrollRight
0051     property alias scrollUp: gridView.scrollUp
0052     property alias scrollDown: gridView.scrollDown
0053     property alias hoveredItem: gridView.hoveredItem
0054     property var history: []
0055     property var lastPosition: null
0056     property bool goingBack: false
0057     property Item backButton: null
0058     property var dialog: null
0059     property Item editor: null
0060 
0061     property int previouslySelectedItemIndex: -1
0062 
0063     function positionViewAtBeginning() {
0064         gridView.positionViewAtBeginning();
0065     }
0066 
0067     function rename() {
0068         if (gridView.currentIndex !== -1) {
0069             var renameAction = folderView.model.action("rename");
0070             if (renameAction && !renameAction.enabled) {
0071                 return;
0072             }
0073 
0074             if (!editor) {
0075                 editor = editorComponent.createObject(listener);
0076             }
0077 
0078             editor.targetItem = gridView.currentItem;
0079         }
0080     }
0081 
0082     function cancelRename() {
0083         if (editor) {
0084             editor.targetItem = null;
0085         }
0086     }
0087 
0088     function linkHere(sourceUrl) {
0089         dir.linkHere(sourceUrl);
0090     }
0091 
0092     function handleDragMove(x, y) {
0093         var child = childAt(x, y);
0094 
0095         if (child !== null && child === backButton) {
0096             hoveredItem = null;
0097             backButton.handleDragMove();
0098         } else {
0099             if (backButton && backButton.containsDrag) {
0100                 backButton.endDragMove();
0101             }
0102 
0103             var pos = mapToItem(gridView.contentItem, x, y);
0104             var item = gridView.itemAt(pos.x, pos.y);
0105 
0106             if (item && item.isDir) {
0107                 hoveredItem = item;
0108             } else {
0109                 hoveredItem = null;
0110             }
0111         }
0112     }
0113 
0114     function endDragMove() {
0115         if (backButton && backButton.active) {
0116             backButton.endDragMove();
0117         } else if (hoveredItem && !hoveredItem.popupDialog) {
0118             hoveredItem = null;
0119         }
0120     }
0121 
0122     function dropItemAt(pos) {
0123         var item = gridView.itemAt(pos.x, pos.y);
0124 
0125         if (item) {
0126             if (item.blank) {
0127                 return -1;
0128             }
0129 
0130             var hOffset = Math.abs(Math.min(gridView.contentX, gridView.originX));
0131             var hPos = mapToItem(item.hoverArea, pos.x + hOffset, pos.y);
0132 
0133             if ((hPos.x < 0 || hPos.y < 0 || hPos.x > item.hoverArea.width || hPos.y > item.hoverArea.height)) {
0134                 return -1;
0135             } else {
0136                 return positioner.map(item.index);
0137             }
0138         }
0139 
0140         return -1;
0141     }
0142 
0143     function drop(target, event, pos) {
0144         var dropPos = mapToItem(gridView.contentItem, pos.x, pos.y);
0145         var dropIndex = gridView.indexAt(dropPos.x, dropPos.y);
0146         var dragPos = mapToItem(gridView.contentItem, listener.dragX, listener.dragY);
0147         var dragIndex = gridView.indexAt(dragPos.x, dragPos.y);
0148 
0149         if (listener.dragX === -1 || dragIndex !== dropIndex) {
0150             dir.drop(target, event, dropItemAt(dropPos), root.isContainment && !Plasmoid.immutable);
0151         }
0152     }
0153 
0154     Connections {
0155         target: dir
0156         function onPopupMenuAboutToShow(dropJob, mimeData, x, y) {
0157             if (root.isContainment && !Plasmoid.immutable) {
0158                 root.processMimeData(mimeData, x, y, dropJob);
0159             }
0160         }
0161     }
0162 
0163     Connections {
0164         target: root
0165         function onExpandedChanged() {
0166             if (root.expanded && dir.status === Folder.FolderModel.Ready && !gridView.model) {
0167                 gridView.model = positioner;
0168             }
0169         }
0170     }
0171 
0172     Binding {
0173         target: Plasmoid
0174         property: "busy"
0175         value: !gridView.model && dir.status === Folder.FolderModel.Listing
0176         restoreMode: Binding.RestoreBinding
0177     }
0178 
0179     function makeBackButton() {
0180         return Qt.createQmlObject("BackButtonItem {}", main);
0181     }
0182 
0183     function doCd(row) {
0184         history.push({ url: url, index: gridView.currentIndex, yPosition: gridView.visibleArea.yPosition});
0185         updateHistory();
0186         dir.cd(row);
0187         gridView.currentIndex = -1;
0188     }
0189 
0190     function doBack() {
0191         goingBack = true;
0192         gridView.currentIndex = -1;
0193         lastPosition = history.pop();
0194         url = lastPosition.url;
0195         updateHistory();
0196     }
0197 
0198     // QML doesn't detect change in the array(history) property, so update it explicitly.
0199     function updateHistory() {
0200         history = history;
0201     }
0202 
0203     Connections {
0204         target: root
0205 
0206         function onIsPopupChanged() {
0207             if (backButton === null && root.useListViewMode) {
0208                 backButton = makeBackButton();
0209             } else if (backButton !== null) {
0210                 backButton.destroy();
0211             }
0212         }
0213     }
0214 
0215     Folder.EventGenerator {
0216         id: eventGenerator
0217     }
0218 
0219     MouseEventListener {
0220         id: listener
0221 
0222         anchors {
0223             topMargin: backButton !== null ? backButton.height : undefined
0224             fill: parent
0225         }
0226 
0227         property alias hoveredItem: gridView.hoveredItem
0228 
0229         property Item pressedItem: null
0230         property int pressX: -1
0231         property int pressY: -1
0232         property int dragX: -1
0233         property int dragY: -1
0234         property var cPress: null
0235         property bool doubleClickInProgress: false
0236 
0237         acceptedButtons: {
0238             if (hoveredItem === null && main.isRootView) {
0239                 return root.isPopup ? (Qt.LeftButton | Qt.MiddleButton | Qt.BackButton) : Qt.LeftButton;
0240             }
0241 
0242             return root.isPopup ? (Qt.LeftButton | Qt.MiddleButton | Qt.RightButton | Qt.BackButton)
0243                 : (Qt.LeftButton | Qt.RightButton);
0244         }
0245 
0246         hoverEnabled: true
0247 
0248         onPressXChanged: {
0249             cPress = mapToItem(gridView.contentItem, pressX, pressY);
0250         }
0251 
0252         onPressYChanged: {
0253             cPress = mapToItem(gridView.contentItem, pressX, pressY);
0254         }
0255 
0256         onPressed: mouse => {
0257             // Ignore press events outside the viewport (i.e. on scrollbars).
0258             if (!scrollArea.viewport.contains(Qt.point(mouse.x, mouse.y))) {
0259                 return;
0260             }
0261 
0262             scrollArea.focus = true;
0263 
0264             if (mouse.buttons & Qt.BackButton) {
0265                 if (root.isPopup && dir.resolvedUrl !== dir.resolve(Plasmoid.configuration.url)) {
0266                     doBack();
0267                     mouse.accepted = true;
0268                 }
0269 
0270                 return;
0271             }
0272 
0273             if (editor && childAt(mouse.x, mouse.y) !== editor) {
0274                 editor.commit();
0275             }
0276 
0277             if (mouse.source === Qt.MouseEventSynthesizedByQt) {
0278                 var index = gridView.indexAt(mouse.x, mouse.y);
0279                 var indexItem = gridView.itemAtIndex(index);
0280                 if (indexItem && indexItem.iconArea) {
0281                     gridView.currentIndex = index;
0282                     hoveredItem = indexItem;
0283                 } else {
0284                     hoveredItem = null;
0285                 }
0286                 if (gridView.hoveredItem && gridView.hoveredItem.toolTip.active) {
0287                     gridView.hoveredItem.toolTip.hideToolTip();
0288                 }
0289             }
0290 
0291             pressX = mouse.x;
0292             pressY = mouse.y;
0293 
0294             if (!hoveredItem || hoveredItem.blank) {
0295                 if (!gridView.ctrlPressed) {
0296                     gridView.currentIndex = -1;
0297                     previouslySelectedItemIndex = -1;
0298                     dir.clearSelection();
0299                 }
0300 
0301                 if (mouse.buttons & Qt.RightButton) {
0302                     clearPressState();
0303                     dir.openContextMenu(main, mouse.modifiers);
0304                     mouse.accepted = true;
0305                 }
0306             } else {
0307                 pressedItem = hoveredItem;
0308 
0309                 var pos = mapToItem(hoveredItem.actionsOverlay, mouse.x, mouse.y);
0310 
0311                 if (!(pos.x <= hoveredItem.actionsOverlay.width && pos.y <= hoveredItem.actionsOverlay.height)) {
0312                     if (gridView.shiftPressed && gridView.currentIndex !== -1) {
0313                         positioner.setRangeSelected(gridView.anchorIndex, hoveredItem.index);
0314                     } else {
0315                         // Deselecting everything else when one item is clicked is handled in onReleased in order to distinguish between drag and click
0316                         if (!gridView.ctrlPressed && !dir.isSelected(positioner.map(hoveredItem.index))) {
0317                             previouslySelectedItemIndex = -1;
0318                             dir.clearSelection();
0319                         }
0320 
0321                         if (gridView.ctrlPressed) {
0322                             dir.toggleSelected(positioner.map(hoveredItem.index));
0323                         } else {
0324                             dir.setSelected(positioner.map(hoveredItem.index));
0325                         }
0326                     }
0327 
0328                     gridView.currentIndex = hoveredItem.index;
0329 
0330                     if (mouse.buttons & Qt.RightButton) {
0331                         if (pressedItem.toolTip && pressedItem.toolTip.active) {
0332                             pressedItem.toolTip.hideToolTip();
0333                         }
0334 
0335                         clearPressState();
0336 
0337                         dir.openContextMenu(hoveredItem, mouse.modifiers);
0338                         mouse.accepted = true;
0339                     }
0340                 }
0341             }
0342 
0343             main.pressed();
0344         }
0345 
0346         onCanceled: pressCanceled()
0347 
0348         onReleased: mouse => {
0349             if (hoveredItem && !hoveredItem.blank && mouse.button !== Qt.RightButton) {
0350                 var pos = mapToItem(hoveredItem.actionsOverlay, mouse.x, mouse.y);
0351                 if (!(pos.x <= hoveredItem.actionsOverlay.width && pos.y <= hoveredItem.actionsOverlay.height)
0352                     && (!(gridView.shiftPressed && gridView.currentIndex !== -1) && !gridView.ctrlPressed)) {
0353                         dir.clearSelection();
0354                         dir.setSelected(positioner.map(hoveredItem.index));
0355                 }
0356             }
0357             pressCanceled();
0358         }
0359 
0360         onPressAndHold: mouse => {
0361             if (mouse.source === Qt.MouseEventSynthesizedByQt) {
0362                 if (pressedItem) {
0363                     if (pressedItem.toolTip && pressedItem.toolTip.active) {
0364                         pressedItem.toolTip.hideToolTip();
0365                     }
0366                 }
0367                 clearPressState();
0368                 if (hoveredItem) {
0369                     dir.openContextMenu(hoveredItem, mouse.modifiers);
0370                 }
0371             }
0372         }
0373 
0374         onClicked: mouse => {
0375             clearPressState();
0376 
0377             if (mouse.button === Qt.RightButton ||
0378                 (editor && childAt(mouse.x, mouse.y) === editor)) {
0379                 return;
0380             }
0381 
0382             if (!hoveredItem || hoveredItem.blank || gridView.currentIndex === -1 || gridView.ctrlPressed || gridView.shiftPressed) {
0383                 // Bug 357367: Replay mouse event, so containment actions assigned to left mouse button work.
0384                 eventGenerator.sendMouseEvent(root, Folder.EventGenerator.MouseButtonPress, mouse.x, mouse.y, mouse.button, mouse.buttons, mouse.modifiers);
0385                 return;
0386             }
0387 
0388             var pos = mapToItem(hoveredItem, mouse.x, mouse.y);
0389 
0390             // Moving from an item to its preview popup dialog doesn't unset hoveredItem
0391             // even though the cursor has left it, so we need to check whether the click
0392             // actually occurred inside the item we expect it in before going ahead. If it
0393             // didn't, clean up (e.g. dismissing the dialog as a side-effect of unsetting
0394             // hoveredItem) and abort.
0395             if (pos.x < 0 || pos.x > hoveredItem.width || pos.y < 0 || pos.y > hoveredItem.height) {
0396                 hoveredItem = null;
0397                 previouslySelectedItemIndex = -1;
0398                 dir.clearSelection();
0399 
0400                 return;
0401             // If the hoveredItem is clicked while having a preview popup dialog open,
0402             // only dismiss the dialog and abort.
0403             } else if (hoveredItem.popupDialog) {
0404                 hoveredItem.closePopup();
0405 
0406                 return;
0407             }
0408 
0409             pos = mapToItem(hoveredItem.actionsOverlay, mouse.x, mouse.y);
0410 
0411             if (!(pos.x <= hoveredItem.actionsOverlay.width && pos.y <= hoveredItem.actionsOverlay.height)) {
0412 
0413                 // Clicked on the label of an already-selected item: rename it
0414                 if (pos.x > hoveredItem.labelArea.x
0415                     && pos.x <= hoveredItem.labelArea.x + hoveredItem.labelArea.width
0416                     && pos.y > hoveredItem.labelArea.y
0417                     && pos.y <= hoveredItem.labelArea.y + hoveredItem.labelArea.height
0418                     && previouslySelectedItemIndex === gridView.currentIndex
0419                     && gridView.currentIndex !== -1
0420                     && !Qt.styleHints.singleClickActivation
0421                     && Plasmoid.configuration.renameInline
0422                     && !doubleClickInProgress
0423                 ) {
0424                     rename();
0425                     return;
0426                 }
0427 
0428                 // Single-click mode or list view and single-clicked on the item or
0429                 // double-click mode and double-clicked on the item: open it
0430                 if (Qt.styleHints.singleClickActivation || root.useListViewMode || doubleClickInProgress || mouse.source === Qt.MouseEventSynthesizedByQt) {
0431                     var func = root.useListViewMode && mouse.button === Qt.LeftButton && hoveredItem.isDir ? doCd : dir.run;
0432                     func(positioner.map(gridView.currentIndex));
0433                     previouslySelectedItemIndex = gridView.currentIndex;
0434                     hoveredItem = null;
0435                 } else {
0436                     // None of the above: select it
0437                     doubleClickInProgress = true;
0438                     doubleClickTimer.interval = Qt.styleHints.mouseDoubleClickInterval;
0439                     doubleClickTimer.start();
0440                     previouslySelectedItemIndex = gridView.currentIndex;
0441                 }
0442             }
0443         }
0444 
0445         onPositionChanged: mouse => {
0446             gridView.ctrlPressed = (mouse.modifiers & Qt.ControlModifier);
0447             gridView.shiftPressed = (mouse.modifiers & Qt.ShiftModifier);
0448 
0449             var cPos = mapToItem(gridView.contentItem, mouse.x, mouse.y);
0450             var item = gridView.itemAt(cPos.x, cPos.y);
0451             var leftEdge = Math.min(gridView.contentX, gridView.originX);
0452 
0453             if (!item || item.blank) {
0454                 if (gridView.hoveredItem && !root.containsDrag && (!dialog || !dialog.containsDrag) && !gridView.hoveredItem.popupDialog) {
0455                     gridView.hoveredItem = null;
0456                 }
0457             } else {
0458                 var fPos = mapToItem(item.frame, mouse.x, mouse.y);
0459 
0460                 if (fPos.x < 0 || fPos.y < 0 || fPos.x > item.frame.width || fPos.y > item.frame.height) {
0461                     gridView.hoveredItem = null;
0462                 }
0463             }
0464 
0465             // Trigger autoscroll.
0466             if (pressX !== -1) {
0467                 gridView.scrollLeft = (mouse.x <= 0 && gridView.contentX > leftEdge);
0468                 gridView.scrollRight = (mouse.x >= gridView.width
0469                     && gridView.contentX < gridView.contentItem.width - gridView.width);
0470                 gridView.scrollUp = (mouse.y <= 0 && gridView.contentY > 0);
0471                 gridView.scrollDown = (mouse.y >= gridView.height
0472                     && gridView.contentY < gridView.contentItem.height - gridView.height);
0473             }
0474 
0475             // Update rubberband geometry.
0476             if (main.rubberBand) {
0477                 var rB = main.rubberBand;
0478 
0479                 if (cPos.x < cPress.x) {
0480                     rB.x = Math.max(leftEdge, cPos.x);
0481                     rB.width = Math.abs(rB.x - cPress.x);
0482                 } else {
0483                     rB.x = cPress.x;
0484                     var ceil = Math.max(gridView.width, gridView.contentItem.width) + leftEdge;
0485                     rB.width = Math.min(ceil - rB.x, Math.abs(rB.x - cPos.x));
0486                 }
0487 
0488                 if (cPos.y < cPress.y) {
0489                     rB.y = Math.max(0, cPos.y);
0490                     rB.height = Math.abs(rB.y - cPress.y);
0491                 } else {
0492                     rB.y = cPress.y;
0493                     var ceil = Math.max(gridView.height, gridView.contentItem.height);
0494                     rB.height = Math.min(ceil - rB.y, Math.abs(rB.y - cPos.y));
0495                 }
0496 
0497                 // Ensure rubberband is at least 1px in size or else it will become
0498                 // invisible and not match any items.
0499                 rB.width = Math.max(1, rB.width);
0500                 rB.height = Math.max(1, rB.height);
0501 
0502                 gridView.rectangleSelect(rB.x, rB.y, rB.width, rB.height);
0503 
0504                 return;
0505             }
0506 
0507             // Drag initiation.
0508             if (pressX !== -1 && root.isDrag(pressX, pressY, mouse.x, mouse.y)) {
0509                 if (pressedItem !== null && dir.isSelected(positioner.map(pressedItem.index))) {
0510                     pressedItem.toolTip.hideToolTip();
0511                     dragX = mouse.x;
0512                     dragY = mouse.y;
0513                     gridView.verticalDropHitscanOffset = pressedItem.iconArea.y + (pressedItem.iconArea.height / 2);
0514                     dir.dragSelected(mouse.x, mouse.y);
0515                     dragX = -1;
0516                     dragY = -1;
0517                     clearPressState();
0518                 } else {
0519                     // Disable rubberband in popup list view mode or while renaming
0520                     if (root.useListViewMode || (editor && editor.targetItem)) {
0521                         return;
0522                     }
0523 
0524                     dir.pinSelection();
0525                     main.rubberBand = rubberBandObject.createObject(gridView.contentItem, {x: cPress.x, y: cPress.y});
0526                     gridView.interactive = false;
0527                 }
0528             }
0529         }
0530 
0531         Component {
0532             id: rubberBandObject
0533 
0534             Folder.RubberBand {
0535                 id: rubberBand
0536 
0537                 width: 0
0538                 height: 0
0539                 z: 99999
0540 
0541                 function close() {
0542                     opacityAnimation.restart();
0543                 }
0544 
0545                 OpacityAnimator {
0546                     id: opacityAnimation
0547                     target: rubberBand
0548                     to: 0
0549                     from: 1
0550                     duration: Kirigami.Units.shortDuration
0551 
0552                     // This easing curve has an elognated start, which works
0553                     // better than a standard easing curve for the rubberband
0554                     // animation, which fades out fast and is generally of a
0555                     // small area.
0556                     easing {
0557                         bezierCurve: [0.4, 0.0, 1, 1]
0558                         type: Easing.Bezier
0559                     }
0560 
0561                     onFinished: {
0562                         rubberBand.visible = false;
0563                         rubberBand.enabled = false;
0564                         rubberBand.destroy();
0565                     }
0566                 }
0567             }
0568         }
0569 
0570         onContainsMouseChanged: {
0571             if (!containsMouse && !main.rubberBand) {
0572                 clearPressState();
0573 
0574                 if (gridView.hoveredItem && !gridView.hoveredItem.popupDialog) {
0575                     gridView.hoveredItem = null;
0576                 }
0577             }
0578         }
0579 
0580         onHoveredItemChanged: {
0581             doubleClickInProgress = false;
0582 
0583             if (!hoveredItem) {
0584                 hoverActivateTimer.stop();
0585             }
0586         }
0587 
0588         function pressCanceled() {
0589             if (main.rubberBand) {
0590                 main.rubberBand.close();
0591                 main.rubberBand = null;
0592 
0593                 gridView.interactive = true;
0594                 gridView.cachedRectangleSelection = null;
0595                 dir.unpinSelection();
0596             }
0597 
0598             clearPressState();
0599             gridView.cancelAutoscroll();
0600         }
0601 
0602         function clearPressState() {
0603             pressedItem = null;
0604             pressX = -1;
0605             pressY = -1;
0606         }
0607 
0608         Timer {
0609             id: doubleClickTimer
0610 
0611             onTriggered: {
0612                 listener.doubleClickInProgress = false;
0613             }
0614         }
0615 
0616         Timer {
0617             id: hoverActivateTimer
0618 
0619             interval: root.hoverActivateDelay
0620 
0621             onTriggered: {
0622                 if (!hoveredItem) {
0623                     return;
0624                 }
0625 
0626                 if (root.useListViewMode) {
0627                     doCd(index);
0628                 } else if (Plasmoid.configuration.popups) {
0629                     hoveredItem.openPopup();
0630                 }
0631             }
0632         }
0633 
0634         FocusScope {
0635             id: scrollArea
0636 
0637             anchors.fill: parent
0638 
0639             focus: true
0640 
0641             property bool ready: false
0642             readonly property int viewportWidth: scrollArea.ready && viewport ? Math.ceil(viewport.width) : 0
0643             readonly property int viewportHeight: scrollArea.ready && viewport ? Math.ceil(viewport.height) : 0
0644             readonly property Flickable viewport: gridView
0645 
0646             Component.onCompleted: {
0647                 scrollArea.ready = true;
0648             }
0649 
0650             GridView {
0651                 id: gridView
0652                 clip: true
0653                 anchors.fill: parent
0654 
0655                 property bool isRootView: false
0656 
0657                 property int iconSize: makeIconSize()
0658                 property int verticalDropHitscanOffset: 0
0659 
0660                 property Item hoveredItem: null
0661 
0662                 property int anchorIndex: 0
0663                 property bool ctrlPressed: false
0664                 property bool shiftPressed: false
0665 
0666                 property bool overflowing: {
0667                     // widthRatio or heightRatio may be 0 when it's not actually
0668                     // overflowing, so account for that.
0669                     let widthOverflow =  visibleArea.widthRatio > 0.0 && visibleArea.widthRatio < 1.0
0670                     let heightOverflow = visibleArea.heightRatio > 0.0 && visibleArea.heightRatio < 1.0
0671                     return widthOverflow || heightOverflow
0672                 }
0673 
0674                 property bool scrollLeft: false
0675                 property bool scrollRight: false
0676                 property bool scrollUp: false
0677                 property bool scrollDown: false
0678 
0679                 property var cachedRectangleSelection: null
0680 
0681                 currentIndex: -1
0682 
0683                 keyNavigationWraps: false
0684                 boundsBehavior: Flickable.StopAtBounds
0685                 focus: true
0686 
0687                 PlasmaComponents.ScrollBar.vertical: PlasmaComponents.ScrollBar {
0688                     id: verticalScrollBar
0689                 }
0690                 PlasmaComponents.ScrollBar.horizontal: PlasmaComponents.ScrollBar {}
0691 
0692                 function calcExtraSpacing(cellSize, containerSize) {
0693                     var availableColumns = Math.floor(containerSize / cellSize);
0694                     var extraSpacing = 0;
0695                     if (availableColumns > 0) {
0696                         var allColumnSize = availableColumns * cellSize;
0697                         var extraSpace = Math.max(containerSize - allColumnSize, 0);
0698                         extraSpacing = extraSpace / availableColumns;
0699                     }
0700                     return Math.floor(extraSpacing);
0701                 }
0702 
0703                 cellWidth: {
0704                     if (root.useListViewMode) {
0705                         return gridView.width - (verticalScrollBar.visible ? verticalScrollBar.width : 0);
0706                     } else {
0707                         var iconWidth = iconSize + (2 * Kirigami.Units.gridUnit) + (2 * Kirigami.Units.smallSpacing);
0708                         if (root.isContainment && isRootView && scrollArea.viewportWidth > 0) {
0709                             var minIconWidth = Math.max(iconWidth, Kirigami.Units.iconSizes.small * ((Plasmoid.configuration.labelWidth * 2) + 4));
0710                             var extraWidth = calcExtraSpacing(minIconWidth, scrollArea.viewportWidth);
0711                             return minIconWidth + extraWidth;
0712                         } else {
0713                             return iconWidth;
0714                         }
0715                     }
0716                 }
0717 
0718                 cellHeight: {
0719                     if (root.useListViewMode) {
0720                         return Math.ceil((Math.max(Kirigami.Units.iconSizes.sizeForLabels, iconSize)
0721                             + Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom,
0722                             listItemSvg.margins.top + listItemSvg.margins.bottom)) / 2) * 2;
0723                     } else {
0724                         // the smallSpacings are for padding
0725                         var iconHeight = iconSize + (Kirigami.Units.gridUnit * Plasmoid.configuration.textLines) + (Kirigami.Units.smallSpacing * 3);
0726                         if (root.isContainment && isRootView && scrollArea.viewportHeight > 0) {
0727                             var extraHeight = calcExtraSpacing(iconHeight, scrollArea.viewportHeight);
0728                             return iconHeight + extraHeight;
0729                         } else {
0730                             return iconHeight;
0731                         }
0732                     }
0733                 }
0734 
0735                 delegate: FolderItemDelegate {
0736                     width: gridView.cellWidth
0737                     height: gridView.cellHeight
0738                 }
0739 
0740                 onContentXChanged: {
0741                     if (hoveredItem) {
0742                         hoverActivateTimer.stop();
0743                     }
0744 
0745                     cancelRename();
0746 
0747                     dir.setDragHotSpotScrollOffset(contentX, contentY);
0748 
0749                     if (contentX === 0) {
0750                         scrollLeft = false;
0751                     }
0752 
0753                     if (contentX === contentItem.width - width) {
0754                         scrollRight = false;
0755                     }
0756 
0757                     // Update rubberband geometry.
0758                     if (main.rubberBand) {
0759                         var rB = main.rubberBand;
0760 
0761                         if (scrollLeft) {
0762                             rB.x = Math.min(gridView.contentX, gridView.originX);
0763                             rB.width = listener.cPress.x;
0764                         }
0765 
0766                         if (scrollRight) {
0767                             var lastCol = gridView.contentX + gridView.width;
0768                             rB.width = lastCol - rB.x;
0769                         }
0770 
0771                         gridView.rectangleSelect(rB.x, rB.y, rB.width, rB.height);
0772                     }
0773                 }
0774 
0775                 onContentYChanged: {
0776                     if (hoveredItem) {
0777                         hoverActivateTimer.stop();
0778                     }
0779 
0780                     cancelRename();
0781 
0782                     dir.setDragHotSpotScrollOffset(contentX, contentY);
0783 
0784                     if (contentY === 0) {
0785                         scrollUp = false;
0786                     }
0787 
0788                     if (contentY === contentItem.height - height) {
0789                         scrollDown = false;
0790                     }
0791 
0792                     // Update rubberband geometry.
0793                     if (main.rubberBand) {
0794                         var rB = main.rubberBand;
0795 
0796                         if (scrollUp) {
0797                             rB.y = 0;
0798                             rB.height = listener.cPress.y;
0799                         }
0800 
0801                         if (scrollDown) {
0802                             var lastRow = gridView.contentY + gridView.height;
0803                             rB.height = lastRow - rB.y;
0804                         }
0805 
0806                         gridView.rectangleSelect(rB.x, rB.y, rB.width, rB.height);
0807                     }
0808                 }
0809 
0810                 onScrollLeftChanged: {
0811                     if (scrollLeft && gridView.visibleArea.widthRatio < 1.0) {
0812                         smoothX.enabled = true;
0813                         contentX = (gridView.flow === GridView.FlowLeftToRight) ? gridView.contentX : gridView.originX;
0814                     } else {
0815                         contentX = contentX;
0816                         smoothX.enabled = false;
0817                     }
0818                 }
0819 
0820                 onScrollRightChanged: {
0821                     if (scrollRight && gridView.visibleArea.widthRatio < 1.0) {
0822                         smoothX.enabled = true;
0823                         contentX = ((gridView.flow === GridView.FlowLeftToRight) ? gridView.contentX : gridView.originX)
0824                             + (contentItem.width - width);
0825                     } else {
0826                         contentX = contentX;
0827                         smoothX.enabled = false;
0828                     }
0829                 }
0830 
0831                 onScrollUpChanged: {
0832                     if (scrollUp && gridView.visibleArea.heightRatio < 1.0) {
0833                         smoothY.enabled = true;
0834                         contentY = 0;
0835                     } else {
0836                         contentY = contentY;
0837                         smoothY.enabled = false;
0838                     }
0839                 }
0840 
0841                 onScrollDownChanged: {
0842                     if (scrollDown && gridView.visibleArea.heightRatio < 1.0) {
0843                         smoothY.enabled = true;
0844                         contentY = contentItem.height - height;
0845                     } else {
0846                         contentY = contentY;
0847                         smoothY.enabled = false;
0848                     }
0849                 }
0850 
0851                 onCurrentIndexChanged: {
0852                     positionViewAtIndex(currentIndex, GridView.Contain);
0853                 }
0854 
0855                 onCachedRectangleSelectionChanged: {
0856                     if (cachedRectangleSelection === null) {
0857                         return;
0858                     }
0859 
0860                     if (cachedRectangleSelection.length) {
0861                         // Set current index to start of selection.
0862                         // cachedRectangleSelection is pre-sorted.
0863                         currentIndex = cachedRectangleSelection[0];
0864                     }
0865 
0866                     dir.updateSelection(cachedRectangleSelection.map(row => positioner.map(row)),
0867                         gridView.ctrlPressed);
0868                 }
0869 
0870                 function makeIconSize() {
0871                     if (root.useListViewMode) {
0872                         return Kirigami.Units.iconSizes.small;
0873                     }
0874 
0875                     return FolderTools.iconSizeFromTheme(Plasmoid.configuration.iconSize);
0876                 }
0877 
0878                 function updateSelection(modifier) {
0879                     if (modifier & Qt.ShiftModifier) {
0880                         positioner.setRangeSelected(anchorIndex, currentIndex);
0881                     } else {
0882                         dir.clearSelection();
0883                         dir.setSelected(positioner.map(currentIndex));
0884                         if (currentIndex === -1) {
0885                             previouslySelectedItemIndex = -1;
0886                         }
0887                         previouslySelectedItemIndex = currentIndex;
0888                     }
0889                 }
0890 
0891                 function cancelAutoscroll() {
0892                     scrollLeft = false;
0893                     scrollRight = false;
0894                     scrollUp = false;
0895                     scrollDown = false;
0896                 }
0897 
0898                 function rectangleSelect(x, y, width, height) {
0899                     var rows = (gridView.flow === GridView.FlowLeftToRight);
0900                     var axis = rows ? gridView.width : gridView.height;
0901                     var step = rows ? cellWidth : cellHeight;
0902                     var perStripe = Math.floor(axis / step);
0903                     var stripes = Math.ceil(gridView.count / perStripe);
0904                     var cWidth = gridView.cellWidth - (2 * Kirigami.Units.smallSpacing);
0905                     var cHeight = gridView.cellHeight - (2 * Kirigami.Units.smallSpacing);
0906                     var midWidth = gridView.cellWidth / 2;
0907                     var midHeight = gridView.cellHeight / 2;
0908                     var indices = [];
0909 
0910                     for (var s = 0; s < stripes; s++) {
0911                         for (var i = 0; i < perStripe; i++) {
0912                             var index = (s * perStripe) + i;
0913 
0914                             if (index >= gridView.count) {
0915                                 break;
0916                             }
0917 
0918                             if (positioner.isBlank(index)) {
0919                                 continue;
0920                             }
0921 
0922                             var itemX = ((rows ? i : s) * gridView.cellWidth);
0923                             var itemY = ((rows ? s : i) * gridView.cellHeight);
0924 
0925                             if (gridView.effectiveLayoutDirection === Qt.RightToLeft) {
0926                                 itemX -= (rows ? gridView.contentX : gridView.originX);
0927                                 itemX += cWidth;
0928                                 itemX = (rows ? gridView.width : gridView.contentItem.width) - itemX;
0929                             }
0930 
0931                             // Check if the rubberband intersects this cell first to avoid doing more
0932                             // expensive work.
0933                             if (main.rubberBand.intersects(Qt.rect(itemX + Kirigami.Units.smallSpacing, itemY + Kirigami.Units.smallSpacing,
0934                                 cWidth, cHeight))) {
0935                                 var item = gridView.contentItem.childAt(itemX + midWidth, itemY + midHeight);
0936 
0937                                 // If this is a visible item, check for intersection with the actual
0938                                 // icon or label rects for better feel.
0939                                 if (item && item.iconArea) {
0940                                     var iconRect = Qt.rect(itemX + item.iconArea.x, itemY + item.iconArea.y,
0941                                         item.iconArea.width, item.iconArea.height);
0942 
0943                                     if (main.rubberBand.intersects(iconRect)) {
0944                                         indices.push(index);
0945                                         continue;
0946                                     }
0947 
0948                                     var labelRect = Qt.rect(itemX + item.labelArea.x, itemY + item.labelArea.y,
0949                                         item.labelArea.width, item.labelArea.height);
0950 
0951                                     if (main.rubberBand.intersects(labelRect)) {
0952                                         indices.push(index);
0953                                         continue;
0954                                     }
0955                                 } else {
0956                                     // Otherwise be content with the cell intersection.
0957                                     indices.push(index);
0958                                 }
0959                             }
0960                         }
0961                     }
0962 
0963                     gridView.cachedRectangleSelection = indices;
0964                 }
0965 
0966                 function runOrCdSelected() {
0967                     if (currentIndex !== -1 && dir.hasSelection()) {
0968                         if (root.useListViewMode && currentItem.isDir) {
0969                             doCd(positioner.map(currentIndex));
0970                         } else {
0971                             dir.runSelected();
0972                         }
0973                     }
0974                 }
0975 
0976                 Behavior on contentX { id: smoothX; enabled: false; SmoothedAnimation { velocity: 700 } }
0977                 Behavior on contentY { id: smoothY; enabled: false; SmoothedAnimation { velocity: 700 } }
0978 
0979                 Keys.onReturnPressed: event => {
0980                     if (event.modifiers === Qt.AltModifier) {
0981                         dir.openPropertiesDialog();
0982                     } else {
0983                         runOrCdSelected();
0984                     }
0985                 }
0986 
0987                 Keys.onEnterPressed: event => Keys.returnPressed(event)
0988 
0989                 Keys.onMenuPressed: event => {
0990                     if (currentIndex !== -1 && dir.hasSelection() && currentItem) {
0991                         dir.setSelected(positioner.map(currentIndex));
0992                         dir.openContextMenu(currentItem.frame, event.modifiers);
0993                     } else {
0994                         // Otherwise let the containment handle it.
0995                         event.accepted = false;
0996                     }
0997                 }
0998 
0999                 Keys.onEscapePressed: event => {
1000                     if (!editor || !editor.targetItem) {
1001                         previouslySelectedItemIndex = -1;
1002                         dir.clearSelection();
1003                         event.accepted = false;
1004                     }
1005                 }
1006 
1007                 Folder.ShortCut {
1008                     Component.onCompleted: {
1009                         installAsEventFilterFor(gridView);
1010                     }
1011 
1012                     onDeleteFile: {
1013                         dir.deleteSelected();
1014                     }
1015 
1016                     onRenameFile: {
1017                         rename();
1018                     }
1019 
1020                     onMoveToTrash: {
1021                         const action = dir.action("trash");
1022                         if (action && action.enabled) {
1023                             action.trigger();
1024                         }
1025                     }
1026 
1027                     onCreateFolder: {
1028                         model.createFolder();
1029                     }
1030                 }
1031 
1032                 Keys.onPressed: event => {
1033                     event.accepted = true;
1034 
1035                     if (event.key === Qt.Key_Control) {
1036                         ctrlPressed = true;
1037                     } else if (event.key === Qt.Key_Shift) {
1038                         shiftPressed = true;
1039 
1040                         if (currentIndex !== -1) {
1041                             anchorIndex = currentIndex;
1042                         }
1043                     } else if (event.key === Qt.Key_Home) {
1044                         currentIndex = 0;
1045                         updateSelection(event.modifiers);
1046                     } else if (event.key === Qt.Key_End) {
1047                         currentIndex = count - 1;
1048                         updateSelection(event.modifiers);
1049                     } else if (event.matches(StandardKey.Copy)) {
1050                         dir.copy();
1051                     } else if (event.matches(StandardKey.Paste)) {
1052                         dir.paste();
1053                     } else if (event.matches(StandardKey.Cut)) {
1054                         dir.cut();
1055                     } else if (event.matches(StandardKey.Undo)) {
1056                         dir.undo();
1057                     } else if (event.matches(StandardKey.Refresh)) {
1058                         dir.refresh();
1059                     } else if (event.matches(StandardKey.SelectAll)) {
1060                         positioner.setRangeSelected(0, count - 1);
1061                     } else {
1062                         event.accepted = false;
1063                     }
1064                 }
1065 
1066                 Keys.onReleased: event => {
1067                     if (event.key === Qt.Key_Control) {
1068                         ctrlPressed = false;
1069                     } else if (event.key === Qt.Key_Shift) {
1070                         shiftPressed = false;
1071                         anchorIndex = 0;
1072                     }
1073                 }
1074 
1075                 Keys.onLeftPressed: event => {
1076                     if (root.isPopup && root.useListViewMode) {
1077                         if (dir.resolvedUrl !== dir.resolve(Plasmoid.configuration.url)) {
1078                             doBack();
1079                         }
1080                     } else if (positioner.enabled) {
1081                         var newIndex = positioner.nearestItem(currentIndex,
1082                             FolderTools.effectiveNavDirection(gridView.flow, gridView.effectiveLayoutDirection, Qt.LeftArrow));
1083 
1084                         if (newIndex !== -1) {
1085                             currentIndex = newIndex;
1086                             updateSelection(event.modifiers);
1087                         }
1088                     } else {
1089                         var oldIndex = currentIndex;
1090 
1091                         moveCurrentIndexLeft();
1092 
1093                         if (oldIndex === currentIndex) {
1094                             return;
1095                         }
1096 
1097                         updateSelection(event.modifiers);
1098                     }
1099                 }
1100 
1101                 Keys.onRightPressed: event => {
1102                     if (root.isPopup && root.useListViewMode) {
1103                         if (currentIndex !== -1 && dir.hasSelection() && currentItem.isDir) {
1104                             doCd(positioner.map(currentIndex));
1105                         }
1106                     } else if (positioner.enabled) {
1107                         var newIndex = positioner.nearestItem(currentIndex,
1108                             FolderTools.effectiveNavDirection(gridView.flow, gridView.effectiveLayoutDirection, Qt.RightArrow));
1109 
1110                         if (newIndex !== -1) {
1111                             currentIndex = newIndex;
1112                             updateSelection(event.modifiers);
1113                         }
1114                     } else {
1115                         var oldIndex = currentIndex;
1116 
1117                         moveCurrentIndexRight();
1118 
1119                         if (oldIndex === currentIndex) {
1120                             return;
1121                         }
1122 
1123                         updateSelection(event.modifiers);
1124                     }
1125                 }
1126 
1127                 Keys.onUpPressed: event => {
1128                     if (positioner.enabled) {
1129                         var newIndex = positioner.nearestItem(currentIndex,
1130                             FolderTools.effectiveNavDirection(gridView.flow, gridView.effectiveLayoutDirection, Qt.UpArrow));
1131 
1132                         if (newIndex !== -1) {
1133                             currentIndex = newIndex;
1134                             updateSelection(event.modifiers);
1135                         }
1136                     } else {
1137                         var oldIndex = currentIndex;
1138 
1139                         moveCurrentIndexUp();
1140 
1141                         if (oldIndex === currentIndex) {
1142                             return;
1143                         }
1144 
1145                         updateSelection(event.modifiers);
1146                     }
1147                 }
1148 
1149                 Keys.onDownPressed: event => {
1150                     if (positioner.enabled) {
1151                         var newIndex = positioner.nearestItem(currentIndex,
1152                             FolderTools.effectiveNavDirection(gridView.flow, gridView.effectiveLayoutDirection, Qt.DownArrow));
1153 
1154                         if (newIndex !== -1) {
1155                             currentIndex = newIndex;
1156                             updateSelection(event.modifiers);
1157                         }
1158                     } else {
1159                         var oldIndex = currentIndex;
1160 
1161                         moveCurrentIndexDown();
1162 
1163                         if (oldIndex === currentIndex) {
1164                             return;
1165                         }
1166 
1167                         updateSelection(event.modifiers);
1168                     }
1169                 }
1170 
1171                 Keys.onBackPressed: event => {
1172                     if (root.isPopup && dir.resolvedUrl !== dir.resolve(Plasmoid.configuration.url)) {
1173                         doBack();
1174                     }
1175                 }
1176 
1177                 Connections {
1178                     target: Plasmoid.configuration
1179 
1180                     function onIconSizeChanged() {
1181                         gridView.iconSize = gridView.makeIconSize();
1182                     }
1183 
1184                     function onViewModeChanged() {
1185                         gridView.iconSize = gridView.makeIconSize();
1186                     }
1187 
1188                     function onUrlChanged() {
1189                         history = [];
1190                         updateHistory();
1191                     }
1192                 }
1193             }
1194 
1195             Kirigami.InlineMessage {
1196                 width: parent.width / 2.0
1197                 anchors.horizontalCenter: parent.horizontalCenter
1198                 type: Kirigami.MessageType.Warning
1199                 text: i18nc("@info",
1200                     "There are a lot of files and folders on the desktop. This can cause bugs and performance issues. Please consider moving some of them elsewhere.")
1201                 // Note: the trigger amount is intentionally lower than the screen mapping cap. We want to warn ahead of hitting our caps.
1202                 visible: isRootView && gridView.count > 2048
1203             }
1204         }
1205 
1206         Folder.WheelInterceptor {
1207             anchors.fill: parent
1208 
1209             enabled: root.isContainment && !gridView.overflowing
1210             destination: root
1211         }
1212 
1213         Folder.FolderModel {
1214             id: dir
1215 
1216             usedByContainment: root.isContainment && main.isRootView
1217             sortDesc: Plasmoid.configuration.sortDesc
1218             sortDirsFirst: Plasmoid.configuration.sortDirsFirst
1219             parseDesktopFiles: (Plasmoid.configuration.url === "desktop:/")
1220             previews: Plasmoid.configuration.previews
1221             previewPlugins: Plasmoid.configuration.previewPlugins
1222             applet: Plasmoid
1223 
1224             onListingCompleted: {
1225                 if (!gridView.model && root.expanded) {
1226                     gridView.model = positioner;
1227                     gridView.currentIndex = isPopup ? 0 : -1;
1228                 } else if (goingBack) {
1229                     goingBack = false;
1230                     gridView.currentIndex = Math.min(lastPosition.index, gridView.count - 1);
1231                     setSelected(positioner.map(gridView.currentIndex));
1232                     gridView.contentY = lastPosition.yPosition * gridView.contentHeight;
1233                 }
1234             }
1235 
1236             onMove: (x, y, urls) => {
1237                 var rows = (gridView.flow === GridView.FlowLeftToRight);
1238                 var axis = rows ? gridView.width : gridView.height;
1239                 var step = rows ? cellWidth : cellHeight;
1240                 var perStripe = Math.floor(axis / step);
1241                 var dropPos = mapToItem(gridView.contentItem, x, y);
1242                 var leftEdge = Math.min(gridView.contentX, gridView.originX);
1243 
1244                 var moves = []
1245                 var itemX = -1;
1246                 var itemY = -1;
1247                 var col = -1;
1248                 var row = -1;
1249                 var from = -1;
1250                 var to = -1;
1251 
1252                 for (var i = 0; i < urls.length; i++) {
1253                     from = positioner.indexForUrl(urls[i]);
1254                     to = -1;
1255 
1256                     if (from === -1) {
1257                         continue;
1258                     }
1259 
1260                     var offset = dir.dragCursorOffset(positioner.map(from));
1261 
1262                     if (offset.x === -1) {
1263                         continue;
1264                     }
1265 
1266                     itemX = dropPos.x + offset.x + (listener.dragX % cellWidth) + (cellWidth / 2);
1267                     itemY = dropPos.y + offset.y + (listener.dragY % cellHeight) + gridView.verticalDropHitscanOffset;
1268 
1269                     if (gridView.effectiveLayoutDirection === Qt.RightToLeft) {
1270                         itemX -= (rows ? gridView.contentX : gridView.originX);
1271                         itemX = (rows ? gridView.width : gridView.contentItem.width) - itemX;
1272                     }
1273 
1274                     col = Math.floor(itemX / gridView.cellWidth);
1275                     row = Math.floor(itemY / gridView.cellHeight);
1276 
1277                     if ((rows ? col : row) < perStripe) {
1278                         to = ((rows ? row : col) * perStripe) + (rows ? col : row);
1279 
1280                         if (to < 0) {
1281                             return;
1282                         }
1283                     }
1284 
1285                     if (from !== to) {
1286                         moves.push(from);
1287                         moves.push(to);
1288                     }
1289                 }
1290 
1291                 if (moves.length) {
1292                     // Update also the currentIndex, otherwise it
1293                     // is not set properly.
1294                     gridView.currentIndex = positioner.move(moves);
1295                     gridView.forceLayout();
1296                 }
1297 
1298                 previouslySelectedItemIndex = -1;
1299             }
1300         }
1301 
1302         Folder.Positioner {
1303             id: positioner
1304 
1305             enabled: isContainment && sortMode === -1
1306 
1307             folderModel: dir
1308 
1309             perStripe: Math.floor((gridView.flow === GridView.FlowLeftToRight)
1310                 ? (gridView.width / gridView.cellWidth)
1311                 : (gridView.height / gridView.cellHeight))
1312         }
1313 
1314         Folder.ItemViewAdapter {
1315             id: viewAdapter
1316 
1317             adapterView: gridView
1318             adapterModel: positioner
1319             adapterIconSize: gridView.iconSize * 2
1320             adapterVisibleArea: Qt.rect(gridView.contentX, gridView.contentY, gridView.contentWidth, gridView.contentHeight)
1321 
1322             Component.onCompleted: {
1323                 gridView.movementStarted.connect(viewAdapter.viewScrolled);
1324                 dir.viewAdapter = viewAdapter;
1325             }
1326         }
1327 
1328         Component {
1329             id: editorComponent
1330 
1331             RenameEditor {
1332                 id: editor
1333 
1334                 visible: false
1335 
1336                 onCommit: {
1337                     if (targetItem) {
1338                         dir.rename(positioner.map(targetItem.index), text);
1339                         targetItem = null;
1340                     }
1341                 }
1342 
1343                 onVisibleChanged: {
1344                     if (root.visible) {
1345                         focus = true;
1346                     } else {
1347                         scrollArea.focus = true;
1348                     }
1349                 }
1350             }
1351         }
1352 
1353         Component.onCompleted: {
1354             dir.requestRename.connect(rename);
1355         }
1356     }
1357 
1358     Component.onCompleted: {
1359         if (backButton === null && root.useListViewMode) {
1360             backButton = makeBackButton();
1361         }
1362     }
1363 }