You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

404 lines
13 KiB

/*****************************************************************************
* Copyright (C) 2019 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* ( at your option ) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
import QtQuick 2.12
import QtQuick.Layouts 1.12
import org.videolan.vlc 0.1
import "qrc:///util/" as Util
import "qrc:///util/Helpers.js" as Helpers
import "qrc:///widgets/" as Widgets
import "qrc:///main/" as MainInterface
import "qrc:///style/"
MainInterface.MainViewLoader {
id: root
// Properties
property var providerModel
property var contextMenu
property var tree
readonly property var currentIndex: _currentView.currentIndex
readonly property bool isViewMultiView: true
// 'loading' property is not available with NetworkDevicesModel
readonly property bool loading: Helpers.get(providerModel, "loading", false)
property var sortModel: [
{ text: I18n.qtr("Alphabetic"), criteria: "name"},
{ text: I18n.qtr("Url"), criteria: "mrl" },
{ text: I18n.qtr("File size"), criteria: "fileSizeRaw64" },
{ text: I18n.qtr("File modified"), criteria: "fileModified" }
]
// fixme remove this
property Item _currentView: currentItem
signal browse(var tree, int reason)
Navigation.cancelAction: function() {
History.previous()
}
model: SortFilterProxyModel {
id: filterModel
sourceModel: providerModel
searchRole: "name"
}
// override the default currentComponent assignment from MainViewLoader
// because we need to show empty label when model is parsing
currentComponent: {
if (filterModel.count == 0 || root.loading)
return emptyLabelComponent
else if (MainCtx.gridView)
return gridComponent
else
return tableComponent
}
onTreeChanged: providerModel.tree = tree
function playSelected() {
providerModel.addAndPlay(filterModel.mapIndexesToSource(selectionModel.selectedIndexes))
}
function playAt(index) {
providerModel.addAndPlay(filterModel.mapIndexToSource(index))
}
function _actionAtIndex(index) {
if ( selectionModel.selectedIndexes.length > 1 ) {
playSelected()
} else {
const data = filterModel.getDataAt(index)
if (data.type === NetworkMediaModel.TYPE_DIRECTORY
|| data.type === NetworkMediaModel.TYPE_NODE) {
browse(data.tree, Qt.TabFocusReason)
} else {
playAt(index)
}
}
}
Widgets.DragItem {
id: networkDragItem
indexes: selectionModel.selectedIndexes
titleRole: "name"
defaultText: I18n.qtr("Unknown Share")
coverProvider: function(index, data) {
// this is used to provide context to NetworkCustomCover
// indexData is networkModel (model data) for this index
// cover is our custom cover that will be loaded insted of default DragItem cover
return {"indexData": data, "cover": custom_cover}
}
onRequestData: {
setData(identifier, selectionModel.selectedIndexes.map(function (x){
return filterModel.getDataAt(x.row)
}))
}
function getSelectedInputItem(cb) {
//directly call the callback
cb(providerModel.getItemsForIndexes(filterModel.mapIndexesToSource(selectionModel.selectedIndexes)))
}
Component {
id: custom_cover
NetworkCustomCover {
networkModel: model.indexData
width: networkDragItem.coverSize
height: networkDragItem.coverSize
// we can not change the size of cover and shodows from here,
// so for best visual use scale image to fit
fillMode: Image.PreserveAspectCrop
bgColor: networkDragItem.colorContext.bg.secondary
color1: networkDragItem.colorContext.fg.primary
accent: networkDragItem.colorContext.accent
}
}
}
Component{
id: gridComponent
MainInterface.MainGridView {
id: gridView
selectionDelegateModel: selectionModel
model: filterModel
headerDelegate: BrowseTreeHeader {
providerModel: root.providerModel
// align header content with grid content
leftPadding: gridView.rowX
width: gridView.width
Navigation.parentItem: root
Navigation.downAction: function () {
focus = false
gridView.forceActiveFocus(Qt.TabFocusReason)
}
}
cellWidth: VLCStyle.gridItem_network_width
cellHeight: VLCStyle.gridCover_network_height + VLCStyle.margin_xsmall + VLCStyle.fontHeight_normal
delegate: NetworkGridItem {
id: delegateGrid
subtitle: ""
height: VLCStyle.gridCover_network_height + VLCStyle.margin_xsmall + VLCStyle.fontHeight_normal
dragItem: networkDragItem
onPlayClicked: playAt(index)
onItemClicked : gridView.leftClickOnItem(modifier, index)
onItemDoubleClicked: {
if (model.type === NetworkMediaModel.TYPE_NODE || model.type === NetworkMediaModel.TYPE_DIRECTORY)
browse(model.tree, Qt.MouseFocusReason)
else
playAt(index)
}
onContextMenuButtonClicked: {
gridView.rightClickOnItem(index)
contextMenu.popup(filterModel.mapIndexesToSource(selectionModel.selectedIndexes), globalMousePos)
}
}
onActionAtIndex: _actionAtIndex(index)
Navigation.parentItem: root
Navigation.upItem: gridView.headerItem
}
}
Component{
id: tableComponent
MainInterface.MainTableView {
id: tableView
readonly property int _nbCols: VLCStyle.gridColumnsForWidth(tableView.availableRowWidth)
readonly property int _nameColSpan: Math.max((_nbCols - 1) / 2, 1)
property Component thumbnailHeader: Widgets.IconLabel {
height: VLCStyle.listAlbumCover_height
width: VLCStyle.listAlbumCover_width
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: VLCStyle.icon_tableHeader
text: VLCIcons.album_cover
color: tableView.colorContext.fg.secondary
}
property Component thumbnailColumn: NetworkThumbnailItem {
onPlayClicked: playAt(index)
}
property var _modelSmall: [{
size: Math.max(2, _nbCols),
model: ({
criteria: "name",
title: "name",
subCriterias: [ "mrl" ],
text: I18n.qtr("Name"),
headerDelegate: thumbnailHeader,
colDelegate: thumbnailColumn
})
}]
property var _modelMedium: [{
size: 1,
model: {
criteria: "thumbnail",
text: I18n.qtr("Cover"),
headerDelegate: thumbnailHeader,
colDelegate: thumbnailColumn
}
}, {
size: tableView._nameColSpan,
model: {
criteria: "name",
text: I18n.qtr("Name")
}
}, {
size: Math.max(_nbCols - _nameColSpan - 1, 1),
model: {
criteria: "mrl",
text: I18n.qtr("Url"),
showContextButton: true
}
}]
dragItem: networkDragItem
model: filterModel
sortModel: (availableRowWidth < VLCStyle.colWidth(4)) ? _modelSmall
: _modelMedium
selectionDelegateModel: selectionModel
focus: true
Navigation.parentItem: root
Navigation.upItem: tableView.headerItem
rowHeight: VLCStyle.tableCoverRow_height
header: BrowseTreeHeader {
providerModel: root.providerModel
width: tableView.width
Navigation.parentItem: root
Navigation.downAction: function () {
focus = false
tableView.forceActiveFocus(Qt.TabFocusReason)
}
}
onActionForSelection: _actionAtIndex(selection[0].row)
onItemDoubleClicked: _actionAtIndex(index)
onContextMenuButtonClicked: contextMenu.popup(filterModel.mapIndexesToSource(selectionModel.selectedIndexes), globalMousePos)
onRightClick: contextMenu.popup(filterModel.mapIndexesToSource(selectionModel.selectedIndexes), globalMousePos)
}
}
Component {
id: emptyLabelComponent
FocusScope {
id: focusScope
Navigation.navigable: layout.Navigation.navigable || (emptyLabel.visible && emptyLabel.button.enabled)
// used by MainDisplay to transfer focus
function setCurrentItemFocus(reason) {
if (!focusScope.Navigation.navigable)
return
if (header.Navigation.navigable)
header.forceActiveFocus(reason)
else
emptyLabel.forceActiveFocus(reason)
}
ColumnLayout {
id: layout
anchors.fill: parent
BrowseTreeHeader {
id: header
focus: true
providerModel: root.providerModel
Layout.fillWidth: true
Navigation.parentItem: root
Navigation.downItem: emptyLabel
}
Widgets.EmptyLabelButton {
id: emptyLabel
visible: !root.loading
// FIXME: find better cover
cover: VLCStyle.noArtVideoCover
coverWidth : VLCStyle.dp(182, VLCStyle.scale)
coverHeight: VLCStyle.dp(114, VLCStyle.scale)
text: I18n.qtr("Nothing to see here, go back.")
button.iconTxt: VLCIcons.back
button.text: I18n.qtr("Back")
button.enabled: !History.previousEmpty
button.width: button.implicitWidth
function onNavigate() {
History.previous()
}
Layout.fillHeight: true
Layout.fillWidth: true
Navigation.parentItem: root
Navigation.upAction: function () {
// FIXME: for some reason default navigation flow doesn't work
// i.e setting Navigtaion.upItem doesn't fallthrough to parent's
// action if Navigtaion.upItem.Navigtaion.navigble is false
if (header.Navigation.navigable)
header.forceActiveFocus(Qt.TabFocusReason)
else
return false // fallthrough default action
}
}
Item {
visible: root.loading
Layout.fillHeight: true
Layout.fillWidth: true
Widgets.BusyIndicatorExt {
id: busyIndicator
runningDelayed: root.loading
anchors.centerIn: parent
z: 1
}
}
}
}
}
}