[vlc-devel] [PATCH] qt: implement recent medias menu

Abel Tesfaye abeltesfaye45 at gmail.com
Fri Apr 12 16:40:41 CEST 2019


The sub menu located at media -> open recent media used to be empty. This commit fixed that.
---
 modules/gui/qt/Makefile.am                    |  3 +
 .../gui/qt/components/player_controller.cpp   |  3 +
 .../gui/qt/components/recent_media_model.cpp  | 97 +++++++++++++++++++
 .../gui/qt/components/recent_media_model.hpp  | 69 +++++++++++++
 modules/gui/qt/dialogs_provider.cpp           |  2 -
 modules/gui/qt/main_interface.cpp             |  3 +-
 modules/gui/qt/qml/menus/MainDropdownMenu.qml |  3 +-
 modules/gui/qt/qml/menus/MediaMenu.qml        | 36 ++++++-
 modules/gui/qt/recents.cpp                    |  1 +
 modules/gui/qt/recents.hpp                    |  9 +-
 10 files changed, 218 insertions(+), 8 deletions(-)
 create mode 100644 modules/gui/qt/components/recent_media_model.cpp
 create mode 100644 modules/gui/qt/components/recent_media_model.hpp

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 5f1498e7ad..203ded3d90 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -103,6 +103,8 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/components/controller.cpp gui/qt/components/controller.hpp \
 	gui/qt/components/controller_widget.cpp \
 	gui/qt/components/controller_widget.hpp \
+	gui/qt/components/recent_media_model.cpp  \
+	gui/qt/components/recent_media_model.hpp \
 	gui/qt/components/voutwindow/videosurface.cpp \
 	gui/qt/components/voutwindow/videosurface.hpp \
 	gui/qt/components/voutwindow/qvoutwindow.cpp \
@@ -253,6 +255,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/components/controller.moc.cpp \
 	gui/qt/components/controller_widget.moc.cpp \
 	gui/qt/components/custom_menus.moc.cpp \
+	gui/qt/components/recent_media_model.moc.cpp \
 	gui/qt/components/voutwindow/videosurface.moc.cpp \
 	gui/qt/components/voutwindow/qvoutwindow.moc.cpp \
 	gui/qt/components/voutwindow/qvoutwindowdummy.moc.cpp \
diff --git a/modules/gui/qt/components/player_controller.cpp b/modules/gui/qt/components/player_controller.cpp
index 5a445d174c..cd8fc33b45 100644
--- a/modules/gui/qt/components/player_controller.cpp
+++ b/modules/gui/qt/components/player_controller.cpp
@@ -202,6 +202,9 @@ static  void on_player_current_media_changed(vlc_player_t *, input_item_t *new_m
         that->UpdateName( newMediaPtr.get() );
         that->UpdateArt( newMediaPtr.get() );
         that->UpdateMeta( newMediaPtr.get() );
+
+        RecentsMRL::getInstance( that->p_intf )->addRecent( newMediaPtr.get()->psz_uri );
+
         emit q->inputChanged( newMediaPtr != nullptr );
     });
 }
