[vlc-devel] [PATCH 10/12] qt: move qml initialisation out of the main interface

Pierre Lamot pierre at videolabs.io
Mon May 11 18:05:00 CEST 2020


---
 modules/gui/qt/Makefile.am              |   3 +
 modules/gui/qt/maininterface/mainui.cpp | 249 ++++++++++++++++++++++++
 modules/gui/qt/maininterface/mainui.hpp |  76 ++++++++
 3 files changed, 328 insertions(+)
 create mode 100644 modules/gui/qt/maininterface/mainui.cpp
 create mode 100644 modules/gui/qt/maininterface/mainui.hpp

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index ce4fd5232b..5ae373c529 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -120,6 +120,8 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/maininterface/compositor_dummy.cpp \
 	gui/qt/maininterface/main_interface.cpp \
 	gui/qt/maininterface/main_interface.hpp \
+	gui/qt/maininterface/mainui.cpp \
+	gui/qt/maininterface/mainui.hpp \
 	gui/qt/maininterface/videosurface.cpp \
 	gui/qt/maininterface/videosurface.hpp \
 	gui/qt/medialibrary/medialib.cpp \
@@ -278,6 +280,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/dialogs/toolbar/toolbareditor.moc.cpp \
 	gui/qt/maininterface/compositor_dummy.moc.cpp \
 	gui/qt/maininterface/main_interface.moc.cpp \
+	gui/qt/maininterface/mainui.moc.cpp \
 	gui/qt/maininterface/videosurface.moc.cpp \
 	gui/qt/medialibrary/medialib.moc.cpp \
 	gui/qt/medialibrary/mlalbum.moc.cpp \
