[vlc-commits] [Git][videolan/vlc][master] 8 commits: libvlccore.sym: Add vlc_media_tree_Add and vlc_media_tree_Remove
Steve Lhomme (@robUx4)
gitlab at videolan.org
Thu Nov 24 13:26:28 UTC 2022
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
df3c041e by Benjamin Arnaud at 2022-11-24T13:10:38+00:00
libvlccore.sym: Add vlc_media_tree_Add and vlc_media_tree_Remove
- - - - -
3318a931 by Benjamin Arnaud at 2022-11-24T13:10:38+00:00
qt/util: Create ClipListModel
This patch adds a helper template class for sorting and filtering QAbstractListModel
item(s). We tried implementing capping from a QSortFilterProxyModel and QML, but both
implementations had flaws:
- The QSortFilterProxyModel has a filterAcceptsRow function, but it does not work for
an item capping scenario.
- Regarding QML we found ways to make it work, but it felt hackish and brought
up issues on our items shadows.
Although a pure QML implementation could be done, a C++ implementation is probably
more elegant. Especially now that we are using a template that can fit several use
case scenarios.
Co-authored-by: Pierre Lamot <pierre at videolabs.io>
- - - - -
38196134 by Benjamin Arnaud at 2022-11-24T13:10:38+00:00
qt/network: Create StandardPathModel
- - - - -
616222e3 by Benjamin Arnaud at 2022-11-24T13:10:38+00:00
qml/BrowseDisplay: Add the 'browseFolders' component
- - - - -
1c89b040 by Benjamin Arnaud at 2022-11-24T13:10:38+00:00
qml/BrowseHomeDisplay: Add the standard paths section
- - - - -
d8dde8e8 by Benjamin Arnaud at 2022-11-24T13:10:38+00:00
qml/BrowseDeviceView: Add anchoring settings
Otherwise the ExpandGridView goes to an invalid height of -1 occasionaly.
- - - - -
1144ba36 by Benjamin Arnaud at 2022-11-24T13:10:38+00:00
qml/BrowseDeviceView: Update 'type' conditions for clarity
- - - - -
c49873e4 by Benjamin Arnaud at 2022-11-24T13:10:38+00:00
qt/networkdevicemodel: Update 'items' implementation
- - - - -
13 changed files:
- modules/gui/qt/Makefile.am
- modules/gui/qt/maininterface/mainui.cpp
- modules/gui/qt/network/networkdevicemodel.cpp
- modules/gui/qt/network/networkdevicemodel.hpp
- modules/gui/qt/network/qml/BrowseDeviceView.qml
- modules/gui/qt/network/qml/BrowseDisplay.qml
- modules/gui/qt/network/qml/BrowseHomeDisplay.qml
- + modules/gui/qt/network/standardpathmodel.cpp
- + modules/gui/qt/network/standardpathmodel.hpp
- + modules/gui/qt/util/cliplistmodel.cpp
- + modules/gui/qt/util/cliplistmodel.hpp
- po/POTFILES.in
- src/libvlccore.sym
Changes:
=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -243,6 +243,8 @@ libqt_plugin_la_SOURCES = \
gui/qt/network/networkmediamodel.hpp \
gui/qt/network/servicesdiscoverymodel.cpp \
gui/qt/network/servicesdiscoverymodel.hpp \
+ gui/qt/network/standardpathmodel.cpp \
+ gui/qt/network/standardpathmodel.hpp \
gui/qt/style/qtthemeprovider.hpp \
gui/qt/style/systempalette.cpp \
gui/qt/style/systempalette.hpp \
@@ -268,6 +270,8 @@ libqt_plugin_la_SOURCES = \
gui/qt/util/asynctask.hpp \
gui/qt/util/audio_device_model.cpp \
gui/qt/util/audio_device_model.hpp \
+ gui/qt/util/cliplistmodel.cpp \
+ gui/qt/util/cliplistmodel.hpp \
gui/qt/util/color_scheme_model.cpp gui/qt/util/color_scheme_model.hpp \
gui/qt/util/color_svg_image_provider.cpp gui/qt/util/color_svg_image_provider.hpp \
gui/qt/util/covergenerator.cpp \
@@ -456,6 +460,7 @@ nodist_libqt_plugin_la_SOURCES = \
gui/qt/network/networksourcesmodel.moc.cpp \
gui/qt/network/networkmediamodel.moc.cpp \
gui/qt/network/servicesdiscoverymodel.moc.cpp \
+ gui/qt/network/standardpathmodel.moc.cpp \
gui/qt/style/systempalette.moc.cpp \
gui/qt/player/input_models.moc.cpp \
gui/qt/player/player_controller.moc.cpp \
@@ -468,6 +473,7 @@ nodist_libqt_plugin_la_SOURCES = \
gui/qt/playlist/playlist_model.moc.cpp \
gui/qt/util/asynctask.moc.cpp \
gui/qt/util/audio_device_model.moc.cpp \
+ gui/qt/util/cliplistmodel.moc.cpp \
gui/qt/util/color_scheme_model.moc.cpp \
gui/qt/util/color_svg_image_provider.moc.cpp \
gui/qt/util/imageluminanceextractor.moc.cpp \
=====================================
modules/gui/qt/maininterface/mainui.cpp
=====================================
@@ -53,6 +53,7 @@
#include "network/networkdevicemodel.hpp"
#include "network/networksourcesmodel.hpp"
#include "network/servicesdiscoverymodel.hpp"
+#include "network/standardpathmodel.hpp"
#include "menus/qml_menu_wrapper.hpp"
@@ -254,6 +255,7 @@ void MainUI::registerQMLTypes()
qmlRegisterType<NetworkDeviceModel>( uri, versionMajor, versionMinor, "NetworkDeviceModel");
qmlRegisterType<NetworkSourcesModel>( uri, versionMajor, versionMinor, "NetworkSourcesModel");
qmlRegisterType<ServicesDiscoveryModel>( uri, versionMajor, versionMinor, "ServicesDiscoveryModel");
+ qmlRegisterType<StandardPathModel>( uri, versionMajor, versionMinor, "StandardPathModel");
qmlRegisterType<MLFoldersModel>( uri, versionMajor, versionMinor, "MLFolderModel");
qmlRegisterType<ImageLuminanceExtractor>( uri, versionMajor, versionMinor, "ImageLuminanceExtractor");
=====================================
modules/gui/qt/network/networkdevicemodel.cpp
=====================================
@@ -24,8 +24,9 @@
#include <maininterface/mainctx.hpp>
NetworkDeviceModel::NetworkDeviceModel( QObject* parent )
- : QAbstractListModel( parent )
+ : ClipListModel(parent)
{
+ m_comparator = ascendingName;
}
QVariant NetworkDeviceModel::data( const QModelIndex& index, int role ) const
@@ -33,7 +34,7 @@ QVariant NetworkDeviceModel::data( const QModelIndex& index, int role ) const
if (!m_ctx)
return {};
auto idx = index.row();
- if ( idx < 0 || (size_t)idx >= m_items.size() )
+ if ( idx < 0 || idx >= count() )
return {};
const auto& item = m_items[idx];
switch ( role )
@@ -70,15 +71,6 @@ QHash<int, QByteArray> NetworkDeviceModel::roleNames() const
};
}
-
-int NetworkDeviceModel::rowCount(const QModelIndex& parent) const
-{
- if ( parent.isValid() )
- return 0;
- return getCount();
-}
-
-
void NetworkDeviceModel::setCtx(MainCtx* ctx)
{
if (ctx) {
@@ -108,109 +100,6 @@ void NetworkDeviceModel::setSourceName(const QString& sourceName)
emit sourceNameChanged();
}
-int NetworkDeviceModel::getCount() const
-{
- return m_count;
-}
-
-int NetworkDeviceModel::maximumCount() const
-{
- return m_maximumCount;
-}
-
-void NetworkDeviceModel::setMaximumCount(int count)
-{
- if (m_maximumCount == count)
- return;
-
- if (count == -1 || m_maximumCount < count)
- {
- m_maximumCount = count;
-
- expandItems();
- }
- else
- {
- m_maximumCount = count;
-
- shrinkItems();
- }
-
- emit maximumCountChanged();
-}
-
-bool NetworkDeviceModel::hasMoreItems() const
-{
- if (m_maximumCount == -1)
- return false;
- else
- return ((size_t) m_count < m_items.size());
-}
-
-QString NetworkDeviceModel::searchPattern() const
-{
- return m_searchPattern;
-}
-
-void NetworkDeviceModel::setSearchPattern(const QString & pattern)
-{
- if (m_searchPattern == pattern)
- return;
-
- m_searchPattern = pattern;
-
- emit searchPatternChanged();
-}
-
-QByteArray NetworkDeviceModel::searchRole() const
-{
- return m_searchRole;
-}
-
-void NetworkDeviceModel::setSearchRole(const QByteArray & role)
-{
- if (m_searchRole == role)
- return;
-
- m_searchRole = role;
-
- emit searchRoleChanged();
-}
-
-QString NetworkDeviceModel::sortCriteria() const
-{
- return m_sortCriteria;
-}
-
-void NetworkDeviceModel::setSortCriteria(const QString & criteria)
-{
- if (m_sortCriteria == criteria)
- return;
-
- m_sortCriteria = criteria;
-
- updateSort();
-
- emit sortCriteriaChanged();
-}
-
-Qt::SortOrder NetworkDeviceModel::sortOrder() const
-{
- return m_sortOrder;
-}
-
-void NetworkDeviceModel::setSortOrder(Qt::SortOrder order)
-{
- if (m_sortOrder == order)
- return;
-
- m_sortOrder = order;
-
- updateSort();
-
- emit sortOrderChanged();
-}
-
bool NetworkDeviceModel::insertIntoPlaylist(const QModelIndexList &itemIdList, ssize_t playlistIndex)
{
if (!(m_ctx && m_sdSource != CAT_MYCOMPUTER))
@@ -222,7 +111,7 @@ bool NetworkDeviceModel::insertIntoPlaylist(const QModelIndexList &itemIdList, s
if ( !id.isValid() )
continue;
const int index = id.row();
- if ( index < 0 || (size_t)index >= m_items.size() )
+ if ( index < 0 || index >= count() )
continue;
medias.append( vlc::playlist::Media {m_items[index].inputItem.get()} );
@@ -237,7 +126,7 @@ bool NetworkDeviceModel::addToPlaylist(int index)
{
if (!(m_ctx && m_sdSource != CAT_MYCOMPUTER))
return false;
- if (index < 0 || (size_t)index >= m_items.size() )
+ if (index < 0 || index >= count() )
return false;
auto item = m_items[index];
vlc::playlist::Media media{ item.inputItem.get() };
@@ -271,12 +160,11 @@ bool NetworkDeviceModel::addToPlaylist(const QModelIndexList &itemIdList)
return ret;
}
-
bool NetworkDeviceModel::addAndPlay(int index)
{
if (!(m_ctx && m_sdSource != CAT_MYCOMPUTER))
return false;
- if (index < 0 || (size_t)index >= m_items.size() )
+ if (index < 0 || index >= count() )
return false;
auto item = m_items[index];
vlc::playlist::Media media{ item.inputItem.get() };
@@ -335,7 +223,7 @@ QVariantList NetworkDeviceModel::getItemsForIndexes(const QModelIndexList & inde
{
int index = modelIndex.row();
- if (index < 0 || (size_t) index >= m_items.size())
+ if (index < 0 || index >= count())
continue;
QmlInputItem input(m_items[index].inputItem.get(), true);
@@ -346,22 +234,34 @@ QVariantList NetworkDeviceModel::getItemsForIndexes(const QModelIndexList & inde
return items;
}
+// Protected ClipListModel implementation
+
+void NetworkDeviceModel::onUpdateSort(const QString & criteria, Qt::SortOrder order) /* override */
+{
+ if (criteria == "mrl")
+ {
+ if (order == Qt::AscendingOrder)
+ m_comparator = ascendingMrl;
+ else
+ m_comparator = descendingMrl;
+ }
+ else
+ {
+ if (order == Qt::AscendingOrder)
+ m_comparator = ascendingName;
+ else
+ m_comparator = descendingName;
+ }
+}
+
bool NetworkDeviceModel::initializeMediaSources()
{
auto libvlc = vlc_object_instance(m_ctx->getIntf());
m_listeners.clear();
- if (!m_items.empty()) {
- beginResetModel();
-
- m_items.clear();
-
- m_count = 0;
- endResetModel();
+ clearItems();
- emit countChanged();
- }
m_name = QString {};
auto provider = vlc_media_source_provider_Get( libvlc );
@@ -436,7 +336,8 @@ void NetworkDeviceModel::ListenerCb::onItemRemoved( MediaTreePtr tree, input_ite
for (auto p_item : itemList)
{
QUrl itemUri = QUrl::fromEncoded(p_item->psz_uri);
- auto it = std::find_if( begin( model->m_items ), end( model->m_items ), [p_item, itemUri](const Item& i) {
+ auto it = std::find_if( begin( model->m_items ), end( model->m_items ),
+ [p_item, itemUri](const NetworkDeviceItem & i) {
return QString::compare( qfu(p_item->psz_name), i.name, Qt::CaseInsensitive ) == 0 &&
itemUri.scheme() == i.mainMrl.scheme();
});
@@ -455,11 +356,10 @@ void NetworkDeviceModel::ListenerCb::onItemRemoved( MediaTreePtr tree, input_ite
continue;
auto idx = std::distance( begin( model->m_items ), it );
- model->removeItem(it, idx, implicitCount);
+ model->eraseItem(it, idx, implicitCount);
}
- if (model->m_maximumCount != -1)
- model->expandItems();
+ model->updateItems();
}, Qt::QueuedConnection);
}
@@ -475,14 +375,14 @@ void NetworkDeviceModel::refreshDeviceList(MediaSourcePtr mediaSource,
int index = 0;
- std::vector<Item>::iterator it = m_items.begin();
+ std::vector<NetworkDeviceItem>::iterator it = m_items.begin();
while (it != m_items.end())
{
if (it->mediaSource != mediaSource)
continue;
- removeItem(it, index, implicitCount);
+ eraseItem(it, index, implicitCount);
index++;
}
@@ -515,17 +415,17 @@ void NetworkDeviceModel::addItems(const std::vector<InputItemPtr> & inputList,
for (const InputItemPtr & inputItem : inputList)
{
- Item item;
+ NetworkDeviceItem item;
item.name = qfu(inputItem->psz_name);
item.mainMrl = QUrl::fromEncoded(inputItem->psz_uri);
- std::vector<Item>::iterator it;
+ std::vector<NetworkDeviceItem>::iterator it;
if (checkDuplicate)
{
- it = std::find_if(begin(m_items), end(m_items), [item](const Item & i)
+ it = std::find_if(begin(m_items), end(m_items), [item](const NetworkDeviceItem & i)
{
return matchItem(item, i);
});
@@ -566,59 +466,18 @@ void NetworkDeviceModel::addItems(const std::vector<InputItemPtr> & inputList,
free(artwork);
}
- int pos = std::distance(begin(m_items), it);
-
- if (m_maximumCount != -1 && m_count >= m_maximumCount)
- {
- // NOTE: When the position is beyond the maximum count we don't notify the view.
- if (pos >= m_maximumCount)
- {
- m_items.insert(it, std::move(item));
-
- continue;
- }
-
- // NOTE: Removing the last item to make room for the new one.
-
- int index = m_count - 1;
-
- beginRemoveRows({}, index, index);
-
- m_count--;
-
- endRemoveRows();
-
- emit countChanged();
- }
-
- beginInsertRows({}, pos, pos);
-
- m_items.insert(it, std::move(item));
-
- m_count++;
-
- endInsertRows();
-
- emit countChanged();
+ insertItem(it, std::move(item));
}
- if (m_maximumCount != -1)
- expandItems();
+ updateItems();
}
-void NetworkDeviceModel::removeItem(std::vector<Item>::iterator & it, int index, int count)
+void NetworkDeviceModel::eraseItem(std::vector<NetworkDeviceItem>::iterator & it,
+ int index, int count)
{
if (index < count)
{
- beginRemoveRows({}, index, index);
-
- it = m_items.erase(it);
-
- m_count--;
-
- endRemoveRows();
-
- emit countChanged();
+ removeItem(it, index);
}
// NOTE: We don't want to notify the view if the item's position is beyond the
// maximumCount.
@@ -626,82 +485,18 @@ void NetworkDeviceModel::removeItem(std::vector<Item>::iterator & it, int index,
it = m_items.erase(it);
}
-void NetworkDeviceModel::expandItems()
-{
- int count = implicitCount();
-
- if (m_count >= count)
- return;
-
- beginInsertRows({}, m_count, count - 1);
-
- m_count = count;
-
- endInsertRows();
-
- emit countChanged();
-}
-
-void NetworkDeviceModel::shrinkItems()
-{
- int count = implicitCount();
-
- if (m_count <= count)
- return;
-
- beginRemoveRows({}, count, m_count - 1);
-
- m_count = count;
-
- endRemoveRows();
-
- emit countChanged();
-}
-
-void NetworkDeviceModel::updateSort()
-{
- if (m_sortCriteria == "mrl")
- {
- if (m_sortOrder == Qt::AscendingOrder)
- m_comparator = ascendingMrl;
- else
- m_comparator = descendingMrl;
- }
- else
- {
- if (m_sortOrder == Qt::AscendingOrder)
- m_comparator = ascendingName;
- else
- m_comparator = descendingName;
- }
-
- beginResetModel();
-
- std::sort(m_items.begin(), m_items.end(), m_comparator);
-
- endResetModel();
-}
-
-int NetworkDeviceModel::implicitCount() const
-{
- assert(m_items.size() < INT32_MAX);
-
- if (m_maximumCount == -1)
- return (int) m_items.size();
- else
- return qMin((int) m_items.size(), m_maximumCount);
-}
-
// Private static function
-/* static */ bool NetworkDeviceModel::matchItem(const Item & a, const Item & b)
+/* static */ bool NetworkDeviceModel::matchItem(const NetworkDeviceItem & a,
+ const NetworkDeviceItem & b)
{
return (QString::compare(a.name, b.name, Qt::CaseInsensitive) == 0
&&
QString::compare(a.mainMrl.scheme(), b.mainMrl.scheme(), Qt::CaseInsensitive) == 0);
}
-/* static */ bool NetworkDeviceModel::ascendingName(const Item & a, const Item & b)
+/* static */ bool NetworkDeviceModel::ascendingName(const NetworkDeviceItem & a,
+ const NetworkDeviceItem & b)
{
int result = QString::compare(a.name, b.name, Qt::CaseInsensitive);
@@ -711,13 +506,15 @@ int NetworkDeviceModel::implicitCount() const
return (QString::compare(a.mainMrl.scheme(), b.mainMrl.scheme(), Qt::CaseInsensitive) <= 0);
}
-/* static */ bool NetworkDeviceModel::ascendingMrl(const Item & a, const Item & b)
+/* static */ bool NetworkDeviceModel::ascendingMrl(const NetworkDeviceItem & a,
+ const NetworkDeviceItem & b)
{
return (QString::compare(a.mainMrl.toString(),
b.mainMrl.toString(), Qt::CaseInsensitive) <= 0);
}
-/* static */ bool NetworkDeviceModel::descendingName(const Item & a, const Item & b)
+/* static */ bool NetworkDeviceModel::descendingName(const NetworkDeviceItem & a,
+ const NetworkDeviceItem & b)
{
int result = QString::compare(a.name, b.name, Qt::CaseInsensitive);
@@ -727,7 +524,8 @@ int NetworkDeviceModel::implicitCount() const
return (QString::compare(a.mainMrl.scheme(), b.mainMrl.scheme(), Qt::CaseInsensitive) >= 0);
}
-/* static */ bool NetworkDeviceModel::descendingMrl(const Item & a, const Item & b)
+/* static */ bool NetworkDeviceModel::descendingMrl(const NetworkDeviceItem & a,
+ const NetworkDeviceItem & b)
{
return (QString::compare(a.mainMrl.toString(),
b.mainMrl.toString(), Qt::CaseInsensitive) >= 0);
=====================================
modules/gui/qt/network/networkdevicemodel.hpp
=====================================
@@ -32,15 +32,24 @@
#include <vlc_cxx_helpers.hpp>
#include "mediatreelistener.hpp"
+#include "util/cliplistmodel.hpp"
#include <memory>
class MainCtx;
-class NetworkDeviceModel : public QAbstractListModel
+
+struct NetworkDeviceItem;
+
+class NetworkDeviceModel : public ClipListModel<NetworkDeviceItem>
{
Q_OBJECT
-public:
+ Q_PROPERTY(MainCtx* ctx READ getCtx WRITE setCtx NOTIFY ctxChanged FINAL)
+ Q_PROPERTY(SDCatType sd_source READ getSdSource WRITE setSdSource NOTIFY sdSourceChanged FINAL)
+ Q_PROPERTY(QString name READ getName NOTIFY nameChanged FINAL)
+ Q_PROPERTY(QString source_name READ getSourceName WRITE setSourceName NOTIFY sourceNameChanged FINAL)
+
+public: // Enums
enum Role {
NETWORK_NAME = Qt::UserRole + 1,
NETWORK_MRL,
@@ -74,36 +83,23 @@ public:
};
Q_ENUM( SDCatType )
+public: // Declarations
+ using MediaSourcePtr = vlc_shared_data_ptr_type(vlc_media_source_t,
+ vlc_media_source_Hold, vlc_media_source_Release);
- Q_PROPERTY(MainCtx* ctx READ getCtx WRITE setCtx NOTIFY ctxChanged FINAL)
- Q_PROPERTY(SDCatType sd_source READ getSdSource WRITE setSdSource NOTIFY sdSourceChanged FINAL)
- Q_PROPERTY(QString name READ getName NOTIFY nameChanged FINAL)
- Q_PROPERTY(QString source_name READ getSourceName WRITE setSourceName NOTIFY sourceNameChanged FINAL)
- Q_PROPERTY(int count READ getCount NOTIFY countChanged FINAL)
-
- Q_PROPERTY(int maximumCount READ maximumCount WRITE setMaximumCount NOTIFY maximumCountChanged
- FINAL)
-
- Q_PROPERTY(bool hasMoreItems READ hasMoreItems NOTIFY countChanged FINAL)
-
- Q_PROPERTY(QByteArray searchRole READ searchRole WRITE setSearchRole
- NOTIFY searchRoleChanged FINAL)
-
- Q_PROPERTY(QString searchPattern READ searchPattern WRITE setSearchPattern
- NOTIFY searchPatternChanged FINAL)
-
- Q_PROPERTY(QString sortCriteria READ sortCriteria WRITE setSortCriteria
- NOTIFY sortCriteriaChanged FINAL)
+ using MediaTreePtr = vlc_shared_data_ptr_type(vlc_media_tree_t,
+ vlc_media_tree_Hold,
+ vlc_media_tree_Release);
- Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder
- NOTIFY sortOrderChanged FINAL)
+ using InputItemPtr = vlc_shared_data_ptr_type(input_item_t,
+ input_item_Hold,
+ input_item_Release);
public:
NetworkDeviceModel( QObject* parent = nullptr );
QVariant data(const QModelIndex& index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
- int rowCount(const QModelIndex& parent = {}) const override;
void setCtx(MainCtx* ctx);
void setSdSource(SDCatType s);
@@ -114,25 +110,6 @@ public:
inline QString getName() { return m_name; }
inline QString getSourceName() { return m_sourceName; }
- int getCount() const;
-
- int maximumCount() const;
- void setMaximumCount(int count);
-
- bool hasMoreItems() const;
-
- QString searchPattern() const;
- void setSearchPattern(const QString & pattern);
-
- QByteArray searchRole() const;
- void setSearchRole(const QByteArray & role);
-
- QString sortCriteria() const;
- void setSortCriteria(const QString & criteria);
-
- Qt::SortOrder sortOrder() const;
- void setSortOrder(Qt::SortOrder order);
-
Q_INVOKABLE bool insertIntoPlaylist( const QModelIndexList& itemIdList, ssize_t playlistIndex );
Q_INVOKABLE bool addToPlaylist( int index );
Q_INVOKABLE bool addToPlaylist(const QVariantList& itemIdList);
@@ -145,68 +122,32 @@ public:
Q_INVOKABLE QVariantList getItemsForIndexes(const QModelIndexList & indexes) const;
+protected: // ClipListModel implementation
+ void onUpdateSort(const QString & criteria, Qt::SortOrder order) override;
+
signals:
void ctxChanged();
void sdSourceChanged();
void sourceNameChanged();
void nameChanged();
- void countChanged();
-
- void maximumCountChanged();
-
- void searchPatternChanged();
- void searchRoleChanged();
-
- void sortCriteriaChanged();
- void sortOrderChanged();
private:
- using MediaSourcePtr = vlc_shared_data_ptr_type(vlc_media_source_t,
- vlc_media_source_Hold, vlc_media_source_Release);
-
- using MediaTreePtr = vlc_shared_data_ptr_type(vlc_media_tree_t,
- vlc_media_tree_Hold,
- vlc_media_tree_Release);
-
- using InputItemPtr = vlc_shared_data_ptr_type(input_item_t,
- input_item_Hold,
- input_item_Release);
-
- struct Item
- {
- QString name;
- QUrl mainMrl;
- std::vector<QUrl> mrls;
- QString protocol;
- ItemType type;
- MediaSourcePtr mediaSource;
- InputItemPtr inputItem;
- QUrl artworkUrl;
- };
-
bool initializeMediaSources();
void refreshDeviceList(MediaSourcePtr mediaSource, input_item_node_t* const children[], size_t count , bool clear);
void addItems(const std::vector<InputItemPtr> & inputList, const MediaSourcePtr & mediaSource);
- void removeItem(std::vector<Item>::iterator & it, int index, int count);
-
- void expandItems();
- void shrinkItems();
-
- void updateSort();
-
- int implicitCount() const;
+ void eraseItem(std::vector<NetworkDeviceItem>::iterator & it, int index, int count);
private: // Static functions
- static bool matchItem(const Item & a, const Item & b);
+ static bool matchItem(const NetworkDeviceItem & a, const NetworkDeviceItem & b);
- static bool ascendingName(const Item & a, const Item & b);
- static bool ascendingMrl (const Item & a, const Item & b);
+ static bool ascendingName(const NetworkDeviceItem & a, const NetworkDeviceItem & b);
+ static bool ascendingMrl (const NetworkDeviceItem & a, const NetworkDeviceItem & b);
- static bool descendingName(const Item & a, const Item & b);
- static bool descendingMrl (const Item & a, const Item & b);
+ static bool descendingName(const NetworkDeviceItem & a, const NetworkDeviceItem & b);
+ static bool descendingMrl (const NetworkDeviceItem & a, const NetworkDeviceItem & b);
private:
struct ListenerCb : public MediaTreeListener::MediaTreeListenerCb {
@@ -224,26 +165,24 @@ private:
MediaSourcePtr mediaSource;
};
- std::vector<Item> m_items;
MainCtx* m_ctx = nullptr;
SDCatType m_sdSource = CAT_UNDEFINED;
QString m_sourceName; // '*' -> all sources
QString m_name; // source long name
- int m_count = 0;
-
- int m_maximumCount = -1;
-
- QString m_searchPattern;
- QByteArray m_searchRole;
-
- QString m_sortCriteria = "name";
-
- std::function<bool(const Item &, const Item &)> m_comparator = ascendingName;
-
- Qt::SortOrder m_sortOrder = Qt::AscendingOrder;
-
std::vector<std::unique_ptr<MediaTreeListener>> m_listeners;
};
+struct NetworkDeviceItem
+{
+ QString name;
+ QUrl mainMrl;
+ std::vector<QUrl> mrls;
+ QString protocol;
+ NetworkDeviceModel::ItemType type;
+ NetworkDeviceModel::MediaSourcePtr mediaSource;
+ NetworkDeviceModel::InputItemPtr inputItem;
+ QUrl artworkUrl;
+};
+
#endif // MLNETWORKDEVICEMODEL_HPP
=====================================
modules/gui/qt/network/qml/BrowseDeviceView.qml
=====================================
@@ -162,10 +162,10 @@ FocusScope {
var data = modelFilter.getDataAt(index)
- if (data.type === NetworkMediaModel.TYPE_DIRECTORY
- ||
- data.type === NetworkMediaModel.TYPE_NODE)
- browse(data.tree, Qt.TabFocusReason);
+ var type = data.type
+
+ if (type === NetworkMediaModel.TYPE_DIRECTORY || type === NetworkMediaModel.TYPE_NODE)
+ browse(data.tree, Qt.TabFocusReason)
else
playAt(index);
}
@@ -179,10 +179,10 @@ FocusScope {
}
function onDoubleClicked(model, index) {
- if (model.type === NetworkMediaModel.TYPE_NODE
- ||
- model.type === NetworkMediaModel.TYPE_DIRECTORY)
- browse(model.tree, Qt.MouseFocusReason);
+ var type = model.type
+
+ if (type === NetworkMediaModel.TYPE_NODE || type === NetworkMediaModel.TYPE_DIRECTORY)
+ browse(model.tree, Qt.MouseFocusReason)
else
playAt(index);
}
@@ -226,6 +226,8 @@ FocusScope {
? -1
: root.maximumRows * nbItemPerRow
+ anchors.fill: parent
+
cellWidth: VLCStyle.gridItem_network_width
cellHeight: VLCStyle.gridItem_network_height
@@ -269,6 +271,8 @@ FocusScope {
readonly property int _nameColSpan: Math.max((_nbCols - 1) / 2, 1)
+ anchors.fill: parent
+
rowHeight: VLCStyle.tableCoverRow_height
displayMarginEnd: root.displayMarginEnd
=====================================
modules/gui/qt/network/qml/BrowseDisplay.qml
=====================================
@@ -41,6 +41,9 @@ Widgets.PageLoader {
pageModel: [{
name: "home",
url: "qrc:///network/BrowseHomeDisplay.qml"
+ }, {
+ name: "folders",
+ component: browseFolders,
}, {
name: "device",
component: browseDevice,
@@ -76,7 +79,10 @@ Widgets.PageLoader {
: null
onSeeAll: {
- History.push(["mc", "network", "device", { title: title, sd_source: sd_source }])
+ if (sd_source === -1)
+ History.push(["mc", "network", "folders", { title: title }])
+ else
+ History.push(["mc", "network", "device", { title: title, sd_source: sd_source }])
stackView.currentItem.setCurrentItemFocus(reason)
}
@@ -94,6 +100,23 @@ Widgets.PageLoader {
// Children
+ Component {
+ id: browseFolders
+
+ BrowseDeviceView {
+ property var sortModel: [
+ { text: I18n.qtr("Alphabetic"), criteria: "name" },
+ { text: I18n.qtr("Url"), criteria: "mrl" }
+ ]
+
+ displayMarginEnd: g_mainDisplay.displayMargin
+
+ model: modelFilter
+
+ sourceModel: StandardPathModel {}
+ }
+ }
+
Component {
id: browseDevice
=====================================
modules/gui/qt/network/qml/BrowseHomeDisplay.qml
=====================================
@@ -38,7 +38,7 @@ FocusScope {
{ text: I18n.qtr("Url"), criteria: "mrl" }
]
- property alias model: deviceSection.model
+ property alias model: foldersSection.model
focus: true
@@ -50,7 +50,12 @@ FocusScope {
onActiveFocusChanged: resetFocus()
function setCurrentItemFocus(reason) {
- deviceSection.setCurrentItemFocus(reason);
+ if (foldersSection.visible)
+ foldersSection.setCurrentItemFocus(reason);
+ else if (deviceSection.visible)
+ deviceSection.setCurrentItemFocus(reason);
+ else if (lanSection.visible)
+ lanSection.setCurrentItemFocus(reason);
}
function _centerFlickableOnItem(item) {
@@ -84,7 +89,11 @@ FocusScope {
//FIXME use the right xxxLabel class
T.Label {
anchors.centerIn: parent
- visible: (deviceSection.model.count === 0 && lanSection.model.count === 0 )
+
+ visible: (foldersSection.model.count === 0 && deviceSection.model.count === 0
+ &&
+ lanSection.model.count === 0)
+
font.pixelSize: VLCStyle.fontHeight_xxlarge
color: root.activeFocus ? VLCStyle.colors.accent : VLCStyle.colors.text
text: I18n.qtr("No network shares found")
@@ -101,6 +110,42 @@ FocusScope {
spacing: VLCStyle.margin_small
+ BrowseDeviceView {
+ id: foldersSection
+
+ width: flickable.width
+ height: contentHeight
+
+ maximumRows: root.maximumRows
+
+ visible: (model.count !== 0)
+
+ model: StandardPathModel
+ {
+ maximumCount: foldersSection.maximumCount
+ }
+
+ title: I18n.qtr("My Folders")
+
+ Navigation.parentItem: root
+
+ Navigation.downAction: function() {
+ if (deviceSection.visible)
+ deviceSection.setCurrentItemFocus(Qt.TabFocusReason)
+ else if (lanSection.visible)
+ lanSection.setCurrentItemFocus(Qt.TabFocusReason)
+ else
+ root.Navigation.defaultNavigationDown()
+ }
+
+ onBrowse: root.browse(tree, reason)
+
+ onSeeAll: root.seeAll(title, -1, reason)
+
+ onActiveFocusChanged: _centerFlickableOnItem(foldersSection)
+ onCurrentIndexChanged: _centerFlickableOnItem(foldersSection)
+ }
+
BrowseDeviceView {
id: deviceSection
@@ -122,8 +167,17 @@ FocusScope {
title: I18n.qtr("My Machine")
+ parentFilter: foldersSection.model
+
Navigation.parentItem: root
+ Navigation.upAction: function() {
+ if (foldersSection.visible)
+ foldersSection.setCurrentItemFocus(Qt.TabFocusReason)
+ else
+ root.Navigation.defaultNavigationUp()
+ }
+
Navigation.downAction: function() {
if (lanSection.visible)
lanSection.setCurrentItemFocus(Qt.TabFocusReason)
@@ -160,13 +214,15 @@ FocusScope {
title: I18n.qtr("My LAN")
- parentFilter: deviceSection.modelFilter
+ parentFilter: foldersSection.model
Navigation.parentItem: root
Navigation.upAction: function() {
if (deviceSection.visible)
deviceSection.setCurrentItemFocus(Qt.TabFocusReason)
+ else if (foldersSection.visible)
+ foldersSection.setCurrentItemFocus(Qt.TabFocusReason)
else
root.Navigation.defaultNavigationUp()
}
@@ -182,7 +238,7 @@ FocusScope {
}
function resetFocus() {
- var widgetlist = [deviceSection, lanSection]
+ var widgetlist = [foldersSection, deviceSection, lanSection]
var i;
for (i in widgetlist) {
if (widgetlist[i].activeFocus && widgetlist[i].visible)
=====================================
modules/gui/qt/network/standardpathmodel.cpp
=====================================
@@ -0,0 +1,167 @@
+/*****************************************************************************
+ * Copyright (C) 2019 VLC authors and VideoLAN
+ *
+ * Authors: Benjamin Arnaud <bunjee at omega.gg>
+ *
+ * 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 "standardpathmodel.hpp"
+
+// VLC includes
+#include "networkmediamodel.hpp"
+
+// Ctor / dtor
+
+StandardPathModel::StandardPathModel(QObject * parent)
+ : ClipListModel(parent)
+{
+ m_comparator = ascendingName;
+
+#ifdef Q_OS_UNIX
+ addItem(QVLCUserDir(VLC_HOME_DIR), qtr("Home"), QUrl());
+#endif
+ addItem(QVLCUserDir(VLC_DESKTOP_DIR), qtr("Desktop"), QUrl());
+ addItem(QVLCUserDir(VLC_DOCUMENTS_DIR), qtr("Documents"), QUrl());
+ addItem(QVLCUserDir(VLC_MUSIC_DIR), qtr("Music"), QUrl());
+ addItem(QVLCUserDir(VLC_VIDEOS_DIR), qtr("Videos"), QUrl());
+ addItem(QVLCUserDir(VLC_DOWNLOAD_DIR), qtr("Download"), QUrl());
+
+ updateItems();
+}
+
+// QAbstractItemModel implementation
+
+QHash<int, QByteArray> StandardPathModel::roleNames() const /* override */
+{
+ return
+ {
+ { PATH_NAME, "name" },
+ { PATH_MRL, "mrl" },
+ { PATH_PROTOCOL, "protocol" },
+ { PATH_TYPE, "type" },
+ { PATH_SOURCE, "source" },
+ { PATH_TREE, "tree" },
+ { PATH_ARTWORK, "artwork" }
+ };
+}
+
+QVariant StandardPathModel::data(const QModelIndex & index, int role) const /* override */
+{
+ int row = index.row();
+
+ if (row < 0 || row >= count())
+ return QVariant();
+
+ const StandardPathItem & item = m_items[row];
+
+ switch (role)
+ {
+ case PATH_NAME:
+ return item.name;
+ case PATH_MRL:
+ return item.mrl;
+ case PATH_PROTOCOL:
+ return item.protocol;
+ case PATH_TYPE:
+ return item.type;
+ case PATH_TREE:
+ return QVariant::fromValue(NetworkTreeItem(item.tree, item.inputItem.get()));
+ case PATH_ARTWORK:
+ return item.artwork;
+ default:
+ return QVariant();
+ }
+}
+
+// Protected ClipListModel implementation
+
+void StandardPathModel::onUpdateSort(const QString & criteria, Qt::SortOrder order) /* override */
+{
+ if (criteria == "mrl")
+ {
+ if (order == Qt::AscendingOrder)
+ m_comparator = ascendingMrl;
+ else
+ m_comparator = descendingMrl;
+ }
+ else
+ {
+ if (order == Qt::AscendingOrder)
+ m_comparator = ascendingName;
+ else
+ m_comparator = descendingName;
+ }
+}
+
+// Private static function
+
+/* static */ bool StandardPathModel::ascendingName(const StandardPathItem & a,
+ const StandardPathItem & b)
+{
+ return (QString::compare(a.name, b.name, Qt::CaseInsensitive) <= 0);
+}
+
+/* static */ bool StandardPathModel::ascendingMrl(const StandardPathItem & a,
+ const StandardPathItem & b)
+{
+ return (QString::compare(a.mrl.toString(), b.mrl.toString(), Qt::CaseInsensitive) <= 0);
+}
+
+/* static */ bool StandardPathModel::descendingName(const StandardPathItem & a,
+ const StandardPathItem & b)
+{
+ return (QString::compare(a.name, b.name, Qt::CaseInsensitive) >= 0);
+}
+
+/* static */ bool StandardPathModel::descendingMrl(const StandardPathItem & a,
+ const StandardPathItem & b)
+{
+ return (QString::compare(a.mrl.toString(), b.mrl.toString(), Qt::CaseInsensitive) >= 0);
+}
+
+// Private functions
+
+void StandardPathModel::addItem(const QString & path, const QString & name, const QUrl & artwork)
+{
+ QUrl url = QUrl::fromLocalFile(path);
+
+ StandardPathItem item;
+
+ item.name = name;
+ item.mrl = url;
+
+ item.protocol = url.scheme();
+
+ item.type = NetworkDeviceModel::TYPE_DIRECTORY;
+
+ input_item_t * inputItem = input_item_NewDirectory(qtu(url.toString()), qtu(name), ITEM_LOCAL);
+
+ item.inputItem = InputItemPtr(inputItem, false);
+
+ vlc_media_tree_t * tree = vlc_media_tree_New();
+
+ vlc_media_tree_Lock(tree);
+
+ vlc_media_tree_Add(tree, &(tree->root), inputItem);
+
+ vlc_media_tree_Unlock(tree);
+
+ item.tree = MediaTreePtr(tree, false);
+
+ item.artwork = artwork;
+
+ m_items.push_back(item);
+}
=====================================
modules/gui/qt/network/standardpathmodel.hpp
=====================================
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * Copyright (C) 2019 VLC authors and VideoLAN
+ *
+ * Authors: Benjamin Arnaud <bunjee at omega.gg>
+ *
+ * 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 STANDARDPATHMODEL_HPP
+#define STANDARDPATHMODEL_HPP
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// VLC includes
+#include <vlc_media_source.h>
+#include <vlc_cxx_helpers.hpp>
+#include "networkdevicemodel.hpp"
+#include "util/cliplistmodel.hpp"
+
+// Qt includes
+#include <QAbstractListModel>
+#include <QStandardPaths>
+#include <QUrl>
+
+struct StandardPathItem;
+
+class StandardPathModel : public ClipListModel<StandardPathItem>
+{
+ Q_OBJECT
+
+public: // Enums
+ // NOTE: Roles should be aligned with the NetworkDeviceModel.
+ enum Role
+ {
+ PATH_NAME = Qt::UserRole + 1,
+ PATH_MRL,
+ PATH_TYPE,
+ PATH_PROTOCOL,
+ PATH_SOURCE,
+ PATH_TREE,
+ PATH_ARTWORK
+ };
+
+public: // Declarations
+ using InputItemPtr = vlc_shared_data_ptr_type(input_item_t,
+ input_item_Hold,
+ input_item_Release);
+
+ using MediaTreePtr = vlc_shared_data_ptr_type(vlc_media_tree_t,
+ vlc_media_tree_Hold,
+ vlc_media_tree_Release);
+
+public:
+ StandardPathModel(QObject * parent = nullptr);
+
+public: // QAbstractItemModel implementation
+ QHash<int, QByteArray> roleNames() const override;
+
+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
+
+protected: // ClipListModel implementation
+ void onUpdateSort(const QString & criteria, Qt::SortOrder order) override;
+
+private: // Static functions
+ static bool ascendingName(const StandardPathItem & a, const StandardPathItem & b);
+ static bool ascendingMrl (const StandardPathItem & a, const StandardPathItem & b);
+
+ static bool descendingName(const StandardPathItem & a, const StandardPathItem & b);
+ static bool descendingMrl (const StandardPathItem & a, const StandardPathItem & b);
+
+private: // Functions
+ void addItem(const QString & path, const QString & name, const QUrl & artwork);
+};
+
+struct StandardPathItem
+{
+ QString name;
+ QUrl mrl;
+
+ QString protocol;
+
+ NetworkDeviceModel::ItemType type;
+
+ StandardPathModel::InputItemPtr inputItem;
+ StandardPathModel::MediaTreePtr tree;
+
+ QUrl artwork;
+};
+
+#endif // STANDARDPATHMODEL_HPP
=====================================
modules/gui/qt/util/cliplistmodel.cpp
=====================================
@@ -0,0 +1,147 @@
+/*****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * Authors: Benjamin Arnaud <bunjee at omega.gg>
+ *
+ * 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 "cliplistmodel.hpp"
+
+// BaseClipListModel
+
+/* explicit */ BaseClipListModel::BaseClipListModel(QObject * parent)
+ : QAbstractListModel(parent) {}
+
+// Interface
+
+void BaseClipListModel::updateItems()
+{
+ int count = implicitCount();
+
+ if (m_count == count) return;
+
+ if (m_count < count)
+ expandItems(count);
+ else
+ shrinkItems(count);
+}
+
+// QAbstractItemModel implementation
+
+int BaseClipListModel::rowCount(const QModelIndex &) const /* override */
+{
+ return count();
+}
+
+// Properties
+
+int BaseClipListModel::count() const
+{
+ return m_count;
+}
+
+int BaseClipListModel::maximumCount() const
+{
+ return m_maximumCount;
+}
+
+void BaseClipListModel::setMaximumCount(int count)
+{
+ if (m_maximumCount == count)
+ return;
+
+ m_maximumCount = count;
+
+ count = implicitCount();
+
+ if (m_count == count)
+ {
+ emit maximumCountChanged();
+
+ return;
+ }
+
+ if (m_count < count)
+ expandItems(count);
+ else
+ shrinkItems(count);
+
+ emit maximumCountChanged();
+}
+
+QString BaseClipListModel::searchPattern() const
+{
+ return m_searchPattern;
+}
+
+void BaseClipListModel::setSearchPattern(const QString & pattern)
+{
+ if (m_searchPattern == pattern)
+ return;
+
+ m_searchPattern = pattern;
+
+ emit searchPatternChanged();
+}
+
+QByteArray BaseClipListModel::searchRole() const
+{
+ return m_searchRole;
+}
+
+void BaseClipListModel::setSearchRole(const QByteArray & role)
+{
+ if (m_searchRole == role)
+ return;
+
+ m_searchRole = role;
+
+ emit searchRoleChanged();
+}
+
+QString BaseClipListModel::sortCriteria() const
+{
+ return m_sortCriteria;
+}
+
+void BaseClipListModel::setSortCriteria(const QString & criteria)
+{
+ if (m_sortCriteria == criteria)
+ return;
+
+ m_sortCriteria = criteria;
+
+ updateSort();
+
+ emit sortCriteriaChanged();
+}
+
+Qt::SortOrder BaseClipListModel::sortOrder() const
+{
+ return m_sortOrder;
+}
+
+void BaseClipListModel::setSortOrder(Qt::SortOrder order)
+{
+ if (m_sortOrder == order)
+ return;
+
+ m_sortOrder = order;
+
+ updateSort();
+
+ emit sortOrderChanged();
+}
=====================================
modules/gui/qt/util/cliplistmodel.hpp
=====================================
@@ -0,0 +1,300 @@
+/*****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * Authors: Benjamin Arnaud <bunjee at omega.gg>
+ *
+ * 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 MODELITEMS_HPP
+#define MODELITEMS_HPP
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+// Qt includes
+#include <QAbstractListModel>
+
+// NOTE: Qt won't let us inherit from QAbstractListModel when declaring a template class. So we
+// specify a base class for properties and signals.
+class BaseClipListModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+ Q_PROPERTY(int maximumCount READ maximumCount WRITE setMaximumCount NOTIFY maximumCountChanged)
+
+ Q_PROPERTY(bool hasMoreItems READ hasMoreItems NOTIFY countChanged)
+
+ Q_PROPERTY(QByteArray searchRole READ searchRole WRITE setSearchRole NOTIFY searchRoleChanged)
+
+ Q_PROPERTY(QString searchPattern READ searchPattern WRITE setSearchPattern
+ NOTIFY searchPatternChanged)
+
+ Q_PROPERTY(QString sortCriteria READ sortCriteria WRITE setSortCriteria
+ NOTIFY sortCriteriaChanged)
+
+ Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
+
+public:
+ BaseClipListModel(QObject * parent = nullptr);
+
+public: // Interface
+ // Convenience function for showing or hiding items according to the implicitCount.
+ void updateItems();
+
+public: // Abstract functions
+ virtual int implicitCount() const = 0;
+
+ virtual bool hasMoreItems() const = 0;
+
+public: // QAbstractItemModel implementation
+ int rowCount(const QModelIndex & parent = QModelIndex()) const override;
+
+protected: // Abstract functions
+ virtual void expandItems(int count) = 0;
+ virtual void shrinkItems(int count) = 0;
+
+ virtual void updateSort() = 0;
+
+signals:
+ void countChanged();
+
+ void maximumCountChanged();
+
+ void searchPatternChanged();
+ void searchRoleChanged();
+
+ void sortCriteriaChanged();
+ void sortOrderChanged();
+
+public: // Properties
+ int count() const;
+
+ int maximumCount() const;
+ void setMaximumCount(int count);
+
+ QString searchPattern() const;
+ void setSearchPattern(const QString & pattern);
+
+ QByteArray searchRole() const;
+ void setSearchRole(const QByteArray & role);
+
+ QString sortCriteria() const;
+ void setSortCriteria(const QString & criteria);
+
+ Qt::SortOrder sortOrder() const;
+ void setSortOrder(Qt::SortOrder order);
+
+protected:
+ int m_count = 0;
+
+ int m_maximumCount = -1;
+
+ QString m_searchPattern;
+ QByteArray m_searchRole;
+
+ QString m_sortCriteria = "name";
+
+ Qt::SortOrder m_sortOrder = Qt::AscendingOrder;
+};
+
+// NOTE: This helper adds support for capping, sorting and filtering QAbstractListModel item(s).
+// We tried implementing capping from a QSortFilterProxyModel and QML, but both
+// implementations had flaws.
+template <typename T>
+class ClipListModel : public BaseClipListModel
+{
+public:
+ typedef typename std::vector<T>::iterator iterator;
+
+public:
+ explicit ClipListModel(QObject * parent = nullptr);
+
+public: // Interface
+ // NOTE: Convenience function that inserts an item and 'clears' model row(s) depending on the
+ // maximum count to preserve item capping.
+ void insertItem(iterator it, const T & item);
+
+ // NOTE: Convenience function that removes an item at a given index and updates the iterator.
+ void removeItem(iterator & it, int index);
+
+ // NOTE: Convenience function that clears the items and resets the model.
+ void clearItems();
+
+public: // BaseClipListModel implementation
+ int implicitCount() const override;
+
+ bool hasMoreItems() const override;
+
+protected: // Abstract functions
+ // NOTE: This function has to return a comparator for the current sorting parameters.
+ virtual void onUpdateSort(const QString & criteria, Qt::SortOrder order) = 0;
+
+protected: // BaseClipListModel implementation
+ void expandItems(int count) override;
+ void shrinkItems(int count) override;
+
+ void updateSort() override;
+
+protected:
+ std::vector<T> m_items;
+
+ std::function<bool(const T &, const T &)> m_comparator;
+};
+
+// Ctor / dtor
+
+template <typename T>
+/* explicit */ ClipListModel<T>::ClipListModel(QObject * parent) : BaseClipListModel(parent) {}
+
+// Interface
+
+template <typename T>
+void ClipListModel<T>::insertItem(iterator it, const T & item)
+{
+ int pos = std::distance(m_items.begin(), it);
+
+ if (m_maximumCount != -1 && m_count >= m_maximumCount)
+ {
+ // NOTE: When the position is beyond the maximum count we don't notify the view.
+ if (pos >= m_maximumCount)
+ {
+ m_items.insert(it, std::move(item));
+
+ return;
+ }
+
+ // NOTE: Removing the last item to make room for the new one.
+
+ int index = m_count - 1;
+
+ beginRemoveRows({}, index, index);
+
+ m_count--;
+
+ endRemoveRows();
+
+ emit countChanged();
+ }
+
+ beginInsertRows({}, pos, pos);
+
+ m_items.insert(it, std::move(item));
+
+ m_count++;
+
+ endInsertRows();
+
+ emit countChanged();
+}
+
+template <typename T>
+void ClipListModel<T>::removeItem(iterator & it, int index)
+{
+ if (index < 0 || index >= count())
+ return;
+
+ beginRemoveRows({}, index, index);
+
+ it = m_items.erase(it);
+
+ m_count--;
+
+ endRemoveRows();
+
+ emit countChanged();
+}
+
+template <typename T>
+void ClipListModel<T>::clearItems()
+{
+ if (m_items.empty())
+ return;
+
+ beginResetModel();
+
+ m_items.clear();
+
+ m_count = 0;
+
+ endResetModel();
+
+ emit countChanged();
+}
+
+// BaseClipListModel implementation
+
+template <typename T>
+int ClipListModel<T>::implicitCount() const /* override */
+{
+ assert(m_items.size() < INT32_MAX);
+
+ if (m_maximumCount == -1)
+ return (int) m_items.size();
+ else
+ return qMin((int) m_items.size(), m_maximumCount);
+}
+
+template <typename T>
+bool ClipListModel<T>::hasMoreItems() const /* override */
+{
+ if (m_maximumCount == -1)
+ return false;
+ else
+ return (m_count < (int) m_items.size());
+}
+
+// Protected BaseClipListModel implementation
+
+template <typename T>
+void ClipListModel<T>::expandItems(int count) /* override */
+{
+ beginInsertRows({}, m_count, count - 1);
+
+ m_count = count;
+
+ endInsertRows();
+
+ emit countChanged();
+}
+
+template <typename T>
+void ClipListModel<T>::shrinkItems(int count) /* override */
+{
+ beginRemoveRows({}, count, m_count - 1);
+
+ m_count = count;
+
+ endRemoveRows();
+
+ emit countChanged();
+}
+
+template <typename T>
+void ClipListModel<T>::updateSort() /* override */
+{
+ onUpdateSort(m_sortCriteria, m_sortOrder);
+
+ beginResetModel();
+
+ std::sort(m_items.begin(), m_items.end(), m_comparator);
+
+ endResetModel();
+}
+
+#endif // MODELITEMS_HPP
=====================================
po/POTFILES.in
=====================================
@@ -830,6 +830,8 @@ modules/gui/qt/menus/menus.hpp
modules/gui/qt/menus/qml/Menubar.qml
modules/gui/qt/menus/qml_menu_wrapper.cpp
modules/gui/qt/menus/qml_menu_wrapper.hpp
+modules/gui/qt/network/standardpathmodel.cpp
+modules/gui/qt/network/standardpathmodel.hpp
modules/gui/qt/network/qml/BrowseDeviceHeader.qml
modules/gui/qt/network/qml/BrowseDeviceView.qml
modules/gui/qt/network/qml/BrowseDisplay.qml
=====================================
src/libvlccore.sym
=====================================
@@ -1000,6 +1000,8 @@ vlc_media_tree_Hold
vlc_media_tree_Release
vlc_media_tree_Lock
vlc_media_tree_Unlock
+vlc_media_tree_Add
+vlc_media_tree_Remove
vlc_media_tree_Find
vlc_media_tree_Preparse
vlc_media_tree_PreparseCancel
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/2d151758edcd66a6e8cbc521e6d79abf0fb4ded1...c49873e4a409df7733d526295d3db8916776253d
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/2d151758edcd66a6e8cbc521e6d79abf0fb4ded1...c49873e4a409df7733d526295d3db8916776253d
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list