[vlc-devel] [RFC 49/82] qt: add base classes for medialibrary model

Pierre Lamot pierre at videolabs.io
Fri Feb 1 14:01:53 CET 2019


---
 modules/gui/qt/Makefile.am                    |   9 +
 .../qt/components/mediacenter/mcmedialib.cpp  | 237 ++++++++++++++++++
 .../qt/components/mediacenter/mcmedialib.hpp  |  82 ++++++
 .../qt/components/mediacenter/mlbasemodel.cpp | 181 +++++++++++++
 .../qt/components/mediacenter/mlbasemodel.hpp | 210 ++++++++++++++++
 .../qt/components/mediacenter/mlhelper.hpp    |  74 ++++++
 .../qt/components/mediacenter/mlqmltypes.hpp  |  61 +++++
 7 files changed, 854 insertions(+)
 create mode 100644 modules/gui/qt/components/mediacenter/mcmedialib.cpp
 create mode 100644 modules/gui/qt/components/mediacenter/mcmedialib.hpp
 create mode 100644 modules/gui/qt/components/mediacenter/mlbasemodel.cpp
 create mode 100644 modules/gui/qt/components/mediacenter/mlbasemodel.hpp
 create mode 100644 modules/gui/qt/components/mediacenter/mlhelper.hpp
 create mode 100644 modules/gui/qt/components/mediacenter/mlqmltypes.hpp

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index e9cd3e61d4..12a21ec7d6 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -118,6 +118,12 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/components/epg/EPGView.cpp gui/qt/components/epg/EPGView.hpp \
 	gui/qt/components/epg/EPGWidget.cpp \
 	gui/qt/components/epg/EPGWidget.hpp \
+	gui/qt/components/mediacenter/mcmedialib.cpp \
+	gui/qt/components/mediacenter/mcmedialib.hpp \
+	gui/qt/components/mediacenter/mlhelper.hpp \
+	gui/qt/components/mediacenter/mlqmltypes.hpp \
+	gui/qt/components/mediacenter/mlbasemodel.cpp \
+	gui/qt/components/mediacenter/mlbasemodel.hpp \
 	gui/qt/components/playlist/media.hpp \
 	gui/qt/components/playlist/playlist_common.cpp \
 	gui/qt/components/playlist/playlist_common.hpp \
@@ -238,6 +244,9 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/components/epg/EPGRuler.moc.cpp \
 	gui/qt/components/epg/EPGView.moc.cpp \
 	gui/qt/components/epg/EPGWidget.moc.cpp \
+	gui/qt/components/mediacenter/mcmedialib.moc.cpp \
+	gui/qt/components/mediacenter/mlqmltypes.moc.cpp \
+	gui/qt/components/mediacenter/mlbasemodel.moc.cpp \
 	gui/qt/components/playlist/playlist_common.moc.cpp \
 	gui/qt/components/playlist/playlist_item.moc.cpp \
 	gui/qt/components/playlist/playlist_model.moc.cpp \
