qml: use a native implementation for medialibrary contextual menu

This commit is contained in:
Pierre Lamot 2020-09-14 10:22:55 +02:00
parent eeaeb09b78
commit a9b7437699
11 changed files with 300 additions and 201 deletions

View File

@ -173,6 +173,12 @@ void MainUI::registerQMLTypes()
registerAnonymousType<MLAlbumTrack>("org.videolan.medialib", 1);
registerAnonymousType<MLGenre>("org.videolan.medialib", 1);
registerAnonymousType<MLVideo>("org.videolan.medialib", 1);
qmlRegisterType<AlbumContextMenu>( "org.videolan.medialib", 0, 1, "AlbumContextMenu" );
qmlRegisterType<ArtistContextMenu>( "org.videolan.medialib", 0, 1, "ArtistContextMenu" );
qmlRegisterType<GenreContextMenu>( "org.videolan.medialib", 0, 1, "GenreContextMenu" );
qmlRegisterType<AlbumTrackContextMenu>( "org.videolan.medialib", 0, 1, "AlbumTrackContextMenu" );
qmlRegisterType<VideoContextMenu>( "org.videolan.medialib", 0, 1, "VideoContextMenu" );
}
qmlRegisterUncreatableType<NavigationHistory>("org.videolan.vlc", 0, 1, "History", "Type of global variable history" );

View File

