[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