[vlc-devel] [PATCH 2/2] Qt GUI: implemented cloud tab.

Paweł Wegner pawel.wegner95 at gmail.com
Thu Oct 27 23:18:04 CEST 2016


---
 include/vlc_interface.h                      |   1 +
 modules/gui/qt/Makefile.am                   |   2 +
 modules/gui/qt/components/open_panels.cpp    | 233 +++++++++++++++++++++++++++
 modules/gui/qt/components/open_panels.hpp    |  71 ++++++++
 modules/gui/qt/dialogs/open.cpp              |  15 ++
 modules/gui/qt/dialogs/open.hpp              |   4 +
 modules/gui/qt/dialogs_provider.cpp          |   7 +
 modules/gui/qt/dialogs_provider.hpp          |   1 +
 modules/gui/qt/menus.cpp                     |   4 +
 modules/gui/qt/pixmaps/types/type_cloud.png  | Bin 0 -> 252 bytes
 modules/gui/qt/pixmaps/types/type_cloud.svgz | Bin 0 -> 448 bytes
 modules/gui/qt/ui/open_cloud.ui              |  19 +++
 modules/gui/qt/vlc.qrc                       |   1 +
 13 files changed, 358 insertions(+)
 create mode 100644 modules/gui/qt/pixmaps/types/type_cloud.png
 create mode 100644 modules/gui/qt/pixmaps/types/type_cloud.svgz
 create mode 100644 modules/gui/qt/ui/open_cloud.ui

