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 }