From c580267a7ea13cb6beb3ca0eff39995b991f03c0 Mon Sep 17 00:00:00 2001 From: Benjamin Arnaud <benjamin.arnaud@videolabs.io> Date: Fri, 19 Feb 2021 11:25:27 +0100 Subject: [PATCH] qt/medialibrary: Create MLPlaylistListModel Signed-off-by: Pierre Lamot <pierre@videolabs.io> --- modules/gui/qt/Makefile.am | 3 + .../qt/medialibrary/mlplaylistlistmodel.cpp | 281 ++++++++++++++++++ .../qt/medialibrary/mlplaylistlistmodel.hpp | 84 ++++++ po/POTFILES.in | 2 + 4 files changed, 370 insertions(+) create mode 100644 modules/gui/qt/medialibrary/mlplaylistlistmodel.cpp create mode 100644 modules/gui/qt/medialibrary/mlplaylistlistmodel.hpp diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am index ffb2fdc65859..6c0516dbced5 100644 --- a/modules/gui/qt/Makefile.am +++ b/modules/gui/qt/Makefile.am @@ -170,6 +170,8 @@ libqt_plugin_la_SOURCES = \ gui/qt/medialibrary/mlvideomodel.hpp \ gui/qt/medialibrary/mlplaylist.cpp \ gui/qt/medialibrary/mlplaylist.hpp \ + gui/qt/medialibrary/mlplaylistlistmodel.cpp \ + gui/qt/medialibrary/mlplaylistlistmodel.hpp \ gui/qt/menus/custom_menus.cpp \ gui/qt/menus/custom_menus.hpp \ gui/qt/menus/qml_menu_wrapper.cpp \ @@ -332,6 +334,7 @@ nodist_libqt_plugin_la_SOURCES = \ gui/qt/medialibrary/mlvideo.moc.cpp \ gui/qt/medialibrary/mlvideomodel.moc.cpp \ gui/qt/medialibrary/mlplaylist.moc.cpp \ + gui/qt/medialibrary/mlplaylistlistmodel.moc.cpp \ gui/qt/menus/custom_menus.moc.cpp \ gui/qt/menus/qml_menu_wrapper.moc.cpp \ gui/qt/menus/menus.moc.cpp \ diff --git a/modules/gui/qt/medialibrary/mlplaylistlistmodel.cpp b/modules/gui/qt/medialibrary/mlplaylistlistmodel.cpp new file mode 100644 index 000000000000..f5f2adfd0ee4 --- /dev/null +++ b/modules/gui/qt/medialibrary/mlplaylistlistmodel.cpp @@ -0,0 +1,281 @@ +/***************************************************************************** + * Copyright (C) 2021 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. + *****************************************************************************/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "mlplaylistlistmodel.hpp" + +// VLC includes +#include <vlc_media_library.h> +#include <qt.hpp> + +// MediaLibrary includes +#include "mlhelper.hpp" +#include "mlplaylist.hpp" + +//================================================================================================= +// MLPlaylistListModel +//================================================================================================= + +MLPlaylistListModel::MLPlaylistListModel(vlc_medialibrary_t * ml, QObject * parent) + : MLBaseModel(parent) +{ + m_ml = ml; +} + +/* explicit */ MLPlaylistListModel::MLPlaylistListModel(QObject * parent) + : MLBaseModel(parent) {} + +//------------------------------------------------------------------------------------------------- + +/* Q_INVOKABLE */ MLItemId MLPlaylistListModel::create(const QString & name) +{ + assert(m_ml); + + vlc_ml_playlist_t * playlist = vlc_ml_playlist_create(m_ml, qtu(name)); + + if (playlist) + return MLItemId(playlist->i_id, VLC_ML_PARENT_PLAYLIST); + else + return MLItemId(); +} + +/* Q_INVOKABLE */ bool MLPlaylistListModel::append(const MLItemId & playlistId, + const QVariantList & ids) +{ + assert(m_ml); + + bool result = true; + + vlc_ml_query_params_t query; + + memset(&query, 0, sizeof(vlc_ml_query_params_t)); + + for (const QVariant & id : ids) + { + if (id.canConvert<MLItemId>() == false) + { + result = false; + + continue; + } + + const MLItemId & itemId = id.value<MLItemId>(); + + if (itemId.id == 0) + { + result = false; + + continue; + } + + // NOTE: When we have a parent it's a collection of media(s). + if (itemId.type != VLC_ML_PARENT_UNKNOWN) + { + ml_unique_ptr<vlc_ml_media_list_t> list; + + list.reset(vlc_ml_list_media_of(m_ml, &query, itemId.type, itemId.id)); + + if (list == nullptr) + { + result = false; + + continue; + } + + for (const vlc_ml_media_t & media : ml_range_iterate<vlc_ml_media_t>(list)) + { + if (vlc_ml_playlist_append(m_ml, playlistId.id, media.i_id) != VLC_SUCCESS) + result = false; + } + } + // NOTE: Otherwise we add the media directly. + else if (vlc_ml_playlist_append(m_ml, playlistId.id, itemId.id) != VLC_SUCCESS) + result = false; + } + + return result; +} + +//------------------------------------------------------------------------------------------------- + +/* Q_INVOKABLE */ bool MLPlaylistListModel::deletePlaylists(const QVariantList & ids) +{ + assert(m_ml); + + bool result = true; + + for (const QVariant & id : ids) + { + if (id.canConvert<MLItemId>() == false) + { + result = false; + + continue; + } + + if (vlc_ml_playlist_delete(m_ml, id.value<MLItemId>().id) != VLC_SUCCESS) + result = false; + } + + return result; +} + +//------------------------------------------------------------------------------------------------- + +/* Q_INVOKABLE */ MLItemId MLPlaylistListModel::getItemId(int index) const +{ + if (index < 0 || index >= rowCount()) + return MLItemId(); + + return item(index)->getId(); +} + +//------------------------------------------------------------------------------------------------- +// QAbstractItemModel implementation +//------------------------------------------------------------------------------------------------- + +QHash<int, QByteArray> MLPlaylistListModel::roleNames() const /* override */ +{ + return + { + { PLAYLIST_ID, "id" }, + { PLAYLIST_NAME, "name" }, + { PLAYLIST_COVER, "cover" }, + { PLAYLIST_COUNT, "count" } + }; +} + +QVariant MLPlaylistListModel::data(const QModelIndex & index, int role) const /* override */ +{ + const MLPlaylist * playlist = static_cast<MLPlaylist *>(item(index.row())); + + if (playlist == nullptr) + return QVariant(); + + switch (role) + { + // NOTE: This is the condition for QWidget view(s). + case Qt::DisplayRole: + if (index.column() == 0) + return QVariant::fromValue(playlist->getName()); + else + return QVariant(); + // NOTE: These are the conditions for QML view(s). + case PLAYLIST_ID: + return QVariant::fromValue(playlist->getId()); + case PLAYLIST_NAME: + return QVariant::fromValue(playlist->getName()); + case PLAYLIST_COVER: + return QVariant::fromValue(playlist->getCover()); + case PLAYLIST_COUNT: + return QVariant::fromValue(playlist->getCount()); + default: + return QVariant(); + } +} + +//------------------------------------------------------------------------------------------------- +// QAbstractItemModel reimplementation +//------------------------------------------------------------------------------------------------- + +QVariant MLPlaylistListModel::headerData(int section, Qt::Orientation orientation, + int role) const /* override */ +{ + if (role != Qt::DisplayRole || orientation == Qt::Vertical) + return QVariant(); + + if (section == 0) + return QVariant::fromValue(qtr("Name")); + else + return QVariant(); +} + +//------------------------------------------------------------------------------------------------- +// Protected MLBaseModel implementation +//------------------------------------------------------------------------------------------------- + +vlc_ml_sorting_criteria_t MLPlaylistListModel::roleToCriteria(int role) const /* override */ +{ + if (role == PLAYLIST_NAME) + return VLC_ML_SORTING_ALPHA; + else + return VLC_ML_SORTING_DEFAULT; +} + +ListCacheLoader<std::unique_ptr<MLItem>> * MLPlaylistListModel::createLoader() const /* override */ +{ + return new Loader(*this); +} + +//------------------------------------------------------------------------------------------------- +// Private MLBaseModel reimplementation +//------------------------------------------------------------------------------------------------- + +void MLPlaylistListModel::onVlcMlEvent(const MLEvent & event) /* override */ +{ + int type = event.i_type; + + if (type == VLC_ML_EVENT_PLAYLIST_ADDED || type == VLC_ML_EVENT_PLAYLIST_UPDATED + || + type == VLC_ML_EVENT_PLAYLIST_DELETED) + { + m_need_reset = true; + + // NOTE: Maybe we should call this from MLBaseModel ? + emit resetRequested(); + } + + MLBaseModel::onVlcMlEvent(event); +} + +//================================================================================================= +// Loader +//================================================================================================= + +MLPlaylistListModel::Loader::Loader(const MLPlaylistListModel & model) + : MLBaseModel::BaseLoader(model) {} + +size_t MLPlaylistListModel::Loader::count() const /* override */ +{ + vlc_ml_query_params_t params = getParams().toCQueryParams(); + + return vlc_ml_count_playlists(m_ml, ¶ms); +} + +std::vector<std::unique_ptr<MLItem>> +MLPlaylistListModel::Loader::load(size_t index, size_t count) const /* override */ +{ + vlc_ml_query_params_t params = getParams(index, count).toCQueryParams(); + + ml_unique_ptr<vlc_ml_playlist_list_t> list(vlc_ml_list_playlists(m_ml, ¶ms)); + + if (list == nullptr) + return {}; + + std::vector<std::unique_ptr<MLItem>> result; + + for (const vlc_ml_playlist_t & playlist : ml_range_iterate<vlc_ml_playlist_t>(list)) + { + result.emplace_back(std::make_unique<MLPlaylist>(m_ml, &playlist)); + } + + return result; +} diff --git a/modules/gui/qt/medialibrary/mlplaylistlistmodel.hpp b/modules/gui/qt/medialibrary/mlplaylistlistmodel.hpp new file mode 100644 index 000000000000..b0b0f346291c --- /dev/null +++ b/modules/gui/qt/medialibrary/mlplaylistlistmodel.hpp @@ -0,0 +1,84 @@ +/***************************************************************************** + * Copyright (C) 2021 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. + *****************************************************************************/ + +#ifndef MLPLAYLISTLISTMODEL_HPP +#define MLPLAYLISTLISTMODEL_HPP + +// MediaLibrary includes +#include "mlbasemodel.hpp" + +// Forward declarations +class vlc_medialibrary_t; +class vlc_ml_playlist_t; + +class MLPlaylistListModel : public MLBaseModel +{ + Q_OBJECT + +public: + enum Roles + { + PLAYLIST_ID = Qt::UserRole + 1, + PLAYLIST_NAME, + PLAYLIST_COVER, + PLAYLIST_COUNT + }; + +public: + MLPlaylistListModel(vlc_medialibrary_t * ml, QObject * parent = nullptr); + + explicit MLPlaylistListModel(QObject * parent = nullptr); + +public: // Interface + Q_INVOKABLE MLItemId create(const QString & name); + + Q_INVOKABLE bool append(const MLItemId & playlistId, const QVariantList & ids); + + Q_INVOKABLE bool deletePlaylists(const QVariantList & ids); + + MLItemId getItemId(int index) const; + +public: // QAbstractItemModel implementation + QHash<int, QByteArray> roleNames() const override; + + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; + +public: // QAbstractItemModel reimplementation + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + +protected: // MLBaseModel implementation + vlc_ml_sorting_criteria_t roleToCriteria(int role) const override; + + ListCacheLoader<std::unique_ptr<MLItem>> * createLoader() const override; + +private: // MLBaseModel implementation + void onVlcMlEvent(const MLEvent & event) override; + +private: + struct Loader : public MLBaseModel::BaseLoader + { + Loader(const MLPlaylistListModel & model); + + size_t count() const override; + + std::vector<std::unique_ptr<MLItem>> load(size_t index, size_t count) const override; + }; +}; + +#endif // MLPLAYLISTLISTMODEL_HPP diff --git a/po/POTFILES.in b/po/POTFILES.in index 9f01428a4768..396418fb24f3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -770,6 +770,8 @@ modules/gui/qt/medialibrary/mlbookmarkmodel.cpp modules/gui/qt/medialibrary/mlbookmarkmodel.hpp modules/gui/qt/medialibrary/mlfoldersmodel.cpp modules/gui/qt/medialibrary/mlfoldersmodel.hpp +modules/gui/qt/medialibrary/mlplaylistlistmodel.cpp +modules/gui/qt/medialibrary/mlplaylistlistmodel.hpp modules/gui/qt/menus/menus.cpp modules/gui/qt/menus/menus.hpp modules/gui/qt/qt.cpp -- GitLab