diff --git a/modules/gui/qt/maininterface/mainui.cpp b/modules/gui/qt/maininterface/mainui.cpp
new file mode 100644
index 0000000000..4c202bb4ef
--- /dev/null
+++ b/modules/gui/qt/maininterface/mainui.cpp
@@ -0,0 +1,249 @@
+#include "mainui.hpp"
+
+#include <cassert>
+
+#include "medialibrary/medialib.hpp"
+#include "medialibrary/mlqmltypes.hpp"
+#include "medialibrary/mlalbummodel.hpp"
+#include "medialibrary/mlartistmodel.hpp"
+#include "medialibrary/mlalbumtrackmodel.hpp"
+#include "medialibrary/mlgenremodel.hpp"
+#include "medialibrary/mlvideomodel.hpp"
+#include "medialibrary/mlrecentsvideomodel.hpp"
+#include "medialibrary/mlfoldersmodel.hpp"
+
+#include "player/player_controller.hpp"
+#include "player/playercontrolbarmodel.hpp"
+
+#include "playlist/playlist_model.hpp"
+#include "playlist/playlist_controller.hpp"
+
+#include "util/qml_main_context.hpp"
+#include "util/qmleventfilter.hpp"
+#include "util/i18n.hpp"
+#include "util/systempalette.hpp"
+#include "util/recent_media_model.hpp"
+#include "util/settings.hpp"
+#include "util/navigation_history.hpp"
+
+#include "dialogs/help/aboutmodel.hpp"
+#include "dialogs/dialogs_provider.hpp"
+#include "dialogs/dialogs/dialogmodel.hpp"
+
+#include "network/networkmediamodel.hpp"
+#include "network/networkdevicemodel.hpp"
+
+#include "maininterface/main_interface.hpp"
+
+#include "videosurface.hpp"
+
+#include <QQuickWindow>
+#include <QQmlContext>
+#include <QQmlFileSelector>
+
+using  namespace vlc::playlist;
+
+namespace {
+
+template<class T>
+void registerAnonymousType( const char *uri, int versionMajor )
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+    qmlRegisterAnonymousType<T>( uri, versionMajor );
+#else
+    qmlRegisterType<T>();
+    VLC_UNUSED( uri );
+    VLC_UNUSED( versionMajor );
+#endif
+}
+
+} // anonymous namespace
+
+
+MainUI::MainUI(intf_thread_t *p_intf, MainInterface *mainInterface,  QObject *parent)
+    : QObject(parent)
+    , m_intf(p_intf)
+    , m_mainInterface(mainInterface)
+{
+    assert(m_intf);
+    assert(m_mainInterface);
+
+    m_settings = getSettings();
+
+    m_hasMedialibrary = (vlc_ml_instance_get( p_intf ) != NULL);
+
+    /* Get the available interfaces */
+    m_extraInterfaces = new VLCVarChoiceModel(p_intf, "intf-add", this);
+
+    /* */
+    m_playlistDocked = m_settings->value( "MainWindow/pl-dock-status", true ).toBool();
+    m_showRemainingTime = m_settings->value( "MainWindow/ShowRemainingTime", false ).toBool();
+
+    registerQMLTypes();
+}
+
+MainUI::~MainUI()
+{
+    /* Save states */
+
+    m_settings->beginGroup("MainWindow");
+    m_settings->setValue( "pl-dock-status", m_playlistDocked );
+    m_settings->setValue( "ShowRemainingTime", m_showRemainingTime );
+
+    /* Save playlist state */
+    m_settings->setValue( "playlist-visible", m_playlistVisible );
+
+    /* Save the stackCentralW sizes */
+    m_settings->endGroup();
+
+}
+
+bool MainUI::setup(QQmlEngine* engine)
+{
+    engine->setOutputWarningsToStandardError(false);
+    connect(engine, &QQmlEngine::warnings, this, &MainUI::onQmlWarning);
+
+    QQmlContext *rootCtx = engine->rootContext();
+
+    rootCtx->setContextProperty( "history", new NavigationHistory(engine) );
+    rootCtx->setContextProperty( "player", m_intf->p_sys->p_mainPlayerController );
+    rootCtx->setContextProperty( "i18n", new I18n(engine) );
+    rootCtx->setContextProperty( "mainctx", new QmlMainContext(m_intf, m_mainInterface, engine));
+    rootCtx->setContextProperty( "mainInterface", m_mainInterface);
+    rootCtx->setContextProperty( "topWindow", m_mainInterface->windowHandle());
+    rootCtx->setContextProperty( "dialogProvider", DialogsProvider::getInstance());
+    rootCtx->setContextProperty( "recentsMedias",  new VLCRecentMediaModel( m_intf, engine ));
+    rootCtx->setContextProperty( "settings",  new Settings( m_intf, engine ));
+    rootCtx->setContextProperty( "systemPalette", new SystemPalette(engine));
+
+    if (m_hasMedialibrary)
+        rootCtx->setContextProperty( "medialib", new MediaLib(m_intf, engine) );
+    else
+        rootCtx->setContextProperty( "medialib", nullptr );
+
+    m_component  = new QQmlComponent(engine, QStringLiteral("qrc:/main/MainInterface.qml"), QQmlComponent::PreferSynchronous, engine);
+    if (m_component->isLoading())
+    {
+        msg_Warn(m_intf, "component is still loading");
+    }
+
+    msg_Info(m_intf, "component state is %u", m_component->status());
+
+    if (m_component->isError())
+    {
+        for(auto& error: m_component->errors())
+            msg_Err(m_intf, "qml loading %s %s:%u", qtu(error.description()), qtu(error.url().toString()), error.line());
+#ifdef QT_STATICPLUGIN
+            assert( !"Missing qml modules from qt contribs." );
+#else
+            msg_Err( m_intf, "Install missing modules using your packaging tool" );
+#endif
+        return false;
+    }
+
+    QObject* rootObject = m_component->create();
+
+
+    if (m_component->isError())
+    {
+        for(auto& error: m_component->errors())
+            msg_Err(m_intf, "qml loading %s %s:%u", qtu(error.description()), qtu(error.url().toString()), error.line());
+        return false;
+    }
+
+    if (rootObject == nullptr)
+    {
+        msg_Err(m_intf, "unable to create main interface, no root item");
+        return false;
+    }
+    m_rootItem = qobject_cast<QQuickItem*>(rootObject);
+    if (!m_rootItem)
+    {
+        msg_Err(m_intf, "unexpected type of qml root item");
+        return false;
+    }
+
+    return true;
+}
+
+
+void MainUI::registerQMLTypes()
+{
+    qRegisterMetaType<VLCTick>();
+    qmlRegisterUncreatableType<VLCTick>("org.videolan.vlc", 0, 1, "VLCTick", "");
+
+    qmlRegisterType<VideoSurface>("org.videolan.vlc", 0, 1, "VideoSurface");
+
+    if (m_hasMedialibrary)
+    {
+        qRegisterMetaType<MLParentId>();
+        qmlRegisterType<MLAlbumModel>( "org.videolan.medialib", 0, 1, "MLAlbumModel" );
+        qmlRegisterType<MLArtistModel>( "org.videolan.medialib", 0, 1, "MLArtistModel" );
+        qmlRegisterType<MLAlbumTrackModel>( "org.videolan.medialib", 0, 1, "MLAlbumTrackModel" );
+        qmlRegisterType<MLGenreModel>( "org.videolan.medialib", 0, 1, "MLGenreModel" );
+        qmlRegisterType<MLVideoModel>( "org.videolan.medialib", 0, 1, "MLVideoModel" );
+        qmlRegisterType<MLRecentsVideoModel>( "org.videolan.medialib", 0, 1, "MLRecentsVideoModel" );
+        qRegisterMetaType<NetworkTreeItem>();
+        qmlRegisterType<NetworkMediaModel>( "org.videolan.medialib", 0, 1, "NetworkMediaModel");
+        qmlRegisterType<NetworkDeviceModel>( "org.videolan.medialib", 0, 1, "NetworkDeviceModel");
+        qmlRegisterType<MlFoldersModel>( "org.videolan.medialib", 0, 1, "MLFolderModel");
+
+        //expose base object, they aren't instanciable from QML side
+        registerAnonymousType<MLAlbum>("org.videolan.medialib", 1);
+        registerAnonymousType<MLArtist>("org.videolan.medialib", 1);
+        registerAnonymousType<MLAlbumTrack>("org.videolan.medialib", 1);
+        registerAnonymousType<MLGenre>("org.videolan.medialib", 1);
+        registerAnonymousType<MLVideo>("org.videolan.medialib", 1);
+    }
+
+    qmlRegisterUncreatableType<NavigationHistory>("org.videolan.vlc", 0, 1, "History", "Type of global variable history" );
+
+    qmlRegisterUncreatableType<TrackListModel>("org.videolan.vlc", 0, 1, "TrackListModel", "available tracks of a media (audio/video/sub)" );
+    qmlRegisterUncreatableType<TitleListModel>("org.videolan.vlc", 0, 1, "TitleListModel", "available titles of a media" );
+    qmlRegisterUncreatableType<ChapterListModel>("org.videolan.vlc", 0, 1, "ChapterListModel", "available titles of a media" );
+    qmlRegisterUncreatableType<ProgramListModel>("org.videolan.vlc", 0, 1, "ProgramListModel", "available programs of a media" );
+    qmlRegisterUncreatableType<VLCVarChoiceModel>("org.videolan.vlc", 0, 1, "VLCVarChoiceModel", "generic variable with choice model" );
+    qmlRegisterUncreatableType<PlayerController>("org.videolan.vlc", 0, 1, "PlayerController", "player controller" );
+
+    qRegisterMetaType<PlaylistPtr>();
+    qRegisterMetaType<PlaylistItem>();
+    qmlRegisterUncreatableType<PlaylistItem>("org.videolan.vlc", 0, 1, "PlaylistItem", "");
+    qmlRegisterType<PlaylistListModel>( "org.videolan.vlc", 0, 1, "PlaylistListModel" );
+    qmlRegisterType<PlaylistControllerModel>( "org.videolan.vlc", 0, 1, "PlaylistControllerModel" );
+
+    qmlRegisterType<AboutModel>( "org.videolan.vlc", 0, 1, "AboutModel" );
+    qRegisterMetaType<DialogId>();
+    qmlRegisterType<DialogModel>("org.videolan.vlc", 0, 1, "DialogModel");
+
+    qmlRegisterType<QmlEventFilter>( "org.videolan.vlc", 0, 1, "EventFilter" );
+
+    qmlRegisterType<PlayerControlBarModel>( "org.videolan.vlc", 0, 1, "PlayerControlBarModel");
+}
+
+void MainUI::onQmlWarning(const QList<QQmlError>& qmlErrors)
+{
+    for (auto& error: qmlErrors)
+    {
+        msg_Warn( m_intf, "qml error %s:%i %s", qtu(error.url().toString()), error.line(), qtu(error.description()) );
+    }
+}
+
+void MainUI::setPlaylistDocked( bool docked )
+{
+    m_playlistDocked = docked;
+
+    emit playlistDockedChanged(docked);
+}
+
+void MainUI::setPlaylistVisible( bool visible )
+{
+    m_playlistVisible = visible;
+
+    emit playlistVisibleChanged(visible);
+}
+
+void MainUI::setShowRemainingTime( bool show )
+{
+    m_showRemainingTime = show;
+    emit showRemainingTimeChanged(show);
+}
diff --git a/modules/gui/qt/maininterface/mainui.hpp b/modules/gui/qt/maininterface/mainui.hpp
new file mode 100644
index 0000000000..07decfdaea
--- /dev/null
+++ b/modules/gui/qt/maininterface/mainui.hpp
@@ -0,0 +1,76 @@
+#ifndef MAINUI_HPP
+#define MAINUI_HPP
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "qt.hpp"
+
+#include <QObject>
+#include <QQmlEngine>
+#include <QQmlError>
+#include <QQuickItem>
+
+class VLCVarChoiceModel;
+
+class MainUI : public QObject
+{
+    Q_OBJECT
+
+    Q_PROPERTY(bool playlistDocked READ isPlaylistDocked WRITE setPlaylistDocked NOTIFY playlistDockedChanged)
+    Q_PROPERTY(bool playlistVisible READ isPlaylistVisible WRITE setPlaylistVisible NOTIFY playlistVisibleChanged)
+    Q_PROPERTY(bool showRemainingTime READ isShowRemainingTime WRITE setShowRemainingTime NOTIFY showRemainingTimeChanged)
+
+    Q_PROPERTY(VLCVarChoiceModel* extraInterfaces READ getExtraInterfaces CONSTANT)
+
+public:
+    explicit MainUI(intf_thread_t *_p_intf, MainInterface* mainInterface, QObject *parent = nullptr);
+    ~MainUI();
+
+    bool setup(QQmlEngine* engine);
+
+    inline QQmlComponent* getComponent() const {return m_component;}
+    inline QQuickItem* getRootObject() const { return m_rootItem; }
+
+public slots:
+    inline bool isPlaylistDocked() const { return m_playlistDocked; }
+    inline bool isPlaylistVisible() const { return m_playlistVisible; }
+    inline bool isShowRemainingTime() const  { return m_showRemainingTime; }
+    inline VLCVarChoiceModel* getExtraInterfaces() const { return m_extraInterfaces; };
+
+    void setPlaylistDocked( bool );
+    void setPlaylistVisible( bool );
+    void setShowRemainingTime( bool );
+
+
+signals:
+    void playlistDockedChanged(bool);
+    void playlistVisibleChanged(bool);
+    void showRemainingTimeChanged(bool);
+
+private slots:
+    void onQmlWarning(const QList<QQmlError>& errors);
+
+private:
+    void registerQMLTypes();
+
+    intf_thread_t* m_intf;
+    MainInterface* m_mainInterface;
+
+    QQmlEngine* m_engine;
+    QQmlComponent* m_component;
+    QQuickItem* m_rootItem;
+
+    QSettings* m_settings;
+
+    bool m_hasMedialibrary;
+
+    bool m_playlistDocked = false;
+    bool m_playlistVisible = false;
+    bool m_showRemainingTime = false;
+    VLCVarChoiceModel* m_extraInterfaces = nullptr;
+
+};
+
+#endif // MAINUI_HPP
-- 
2.25.1



More information about the vlc-devel mailing list