diff --git a/modules/gui/qt/components/recent_media_model.cpp b/modules/gui/qt/components/recent_media_model.cpp
new file mode 100644
index 0000000000..447409ce20
--- /dev/null
+++ b/modules/gui/qt/components/recent_media_model.cpp
@@ -0,0 +1,97 @@
+/*****************************************************************************
+ * 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 "recent_media_model.hpp"
+#include <cassert>
+
+namespace {
+    enum Roles
+    {
+        MRLRole = Qt::UserRole
+    };
+}
+
+VLCRecentMediaModel::VLCRecentMediaModel(intf_thread_t *p_intf,QObject *parent)
+    : QAbstractListModel(parent)
+{
+    assert(p_intf);
+    rmrl = RecentsMRL::getInstance(p_intf);
+
+    connect(rmrl, SIGNAL(saved()), this, SLOT(update()));
+    connect(this, SIGNAL(limitChanged()), this, SLOT(update()));
+
+    update();
+}
+
+int VLCRecentMediaModel::rowCount(QModelIndex const & ) const
+{
+    return items.count();
+}
+
+QVariant VLCRecentMediaModel::data(QModelIndex const &index, const int role) const
+{
+    if (!index.isValid())
+        return {};
+    switch (role)
+    {
+        case MRLRole :
+            return QVariant::fromValue(items[index.row()]);
+        default :
+            return {};
+    }
+}
+
+QHash<int, QByteArray> VLCRecentMediaModel::roleNames() const
+{
+    QHash<int, QByteArray> roleNames;
+    roleNames.insert(MRLRole, "mrl");
+    return roleNames;
+}
+
+void VLCRecentMediaModel::clear()
+{
+    if (!items.isEmpty())
+    {
+        rmrl->clear();
+        update();
+    }
+}
+
+void VLCRecentMediaModel::update()
+{
+    beginResetModel();
+    items = rmrl->recentList().mid(0,i_limit);
+    endResetModel();
+}
+
+QStringList VLCRecentMediaModel::getItems()
+{
+    return items;
+}
+
+int VLCRecentMediaModel::getLimit() const
+{
+    return i_limit; 
+}
+
+void VLCRecentMediaModel::setLimit(int l)
+{
+    i_limit = l;
+    update();
+    emit limitChanged();
+}
diff --git a/modules/gui/qt/components/recent_media_model.hpp b/modules/gui/qt/components/recent_media_model.hpp
new file mode 100644
index 0000000000..c37fae9b77
--- /dev/null
+++ b/modules/gui/qt/components/recent_media_model.hpp
@@ -0,0 +1,69 @@
+/*****************************************************************************
+ * 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 VLC_RECENT_MEDIA_MODEL_HPP
+#define VLC_RECENT_MEDIA_MODEL_HPP
+
+#ifdef HAVE_CONFIG_H
+
+# include "config.h"
+
+#endif
+
+#include "qt.hpp"
+#include <QAbstractListModel>
+
+#include <QObject>
+#include <QStringList>
+#include "recents.hpp"
+
+class VLCRecentMediaModel : public QAbstractListModel
+{
+    Q_OBJECT
+    Q_PROPERTY(int limit READ getLimit WRITE setLimit NOTIFY limitChanged)
+
+public:
+    VLCRecentMediaModel(intf_thread_t *p_intf,QObject * parent = nullptr);
+
+    Q_INVOKABLE void clear();
+
+    Q_INVOKABLE int rowCount(QModelIndex const &parent = {}) const  override;
+
+    QVariant data(QModelIndex const &index, const int role = Qt::DisplayRole) const  override;
+
+    QHash<int, QByteArray> roleNames() const override;
+
+    QStringList items;
+
+    void setLimit(int l);
+    int getLimit() const;
+
+private:
+    RecentsMRL *rmrl;
+    int i_limit = 10;
+
+signals:
+    void limitChanged();
+
+public slots:
+    void update();
+    QStringList getItems();
+
+};
+
+#endif // VLC_RECENT_MEDIA_MODEL_HPP
diff --git a/modules/gui/qt/dialogs_provider.cpp b/modules/gui/qt/dialogs_provider.cpp
index 17d6b35a44..58c88a7c1f 100644
--- a/modules/gui/qt/dialogs_provider.cpp
+++ b/modules/gui/qt/dialogs_provider.cpp
@@ -566,8 +566,6 @@ QString DialogsProvider::getDirectoryDialog( intf_thread_t *p_intf )
     dir = qfu( uri );
     free( uri );
 
-    RecentsMRL::getInstance( p_intf )->addRecent( dir );
-
     return dir;
 }
 
diff --git a/modules/gui/qt/main_interface.cpp b/modules/gui/qt/main_interface.cpp
index 7f135f93ba..ac56e3bc2d 100644
--- a/modules/gui/qt/main_interface.cpp
+++ b/modules/gui/qt/main_interface.cpp
@@ -51,6 +51,7 @@
 #include "components/mediacenter/mlgenremodel.hpp"
 #include "components/mediacenter/mlvideomodel.hpp"
 #include "components/mediacenter/mlnetworkmodel.hpp"
+#include "components/recent_media_model.hpp"
 
 #include "components/navigation_history.hpp"
 #include "components/aboutmodel.hpp"
@@ -63,7 +64,6 @@
 #include "util/qmleventfilter.hpp"
 
 #include "menus.hpp"                            // Menu creation
-#include "recents.hpp"                          // RecentItems when DnD
 
 #include <QCloseEvent>
 #include <QKeyEvent>
@@ -379,6 +379,7 @@ void MainInterface::createMainWidget( QSettings * )
     rootCtx->setContextProperty( "rootQMLView", mediacenterView);
     rootCtx->setContextProperty( "rootWindow", this);
     rootCtx->setContextProperty( "dialogProvider", DialogsProvider::getInstance());
+    rootCtx->setContextProperty( "recentsMedias",  new VLCRecentMediaModel( p_intf, this ));
 
     if (b_hasMedialibrary)
     {
diff --git a/modules/gui/qt/qml/menus/MainDropdownMenu.qml b/modules/gui/qt/qml/menus/MainDropdownMenu.qml
index 4ea0025281..8df4e56c20 100644
--- a/modules/gui/qt/qml/menus/MainDropdownMenu.qml
+++ b/modules/gui/qt/qml/menus/MainDropdownMenu.qml
@@ -21,7 +21,8 @@ import QtQuick.Controls 2.4
 import "qrc:///utils/" as Utils
 
 //main menus, to be used as a dropdown menu
-Utils.MenuExt {
+Utils.MenuExt {    
+    id: mainDropdownMenu
     //make the menu modal, as we are not attached to a QQuickWindow
     modal: true
     closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
diff --git a/modules/gui/qt/qml/menus/MediaMenu.qml b/modules/gui/qt/qml/menus/MediaMenu.qml
index 8414b14f8b..8f95dc19ee 100644
--- a/modules/gui/qt/qml/menus/MediaMenu.qml
+++ b/modules/gui/qt/qml/menus/MediaMenu.qml
@@ -30,7 +30,41 @@ Utils.MenuExt {
     Action { text: qsTr("Open &Capture Device...");       onTriggered: dialogProvider.openCaptureDialog();         icon.source:"qrc:/type/capture-card.svg"; shortcut: "Ctrl+C" }
     Action { text: qsTr("Open &Location from clipboard"); onTriggered: dialogProvider.openUrlDialog();                                                       shortcut: "Ctrl+V" }
 
-    /* FIXME recent */
+
+    Utils.MenuExt {
+        id: recentsMenu
+        title: qsTr("Open &Recent Media")
+        property bool hasData: true
+        onAboutToShow:{
+            recentsMenu.hasData = Boolean(recentsMedias.rowCount())
+        }
+        Instantiator {
+            model: recentsMedias
+            Utils.MenuItemExt {
+                text: mrl
+                onTriggered:{
+                    mainDropdownMenu.close() //needed since menuItem isn't a direct child of a menu
+                    mainPlaylistController.append([mrl], true)
+                }
+
+                Shortcut {
+                    sequence: "Ctrl+" + (index + 1)
+                    onActivated:  mainPlaylistController.append([mrl], true)
+                    context: Qt.ApplicationShortcut
+                }
+            }
+            onObjectAdded: recentsMenu.insertItem(recentsMenu.count - 2, object)
+            onObjectRemoved: recentsMenu.removeItem(object)
+        }
+
+        MenuSeparator{}
+
+        Utils.MenuItemExt {
+            text: qsTr("Clear")
+            enabled: recentsMenu.hasData
+            onTriggered:recentsMedias.clear()
+        }
+    }
 
     Action { text: qsTr("Save Playlist to &File...");     onTriggered: dialogProvider.savePlayingToPlaylist();     icon.source: "";                      shortcut: "Ctrl+Y" }
     Action { text: qsTr("Conve&rt / Save..." );           onTriggered: dialogProvider.openAndTranscodingDialogs(); icon.source: "";                      shortcut: "Ctrl+R" }