diff --git a/include/vlc_interface.h b/include/vlc_interface.h
index a4006f0..d42a19a 100644
--- a/include/vlc_interface.h
+++ b/include/vlc_interface.h
@@ -118,6 +118,7 @@ typedef enum vlc_intf_dialog {
     INTF_DIALOG_NET,
     INTF_DIALOG_CAPTURE,
     INTF_DIALOG_SAT,
+    INTF_DIALOG_CLOUD,
     INTF_DIALOG_DIRECTORY,
 
     INTF_DIALOG_STREAMWIZARD,
diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index ab413ac..36525f3 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -213,6 +213,7 @@ nodist_libqt_plugin_la_SOURCES += \
 	ui/open_disk.h \
 	ui/open_net.h \
 	ui/open_capture.h \
+	ui/open_cloud.h \
 	ui/open.h \
 	ui/vlm.h \
 	ui/podcast_configuration.h \
@@ -253,6 +254,7 @@ libqt_plugin_la_UI = \
 	ui/open_disk.ui \
 	ui/open_net.ui \
 	ui/open_capture.ui \
+	ui/open_cloud.ui \
 	ui/open.ui \
 	ui/podcast_configuration.ui \
 	ui/profiles.ui \
diff --git a/modules/gui/qt/components/open_panels.cpp b/modules/gui/qt/components/open_panels.cpp
index 9f05548..e60dbbf 100644
--- a/modules/gui/qt/components/open_panels.cpp
+++ b/modules/gui/qt/components/open_panels.cpp
@@ -53,6 +53,7 @@
 #include <QUrl>
 #include <QMimeData>
 #include <QDropEvent>
+#include <QDesktopServices>
 
 #define I_DEVICE_TOOLTIP \
     I_DIR_OR_FOLDER( N_("Select a device or a VIDEO_TS directory"), \
@@ -1403,3 +1404,235 @@ void CaptureOpenPanel::advancedDialog()
     module_config_free( p_config );
 }
 
+#ifdef WITH_LIBCLOUDSTORAGE
+
+using cloudstorage::IItem;
+using cloudstorage::ICloudProvider;
+
+namespace
+{
+class CloudCallback : public cloudstorage::ICloudProvider::ICallback
+{
+public:
+    Status userConsentRequired( const ICloudProvider& provider ) override
+    {
+        QDesktopServices::openUrl( QUrl( provider.authorizeLibraryUrl().c_str() ) );
+        return Status::WaitForAuthorizationCode;
+    }
+
+    void accepted( const ICloudProvider& ) override
+    {
+    }
+
+    void declined( const ICloudProvider& ) override
+    {
+    }
+
+    void error( const ICloudProvider&,
+                const std::string& ) override
+    {
+    }
+};
+
+class CloudListDirectoryCallback : public cloudstorage::IListDirectoryCallback {
+public:
+    CloudListDirectoryCallback( DirectoryModel *model ) : model( model )
+    {
+    }
+
+    void receivedItem( IItem::Pointer item ) override
+    {
+        model->addItem( item );
+    }
+
+    void done( const std::vector<IItem::Pointer>& ) override
+    {
+    }
+
+    void error( const std::string& ) override
+    {
+    }
+
+private:
+    DirectoryModel* model;
+};
+} // namespace
+
+CloudOpenPanel::CloudOpenPanel( QWidget *parent, intf_thread_t *t ) :
+                                  OpenPanel( parent, t )
+{
+    cloudStorage = cloudstorage::ICloudStorage::create();
+    QWidget* selectProvider = new QWidget( this );
+    QVBoxLayout* selectProviderLayout = new QVBoxLayout;
+    for ( auto t : cloudStorage->providers() )
+    {
+        QSettings settings;
+        std::string token = settings.value( t->name().c_str() ).toString().toStdString();
+        t->initialize( {token, std::unique_ptr<CloudCallback>( new CloudCallback ),
+                       nullptr, nullptr, nullptr, {}} );
+        QPushButton* button = new QPushButton( t->name().c_str() );
+        selectProviderLayout->addWidget( button );
+        connect( button, &QPushButton::pressed, this, &CloudOpenPanel::buttonClicked );
+    }
+    selectProvider->setLayout( selectProviderLayout );
+    CloudListView* selectFile = new CloudListView( this );
+    selectFile->setModel( &directoryModel );
+    connect( selectFile, &QListView::doubleClicked, this, &CloudOpenPanel::itemClicked );
+    connect( selectFile, &CloudListView::selectedItemChanged, this, &CloudOpenPanel::selectionChanged );
+    QHBoxLayout* mainLayout = new QHBoxLayout( this );
+    mainLayout->addWidget( selectProvider );
+    mainLayout->addWidget( selectFile );
+    setLayout( mainLayout );
+    ui.setupUi( this );
+}
+
+CloudOpenPanel::~CloudOpenPanel()
+{
+    save();
+}
+
+void CloudOpenPanel::save()
+{
+    if ( currentProvider )
+    {
+        QSettings settings;
+        settings.setValue( currentProvider->name().c_str(), currentProvider->token().c_str() );
+    }
+}
+
+void CloudOpenPanel::clear()
+{
+    emit mrlUpdated( QStringList(), "" );
+}
+
+void CloudOpenPanel::keyPressEvent( QKeyEvent *e )
+{
+    OpenPanel::keyPressEvent( e );
+    if ( !e->isAccepted() && e->key() == Qt::Key_Backspace )
+    {
+        if ( !directoryStack.empty() )
+        {
+            currentDirectory = directoryStack.back();
+            directoryStack.pop_back();
+            listDirectory();
+        }
+        else
+        {
+            directoryModel.clear();
+            currentDirectory = nullptr;
+            currentProvider = nullptr;
+        }
+        emit mrlUpdated( QStringList(), "" );
+        e->accept();
+    }
+}
+
+void CloudOpenPanel::buttonClicked()
+{
+    save();
+    directoryStack.clear();
+    QPushButton* button = static_cast<QPushButton*>( sender() );
+    currentProvider = cloudStorage->provider( button->text().toStdString() );
+    currentDirectory = currentProvider->rootDirectory();
+    listDirectory();
+}
+
+void CloudOpenPanel::itemClicked( const QModelIndex& index )
+{
+    auto item = directoryModel.get( index.row() );
+    if ( item->type() == cloudstorage::IItem::FileType::Directory )
+    {
+        directoryStack.push_back( currentDirectory );
+        currentDirectory = item;
+        listDirectory();
+    }
+    else
+    {
+        itemDataRequest = currentProvider->getItemDataAsync( item->id(), [this]( IItem::Pointer i ) {
+            if ( !i ) return;
+            QStringList list;
+            list << i->url().c_str();
+            emit methodChanged( qfu( "network-caching" ) );
+            emit mrlUpdated( list, "" );
+        } );
+    }
+}
+
+void CloudOpenPanel::selectionChanged()
+{
+    emit mrlUpdated( QStringList(), "" );
+}
+
+void CloudOpenPanel::listDirectory()
+{
+    directoryModel.clear();
+    std::unique_ptr<CloudListDirectoryCallback> callback( new CloudListDirectoryCallback( &directoryModel ) );
+    listDirectoryRequest = currentProvider->listDirectoryAsync( currentDirectory,
+                                                                std::move( callback ) );
+}
+
+void CloudOpenPanel::updateMRL()
+{
+    emit mrlUpdated( QStringList(), "" );
+}
+
+void CloudListView::selectionChanged( const QItemSelection&, const QItemSelection& )
+{
+    emit selectedItemChanged();
+}
+
+void DirectoryModel::addItem( IItem::Pointer item )
+{
+  beginInsertRows( QModelIndex(), rowCount(), rowCount() );
+  {
+    QMutexLocker lock( &mutex );
+    list.push_back( item );
+  }
+  endInsertRows();
+}
+
+IItem::Pointer DirectoryModel::get( int idx ) const
+{
+    QMutexLocker lock( &mutex );
+    return list[idx];
+}
+
+QVariant DirectoryModel::getName( int idx ) const
+{
+    QMutexLocker lock( &mutex );
+    return QString::fromStdString( list[idx]->filename() );
+}
+
+QVariant DirectoryModel::getIcon( int idx ) const
+{
+    QMutexLocker lock( &mutex );
+    auto item = list[idx];
+    if ( item->type() == IItem::FileType::Directory )
+        return QFileIconProvider().icon( QFileIconProvider::Folder );
+    else
+        return QFileIconProvider().icon( QFileIconProvider::File );
+}
+
+void DirectoryModel::clear()
+{
+    beginRemoveRows( QModelIndex(), 0, rowCount() - 1 );
+    list.clear();
+    endRemoveRows();
+}
+
+int DirectoryModel::rowCount( const QModelIndex & ) const
+{
+    QMutexLocker lock( &mutex );
+    return list.size();
+}
+
+QVariant DirectoryModel::data( const QModelIndex &index, int role ) const
+{
+    if ( role == Qt::DisplayRole )
+        return getName( index.row() );
+    else if ( role == Qt::DecorationRole )
+        return getIcon( index.row() );
+    return QVariant();
+}
+
+#endif
diff --git a/modules/gui/qt/components/open_panels.hpp b/modules/gui/qt/components/open_panels.hpp
index d124a25..542a3fc 100644
--- a/modules/gui/qt/components/open_panels.hpp
+++ b/modules/gui/qt/components/open_panels.hpp
@@ -38,11 +38,20 @@
 #include "ui/open_disk.h"
 #include "ui/open_net.h"
 #include "ui/open_capture.h"
+#include "ui/open_cloud.h"
 
 #include <QFileDialog>
+#include <QMutex>
 
 #include <limits.h>
 
+#ifdef WITH_LIBCLOUDSTORAGE
+  #include <ICloudStorage.h>
+  #include <ICloudProvider.h>
+  #include <IRequest.h>
+  #include <IItem.h>
+#endif
+
 #define setSpinBoxFreq( spinbox ){ spinbox->setRange ( 0, INT_MAX ); \
     spinbox->setAccelerated( true ); }
 