diff --git a/modules/gui/qt/components/mediacenter/mcmedialib.cpp b/modules/gui/qt/components/mediacenter/mcmedialib.cpp
new file mode 100644
index 0000000000..15ae56fc65
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mcmedialib.cpp
@@ -0,0 +1,237 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#include "mcmedialib.hpp"
+#include "mlhelper.hpp"
+#include "recents.hpp"
+
+#include <vlc_playlist.h>
+#include <vlc_input_item.h>
+#include "components/playlist/media.hpp"
+#include "components/playlist/playlist_controler.hpp"
+
+MCMediaLib::MCMediaLib(intf_thread_t *_intf, QObject *_parent)
+    : QObject( _parent )
+    , m_intf( _intf )
+    , m_gridView( true )
+    , m_ml( vlcMl() )
+    , m_event_cb( nullptr, [this](vlc_ml_event_callback_t* cb ) {
+        vlc_ml_event_unregister_callback( m_ml, cb );
+      })
+{
+    m_event_cb.reset( vlc_ml_event_register_callback( m_ml, MCMediaLib::onMediaLibraryEvent,
+                                                      this ) );
+}
+
+// Should the items be displayed as a grid or as list ?
+bool MCMediaLib::isGridView() const
+{
+    return m_gridView;
+}
+
+void MCMediaLib::setGridView(bool state)
+{
+    m_gridView = state;
+    emit gridViewChanged();
+}
+
+void MCMediaLib::openMRLFromMedia(const vlc_ml_media_t& media, bool start )
+{
+    if (!media.p_files)
+        return;
+    for ( const vlc_ml_file_t& mediafile: ml_range_iterate<vlc_ml_file_t>(media.p_files) )
+    {
+        if (mediafile.psz_mrl)
+            Open::openMRL(m_intf, mediafile.psz_mrl, start);
+        start = false;
+    }
+}
+
+void MCMediaLib::addToPlaylist(const QString& mrl)
+{
+    vlc::playlist::Media media{ mrl, mrl };
+    m_intf->p_sys->p_mainPlaylistControler->append( {media}, false );
+}
+
+void MCMediaLib::addToPlaylist(const QUrl& mrl)
+{
+    vlc::playlist::Media media{ mrl.toString(QUrl::None), mrl.fileName() };
+    m_intf->p_sys->p_mainPlaylistControler->append( {media} , false );
+}
+
+// A specific item has been asked to be added to the playlist
+void MCMediaLib::addToPlaylist(const MLParentId & itemId)
+{
+    //invalid item
+    if (itemId.id == 0)
+        return;
+
+    if (itemId.type == VLC_ML_PARENT_UNKNOWN)
+    {
+        input_item_t* item = vlc_ml_get_input_item( m_ml, itemId.id );
+        if (item) {
+            QVector<vlc::playlist::Media> medias = { vlc::playlist::Media(item) };
+            m_intf->p_sys->p_mainPlaylistControler->append(medias, false);
+        }
+    }
+    else
+    {
+        vlc_ml_query_params_t query;
+        memset(&query, 0, sizeof(vlc_ml_query_params_t));
+        ml_unique_ptr<vlc_ml_media_list_t> media_list(vlc_ml_list_media_of( m_ml, &query, itemId.type, itemId.id));
+
+        auto mediaRange = ml_range_iterate<vlc_ml_media_t>( media_list );
+        QVector<vlc::playlist::Media> medias;
+        std::transform(mediaRange.begin(), mediaRange.end(), std::back_inserter(medias), [&](vlc_ml_media_t& m) {
+            input_item_t* item = vlc_ml_get_input_item( m_ml, m.i_id );
+            return vlc::playlist::Media(item);
+        });
+        m_intf->p_sys->p_mainPlaylistControler->append(medias, false);
+    }
+}
+
+void MCMediaLib::addToPlaylist(const QVariantList& itemIdList)
+{
+    for (const QVariant& varValue: itemIdList)
+    {
+        if (varValue.canConvert<QUrl>())
+        {
+            auto mrl = varValue.value<QUrl>();
+            addToPlaylist(mrl);
+        }
+        else if (varValue.canConvert<QString>())
+        {
+            auto mrl = varValue.value<QString>();
+            addToPlaylist(mrl);
+        }
+        else if (varValue.canConvert<MLParentId>())
+        {
+            MLParentId itemId = varValue.value<MLParentId>();
+            addToPlaylist(itemId);
+        }
+    }
+}
+
+// A specific item has been asked to be played,
+// so it's added to the playlist and played
+void MCMediaLib::addAndPlay(const MLParentId & itemId )
+{
+    if (itemId.id == 0)
+        return;
+    if (itemId.type == VLC_ML_PARENT_UNKNOWN)
+    {
+        input_item_t* item = vlc_ml_get_input_item( m_ml, itemId.id );
+        if (item) {
+            QVector<vlc::playlist::Media> medias = { vlc::playlist::Media(item) };
+            m_intf->p_sys->p_mainPlaylistControler->append(medias, true);
+            input_item_Release( item );
+        }
+    }
+    else
+    {
+        vlc_ml_query_params_t query;
+        memset(&query, 0, sizeof(vlc_ml_query_params_t));
+        ml_unique_ptr<vlc_ml_media_list_t> media_list(vlc_ml_list_media_of( m_ml, &query, itemId.type, itemId.id));
+
+        auto mediaRange = ml_range_iterate<vlc_ml_media_t>( media_list );
+        QVector<vlc::playlist::Media> medias;
+        std::transform(mediaRange.begin(), mediaRange.end(), std::back_inserter(medias), [&](vlc_ml_media_t& m) {
+            input_item_t* item = vlc_ml_get_input_item( m_ml, m.i_id );
+            auto res = vlc::playlist::Media(item);
+            if ( item )
+                input_item_Release( item );
+            return res;
+        });
+        m_intf->p_sys->p_mainPlaylistControler->append(medias, true);
+    }
+}
+
+void MCMediaLib::addAndPlay(const QString& mrl)
+{
+    vlc::playlist::Media media{ mrl, mrl };
+    m_intf->p_sys->p_mainPlaylistControler->append( {media}, true );
+}
+
+void MCMediaLib::addAndPlay(const QUrl& mrl)
+{
+    vlc::playlist::Media media{ mrl.toString(QUrl::None), mrl.fileName() };
+    m_intf->p_sys->p_mainPlaylistControler->append( {media}, true );
+}
+
+
+void MCMediaLib::addAndPlay(const QVariantList& itemIdList)
+{
+    bool b_start = true;
+    for (const QVariant& varValue: itemIdList)
+    {
+        if (varValue.canConvert<QUrl>())
+        {
+            auto mrl = varValue.value<QUrl>();
+            if (b_start)
+                addAndPlay(mrl);
+            else
+                addToPlaylist(mrl);
+        }
+        if (varValue.canConvert<QString>())
+        {
+            auto mrl = varValue.value<QString>();
+            if (b_start)
+                addAndPlay(mrl);
+            else
+                addToPlaylist(mrl);
+        }
+        else if (varValue.canConvert<MLParentId>())
+        {
+            MLParentId itemId = varValue.value<MLParentId>();
+            if (b_start)
+                addAndPlay(itemId);
+            else
+                addToPlaylist(itemId);
+        } else {
+            continue;
+        }
+        b_start = false;
+    }
+}
+
+vlc_medialibrary_t* MCMediaLib::vlcMl()
+{
+    return vlc_ml_instance_get( m_intf );
+}
+
+void MCMediaLib::onMediaLibraryEvent( void* data, const vlc_ml_event_t* event )
+{
+    MCMediaLib* self = static_cast<MCMediaLib*>( data );
+    switch ( event->i_type )
+    {
+        case VLC_ML_EVENT_PARSING_PROGRESS_UPDATED:
+            self->emit progressUpdated( event->parsing_progress.i_percent );
+            break;
+        case VLC_ML_EVENT_DISCOVERY_STARTED:
+            self->emit discoveryStarted();
+            break;
+        case VLC_ML_EVENT_DISCOVERY_PROGRESS:
+            self->emit discoveryProgress( event->discovery_progress.psz_entry_point );
+            break;
+        case VLC_ML_EVENT_DISCOVERY_COMPLETED:
+            self->emit discoveryCompleted();
+            break;
+        default:
+            break;
+    }
+}
diff --git a/modules/gui/qt/components/mediacenter/mcmedialib.hpp b/modules/gui/qt/components/mediacenter/mcmedialib.hpp
new file mode 100644
index 0000000000..0eeb714c9a
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mcmedialib.hpp
@@ -0,0 +1,82 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+#pragma once
+
+#include <Qt>
+#include <QAbstractListModel>
+#include <QVariant>
+#include <QHash>
+#include <QByteArray>
+#include <QList>
+#include <QQuickWidget>
+#include <QQuickItem>
+#include <QMetaObject>
+#include <QMetaMethod>
+#include <QQmlEngine>
+
+#include <memory>
+
+#include "qt.hpp"
+#include "mlqmltypes.hpp"
+
+class MCMediaLib : public QObject
+{
+    Q_OBJECT
+
+    Q_PROPERTY(bool gridView READ isGridView WRITE setGridView NOTIFY gridViewChanged)
+
+public:
+    MCMediaLib(intf_thread_t* _intf, QObject* _parent = nullptr );
+
+    Q_INVOKABLE void addToPlaylist(const MLParentId &itemId);
+    Q_INVOKABLE void addToPlaylist(const QString& mrl);
+    Q_INVOKABLE void addToPlaylist(const QUrl& mrl);
+    Q_INVOKABLE void addToPlaylist(const QVariantList& itemIdList);
+
+    Q_INVOKABLE void addAndPlay(const MLParentId &itemId);
+    Q_INVOKABLE void addAndPlay(const QString& mrl);
+    Q_INVOKABLE void addAndPlay(const QUrl& mrl);
+    Q_INVOKABLE void addAndPlay(const QVariantList&itemIdList);
+
+
+    vlc_medialibrary_t* vlcMl();
+
+signals:
+    void gridViewChanged();
+    void discoveryStarted();
+    void discoveryProgress( QString entryPoint );
+    void discoveryCompleted();
+    void progressUpdated( quint32 percent );
+
+private:
+    bool isGridView() const;
+    void setGridView(bool);
+    static void onMediaLibraryEvent( void* data, const vlc_ml_event_t* event );
+
+private:
+    void openMRLFromMedia(const vlc_ml_media_t& media, bool start );
+
+    intf_thread_t* m_intf;
+
+    bool m_gridView;
+
+    /* Medialibrary */
+    vlc_medialibrary_t* m_ml;
+    std::unique_ptr<vlc_ml_event_callback_t, std::function<void(vlc_ml_event_callback_t*)>> m_event_cb;
+
+};
diff --git a/modules/gui/qt/components/mediacenter/mlbasemodel.cpp b/modules/gui/qt/components/mediacenter/mlbasemodel.cpp
new file mode 100644
index 0000000000..64d87f9be3
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mlbasemodel.cpp
@@ -0,0 +1,181 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#include <cassert>
+#include "mlbasemodel.hpp"
+#include "mcmedialib.hpp"
+#include <vlc_cxx_helpers.hpp>
+
+MLBaseModel::MLBaseModel(QObject *parent)
+    : QAbstractListModel(parent)
+    , m_ml(nullptr)
+    , m_search_pattern_cstr( nullptr, &free )
+    , m_nb_max_items( 0 )
+    , m_ml_event_handle( nullptr, [this](vlc_ml_event_callback_t* cb ) {
+            assert( m_ml != nullptr );
+            vlc_ml_event_unregister_callback( m_ml, cb );
+        })
+    , m_need_reset( false )
+    , m_is_reloading( false )
+{
+    vlc_mutex_init( &m_item_lock );
+    memset(&m_query_param, 0, sizeof(vlc_ml_query_params_t));
+    m_query_param.b_desc = false;
+    m_query_param.i_nbResults = 20; //FIXME: value for test
+    m_query_param.i_sort = VLC_ML_SORTING_DEFAULT;
+
+    connect( this, &MLBaseModel::resetRequested, this, &MLBaseModel::onResetRequested );
+}
+
+MLBaseModel::~MLBaseModel()
+{
+    vlc_mutex_destroy( &m_item_lock );
+}
+
+void MLBaseModel::sortByColumn(QByteArray name, Qt::SortOrder order)
+{
+    beginResetModel();
+    m_query_param.b_desc = (order == Qt::SortOrder::DescendingOrder);
+    m_query_param.i_sort = nameToCriteria(name);
+    clear();
+    endResetModel();
+}
+
+void MLBaseModel::onResetRequested()
+{
+    beginResetModel();
+    clear();
+    endResetModel();
+}
+
+void MLBaseModel::onVlcMlEvent(const vlc_ml_event_t* event)
+{
+    switch(event->i_type)
+    {
+        case VLC_ML_EVENT_BACKGROUND_IDLE_CHANGED:
+            if ( event->background_idle_changed.b_idle == false )
+                m_is_reloading = true;
+            else
+            {
+                m_is_reloading = false;
+                if ( m_need_reset )
+                {
+                    emit resetRequested();
+                    m_need_reset = false;
+                }
+            }
+            break;
+    }
+}
+
+void MLBaseModel::onVlcMlEvent(void* data, const vlc_ml_event_t* event)
+{
+    auto self = static_cast<MLBaseModel*>(data);
+    self->onVlcMlEvent(event);
+}
+
+MLParentId MLBaseModel::parentId() const
+{
+    return m_parent;
+}
+
+void MLBaseModel::setParentId(MLParentId parentId)
+{
+    beginResetModel();
+    m_parent = parentId;
+    clear();
+    endResetModel();
+    emit parentIdChanged();
+}
+
+void MLBaseModel::unsetParentId()
+{
+    beginResetModel();
+    m_parent = MLParentId();
+    clear();
+    endResetModel();
+    emit parentIdChanged();
+}
+
+MCMediaLib* MLBaseModel::ml() const
+{
+    return m_mcMediaLib;
+}
+
+void MLBaseModel::setMl(MCMediaLib* mcMl)
+{
+    m_ml = mcMl->vlcMl();
+    m_mcMediaLib = mcMl;
+    if ( m_ml_event_handle == nullptr )
+        m_ml_event_handle.reset( vlc_ml_event_register_callback( m_ml, onVlcMlEvent, this ) );
+}
+
+const QString& MLBaseModel::searchPattern() const
+{
+    return m_search_pattern;
+}
+
+void MLBaseModel::setSearchPattern( const QString& pattern )
+{
+    beginResetModel();
+    if ( pattern.length() >= 3 )
+        m_search_pattern_cstr = vlc::wrap_cptr( strdup( qtu( pattern ) ) );
+    else
+        m_search_pattern_cstr.reset();
+    m_search_pattern = pattern;
+    m_query_param.psz_pattern = m_search_pattern_cstr.get();
+    clear();
+    endResetModel();
+}
+
+Qt::SortOrder MLBaseModel::getSortOrder() const
+{
+    return m_query_param.b_desc ? Qt::SortOrder::DescendingOrder : Qt::SortOrder::AscendingOrder;
+}
+
+void MLBaseModel::setSortOder(Qt::SortOrder order)
+{
+    beginResetModel();
+    m_query_param.b_desc = (order == Qt::SortOrder::DescendingOrder);
+    clear();
+    endResetModel();
+    emit sortOrderChanged();
+}
+
+const QString MLBaseModel::getSortCriteria() const
+{
+    return criteriaToName(m_query_param.i_sort);
+}
+
+void MLBaseModel::setSortCriteria(const QString& criteria)
+{
+    beginResetModel();
+    m_query_param.i_sort = nameToCriteria(criteria.toUtf8());
+    clear();
+    endResetModel();
+    emit sortCriteriaChanged();
+}
+
+void MLBaseModel::unsetSortCriteria()
+{
+    beginResetModel();
+    m_query_param.i_sort = VLC_ML_SORTING_DEFAULT;
+    clear();
+    endResetModel();
+    emit sortCriteriaChanged();
+}
diff --git a/modules/gui/qt/components/mediacenter/mlbasemodel.hpp b/modules/gui/qt/components/mediacenter/mlbasemodel.hpp
new file mode 100644
index 0000000000..cb8af2ca90
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mlbasemodel.hpp
@@ -0,0 +1,210 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#ifndef MLBASEMODEL_HPP
+#define MLBASEMODEL_HPP
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "vlc_common.h"
+
+#include <memory>
+#include <QObject>
+#include <QAbstractListModel>
+#include "vlc_media_library.h"
+#include "mlqmltypes.hpp"
+#include "mcmedialib.hpp"
+#include <memory>
+
+class MCMediaLib;
+
+class MLBaseModel : public QAbstractListModel
+{
+    Q_OBJECT
+
+public:
+    explicit MLBaseModel(QObject *parent = nullptr);
+    virtual ~MLBaseModel();
+
+    Q_INVOKABLE void sortByColumn(QByteArray name, Qt::SortOrder order);
+
+    Q_INVOKABLE virtual QObject *get(unsigned int idx) const = 0;
+
+    Q_PROPERTY( MLParentId parentId READ parentId WRITE setParentId NOTIFY parentIdChanged RESET unsetParentId )
+    Q_PROPERTY( MCMediaLib* ml READ ml WRITE setMl )
+    Q_PROPERTY( unsigned int maxItems MEMBER m_nb_max_items )
+    Q_PROPERTY( QString searchPattern READ searchPattern WRITE setSearchPattern )
+
+    Q_PROPERTY( Qt::SortOrder sortOrder READ getSortOrder WRITE setSortOder NOTIFY sortOrderChanged )
+    Q_PROPERTY( QString sortCriteria READ getSortCriteria WRITE setSortCriteria NOTIFY sortCriteriaChanged RESET unsetSortCriteria )
+
+signals:
+    void parentIdChanged();
+    void resetRequested();
+    void sortOrderChanged();
+    void sortCriteriaChanged();
+
+protected slots:
+    void onResetRequested();
+
+private:
+    static void onVlcMlEvent( void* data, const vlc_ml_event_t* event );
+
+protected:
+    virtual void clear() = 0;
+    virtual vlc_ml_sorting_criteria_t roleToCriteria(int role) const = 0;
+    virtual vlc_ml_sorting_criteria_t nameToCriteria(QByteArray) const {
+        return VLC_ML_SORTING_DEFAULT;
+    }
+    virtual QByteArray criteriaToName(vlc_ml_sorting_criteria_t ) const
+    {
+        return "";
+    }
+
+    MLParentId parentId() const;
+    void setParentId(MLParentId parentId);
+    void unsetParentId();
+
+    MCMediaLib* ml() const;
+    void setMl(MCMediaLib* ml);
+
+    const QString& searchPattern() const;
+    void setSearchPattern( const QString& pattern );
+
+    Qt::SortOrder getSortOrder() const;
+    void setSortOder(Qt::SortOrder order);
+    const QString getSortCriteria() const;
+    void setSortCriteria(const QString& criteria);
+    void unsetSortCriteria();
+
+    virtual void onVlcMlEvent( const vlc_ml_event_t* event );
+
+    MLParentId m_parent;
+
+    vlc_medialibrary_t* m_ml;
+    MCMediaLib* m_mcMediaLib;
+    mutable vlc_ml_query_params_t m_query_param;
+    std::unique_ptr<char, void(*)(void*)> m_search_pattern_cstr;
+    QString m_search_pattern;
+
+    unsigned int m_nb_max_items;
+
+    mutable vlc_mutex_t m_item_lock;
+
+    std::unique_ptr<vlc_ml_event_callback_t,
+                    std::function<void(vlc_ml_event_callback_t*)>> m_ml_event_handle;
+    std::atomic_bool m_need_reset;
+    std::atomic_bool m_is_reloading;
+};
+
+/**
+ * Implements a basic sliding window.
+ * const_cast & immutable are unavoidable, since all access member functions
+ * are marked as const. fetchMore & canFetchMore don't allow for the full size
+ * to be known (so the scrollbar would grow as we scroll, until we displayed all
+ * elements), and implies having all elements loaded in RAM at all time.
+ */
+template <typename T>
+class MLSlidingWindowModel : public MLBaseModel
+{
+public:
+    static constexpr size_t BatchSize = 100;
+
+    MLSlidingWindowModel(QObject* parent = nullptr)
+        : MLBaseModel(parent)
+        , m_initialized(false)
+    {
+        m_query_param.i_nbResults = BatchSize;
+    }
+
+    int rowCount(const QModelIndex &parent) const override
+    {
+        if (parent.isValid())
+            return 0;
+        vlc_mutex_locker lock( &m_item_lock );
+        if ( m_initialized == false )
+        {
+            m_total_count = countTotalElements();
+            m_initialized = true;
+            m_item_list = const_cast<MLSlidingWindowModel<T>*>(this)->fetch();
+        }
+        return m_total_count;
+    }
+
+    QObject* get(unsigned int idx) const override
+    {
+        vlc_mutex_locker lock( &m_item_lock );
+        T* obj = item( idx );
+        if (!obj)
+            return nullptr;
+        return obj->clone();
+    }
+
+    void clear() override
+    {
+        vlc_mutex_locker lock( &m_item_lock );
+        m_query_param.i_offset = 0;
+        m_initialized = false;
+        m_total_count = 0;
+        m_item_list.clear();
+    }
+
+protected:
+    T* item(unsigned int idx) const
+    {
+        // Must be called in a locked context
+        if ( m_initialized == false )
+        {
+            m_total_count = countTotalElements();
+            if ( m_total_count > 0 )
+                m_item_list = const_cast<MLSlidingWindowModel<T>*>(this)->fetch();
+            m_initialized = true;
+        }
+
+        if ( m_total_count == 0 || idx >= m_total_count || idx < 0 )
+            return nullptr;
+
+        if ( idx < m_query_param.i_offset ||  idx >= m_query_param.i_offset + m_item_list.size() )
+        {
+            if (m_query_param.i_nbResults == 0)
+                m_query_param.i_offset = 0;
+            else
+                m_query_param.i_offset = idx - idx % m_query_param.i_nbResults;
+            m_item_list = const_cast<MLSlidingWindowModel<T>*>(this)->fetch();
+        }
+
+        //db has changed
+        if ( idx - m_query_param.i_offset >= m_item_list.size() || idx - m_query_param.i_offset < 0 )
+            return nullptr;
+        return m_item_list[idx - m_query_param.i_offset].get();
+    }
+
+private:
+    virtual size_t countTotalElements() const = 0;
+    virtual std::vector<std::unique_ptr<T>> fetch() = 0;
+
+protected:
+    mutable std::vector<std::unique_ptr<T>> m_item_list;
+
+private:
+    mutable bool m_initialized;
+    mutable size_t m_total_count;
+};
+
+#endif // MLBASEMODEL_HPP
diff --git a/modules/gui/qt/components/mediacenter/mlhelper.hpp b/modules/gui/qt/components/mediacenter/mlhelper.hpp
new file mode 100644
index 0000000000..e4369b2795
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mlhelper.hpp
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#ifndef MLHELPER_HPP
+#define MLHELPER_HPP
+
+#include <memory>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vlc_media_library.h"
+
+template<typename T>
+class MLDeleter
+{
+public:
+    void operator() (T* obj) {
+        vlc_ml_release(obj);
+    }
+};
+
+template<typename T>
+using ml_unique_ptr = std::unique_ptr<T, MLDeleter<T> >;
+
+template<typename T>
+class MLListRange
+{
+public:
+    MLListRange( T* begin, T* end )
+        : m_begin(begin)
+        , m_end(end)
+    {
+    }
+
+    T* begin() const
+    {
+        return m_begin;
+    }
+
+    T* end() const
+    {
+        return m_end;
+    }
+
+private:
+    T* m_begin;
+    T* m_end;
+};
+
+template<typename T, typename L>
+MLListRange<T> ml_range_iterate(L& list)
+{
+    return MLListRange<T>{ list->p_items, list->p_items + list->i_nb_items };
+}
+
+
+#endif // MLHELPER_HPP
diff --git a/modules/gui/qt/components/mediacenter/mlqmltypes.hpp b/modules/gui/qt/components/mediacenter/mlqmltypes.hpp
new file mode 100644
index 0000000000..7e963521b8
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mlqmltypes.hpp
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#ifndef MLQMLTYPES_HPP
+#define MLQMLTYPES_HPP
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <QObject>
+#include <vlc_common.h>
+#include <vlc_media_library.h>
+
+class MLParentId
+{
+    Q_GADGET
+public:
+    MLParentId() : id(0), type( VLC_ML_PARENT_UNKNOWN ) {}
+    MLParentId( int64_t i, vlc_ml_parent_type t ) : id( i ), type( t ) {}
+    bool operator!=( const MLParentId& lhs )
+    {
+        return id != lhs.id || type != lhs.type;
+    }
+    int64_t id;
+    vlc_ml_parent_type type;
+
+    Q_INVOKABLE inline QString toString() const {
+
+#define ML_PARENT_TYPE_CASE(type) case type: return QString("%1 - %2").arg(#type).arg(id)
+        switch (type) {
+            ML_PARENT_TYPE_CASE(VLC_ML_PARENT_ALBUM);
+            ML_PARENT_TYPE_CASE(VLC_ML_PARENT_ARTIST);
+            ML_PARENT_TYPE_CASE(VLC_ML_PARENT_SHOW);
+            ML_PARENT_TYPE_CASE(VLC_ML_PARENT_GENRE);
+            ML_PARENT_TYPE_CASE(VLC_ML_PARENT_PLAYLIST);
+        default:
+            return QString("UNKNONW - %2").arg(id);
+        }
+#undef ML_PARENT_TYPE_CASE
+    }
+};
+
+Q_DECLARE_METATYPE(MLParentId)
+
+#endif // MLQMLTYPES_HPP
-- 
2.19.1



More information about the vlc-devel mailing list