Warning, /maui/mauikit-filebrowsing/src/controls.5/FileBrowser.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 * Copyright 2018 Camilo Higuita <milo.h@aol.com> 0003 * 0004 * This program is free software; you can redistribute it and/or modify 0005 * it under the terms of the GNU Library General Public License as 0006 * published by the Free Software Foundation; either version 2, or 0007 * (at your option) any later version. 0008 * 0009 * This program is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 * GNU General Public License for more details 0013 * 0014 * You should have received a copy of the GNU Library General Public 0015 * License along with this program; if not, write to the 0016 * Free Software Foundation, Inc., 0017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0018 */ 0019 0020 import QtQuick 2.14 0021 import QtQml 2.14 0022 0023 import QtQuick.Controls 2.14 0024 import QtQuick.Layouts 1.3 0025 0026 import org.mauikit.controls 1.3 as Maui 0027 import org.mauikit.filebrowsing 1.3 as FB 0028 0029 import "private" as Private 0030 0031 /*! 0032 * A control to list and browse the file system, with convinient properties 0033 * for filtering and sorting its contents 0034 * 0035 * There are three different possible ways to display the contents: Grid, List and Miller views. 0036 * Some basic file item actions are implemented by default, like copy, cut, rename and remove. 0037 * 0038 * This component functionality can be easily expanded to be more feature rich. 0039 */ 0040 Maui.Page 0041 { 0042 id: control 0043 0044 onGoBackTriggered: control.goBack() 0045 onGoForwardTriggered: control.goForward() 0046 0047 title: view.title 0048 0049 focus: true 0050 0051 flickable: control.currentView.flickable 0052 0053 floatingFooter: false 0054 0055 showTitle: false 0056 0057 /*! 0058 * \qmlproperty FileBrowser::currentPath 0059 * 0060 * The current path of the directory URL. 0061 * To list a directory path, or other location, use the right schemas, 0062 * some of them are file://, webdav://, trash:///, tags:// 0063 */ 0064 property alias currentPath : _browser.path 0065 onCurrentPathChanged : _searchField.clear() 0066 0067 /*! 0068 * \qmlproperty BrowserSettings FileBrowser::settings 0069 * 0070 * A group of properties for controlling the sorting, listing and behaviour of the file browser. 0071 * For more details check the BrowserSettings documentation. 0072 */ 0073 property alias settings : _browser.settings 0074 0075 /*! 0076 * \qmlproperty Item FileBrowser::view 0077 * 0078 * The browser can be in two different view states: the file browsing or the search view, this 0079 * property gives access to the current view in use. 0080 */ 0081 property alias view : _stackView.currentItem 0082 0083 property alias browser : _browser 0084 /*! 0085 * \qmlproperty DropArea FileBrowser::dropArea 0086 * 0087 * Drop area component, for dropping files. 0088 * By default sonme drop actions are handled, for other type of uris this property can be used to handle those. 0089 */ 0090 property alias dropArea : _dropArea 0091 0092 /*! 0093 * \qmlproperty int FileBrowser::currentIndex 0094 * 0095 * Current index of the item selected in the file browser. 0096 */ 0097 property int currentIndex : -1 0098 0099 Binding on currentIndex 0100 { 0101 value: currentView.currentIndex 0102 // restoreMode: Binding.RestoreBindingOrValue 0103 } 0104 0105 /*! 0106 * \qmlproperty Item FileBrowser::currentView 0107 * 0108 * Current view of the file browser. Possible views are List = ListBrowser 0109 * Grid = GridView 0110 * Miller = ListView 0111 */ 0112 readonly property QtObject currentView : _stackView.currentItem.browser 0113 0114 /*! 0115 * The file browser model list controller being used. The List and Grid views use the same FMList, the 0116 * Miller columns use several different models, one for each column. 0117 */ 0118 readonly property FB.FMList currentFMList : view.currentFMList 0119 0120 /*! 0121 * The file browser data model being used. The List and Grid views use the same model, the 0122 * Miller columns use several different FMList controllers, one for each column. 0123 */ 0124 readonly property Maui.BaseModel currentFMModel : view.currentFMModel 0125 0126 /*! 0127 * isSearchView : bool 0128 * If the file browser current view is the search view. 0129 */ 0130 readonly property bool isSearchView : _stackView.currentItem.objectName === "searchView" 0131 0132 /*! 0133 * If the file browser enters selection mode, allowing the selection of multiple items. 0134 */ 0135 property bool selectionMode: false 0136 0137 /*! 0138 * \qmlproperty int FileBrowser::gridItemSize 0139 * 0140 * Size of the items in the grid view. The size is for the combined thumbnail/icon and the title label. 0141 */ 0142 property alias gridItemSize : _browser.gridItemSize 0143 0144 /*! 0145 * \qmlproperty int FileBrowser::listItemSize 0146 * 0147 * Size of the items in the grid view. The size is for the combined thumbnail/icon and the title label. 0148 */ 0149 property alias listItemSize : _browser.listItemSize 0150 0151 /*! 0152 * \qmlproperty var FileBrowser::indexHistory 0153 * 0154 * History of the items indexes. 0155 */ 0156 property var indexHistory : [] 0157 0158 // need to be set by the implementation as features 0159 /*! 0160 * 0161 */ 0162 property Maui.SelectionBar selectionBar : null //TODO remove 0163 0164 0165 //access to the loaded the dialog components 0166 /*! 0167 * \qmlproperty Dialog FileBrowser::dialog 0168 * The message and action dialogs are loaded when needed. 0169 * This property gives access to the current dialog opened. 0170 */ 0171 property alias dialog : dialogLoader.item 0172 0173 property alias readOnly : _browser.readOnly 0174 0175 0176 //signals 0177 /*! 0178 * An item was clicked. 0179 */ 0180 signal itemClicked(int index) 0181 0182 /** 0183 * An item was double clicked. 0184 */ 0185 signal itemDoubleClicked(int index) 0186 0187 /*! 0188 * An item was right clicked, on mobile devices this is translated from a long press and relase. 0189 */ 0190 signal itemRightClicked(int index) 0191 0192 /*! 0193 * The left emblem of the item was clicked. 0194 */ 0195 signal itemLeftEmblemClicked(int index) 0196 0197 /*! 0198 * The right emblem of the item was clicked. 0199 */ 0200 signal itemRightEmblemClicked(int index) 0201 0202 /*! 0203 * The file browser empty area was right clicked. 0204 */ 0205 signal rightClicked() 0206 0207 /*! 0208 * The file browser empty area was right clicked. 0209 */ 0210 signal areaClicked(var mouse) 0211 0212 0213 /*! 0214 * A key, physical or not, was pressed. 0215 * The event contains the relevant information. 0216 */ 0217 signal keyPress(var event) 0218 0219 /*! 0220 * File URLS were dropped onto the file browser area. 0221 */ 0222 signal urlsDropped(var urls) 0223 0224 headBar.forceCenterMiddleContent: isWide 0225 headBar.visible: control.settings.searchBarVisible 0226 headBar.leftContent: Loader 0227 { 0228 asynchronous: true 0229 active: control.isSearchView 0230 visible: active 0231 sourceComponent: ToolButton 0232 { 0233 text: i18nd("mauikitfilebrowsing", "Back") 0234 icon.name: "go-previous" 0235 onClicked: control.quitSearch() 0236 } 0237 } 0238 0239 Maui.InfoDialog 0240 { 0241 id: _quitSearchDialog 0242 title: i18n("Quit") 0243 message: i18n("Are you sure you want to quit the current search in progress?") 0244 onAccepted: 0245 { 0246 _stackView.pop() 0247 _browser.forceActiveFocus() 0248 } 0249 0250 onRejected: close() 0251 } 0252 0253 headBar.middleContent: Maui.SearchField 0254 { 0255 id: _searchField 0256 focus: true 0257 Layout.fillWidth: true 0258 Layout.maximumWidth: 500 0259 Layout.alignment: Qt.AlignCenter 0260 placeholderText: _filterButton.checked ? i18nd("mauikitfilebrowsing", "Filter") : ("Search") 0261 inputMethodHints: Qt.ImhNoAutoUppercase 0262 0263 onAccepted: 0264 { 0265 if(_filterButton.checked) 0266 { 0267 if(text.includes(",")) 0268 { 0269 control.view.filters = text.split(",") 0270 }else 0271 { 0272 control.view.filter = text 0273 } 0274 0275 }else 0276 { 0277 control.search(text) 0278 } 0279 } 0280 0281 onCleared: 0282 { 0283 if(_filterButton.checked) 0284 { 0285 control.currentFMModel.clearFilters() 0286 } 0287 } 0288 0289 onTextChanged: 0290 { 0291 if(_filterButton.checked) 0292 _searchField.accepted() 0293 } 0294 0295 Keys.enabled: _filterButton.checked 0296 Keys.onPressed: 0297 { 0298 // Shortcut for clearing selection 0299 if(event.key == Qt.Key_Up) 0300 { 0301 control.currentView.forceActiveFocus() 0302 } 0303 } 0304 0305 actions: Action 0306 { 0307 id: _filterButton 0308 icon.name: "view-filter" 0309 // text: i18nd("mauikitfilebrowsing", "Filter") 0310 checkable: true 0311 checked: true 0312 onTriggered: 0313 { 0314 control.view.filter = "" 0315 _searchField.clear() 0316 _searchField.forceActiveFocus() 0317 } 0318 } 0319 } 0320 0321 footBar.visible: control.currentPath.startsWith("trash:/") 0322 0323 footerPositioning: ListView.InlineFooter 0324 0325 footBar.rightContent: Button 0326 { 0327 visible: control.currentPath.startsWith("trash:/") 0328 icon.name: "trash-empty" 0329 text: i18nd("mauikitfilebrowsing", "Empty Trash") 0330 onClicked: FB.FM.emptyTrash() 0331 } 0332 0333 Loader 0334 { 0335 id: dialogLoader 0336 } 0337 0338 Component 0339 { 0340 id: removeDialogComponent 0341 0342 Maui.FileListingDialog 0343 { 0344 id: _removeDialog 0345 0346 property double freedSpace : calculateFreedSpace(urls) 0347 0348 title: i18nd("mauikitfilebrowsing", "Removing %1 files", urls.length) 0349 message: i18nd("mauikitfilebrowsing", "Delete %1 \nTotal freed space %2", (Maui.Handy.isLinux ? "or move to trash?" : "? This action can not be undone."), Maui.Handy.formatSize(freedSpace)) 0350 0351 actions: [ 0352 Action 0353 { 0354 text: i18nd("mauikitfilebrowsing", "Cancel") 0355 onTriggered: _removeDialog.close() 0356 }, 0357 0358 Action 0359 { 0360 text: i18nd("mauikitfilebrowsing", "Delete") 0361 onTriggered: 0362 { 0363 control.currentFMList.removeFiles(urls) 0364 close() 0365 } 0366 }, 0367 Action 0368 { 0369 text: i18nd("mauikitfilebrowsing", "Trash") 0370 enabled: Maui.Handy.isLinux 0371 onTriggered: 0372 { 0373 control.currentFMList.moveToTrash(urls) 0374 close() 0375 } 0376 } 0377 ] 0378 0379 function calculateFreedSpace(urls) 0380 { 0381 var size = 0 0382 for(var url of urls) 0383 { 0384 size += parseFloat(FB.FM.getFileInfo(url).size) 0385 } 0386 0387 return size 0388 } 0389 } 0390 } 0391 0392 Component 0393 { 0394 id: newDialogComponent 0395 // 0396 Maui.InputDialog 0397 { 0398 id: _newDialog 0399 0400 title: _newActions.currentIndex === 0 ? i18nd("mauikitfilebrowsing", "New folder") : i18nd("mauikitfilebrowsing", "New file") 0401 message: i18nd("mauikitfilebrowsing", "Create a new folder or a file with a custom name.") 0402 0403 template.iconSource: FB.FM.getIconName(textEntry.text) 0404 template.iconVisible: true 0405 0406 onFinished: 0407 { 0408 if(_newDirOp.checked) 0409 { 0410 control.currentFMList.createDir(text) 0411 return 0412 } 0413 0414 if(_newFileOp.checked) 0415 { 0416 control.currentFMList.createFile(text) 0417 return 0418 } 0419 } 0420 0421 textEntry.placeholderText: i18nd("mauikitfilebrowsing", "Name") 0422 0423 Maui.ToolActions 0424 { 0425 id: _newActions 0426 expanded: true 0427 autoExclusive: true 0428 display: ToolButton.TextBesideIcon 0429 0430 Action 0431 { 0432 id: _newDirOp 0433 icon.name: "folder-new" 0434 text: i18nd("mauikitfilebrowsing", "Folder") 0435 checked: String(_newDialog.textEntry.text).indexOf(".") < 0 0436 } 0437 0438 Action 0439 { 0440 id: _newFileOp 0441 icon.name: "document-new" 0442 text: i18nd("mauikitfilebrowsing", "File") 0443 checked: String(_newDialog.textEntry.text).indexOf(".") >= 0 0444 } 0445 } 0446 } 0447 } 0448 0449 Component 0450 { 0451 id: renameDialogComponent 0452 0453 Maui.InputDialog 0454 { 0455 id: _renameDialog 0456 0457 property var item : ({}) 0458 0459 title: i18nd("mauikitfilebrowsing", "Rename") 0460 message: i18nd("mauikitfilebrowsing", "Change the name of a file or folder. Write a new name and click Rename to apply the change.") 0461 0462 // headBar.visible: false 0463 0464 template.iconSource: item.icon 0465 template.imageSource: item.thumbnail 0466 template.iconSizeHint: Maui.Style.iconSizes.huge 0467 0468 textEntry.text: item.label 0469 textEntry.placeholderText: i18nd("mauikitfilebrowsing", "New name") 0470 0471 onFinished: control.currentFMList.renameFile(item.path, textEntry.text) 0472 onRejected: close() 0473 0474 // acceptButton.text: i18nd("mauikitfilebrowsing", "Rename") 0475 // rejectButton.text: i18nd("mauikitfilebrowsing", "Cancel") 0476 0477 onOpened: 0478 { 0479 item = control.currentFMModel.get(control.currentIndex) 0480 0481 if(_renameDialog.textEntry.text.lastIndexOf(".") >= 0) 0482 { 0483 _renameDialog.textEntry.select(0, _renameDialog.textEntry.text.lastIndexOf(".")) 0484 }else 0485 { 0486 _renameDialog.textEntry.selectAll() 0487 } 0488 } 0489 } 0490 } 0491 0492 Component 0493 { 0494 id: _newTagDialogComponent 0495 FB.NewTagDialog {} 0496 } 0497 0498 property string typingQuery 0499 0500 Maui.Chip 0501 { 0502 z: control.z + 99999 0503 Maui.Theme.colorSet:Maui.Theme.Complementary 0504 visible: _typingTimer.running 0505 label.text: typingQuery 0506 anchors.left: parent.left 0507 anchors.top: parent.top 0508 showCloseButton: false 0509 anchors.margins: Maui.Style.space.medium 0510 } 0511 0512 Timer 0513 { 0514 id: _typingTimer 0515 interval: 250 0516 onTriggered: 0517 { 0518 const index = control.currentFMList.indexOfName(typingQuery) 0519 if(index > -1) 0520 { 0521 console.log("FOUDN TRYPIGN IDNEX", index) 0522 control.currentIndex = control.currentFMModel.mappedFromSource(index) 0523 } 0524 0525 typingQuery = "" 0526 } 0527 } 0528 0529 Connections 0530 { 0531 target: control.currentView 0532 ignoreUnknownSignals: true 0533 0534 function onKeyPress(event) 0535 { 0536 const index = control.currentIndex 0537 const item = control.currentFMModel.get(index) 0538 0539 var pat = /^([a-zA-Z0-9 _-]+)$/ 0540 0541 if(event.count === 1 && pat.test(event.text)) 0542 { 0543 typingQuery += event.text 0544 _typingTimer.restart() 0545 event.accepted = true 0546 } 0547 0548 // Shortcuts for refreshing 0549 if((event.key === Qt.Key_F5)) 0550 { 0551 control.currentFMList.refresh() 0552 event.accepted = true 0553 } 0554 0555 // Shortcuts for renaming 0556 if((event.key === Qt.Key_F2)) 0557 { 0558 dialogLoader.sourceComponent = renameDialogComponent 0559 dialog.open() 0560 event.accepted = true 0561 } 0562 0563 // Shortcuts for selecting file 0564 if((event.key === Qt.Key_A) && (event.modifiers & Qt.ControlModifier)) 0565 { 0566 control.selectAll() 0567 event.accepted = true 0568 } 0569 0570 if((event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Down || event.key === Qt.Key_Up) && (event.modifiers & Qt.ControlModifier) && (event.modifiers & Qt.ShiftModifier)) 0571 { 0572 if(control.selectionBar && control.selectionBar.contains(item.path)) 0573 { 0574 control.selectionBar.removeAtUri(item.path) 0575 }else 0576 { 0577 control.addToSelection(item) 0578 } 0579 //event.accepted = true 0580 } 0581 0582 //shortcut for opening files 0583 if(event.key === Qt.Key_Return) 0584 { 0585 indexHistory.push(index) 0586 control.openItem(index) 0587 event.accepted = true 0588 } 0589 0590 // Shortcut for pasting an item 0591 if((event.key == Qt.Key_V) && (event.modifiers & Qt.ControlModifier)) 0592 { 0593 control.paste() 0594 event.accepted = true 0595 } 0596 0597 // Shortcut for cutting an item 0598 if((event.key == Qt.Key_X) && (event.modifiers & Qt.ControlModifier)) 0599 { 0600 const urls = filterSelection(control.currentPath, item.path) 0601 control.cut(urls) 0602 event.accepted = true 0603 } 0604 0605 // Shortcut for copying an item 0606 if((event.key == Qt.Key_C) && (event.modifiers & Qt.ControlModifier)) 0607 { 0608 const urls = filterSelection(control.currentPath, item.path) 0609 control.copy(urls) 0610 event.accepted = true 0611 } 0612 0613 // Shortcut for removing an item 0614 if(event.key === Qt.Key_Delete) 0615 { 0616 const urls = filterSelection(control.currentPath, item.path) 0617 control.remove(urls) 0618 event.accepted = true 0619 } 0620 0621 // Shortcut for going back in browsing history 0622 if(event.key === Qt.Key_Backspace || event.key == Qt.Key_Back) 0623 { 0624 if(control.selectionBar && control.selectionBar.count> 0) 0625 { 0626 control.selectionBar.clear() 0627 } 0628 else 0629 { 0630 control.goBack() 0631 } 0632 event.accepted = true 0633 } 0634 0635 // Shortcut for clearing selection and filtering 0636 if(event.key === Qt.Key_Escape) //TODO not working, the event is not catched or emitted or is being accepted else where? 0637 { 0638 if(control.selectionBar && control.selectionBar.count > 0) 0639 { 0640 control.selectionBar.clear() 0641 } 0642 0643 control.view.filter = "" 0644 event.accepted = true 0645 } 0646 0647 //Shortcut for opening filtering 0648 if((event.key === Qt.Key_F) && (event.modifiers & Qt.ControlModifier)) 0649 { 0650 control.toggleSearchBar() 0651 event.accepted = true 0652 } 0653 0654 control.keyPress(event) 0655 } 0656 0657 function onItemsSelected(indexes) 0658 { 0659 if(indexes.length) 0660 { 0661 control.currentIndex = indexes[0] 0662 control.selectIndexes(indexes) 0663 } 0664 } 0665 0666 function onItemClicked(index) 0667 { 0668 control.currentIndex = index 0669 indexHistory.push(index) 0670 control.itemClicked(index) 0671 control.currentView.forceActiveFocus() 0672 } 0673 0674 function onItemDoubleClicked(index) 0675 { 0676 control.currentIndex = index 0677 indexHistory.push(index) 0678 control.itemDoubleClicked(index) 0679 control.currentView.forceActiveFocus() 0680 } 0681 0682 function onItemRightClicked(index) 0683 { 0684 control.currentIndex = index 0685 control.itemRightClicked(index) 0686 control.currentView.forceActiveFocus() 0687 } 0688 0689 function onItemToggled(index) 0690 { 0691 const item = control.currentFMModel.get(index) 0692 0693 if(control.selectionBar && control.selectionBar.contains(item.path)) 0694 { 0695 control.selectionBar.removeAtUri(item.path) 0696 }else 0697 { 0698 control.addToSelection(item) 0699 } 0700 control.itemLeftEmblemClicked(index) 0701 control.currentView.forceActiveFocus() 0702 } 0703 0704 0705 function onAreaClicked(mouse) 0706 { 0707 if(control.isSearchView) 0708 return 0709 0710 if(!Maui.Handy.isMobile && mouse.button === Qt.RightButton) 0711 { 0712 control.rightClicked() 0713 } 0714 0715 control.areaClicked(mouse) 0716 control.currentView.forceActiveFocus() 0717 } 0718 } 0719 0720 Maui.ContextualMenu 0721 { 0722 id: _dropMenu 0723 property string urls 0724 enabled: !control.isSearchView 0725 0726 MenuItem 0727 { 0728 enabled: !control.readOnly 0729 text: i18nd("mauikitfilebrowsing", "Copy Here") 0730 icon.name: "edit-copy" 0731 onTriggered: 0732 { 0733 const urls = _dropMenu.urls.split(",") 0734 control.currentFMList.copyInto(urls) 0735 } 0736 } 0737 0738 MenuItem 0739 { 0740 enabled: !control.readOnly 0741 text: i18nd("mauikitfilebrowsing", "Move Here") 0742 icon.name: "edit-move" 0743 onTriggered: 0744 { 0745 const urls = _dropMenu.urls.split(",") 0746 control.currentFMList.cutInto(urls) 0747 } 0748 } 0749 0750 MenuItem 0751 { 0752 enabled: !control.readOnly 0753 0754 text: i18nd("mauikitfilebrowsing", "Link Here") 0755 icon.name: "edit-link" 0756 onTriggered: 0757 { 0758 const urls = _dropMenu.urls.split(",") 0759 for(var i in urls) 0760 control.currentFMList.createSymlink(urls[i]) 0761 } 0762 } 0763 0764 MenuItem 0765 { 0766 enabled: FB.FM.isDir(_dropMenu.urls.split(",")[0]) 0767 text: i18nd("mauikitfilebrowsing", "Open Here") 0768 icon.name: "folder-open" 0769 onTriggered: 0770 { 0771 const urls = _dropMenu.urls.split(",") 0772 control.browser.path = urls[0] 0773 } 0774 } 0775 0776 MenuSeparator {} 0777 0778 MenuItem 0779 { 0780 text: i18nd("mauikitfilebrowsing", "Cancel") 0781 icon.name: "dialog-cancel" 0782 onTriggered: _dropMenu.close() 0783 } 0784 } 0785 0786 StackView 0787 { 0788 id: _stackView 0789 anchors.fill: parent 0790 0791 initialItem: DropArea 0792 { 0793 id: _dropArea 0794 property alias browser : _browser 0795 property alias currentFMList : _browser.currentFMList 0796 property alias currentFMModel: _browser.currentFMModel 0797 property alias filter: _browser.filter 0798 property alias filters: _browser.filters 0799 property alias title : _browser.title 0800 0801 onDropped: 0802 { 0803 if(drop.urls) 0804 { 0805 _dropMenu.urls = drop.urls.join(",") 0806 _dropMenu.show() 0807 control.urlsDropped(drop.urls) 0808 } 0809 } 0810 0811 opacity: _dropArea.containsDrag ? 0.5 : 1 0812 0813 Private.BrowserView 0814 { 0815 id: _browser 0816 anchors.fill: parent 0817 selectionMode: control.selectionMode 0818 0819 Binding on currentIndex 0820 { 0821 value: control.currentIndex 0822 restoreMode: Binding.RestoreBindingOrValue 0823 } 0824 0825 Loader 0826 { 0827 active: (control.currentPath === "tags://" || control.currentPath === "tags:///") && !control.readOnly 0828 visible: active 0829 asynchronous: true 0830 0831 anchors.right: parent.right 0832 anchors.bottom: parent.bottom 0833 anchors.rightMargin: Maui.Style.toolBarHeight 0834 anchors.bottomMargin: Maui.Style.toolBarHeight + control.flickable.bottomMargin 0835 0836 sourceComponent: Maui.FloatingButton 0837 { 0838 icon.name : "list-add" 0839 onClicked: 0840 { 0841 dialogLoader.sourceComponent = _newTagDialogComponent 0842 dialog.open() 0843 } 0844 } 0845 } 0846 } 0847 } 0848 0849 Component 0850 { 0851 id: _searchBrowserComponent 0852 0853 Private.BrowserView 0854 { 0855 id: _searchBrowser 0856 property alias browser : _searchBrowser 0857 readOnly: true 0858 path: control.currentPath 0859 Binding on currentIndex 0860 { 0861 value: control.currentIndex 0862 restoreMode: Binding.RestoreBindingOrValue 0863 } 0864 0865 objectName: "searchView" 0866 gridItemSize: control.gridItemSize 0867 listItemSize: control.listItemSize 0868 0869 currentFMList.autoLoad: false 0870 settings.viewType: control.settings.viewType 0871 settings.sortBy: control.settings.sortBy 0872 settings.showHiddenFiles: control.settings.showHiddenFiles 0873 settings.group: control.settings.group 0874 settings.foldersFirst: control.settings.foldersFirst 0875 0876 } 0877 } 0878 } 0879 0880 Component.onCompleted: 0881 { 0882 control.currentView.forceActiveFocus() 0883 } 0884 0885 /** 0886 * 0887 **/ 0888 function copy(urls) 0889 { 0890 if(urls.length <= 0) 0891 { 0892 return 0893 } 0894 0895 Maui.Handy.copyToClipboard({"urls": urls}, false) 0896 } 0897 0898 /** 0899 * 0900 **/ 0901 function cut(urls) 0902 { 0903 if(control.readOnly) 0904 return 0905 0906 if(urls.length <= 0) 0907 { 0908 return 0909 } 0910 0911 Maui.Handy.copyToClipboard({"urls": urls}, true) 0912 } 0913 0914 /** 0915 * 0916 **/ 0917 function paste() 0918 { 0919 control.currentFMList.paste() 0920 } 0921 0922 /** 0923 * 0924 **/ 0925 function remove(urls) 0926 { 0927 if(urls.length <= 0) 0928 { 0929 return 0930 } 0931 0932 dialogLoader.sourceComponent = removeDialogComponent 0933 dialog.urls = urls 0934 dialog.open() 0935 } 0936 0937 /** 0938 * 0939 **/ 0940 function openItem(index) 0941 { 0942 const item = control.currentFMModel.get(index) 0943 const path = item.path 0944 0945 switch(control.currentFMList.pathType) 0946 { 0947 case FB.FMList.CLOUD_PATH: //TODO deprecrated and needs to be removed or clean up for 1.1 0948 if(item.isdir === "true") 0949 { 0950 control.openFolder(path) 0951 } 0952 else 0953 { 0954 FB.FM.openCloudItem(item) 0955 } 0956 break; 0957 default: 0958 if(control.selectionMode && item.isdir == "false") 0959 { 0960 if(control.selectionBar && control.selectionBar.contains(item.path)) 0961 { 0962 control.selectionBar.removeAtPath(item.path) 0963 }else 0964 { 0965 control.addToSelection(item) 0966 } 0967 } 0968 else 0969 { 0970 if(item.isdir == "true") 0971 { 0972 control.openFolder(path) 0973 } 0974 else 0975 { 0976 control.openFile(path) 0977 } 0978 } 0979 } 0980 } 0981 0982 /** 0983 * 0984 **/ 0985 function openFile(path) 0986 { 0987 FB.FM.openUrl(path) 0988 } 0989 0990 /** 0991 * 0992 **/ 0993 function openFolder(path) 0994 { 0995 if(!String(path).length) 0996 { 0997 return; 0998 } 0999 1000 if(control.isSearchView) 1001 { 1002 control.quitSearch() 1003 } 1004 1005 control.currentPath = path 1006 _browser.forceActiveFocus() 1007 } 1008 1009 /** 1010 * 1011 **/ 1012 function goBack() 1013 { 1014 openFolder(control.currentFMList.previousPath()) 1015 // control.currentIndex = indexHistory.pop() 1016 } 1017 1018 /** 1019 * 1020 **/ 1021 function goForward() 1022 { 1023 openFolder(control.currentFMList.posteriorPath()) 1024 } 1025 1026 /** 1027 * 1028 **/ 1029 function goUp() 1030 { 1031 openFolder(control.currentFMList.parentPath) 1032 } 1033 1034 /** 1035 * For this to work the implementation needs to have passed a selectionBar 1036 **/ 1037 function addToSelection(item) 1038 { 1039 if(control.selectionBar == null || item.path.startsWith("tags://") || item.path.startsWith("applications://")) 1040 { 1041 return 1042 } 1043 1044 control.selectionBar.append(item.path, item) 1045 } 1046 1047 1048 /** 1049 * Given a list of indexes add them to the selectionBar 1050 **/ 1051 function selectIndexes(indexes) 1052 { 1053 if(control.selectionBar == null) 1054 { 1055 return 1056 } 1057 1058 for(var i in indexes) 1059 addToSelection(control.currentFMModel.get(indexes[i])) 1060 } 1061 1062 /** 1063 * 1064 **/ 1065 function selectAll() //TODO for now dont select more than 100 items so things dont freeze or break 1066 { 1067 if(control.selectionBar == null) 1068 { 1069 return 1070 } 1071 1072 selectIndexes([...Array( control.currentFMList.count ).keys()]) 1073 } 1074 1075 /** 1076 * 1077 **/ 1078 function bookmarkFolder(paths) //multiple paths 1079 { 1080 for(var i in paths) 1081 { 1082 FB.FM.bookmark(paths[i]) 1083 } 1084 } 1085 1086 function toggleSearchBar() //only opens the searchbar toolbar, not the search view page 1087 { 1088 if(control.settings.searchBarVisible) 1089 { 1090 control.settings.searchBarVisible = false 1091 quitSearch() 1092 _browser.forceActiveFocus() 1093 }else 1094 { 1095 control.settings.searchBarVisible = true 1096 _searchField.forceActiveFocus() 1097 } 1098 } 1099 1100 /** 1101 * 1102 **/ 1103 function openSearch() //opens the search view and focuses the search field 1104 { 1105 if(!control.isSearchView) 1106 { 1107 _stackView.push(_searchBrowserComponent) 1108 } 1109 control.settings.searchBarVisible = true 1110 _searchField.forceActiveFocus() 1111 } 1112 1113 /** 1114 * 1115 **/ 1116 function quitSearch() 1117 { 1118 if(control.currentView.loading) 1119 { 1120 _quitSearchDialog.open() 1121 return 1122 } 1123 1124 _stackView.pop() 1125 _browser.forceActiveFocus() 1126 } 1127 1128 /** 1129 * 1130 **/ 1131 function search(query) 1132 { 1133 openSearch() 1134 _searchField.text = query 1135 1136 _stackView.currentItem.title = i18nd("mauikitfilebrowsing", "Search: %1", query) 1137 _stackView.currentItem.currentFMList.search(query, true) 1138 1139 _stackView.currentItem.forceActiveFocus() 1140 } 1141 1142 /** 1143 * 1144 **/ 1145 function newItem() 1146 { 1147 if(control.isSearchView) 1148 return; 1149 1150 dialogLoader.sourceComponent = newDialogComponent 1151 dialog.open() 1152 dialog.forceActiveFocus() 1153 } 1154 1155 /** 1156 * 1157 **/ 1158 function renameItem() 1159 { 1160 if(control.isSearchView) 1161 return; 1162 1163 dialogLoader.sourceComponent= renameDialogComponent 1164 dialog.open() 1165 dialog.forceActiveFocus() 1166 } 1167 1168 /** 1169 * 1170 **/ 1171 function removeItem() 1172 { 1173 if(control.isSearchView) 1174 return; 1175 1176 dialogLoader.sourceComponent= renameDialogComponent 1177 dialog.open() 1178 dialog.forceActiveFocus() 1179 } 1180 1181 /** 1182 * Filters the content of the selection to the current path. The currentPath must be a directory, so the selection can be compared if it is its parent directory. The itemPath is a default item path in case the selectionBar is empty 1183 **/ 1184 function filterSelection(currentPath, itemPath) 1185 { 1186 var res = [] 1187 1188 if(selectionBar && selectionBar.count > 0 && selectionBar.contains(itemPath)) 1189 { 1190 const uris = selectionBar.uris 1191 for(var uri of uris) 1192 { 1193 if(String(FB.FM.parentDir(uri)) === currentPath) 1194 { 1195 res.push(uri) 1196 } 1197 } 1198 1199 } else 1200 { 1201 res = [itemPath] 1202 } 1203 1204 return res 1205 } 1206 1207 function forceActiveFocus() 1208 { 1209 control.currentView.forceActiveFocus() 1210 } 1211 }