@@ -230,4 +239,66 @@ private slots:
     void advancedDialog();
 };
 
+#ifdef WITH_LIBCLOUDSTORAGE
+class DirectoryModel : public QAbstractListModel
+{
+public:
+    int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
+    QVariant data( const QModelIndex& index, int ) const override;
+    void addItem( cloudstorage::IItem::Pointer item );
+    cloudstorage::IItem::Pointer get( int ) const;
+    QVariant getName( int ) const;
+    QVariant getIcon( int ) const;
+    void clear();
+
+private:
+    mutable QMutex mutex;
+    std::vector<cloudstorage::IItem::Pointer> list;
+};
+
+class CloudListView : public QListView
+{
+    Q_OBJECT
+public:
+    using QListView::QListView;
+
+    void selectionChanged( const QItemSelection &selected, const QItemSelection &deselected ) override;
+
+signals:
+    void selectedItemChanged();
+};
+
+class CloudOpenPanel : public OpenPanel
+{
+    Q_OBJECT
+public:
+    CloudOpenPanel( QWidget *, intf_thread_t * );
+    ~CloudOpenPanel();
+
+    void save();
+    void clear();
+
+protected:
+    void keyPressEvent( QKeyEvent* ) override;
+
+private:
+    Ui::OpenCloud ui;
+    DirectoryModel directoryModel;
+    cloudstorage::ICloudStorage::Pointer cloudStorage;
+    cloudstorage::ICloudProvider::Pointer currentProvider;
+    cloudstorage::IItem::Pointer currentDirectory;
+    cloudstorage::ICloudProvider::ListDirectoryRequest::Pointer listDirectoryRequest;
+    cloudstorage::ICloudProvider::GetItemDataRequest::Pointer itemDataRequest;
+    std::vector<cloudstorage::IItem::Pointer> directoryStack;
+
+    void buttonClicked();
+    void itemClicked( const QModelIndex& );
+    void selectionChanged();
+    void listDirectory();
+
+public slots:
+    void updateMRL();
+};
+#endif
+
 #endif