diff --git a/modules/gui/qt/recents.cpp b/modules/gui/qt/recents.cpp
index 0857bbba76..4ba7d38fb1 100644
--- a/modules/gui/qt/recents.cpp
+++ b/modules/gui/qt/recents.cpp
@@ -158,6 +158,7 @@ void RecentsMRL::save()
 {
     getSettings()->setValue( "RecentsMRL/list", recents );
     getSettings()->setValue( "RecentsMRL/times", times );
+    emit saved();
 }
 
 void RecentsMRL::playMRL( const QString &mrl )
diff --git a/modules/gui/qt/recents.hpp b/modules/gui/qt/recents.hpp
index 86215f21ff..bb2286ca2c 100644
--- a/modules/gui/qt/recents.hpp
+++ b/modules/gui/qt/recents.hpp
@@ -54,16 +54,16 @@ class RecentsMRL : public QObject, public Singleton<RecentsMRL>
     friend class Singleton<RecentsMRL>;
 
 public:
+    
     void addRecent( const QString & );
-    QStringList recentList();
     QSignalMapper *signalMapper;
 
     vlc_tick_t time( const QString &mrl );
     void setTime( const QString &mrl, const vlc_tick_t time );
+    virtual ~RecentsMRL();
 
 private:
     RecentsMRL( intf_thread_t* _p_intf );
-    virtual ~RecentsMRL();
 
     intf_thread_t *p_intf;
 
@@ -74,8 +74,11 @@ private:
 
     void load();
     void save();
-
+     
+signals:
+       void saved();
 public slots:
+    QStringList recentList();
     void clear();
     void playMRL( const QString & );
 };
-- 
2.19.1



More information about the vlc-devel mailing list