@ -96,6 +96,11 @@ Widgets.NavigableFocusScope {
model: albumModelId
}
AlbumContextMenu {
id: contextMenu
model: albumModelId
}
Component {
id: gridComponent
@ -127,6 +132,12 @@ Widgets.NavigableFocusScope {
if ( model.id !== undefined ) { medialib.addAndPlay( model.id ) }
}
onContextMenuButtonClicked: {
contextMenu.popup(selectionModel.selectedIndexes, globalMousePos, {
"information": index
})
}
Behavior on opacity {
NumberAnimation {
duration: 100
@ -155,30 +166,12 @@ Widgets.NavigableFocusScope {
onSelectionUpdated: selectionModel.updateSelection( keyModifiers, oldIndex, newIndex )
navigationParent: root
}
}
Widgets.MenuExt {
id: contextMenu
property var model: ({})
closePolicy: Popup.CloseOnReleaseOutside | Popup.CloseOnEscape
Widgets.MenuItemExt {
id: playMenuItem
text: "Play from start"
onTriggered: {
medialib.addAndPlay( contextMenu.model.id )
history.push(["player"])
Connections {
target: contextMenu
onShowMediaInformation: gridView_id.switchExpandItem( index )
}
}
Widgets.MenuItemExt {
text: "Enqueue"
onTriggered: medialib.addToPlaylist( contextMenu.model.id )
}
onClosed: contextMenu.parent.forceActiveFocus()
}
Component {
@ -210,10 +203,8 @@ Widgets.NavigableFocusScope {
tableView_id.currentIndex = 0;
}
onContextMenuButtonClicked: {
contextMenu.model = menuModel
contextMenu.popup(menuParent)
}
onContextMenuButtonClicked: contextMenu.popup(selectionModel.selectedIndexes, menuParent.mapToGlobal(0,0))
onRightClick: contextMenu.popup(selectionModel.selectedIndexes, globalMousePos)
Widgets.TableColumns {
id: tableColumns

View File

@ -224,6 +224,16 @@ Widgets.NavigableFocusScope {
}
}
AlbumContextMenu {
id: contextMenu
model: albumModel
}
AlbumTrackContextMenu {
id: trackContextMenu
model: trackModel
}
Component {
id: gridComponent
@ -253,6 +263,8 @@ Widgets.NavigableFocusScope {
if ( model.id !== undefined ) { medialib.addAndPlay( model.id ) }
}
onContextMenuButtonClicked: contextMenu.popup(albumSelectionModel.selectedIndexes, globalMousePos, { "information" : index})
Behavior on opacity {
NumberAnimation {
duration: 100
@ -281,30 +293,13 @@ Widgets.NavigableFocusScope {
onSelectAll: albumSelectionModel.selectAll()
onSelectionUpdated: albumSelectionModel.updateSelection( keyModifiers, oldIndex, newIndex )
navigationParent: root
}
}
Widgets.MenuExt {
id: contextMenu
property var model: ({})
closePolicy: Popup.CloseOnReleaseOutside | Popup.CloseOnEscape
Widgets.MenuItemExt {
id: playMenuItem
text: i18n.qtr("Play from start")
onTriggered: {
medialib.addAndPlay( contextMenu.model.id )
history.push(["player"])
Connections {
target: contextMenu
onShowMediaInformation: gridView_id.switchExpandItem( index )
}
}
Widgets.MenuItemExt {
text: i18n.qtr("Enqueue")
onTriggered: medialib.addToPlaylist( contextMenu.model.id )
}
onClosed: contextMenu.parent.forceActiveFocus()
}
Component {
@ -338,10 +333,8 @@ Widgets.NavigableFocusScope {
tableView_id.currentIndex = 0;
}
onContextMenuButtonClicked: {
contextMenu.model = menuModel
contextMenu.popup(menuParent)
}
onContextMenuButtonClicked: trackContextMenu.popup(trackSelectionModel.selectedIndexes, menuParent.mapToGlobal(0,0))
onRightClick: trackContextMenu.popup(trackSelectionModel.selectedIndexes, globalMousePos)
Widgets.TableColumns {
id: tableColumns

View File

@ -124,27 +124,9 @@ Widgets.NavigableFocusScope {
model: artistModel
}
Widgets.MenuExt {
ArtistContextMenu {
id: contextMenu
property var model: ({})
closePolicy: Popup.CloseOnReleaseOutside | Popup.CloseOnEscape
Widgets.MenuItemExt {
id: playMenuItem
text: i18n.qtr("Play")
onTriggered: {
medialib.addAndPlay( contextMenu.model.id )
history.push(["player"])
}
}
Widgets.MenuItemExt {
text: "Enqueue"
onTriggered: medialib.addToPlaylist( contextMenu.model.id )
}
onClosed: contextMenu.parent.forceActiveFocus()
model: artistModel
}
Component {
@ -195,6 +177,8 @@ Widgets.NavigableFocusScope {
}
onItemDoubleClicked: artistAllView.showAlbumView(model)
onContextMenuButtonClicked: contextMenu.popup(selectionModel.selectedIndexes, globalMousePos)
}
}
}
@ -233,11 +217,8 @@ Widgets.NavigableFocusScope {
onItemDoubleClicked: {
artistAllView.showAlbumView(model)
}
onContextMenuButtonClicked: {
contextMenu.model = menuModel
contextMenu.popup(menuParent)
}
onContextMenuButtonClicked: contextMenu.popup(selectionModel.selectedIndexes, menuParent.mapToGlobal(0,0))
onRightClick: contextMenu.popup(selectionModel.selectedIndexes, globalMousePos)
Widgets.TableColumns {
id: tableColumns

View File

@ -87,27 +87,6 @@ Widgets.NavigableFocusScope {
}
}
Widgets.MenuExt {
id: contextMenu
property var model: ({})
closePolicy: Popup.CloseOnReleaseOutside | Popup.CloseOnEscape
onClosed: contextMenu.parent.forceActiveFocus()
Widgets.MenuItemExt {
id: playMenuItem
text: "Play from start"
onTriggered: {
medialib.addAndPlay( contextMenu.model.id )
history.push(["player"])
}
}
Widgets.MenuItemExt {
text: "Enqueue"
onTriggered: medialib.addToPlaylist( contextMenu.model.id )
}
}
function _actionAtIndex(index) {
if (selectionModel.selectedIndexes.length > 1) {
medialib.addAndPlay(model.getIdsForIndexes(selectionModel.selectedIndexes))
@ -138,6 +117,11 @@ Widgets.NavigableFocusScope {
}
}
GenreContextMenu {
id: contextMenu
model: genreModel
}
/* Grid View */
Component {
id: gridComponent
@ -172,6 +156,10 @@ Widgets.NavigableFocusScope {
medialib.addAndPlay(model.id)
}
onContextMenuButtonClicked: {
contextMenu.popup(selectionModel.selectedIndexes, globalMousePos)
}
Column {
anchors.centerIn: parent
opacity: item._highlighted ? .3 : 1
@ -262,10 +250,8 @@ Widgets.NavigableFocusScope {
root.showAlbumView(model)
}
onContextMenuButtonClicked: {
contextMenu.model = menuModel
contextMenu.popup(menuParent)
}
onContextMenuButtonClicked: contextMenu.popup(selectionModel.selectedIndexes, menuParent.mapToGlobal(0,0))
onRightClick: contextMenu.popup(selectionModel.selectedIndexes, globalMousePos)
}
}

View File

@ -66,6 +66,10 @@ Widgets.KeyNavigableTableView {
onActionForSelection: medialib.addAndPlay(model.getIdsForIndexes( selection ))
onContextMenuButtonClicked: contextMenu.popup(selectionModel.selectedIndexes, menuParent.mapToGlobal(0,0))
onRightClick: contextMenu.popup(selectionModel.selectedIndexes, globalMousePos)
Widgets.TableColumns {
id: tableColumns
}
@ -91,4 +95,9 @@ Widgets.KeyNavigableTableView {
model: rootmodel
}
AlbumTrackContextMenu {
id: contextMenu
model: rootmodel
}
}

View File

@ -27,29 +27,6 @@ Widgets.NavigableFocusScope {
property alias sortModel: tracklistdisplay_id.sortModel
property alias model: tracklistdisplay_id.model
Widgets.MenuExt {
id: contextMenu
property var model: ({})
closePolicy: Popup.CloseOnReleaseOutside | Popup.CloseOnEscape
Widgets.MenuItemExt {
id: playMenuItem
text: "Play from start"
onTriggered: {
medialib.addAndPlay( contextMenu.model.id )
history.push(["player"])
}
}
Widgets.MenuItemExt {
text: "Enqueue"
onTriggered: medialib.addToPlaylist( contextMenu.model.id )
}
onClosed: contextMenu.parent.forceActiveFocus()
}
MusicTrackListDisplay {
id: tracklistdisplay_id
anchors.fill: parent
@ -62,11 +39,6 @@ Widgets.NavigableFocusScope {
else
tracklistdisplay_id.currentIndex = 0;
}
onContextMenuButtonClicked: {
contextMenu.model = menuModel
contextMenu.popup(menuParent)
}
}
EmptyLabel {

View File

@ -67,58 +67,6 @@ Widgets.NavigableFocusScope {
history.push(["player"])
}
Widgets.MenuExt {
id: contextMenu
property var model: ({})
property int itemIndex: -1
closePolicy: Popup.CloseOnReleaseOutside | Popup.CloseOnEscape
Widgets.MenuItemExt {
id: playMenuItem
text: "Play from start"
onTriggered: {
medialib.addAndPlay( contextMenu.model.id )
history.push(["player"])
}
}
Widgets.MenuItemExt {
text: "Play all"
onTriggered: console.log("not implemented")
}
Widgets.MenuItemExt {
text: "Play as audio"
onTriggered: console.log("not implemented")
}
Widgets.MenuItemExt {
text: "Enqueue"
onTriggered: medialib.addToPlaylist( contextMenu.model.id )
}
Widgets.MenuItemExt {
enabled: mainInterface.gridView
text: "Information"
onTriggered: {
view.currentItem.switchExpandItem(contextMenu.itemIndex)
}
}
Widgets.MenuItemExt {
text: "Download subtitles"
onTriggered: console.log("not implemented")
}
Widgets.MenuItemExt {
text: "Add to playlist"
onTriggered: console.log("not implemented")
}
Widgets.MenuItemExt {
text: "Delete"
onTriggered: g_dialogs.ask(i18n.qtr("Are you sure you want to delete?"), function() {
console.log("unimplemented")
})
}
onClosed: contextMenu.parent.forceActiveFocus()
}
MLVideoModel {
id: videoModel
ml: medialib
@ -135,6 +83,12 @@ Widgets.NavigableFocusScope {
model: videoModel
}
VideoContextMenu {
id: contextMenu
model: videoModel
}
Component {
id: gridComponent
@ -159,11 +113,9 @@ Widgets.NavigableFocusScope {
opacity: videosGV.expandIndex !== -1 && videosGV.expandIndex !== videoGridItem.index ? .7 : 1
onContextMenuButtonClicked: {
contextMenu.model = videoGridItem.model
contextMenu.itemIndex = index
contextMenu.popup()
}
onContextMenuButtonClicked: contextMenu.popup(selectionModel.selectedIndexes, globalMousePos, {
"information" : index
} )
onItemClicked : {
selectionModel.updateSelection( modifier , videosGV.currentIndex, index)
@ -206,6 +158,11 @@ Widgets.NavigableFocusScope {
onSelectAll:selectionModel.selectAll()
onSelectionUpdated: selectionModel.updateSelection( keyModifiers, oldIndex, newIndex )
onActionAtIndex: _actionAtIndex( index )
Connections {
target: contextMenu
onShowMediaInformation: videosGV.switchExpandItem(index)
}
}
}
@ -217,17 +174,14 @@ Widgets.NavigableFocusScope {
height: view.height
width: view.width
model: videoModel
onContextMenuButtonClicked:{
contextMenu.model = menuModel
contextMenu.popup(menuParent)
}
onRightClick:{
contextMenu.model = menuModel
contextMenu.popup()
}
navigationParent: root
selectionDelegateModel: selectionModel
onContextMenuButtonClicked: contextMenu.popup(selectionModel.selectedIndexes, menuParent.mapToGlobal(0,0) )
onRightClick: contextMenu.popup(selectionModel.selectedIndexes, globalMousePos )
}
}

View File

@ -28,13 +28,6 @@ import "qrc:///style/"
Widgets.KeyNavigableTableView {
id: listView_id
model: MLVideoModel {
ml: medialib
}
selectionDelegateModel: Util.SelectableDelegateModel {
model: listView_id.model
}
property Component thumbnailHeader: Item {
Widgets.IconLabel {
height: VLCStyle.listAlbumCover_height

View File

@ -18,6 +18,12 @@
#include "qml_menu_wrapper.hpp"
#include "menus.hpp"
#include "util/qml_main_context.hpp"
#include "medialibrary/medialib.hpp"
#include "medialibrary/mlvideomodel.hpp"
#include "medialibrary/mlalbummodel.hpp"
#include "medialibrary/mlartistmodel.hpp"
#include "medialibrary/mlgenremodel.hpp"
#include "medialibrary/mlalbumtrackmodel.hpp"
#include <QSignalMapper>
@ -75,3 +81,128 @@ void QmlGlobalMenu::popup(QPoint pos)
menu->popup(pos);
}
BaseMedialibMenu::BaseMedialibMenu(QObject* parent)
: QObject(parent)
{}
void BaseMedialibMenu::medialibAudioContextMenu(MediaLib* ml, const QVariantList& mlId, const QPoint& pos, const QVariantMap& options)
{
QMenu* menu = new QMenu();
QAction* action;
menu->setAttribute(Qt::WA_DeleteOnClose);
action = menu->addAction( qtr("Add and play") );
connect(action, &QAction::triggered, [ml, mlId]( ) {
ml->addAndPlay(mlId);
});
action = menu->addAction( qtr("Enqueue") );
connect(action, &QAction::triggered, [ml, mlId]( ) {
ml->addToPlaylist(mlId);
});
if (options.contains("information") && options["information"].type() == QVariant::Int) {
action = menu->addAction( qtr("Information") );
QSignalMapper* sigmapper = new QSignalMapper(menu);
connect(action, &QAction::triggered, sigmapper, QOverload<>::of(&QSignalMapper::map));
sigmapper->setMapping(action, options["information"].toInt());
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
connect(sigmapper, &QSignalMapper::mappedInt, this, &BaseMedialibMenu ::showMediaInformation);
#else
connect(sigmapper, QOverload<int>::of(&QSignalMapper::mapped), this, &BaseMedialibMenu::showMediaInformation);
#endif
}
menu->popup(pos);
}
AlbumContextMenu::AlbumContextMenu(QObject* parent)
: BaseMedialibMenu(parent)
{}
void AlbumContextMenu::popup(const QModelIndexList& selected, QPoint pos, QVariantMap options)
{
BaseMedialibMenu::popup(m_model, MLAlbumModel::ALBUM_ID, selected, pos, options);
}
ArtistContextMenu::ArtistContextMenu(QObject* parent)
: BaseMedialibMenu(parent)
{}
void ArtistContextMenu::popup(const QModelIndexList &selected, QPoint pos, QVariantMap options)
{
BaseMedialibMenu::popup(m_model, MLArtistModel::ARTIST_ID, selected, pos, options);
}
GenreContextMenu::GenreContextMenu(QObject* parent)
: BaseMedialibMenu(parent)
{}
void GenreContextMenu::popup(const QModelIndexList& selected, QPoint pos, QVariantMap options)
{
BaseMedialibMenu::popup(m_model, MLGenreModel::GENRE_ID, selected, pos, options);
}
AlbumTrackContextMenu::AlbumTrackContextMenu(QObject* parent)
: BaseMedialibMenu(parent)
{}
void AlbumTrackContextMenu::popup(const QModelIndexList &selected, QPoint pos, QVariantMap options)
{
BaseMedialibMenu::popup(m_model, MLAlbumTrackModel::TRACK_ID, selected, pos, options);
}
VideoContextMenu::VideoContextMenu(QObject* parent)
: QObject(parent)
{}
void VideoContextMenu::popup(const QModelIndexList& selected, QPoint pos, QVariantMap options)
{
if (!m_model)
return;
QMenu* menu = new QMenu();
QAction* action;
menu->setAttribute(Qt::WA_DeleteOnClose);
MediaLib* ml= m_model->ml();
QVariantList itemIdList;
for (const QModelIndex& modelIndex : selected)
itemIdList.push_back(m_model->data(modelIndex, MLVideoModel::VIDEO_ID));
action = menu->addAction( qtr("Add and play") );
connect(action, &QAction::triggered, [ml, itemIdList]( ) {
ml->addAndPlay(itemIdList);
});
action = menu->addAction( qtr("Enqueue") );
connect(action, &QAction::triggered, [ml, itemIdList]( ) {
ml->addToPlaylist(itemIdList);
});
action = menu->addAction( qtr("Play as audio") );
connect(action, &QAction::triggered, [ml, itemIdList]( ) {
QStringList options({":no-video"});
ml->addAndPlay(itemIdList, &options);
});
if (options.contains("information") && options["information"].type() == QVariant::Int) {
action = menu->addAction( qtr("Information") );
QSignalMapper* sigmapper = new QSignalMapper(menu);
connect(action, &QAction::triggered, sigmapper, QOverload<>::of(&QSignalMapper::map));
sigmapper->setMapping(action, options["information"].toInt());
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
connect(sigmapper, &QSignalMapper::mappedInt, this, &VideoContextMenu::showMediaInformation);
#else
connect(sigmapper, QOverload<int>::of(&QSignalMapper::mapped), this, &VideoContextMenu::showMediaInformation);
#endif
}
menu->popup(pos);
}

View File

@ -25,6 +25,12 @@
#include "menus.hpp"
class MediaLib;
class MLAlbumModel;
class MLGenreModel;
class MLArtistModel;
class MLAlbumTrackModel;
class MLVideoModel;
class QmlMainContext;
#define SIMPLE_MENU_PROPERTY(type, name, defaultValue) \
@ -47,6 +53,83 @@ public slots:
void popup( QPoint pos );
};
class BaseMedialibMenu : public QObject
{
Q_OBJECT
public:
BaseMedialibMenu(QObject* parent = nullptr);
signals:
void showMediaInformation(int index);
protected:
void medialibAudioContextMenu(MediaLib* ml, const QVariantList& mlId, const QPoint& pos, const QVariantMap& options);
template<typename ModelType>
void popup(ModelType* model, typename ModelType::Roles role, const QModelIndexList &selected, const QPoint& pos, const QVariantMap& options) {
if (!model)
return;
MediaLib* ml= model->ml();
if (!ml)
return;
QVariantList itemIdList;
for (const QModelIndex& modelIndex : selected)
itemIdList.push_back(model->data(modelIndex, role));
medialibAudioContextMenu(ml, itemIdList, pos, options);
}
};
class AlbumContextMenu : public BaseMedialibMenu {
Q_OBJECT
SIMPLE_MENU_PROPERTY(MLAlbumModel*, model, nullptr)
public:
AlbumContextMenu(QObject* parent = nullptr);
public slots:
void popup(const QModelIndexList& selected, QPoint pos, QVariantMap options = {});
};
class ArtistContextMenu : public BaseMedialibMenu {
Q_OBJECT
SIMPLE_MENU_PROPERTY(MLArtistModel*, model, nullptr)
public:
ArtistContextMenu(QObject* parent = nullptr);
public slots:
void popup(const QModelIndexList& selected, QPoint pos, QVariantMap options = {});
};
class GenreContextMenu : public BaseMedialibMenu {
Q_OBJECT
SIMPLE_MENU_PROPERTY(MLGenreModel*, model, nullptr)
public:
GenreContextMenu(QObject* parent = nullptr);
public slots:
void popup(const QModelIndexList& selected, QPoint pos, QVariantMap options = {});
};
class AlbumTrackContextMenu : public BaseMedialibMenu {
Q_OBJECT
SIMPLE_MENU_PROPERTY(MLAlbumTrackModel*, model, nullptr)
public:
AlbumTrackContextMenu(QObject* parent = nullptr);
public slots:
void popup(const QModelIndexList& selected, QPoint pos, QVariantMap options = {});
};
class VideoContextMenu : public QObject {
Q_OBJECT
SIMPLE_MENU_PROPERTY(MLVideoModel*, model, nullptr)
public:
VideoContextMenu(QObject* parent = nullptr);
public slots:
void popup(const QModelIndexList& selected, QPoint pos, QVariantMap options = {} );
signals:
void showMediaInformation(int index);
};
#undef SIMPLE_MENU_PROPERTY
#endif // QMLMENUWRAPPER_HPP