diff --git a/modules/gui/qt/dialogs/open.cpp b/modules/gui/qt/dialogs/open.cpp
index 224cfa5..2625393 100644
--- a/modules/gui/qt/dialogs/open.cpp
+++ b/modules/gui/qt/dialogs/open.cpp
@@ -84,6 +84,9 @@ OpenDialog::OpenDialog( QWidget *parent,
     discOpenPanel    = new DiscOpenPanel( this, p_intf );
     netOpenPanel     = new NetOpenPanel( this, p_intf );
     captureOpenPanel = new CaptureOpenPanel( this, p_intf );
+#ifdef WITH_LIBCLOUDSTORAGE
+    cloudOpenPanel   = new CloudOpenPanel( this, p_intf );
+#endif
 
     /* Insert the tabs */
     ui.Tab->insertTab( OPEN_FILE_TAB, fileOpenPanel, QIcon( ":/type/file-asym" ),
@@ -94,6 +97,10 @@ OpenDialog::OpenDialog( QWidget *parent,
                        qtr( "&Network" ) );
     ui.Tab->insertTab( OPEN_CAPTURE_TAB, captureOpenPanel,
                        QIcon( ":/type/capture-card" ), qtr( "Capture &Device" ) );
+#ifdef WITH_LIBCLOUDSTORAGE
+    ui.Tab->insertTab( OPEN_CLOUD_TAB, cloudOpenPanel, QIcon( ":/type/cloud" ),
+                       qtr( "&Cloud" ) );
+#endif
 
     /* Hide the Slave input widgets */
     ui.slaveLabel->hide();
@@ -141,6 +148,10 @@ OpenDialog::OpenDialog( QWidget *parent,
              this, updateMRL( const QStringList&, const QString& ) );
     CONNECT( captureOpenPanel, mrlUpdated( const QStringList&, const QString& ),
              this, updateMRL( const QStringList&, const QString& ) );
+#ifdef WITH_LIBCLOUDSTORAGE
+    CONNECT( cloudOpenPanel, mrlUpdated( const QStringList&, const QString& ),
+             this, updateMRL( const QStringList&, const QString& ) );
+#endif
 
     CONNECT( fileOpenPanel, methodChanged( const QString& ),
              this, newCachingMethod( const QString& ) );
@@ -150,6 +161,10 @@ OpenDialog::OpenDialog( QWidget *parent,
              this, newCachingMethod( const QString& ) );
     CONNECT( captureOpenPanel, methodChanged( const QString& ),
              this, newCachingMethod( const QString& ) );
+#ifdef WITH_LIBCLOUDSTORAGE
+    CONNECT( cloudOpenPanel, methodChanged( const QString& ),
+             this, newCachingMethod( const QString& ) );
+#endif
 
     /* Advanced frame Connects */
     CONNECT( ui.slaveCheckbox, toggled( bool ), this, updateMRL() );
diff --git a/modules/gui/qt/dialogs/open.hpp b/modules/gui/qt/dialogs/open.hpp
index 0ce6f81..f292760 100644
--- a/modules/gui/qt/dialogs/open.hpp
+++ b/modules/gui/qt/dialogs/open.hpp
@@ -40,6 +40,7 @@ enum {
     OPEN_DISC_TAB,
     OPEN_NETWORK_TAB,
     OPEN_CAPTURE_TAB,
+    OPEN_CLOUD_TAB,
     OPEN_TAB_MAX
 };
 
@@ -98,6 +99,9 @@ private:
     NetOpenPanel *netOpenPanel;
     DiscOpenPanel *discOpenPanel;
     CaptureOpenPanel *captureOpenPanel;
+#ifdef WITH_LIBCLOUDSTORAGE
+    CloudOpenPanel *cloudOpenPanel;
+#endif
 
     int i_action_flag;
     bool b_pl;
diff --git a/modules/gui/qt/dialogs_provider.cpp b/modules/gui/qt/dialogs_provider.cpp
index 5951b65..ff1fc98 100644
--- a/modules/gui/qt/dialogs_provider.cpp
+++ b/modules/gui/qt/dialogs_provider.cpp
@@ -139,6 +139,8 @@ void DialogsProvider::customEvent( QEvent *event )
         case INTF_DIALOG_SAT:
         case INTF_DIALOG_CAPTURE:
             openCaptureDialog(); break;
+        case INTF_DIALOG_CLOUD:
+            openCloudDialog(); break;
         case INTF_DIALOG_DIRECTORY:
             PLAppendDir(); break;
         case INTF_DIALOG_PLAYLIST:
@@ -426,6 +428,11 @@ void DialogsProvider::openCaptureDialog()
     openDialog( OPEN_CAPTURE_TAB );
 }
 
+void DialogsProvider::openCloudDialog()
+{
+    openDialog( OPEN_CLOUD_TAB );
+}
+
 /* Same as the open one, but force the enqueue */
 void DialogsProvider::PLAppendDialog( int tab )
 {
diff --git a/modules/gui/qt/dialogs_provider.hpp b/modules/gui/qt/dialogs_provider.hpp
index 01faa11..46bc89f 100644
--- a/modules/gui/qt/dialogs_provider.hpp
+++ b/modules/gui/qt/dialogs_provider.hpp
@@ -153,6 +153,7 @@ public slots:
     void openUrlDialog();
     void openNetDialog();
     void openCaptureDialog();
+    void openCloudDialog();
 
     void PLAppendDialog( int tab = OPEN_FILE_TAB );
     void MLAppendDialog( int tab = OPEN_FILE_TAB );
diff --git a/modules/gui/qt/menus.cpp b/modules/gui/qt/menus.cpp
index 8af0317..78563ff 100644
--- a/modules/gui/qt/menus.cpp
+++ b/modules/gui/qt/menus.cpp
@@ -370,6 +370,10 @@ QMenu *VLCMenuBar::FileMenu( intf_thread_t *p_intf, QWidget *parent, MainInterfa
         ":/type/network", SLOT( openNetDialog() ), "Ctrl+N" );
     addDPStaticEntry( menu, qtr( "Open &Capture Device..." ),
         ":/type/capture-card", SLOT( openCaptureDialog() ), "Ctrl+C" );
+#ifdef WITH_LIBCLOUDSTORAGE
+    addDPStaticEntry( menu, qtr( "Open Cloud File..."),
+        ":/type/cloud", SLOT( openCloudDialog() ) );
+#endif
 
     addDPStaticEntry( menu, qtr( "Open &Location from clipboard" ),
                       NULL, SLOT( openUrlDialog() ), "Ctrl+V" );
diff --git a/modules/gui/qt/pixmaps/types/type_cloud.png b/modules/gui/qt/pixmaps/types/type_cloud.png
new file mode 100644
index 0000000000000000000000000000000000000000..f68cb091452b5a315ee2d411ac7a836545c6142a
GIT binary patch
literal 252
zcmeAS at N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf<Z~8yL>4nJ
za0`PlBg3pY5<tOuo-U3d7QI(58uBqZN*w(t&&9b^_(I1EnFG8naZ~uVs886 at 9-ukL
zY4L at VULq<QGg3C4Of!%EI4S&$&%gK8#)t2(4lJ-c#-u!F!ZhA>iLK#Jq|;m<2ykAL
zw6Jhh=g)gIhxypN;{g at Ta%C^3?TC}lmHEIkd$!Qz&3=!rRJS&8U)j%iT<GfNUB|jJ
uTgANX{>z#iU|HLAl0RqT`U}6rzp^R)a6cNT-Mkj)QU*^~KbLh*2~7a8Qd>X(

literal 0
HcmV?d00001

diff --git a/modules/gui/qt/pixmaps/types/type_cloud.svgz b/modules/gui/qt/pixmaps/types/type_cloud.svgz
new file mode 100644
index 0000000000000000000000000000000000000000..4258dd1fce7fe73b0ec7a3860a6e28144023a4c5
GIT binary patch
literal 448
zcmV;x0YCm9iwFpKToPCS17mD&b!0Acc4q)>P+f1FFcADJu3zp2ufG9bfk?TFqDpBS
zscEY|RRpX9g>ne!amlamnncw}tt_usyEC)1&aTeCI&$*k)E at hsN)VJ>71_J}=iS4P
z`x`Qy4usr)y}tXfBOAu~cfI3$|F9=tzTFZDlJlES8$veCJP%vWmt}!P!*M+D+p!#)
zwwgF1c|anIqnwmb&-JFrf^_5CLo?^pN;RA*Y3rQcmCt_sDJhxe=g#NU_vK^f*<)Ef
z9meDDzTWnJAp#GQ!hKIK{Uh<z`sMm~&glh+lBKQZ=I<ojdOHneg#(7sPkuc4wb)NN
z{dX57gb3c>Alq}-_D}x<O6MG3yR^uLa&8E2^ijJMWTdnPRS70RMFJF4VAfYdjMdmO
zD<Nf4CJ<w^ki6y<GcmFSOR*HG1PqhHfR5s%VyMduUIZ!@gJmj44NM5Bm~vo|XH6I`
z!7-ac8d(8$XA=}q+M*S$A{9G?V4{VqL_ny>2rM}PE=q%plZ{GZNIDUT${>#gP%6=-
qPO!gbsRl#H&ZGi;3Wy_P^g1WRi%)o=yvV|T7JmRtZbsyP0ssJ2!P9R5

literal 0
HcmV?d00001

diff --git a/modules/gui/qt/ui/open_cloud.ui b/modules/gui/qt/ui/open_cloud.ui
new file mode 100644
index 0000000..9844411
--- /dev/null
+++ b/modules/gui/qt/ui/open_cloud.ui
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>OpenCloud</class>
+ <widget class="QWidget" name="OpenCloud">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/modules/gui/qt/vlc.qrc b/modules/gui/qt/vlc.qrc
index fbf5bfd..30c4971 100644
--- a/modules/gui/qt/vlc.qrc
+++ b/modules/gui/qt/vlc.qrc
@@ -90,6 +90,7 @@
         <file alias="stream">pixmaps/types/type_stream.png</file>
         <file alias="node">pixmaps/types/type_node.png</file>
         <file alias="playlist">pixmaps/types/type_playlist.png</file>
+        <file alias="cloud">pixmaps/types/type_cloud.png</file>
     </qresource>
     <qresource prefix="/">
         <file alias="down_arrow">pixmaps/arrow_down_dark.png</file>
-- 
2.9.3



More information about the vlc-devel mailing list