qml: Create PlaylistMediaDisplay
[vlc.git] / modules / gui / qt / medialibrary / qml / PlaylistMediaDisplay.qml
blobd982c633f6a9189e1298b9f11c0bb377680cddcd
1 /*****************************************************************************
2  * Copyright (C) 2021 VLC authors and VideoLAN
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * ( at your option ) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17  *****************************************************************************/
19 import QtQuick          2.11
20 import QtQuick.Controls 2.4
21 import QtQuick.Layouts  1.3
22 import QtQml.Models     2.2
24 import org.videolan.medialib 0.1
26 import "qrc:///widgets/" as Widgets
27 import "qrc:///main/"    as MainInterface
28 import "qrc:///util/"    as Util
29 import "qrc:///style/"
31 Widgets.NavigableFocusScope {
32     id: root
34     //---------------------------------------------------------------------------------------------
35     // Properties
36     //---------------------------------------------------------------------------------------------
38     readonly property bool isViewMultiView: false
40     readonly property int currentIndex: currentItem.currentIndex
42     property int     initialIndex: 0
43     property variant initialId
44     property string  initialName
46     // NOTE: Specify an optionnal header for the view.
47     property Component header: undefined
49     property Item headerItem: (currentItem) ? currentItem.headerItem : undefined
51     //---------------------------------------------------------------------------------------------
52     // Aliases
53     //---------------------------------------------------------------------------------------------
55     // NOTE: This is used to determine which media(s) shall be displayed.
56     property alias parentId: model.parentId
58     // NOTE: The name of the playlist.
59     property alias name: label.text
61     property alias model: model
63     property alias currentItem: view
65     //---------------------------------------------------------------------------------------------
67     property alias dragItem: dragItem
69     //---------------------------------------------------------------------------------------------
70     // Settings
71     //---------------------------------------------------------------------------------------------
73     navigationCancel: function() {
74         if (currentItem.currentIndex <= 0) {
75             defaultNavigationCancel()
76         } else {
77             currentItem.currentIndex = 0;
79             currentItem.positionViewAtIndex(0, ItemView.Contain);
80         }
81     }
83     //---------------------------------------------------------------------------------------------
84     // Events
85     //---------------------------------------------------------------------------------------------
87     onModelChanged: resetFocus()
89     onInitialIndexChanged: resetFocus()
91     //---------------------------------------------------------------------------------------------
92     // Functions
93     //---------------------------------------------------------------------------------------------
95     function setCurrentItemFocus() { view.currentItem.forceActiveFocus() }
97     function resetFocus() {
98         if (model.count === 0) return
100         var initialIndex = root.initialIndex
102         if (initialIndex >= model.count)
103             initialIndex = 0
105         modelSelect.select(model.index(initialIndex, 0), ItemSelectionModel.ClearAndSelect);
107         if (currentItem)
108             currentItem.positionViewAtIndex(initialIndex, ItemView.Contain);
109     }
111     //---------------------------------------------------------------------------------------------
112     // Private
114     function _actionAtIndex(index) {
115         g_mainDisplay.showPlayer();
117         medialib.addAndPlay(model.getIdsForIndexes(modelSelect.selectedIndexes));
118     }
120     //---------------------------------------------------------------------------------------------
121     // Childs
122     //---------------------------------------------------------------------------------------------
124     MLPlaylistModel {
125         id: model
127         ml: medialib
129         parentId: initialId
131         onCountChanged: {
132             if (count === 0 || modelSelect.hasSelection) return;
134             resetFocus();
135         }
136     }
138     Widgets.SubtitleLabel {
139         id: label
141         anchors.top: parent.top
143         anchors.topMargin: VLCStyle.margin_normal
145         width: root.width
147         leftPadding  : VLCStyle.margin_xlarge
148         bottomPadding: VLCStyle.margin_xsmall
150         text: initialName
151     }
153     Widgets.DragItem {
154         id: dragItem
156         function updateComponents(maxCovers) {
157             var items = modelSelect.selectedIndexes.slice(0, maxCovers).map(function (x){
158                 return model.getDataAt(x.row);
159             })
161             var covers = items.map(function (item) {
162                 return { artwork: item.thumbnail || VLCStyle.noArtCover }
163             });
165             var title = items.map(function (item) {
166                 return item.title
167             }).join(", ");
169             return {
170                 covers: covers,
171                 title: title,
172                 count: modelSelect.selectedIndexes.length
173             }
174         }
176         function insertIntoPlaylist(index) {
177             medialib.insertIntoPlaylist(index,
178                                         model.getIdsForIndexes(modelSelect.selectedIndexes));
179         }
180     }
182     Util.SelectableDelegateModel {
183         id: modelSelect
185         model: root.model
186     }
188     PlaylistMediaContextMenu {
189         id: contextMenu
191         model: root.model
192     }
194     PlaylistMedia
195     {
196         id: view
198         //-------------------------------------------------------------------------------------
199         // Settings
201         anchors.left  : parent.left
202         anchors.right : parent.right
203         anchors.top   : label.bottom
204         anchors.bottom: parent.bottom
206         clip: true
208         focus: (model.count !== 0)
210         model: root.model
212         selectionDelegateModel: modelSelect
214         dragItem: root.dragItem
216         header: root.header
218         headerTopPadding: VLCStyle.margin_normal
220         headerPositioning: ListView.InlineHeader
222         navigationParent: root
223         navigationUpItem: (headerItem) ? headerItem.focus : undefined
225         //-------------------------------------------------------------------------------------
226         // Events
228         onContextMenuButtonClicked: contextMenu.popup(modelSelect.selectedIndexes,
229                                                       menuParent.mapToGlobal(0,0))
231         onRightClick: contextMenu.popup(modelSelect.selectedIndexes, globalMousePos)
232     }
234     EmptyLabel {
235         anchors.fill: parent
237         visible: (model.count === 0)
239         focus: visible
241         text: i18n.qtr("No media found")
243         cover: VLCStyle.noArtAlbumCover
245         navigationParent: root
246     }