Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (8)
Showing
with 479 additions and 562 deletions
......@@ -314,8 +314,6 @@ libqt_plugin_la_SOURCES = \
gui/qt/util/selectable_list_model.cpp \
gui/qt/util/selectable_list_model.hpp \
gui/qt/util/singleton.hpp \
gui/qt/util/sortfilterproxymodel.cpp \
gui/qt/util/sortfilterproxymodel.hpp \
gui/qt/util/soutchain.cpp gui/qt/util/soutchain.hpp \
gui/qt/util/validators.cpp gui/qt/util/validators.hpp \
gui/qt/util/varcommon_p.hpp \
......@@ -509,7 +507,6 @@ nodist_libqt_plugin_la_SOURCES = \
gui/qt/util/flickable_scroll_handler.moc.cpp \
gui/qt/util/renderer_manager.moc.cpp \
gui/qt/util/selectable_list_model.moc.cpp \
gui/qt/util/sortfilterproxymodel.moc.cpp \
gui/qt/util/validators.moc.cpp \
gui/qt/util/varchoicemodel.moc.cpp \
gui/qt/util/variables.moc.cpp \
......
......@@ -38,7 +38,6 @@
#include "util/i18n.hpp"
#include "util/keyhelper.hpp"
#include "style/systempalette.hpp"
#include "util/sortfilterproxymodel.hpp"
#include "util/navigation_history.hpp"
#include "util/flickable_scroll_handler.hpp"
#include "util/color_svg_image_provider.hpp"
......@@ -306,7 +305,6 @@ void MainUI::registerQMLTypes()
qmlRegisterType<NetworkMediaContextMenu>( uri, versionMajor, versionMinor, "NetworkMediaContextMenu" );
qmlRegisterType<NetworkDeviceContextMenu>( uri, versionMajor, versionMinor, "NetworkDeviceContextMenu" );
qmlRegisterType<PlaylistContextMenu>( uri, versionMajor, versionMinor, "PlaylistContextMenu" );
qmlRegisterType<SortFilterProxyModel>( uri, versionMajor, versionMinor, "SortFilterProxyModel" );
qmlRegisterUncreatableType<NavigationAttached>( uri, versionMajor, versionMinor, "Navigation", "Navigation is only available via attached properties");
......
......@@ -42,7 +42,7 @@ class MediaLib;
template<typename T>
class ListCache;
using MLListCache = ListCache<std::unique_ptr<MLItem>>;
struct MLListCacheLoader;
class MLListCacheLoader;
/* Medialib data loader for the cache */
class MLBaseModelPrivate;
......@@ -149,7 +149,7 @@ private:
};
struct MLListCacheLoader: public QObject, public ListCacheLoader<std::unique_ptr<MLItem>>
class MLListCacheLoader: public QObject, public ListCacheLoader<std::unique_ptr<MLItem>>
{
Q_OBJECT
public:
......
......@@ -131,7 +131,6 @@ moc_headers = files(
'util/flickable_scroll_handler.hpp',
'util/renderer_manager.hpp',
'util/selectable_list_model.hpp',
'util/sortfilterproxymodel.hpp',
'util/validators.hpp',
'util/varchoicemodel.hpp',
'util/variables.hpp',
......@@ -438,8 +437,6 @@ some_sources = files(
'util/selectable_list_model.cpp',
'util/selectable_list_model.hpp',
'util/singleton.hpp',
'util/sortfilterproxymodel.cpp',
'util/sortfilterproxymodel.hpp',
'util/soutchain.cpp',
'util/soutchain.hpp',
'util/validators.cpp',
......
......@@ -224,7 +224,7 @@ public:
public:
bool loading() const override
{
return m_parsing && BaseModelPrivateT<NetworkMediaItemPtr>::loading();
return m_parsing || BaseModelPrivateT<NetworkMediaItemPtr>::loading();
}
LocalListCacheLoader<NetworkMediaItemPtr>::ItemCompare getSortFunction() const
......
......@@ -16,136 +16,229 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <QQmlFile>
#include "networksourcesmodel.hpp"
#include "networkmediamodel.hpp"
#include "util/base_model_p.hpp"
#include "util/locallistcacheloader.hpp"
#include "playlist/media.hpp"
#include "playlist/playlist_controller.hpp"
NetworkSourcesModel::NetworkSourcesModel( QObject* parent )
: QAbstractListModel( parent )
{
}
#include <QQmlFile>
QVariant NetworkSourcesModel::data( const QModelIndex& index, int role ) const
#include <memory>
#include <vlc_media_source.h>
#include <vlc_cxx_helpers.hpp>
namespace {
struct SourceItem
{
if (!m_ctx)
return {};
auto idx = index.row();
if ( idx < 0 || (size_t)idx >= m_items.size() )
return {};
const auto& item = m_items[idx];
switch ( role )
SourceItem()
{
case SOURCE_NAME:
return item.name;
case SOURCE_LONGNAME:
return item.longName;
case SOURCE_TYPE:
return idx == 0 ? TYPE_DUMMY : TYPE_SOURCE;
case SOURCE_ARTWORK:
return item.artworkUrl;
default:
return {};
isDummy = true;
}
}
QHash<int, QByteArray> NetworkSourcesModel::roleNames() const
{
return {
{ SOURCE_NAME, "name" },
{ SOURCE_LONGNAME, "long_name" },
{ SOURCE_TYPE, "type" },
{ SOURCE_ARTWORK, "artwork" }
};
}
explicit SourceItem(const vlc_media_source_meta* meta)
: isDummy(false)
, name(qfu(meta->name))
, longName(qfu(meta->longname))
{
if ( name.startsWith( "podcast" ) )
{
artworkUrl = QUrl("qrc:///sd/podcast.svg");
}
else if ( name.startsWith("lua{") )
{
int i_head = name.indexOf( "sd='" ) + 4;
int i_tail = name.indexOf( '\'', i_head );
const QString iconName = QString( "qrc:///sd/%1.svg" ).arg( name.mid( i_head, i_tail - i_head ) );
artworkUrl = QFileInfo::exists( QQmlFile::urlToLocalFileOrQrc(iconName) ) ? QUrl(iconName)
: QUrl("qrc:///sd/network.svg");
}
}
int NetworkSourcesModel::rowCount(const QModelIndex& parent) const
{
if ( parent.isValid() )
return 0;
return getCount();
}
bool isDummy;
QString name;
QString longName;
QUrl artworkUrl;
};
using SourceItemPtr = std::shared_ptr<SourceItem>;
using SourceItemLists = std::vector<SourceItemPtr>;
void NetworkSourcesModel::setCtx(MainCtx* ctx)
{
if (ctx) {
m_ctx = ctx;
}
if (m_ctx) {
initializeMediaTree();
}
emit ctxChanged();
}
int NetworkSourcesModel::getCount() const
class NetworkSourcesModelPrivate
: public BaseModelPrivateT<SourceItemPtr>
, public LocalListCacheLoader<SourceItemPtr>::ModelSource
{
assert( m_items.size() < INT32_MAX );
return static_cast<int>( m_items.size() );
}
Q_DECLARE_PUBLIC(NetworkSourcesModel);
QMap<QString, QVariant> NetworkSourcesModel::getDataAt(int idx)
{
QMap<QString, QVariant> dataDict;
QHash<int,QByteArray> roles = roleNames();
for (auto role: roles.keys()) {
dataDict[roles[role]] = data(index(idx), role);
public: //Ctor/Dtor
NetworkSourcesModelPrivate(NetworkSourcesModel* pub)
: BaseModelPrivateT<SourceItemPtr>(pub)
{}
public:
const SourceItem* getItemForRow(int row) const
{
const SourceItemPtr* ref = item(row);
if (ref)
return ref->get();
return nullptr;
}
return dataDict;
}
bool NetworkSourcesModel::initializeMediaTree()
{
auto libvlc = vlc_object_instance(m_ctx->getIntf());
public: // BaseModelPrivate implementation
if (!m_items.empty()) {
beginResetModel();
endResetModel();
emit countChanged();
LocalListCacheLoader<SourceItemPtr>::ItemCompare getSortFunction() const
{
if (m_sortOrder == Qt::DescendingOrder)
return [](const SourceItemPtr& a, const SourceItemPtr& b) {
//always put our dummy item first
if (a->isDummy)
return true;
if (b->isDummy)
return false;
return QString::compare(a->name, b->name, Qt::CaseInsensitive) > 0;
};
else
return [](const SourceItemPtr& a, const SourceItemPtr& b) {
//always put our dummy item first
if (a->isDummy)
return true;
if (b->isDummy)
return false;
return QString::compare(a->name, b->name, Qt::CaseInsensitive) < 0;
};
}
std::unique_ptr<ListCacheLoader<SourceItemPtr>> createLoader() const override
{
return std::make_unique<LocalListCacheLoader<SourceItemPtr>>(
this, m_searchPattern, getSortFunction());
}
m_items = {Item{}}; // dummy item that UI uses to add entry for "add a service"
auto provider = vlc_media_source_provider_Get( libvlc );
bool initializeModel() override
{
Q_Q(NetworkSourcesModel);
if (m_qmlInitializing || !q->m_ctx)
return false;
using SourceMetaPtr = std::unique_ptr<vlc_media_source_meta_list_t,
decltype( &vlc_media_source_meta_list_Delete )>;
auto libvlc = vlc_object_instance(q->m_ctx->getIntf());
SourceMetaPtr providerList( vlc_media_source_provider_List( provider, static_cast<services_discovery_category_e>(m_sdSource) ),
&vlc_media_source_meta_list_Delete );
if ( providerList == nullptr )
return false;
if (!m_items.empty())
m_items.clear();
auto nbProviders = vlc_media_source_meta_list_Count( providerList.get() );
auto provider = vlc_media_source_provider_Get( libvlc );
//add a dummy item
m_items.push_back(std::make_shared<SourceItem>());
beginResetModel();
for ( auto i = 0u; i < nbProviders; ++i )
{
auto meta = vlc_media_source_meta_list_Get( providerList.get(), i );
using SourceMetaPtr = std::unique_ptr<vlc_media_source_meta_list_t,
decltype( &vlc_media_source_meta_list_Delete )>;
Item item;
item.name = qfu(meta->name);
item.longName = qfu(meta->longname);
SourceMetaPtr providerList( vlc_media_source_provider_List( provider, static_cast<services_discovery_category_e>(m_sdSource) ),
&vlc_media_source_meta_list_Delete );
if ( providerList == nullptr )
return false;
if ( item.name.startsWith( "podcast" ) )
{
item.artworkUrl = QUrl("qrc:///sd/podcast.svg");
}
else if ( item.name.startsWith("lua{") )
auto nbProviders = vlc_media_source_meta_list_Count( providerList.get() );
for ( auto i = 0u; i < nbProviders; ++i )
{
int i_head = item.name.indexOf( "sd='" ) + 4;
int i_tail = item.name.indexOf( '\'', i_head );
const QString iconName = QString( "qrc:///sd/%1.svg" ).arg( item.name.mid( i_head, i_tail - i_head ) );
item.artworkUrl = QFileInfo::exists( QQmlFile::urlToLocalFileOrQrc(iconName) ) ? QUrl(iconName)
: QUrl("qrc:///sd/network.svg");
auto meta = vlc_media_source_meta_list_Get( providerList.get(), i );
SourceItemPtr item = std::make_shared<SourceItem>(meta);
m_items.push_back( item );
}
m_items.push_back( std::move(item) );
return true;
}
public: // LocalListCacheLoader::ModelSource implementation
size_t getModelRevision() const override
{
return 1;
}
std::vector<SourceItemPtr> getModelData(const QString& pattern) const override
{
if (pattern.isEmpty())
return m_items;
std::vector<SourceItemPtr> items;
std::copy_if(
m_items.cbegin(), m_items.cend(),
std::back_inserter(items),
[&pattern](const SourceItemPtr& item){
return item->name.contains(pattern, Qt::CaseInsensitive);
});
return items;
}
endResetModel();
emit countChanged();
return m_items.empty() == false;
public: // Data
services_discovery_category_e m_sdSource = services_discovery_category_e::SD_CAT_INTERNET;
std::vector<SourceItemPtr> m_items;
};
// ListCache specialisation
template<>
bool ListCache<SourceItemPtr>::compareItems(const SourceItemPtr& a, const SourceItemPtr& b)
{
//just compare the pointers here
return a == b;
}
NetworkSourcesModel::NetworkSourcesModel( QObject* parent )
: BaseModel( new NetworkSourcesModelPrivate(this), parent )
{
}
QVariant NetworkSourcesModel::data( const QModelIndex& index, int role ) const
{
Q_D(const NetworkSourcesModel);
if (!m_ctx)
return {};
const SourceItem* item = d->getItemForRow(index.row());
if (!item)
return {};
switch ( role )
{
case SOURCE_NAME:
return item->name;
case SOURCE_LONGNAME:
return item->longName;
case SOURCE_TYPE:
return item->isDummy ? TYPE_DUMMY : TYPE_SOURCE;
case SOURCE_ARTWORK:
return item->artworkUrl;
default:
return {};
}
}
QHash<int, QByteArray> NetworkSourcesModel::roleNames() const
{
return {
{ SOURCE_NAME, "name" },
{ SOURCE_LONGNAME, "long_name" },
{ SOURCE_TYPE, "type" },
{ SOURCE_ARTWORK, "artwork" }
};
}
void NetworkSourcesModel::setCtx(MainCtx* ctx)
{
Q_D(NetworkSourcesModel);
if (ctx == m_ctx)
return;
m_ctx = ctx;
d->initializeModel();
emit ctxChanged();
}
......@@ -23,21 +23,16 @@
#include "config.h"
#endif
#include <QAbstractListModel>
#include <vlc_media_source.h>
#include <vlc_cxx_helpers.hpp>
#include "util/base_model.hpp"
#include "maininterface/mainctx.hpp"
#include <maininterface/mainctx.hpp>
#include <memory>
class NetworkSourcesModel : public QAbstractListModel
class NetworkSourcesModelPrivate;
class NetworkSourcesModel : public BaseModel
{
Q_OBJECT
Q_PROPERTY(MainCtx* ctx READ getCtx WRITE setCtx NOTIFY ctxChanged FINAL)
Q_PROPERTY(int count READ getCount NOTIFY countChanged FINAL)
public:
enum Role {
......@@ -58,34 +53,18 @@ public:
QVariant data(const QModelIndex& index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex& parent = {}) const override;
public: // properties
void setCtx(MainCtx* ctx);
inline MainCtx* getCtx() { return m_ctx; }
int getCount() const;
Q_INVOKABLE QMap<QString, QVariant> getDataAt(int index);
signals:
void ctxChanged();
void countChanged();
private:
struct Item
{
QString name;
QString longName;
QUrl artworkUrl;
};
bool initializeMediaTree();
private:
std::vector<Item> m_items;
MainCtx* m_ctx = nullptr;
services_discovery_category_e m_sdSource = services_discovery_category_e::SD_CAT_INTERNET;
Q_DECLARE_PRIVATE(NetworkSourcesModel);
};
#endif // MLNetworkSourcesModel_HPP
......@@ -29,7 +29,11 @@ Widgets.KeyNavigableListView {
// required by g_root to indicate view with 'grid' or 'list' mode
readonly property bool isViewMultiView: false
model: discoveryFilterModel
model: ServicesDiscoveryModel {
id: discoveryModel
ctx: MainCtx
}
topMargin: VLCStyle.margin_large
leftMargin: VLCStyle.margin_large
rightMargin: VLCStyle.margin_large
......@@ -115,9 +119,9 @@ Widgets.KeyNavigableListView {
onClicked: {
if (model.state === ServicesDiscoveryModel.NOTINSTALLED)
discoveryModel.installService(discoveryFilterModel.mapIndexToSource(index))
discoveryModel.installService(index)
else if (model.state === ServicesDiscoveryModel.INSTALLED)
discoveryModel.installService(discoveryFilterModel.mapIndexToSource(index))
discoveryModel.removeService(index)
}
}
}
......@@ -148,17 +152,4 @@ Widgets.KeyNavigableListView {
color: servicesView.colorContext.fg.primary
z: 1
}
ServicesDiscoveryModel {
id: discoveryModel
ctx: MainCtx
}
SortFilterProxyModel {
id: discoveryFilterModel
sourceModel: discoveryModel
searchRole: "name"
}
}
......@@ -32,7 +32,7 @@ MainInterface.MainGridView {
readonly property bool isViewMultiView: false
selectionDelegateModel: selectionModel
model: sourcesFilterModel
model: sourcesModel
topMargin: VLCStyle.margin_large
cellWidth: VLCStyle.gridItem_network_width
cellHeight: VLCStyle.gridCover_network_height + VLCStyle.margin_xsmall + VLCStyle.fontHeight_normal
......@@ -96,7 +96,7 @@ MainInterface.MainGridView {
}
onActionAtIndex: {
const itemData = sourcesFilterModel.getDataAt(index);
const itemData = sourcesModel.getDataAt(index);
if (itemData.type === NetworkSourcesModel.TYPE_DUMMY)
History.push(["mc", "discover", "services", "services_manage"], Qt.TabFocusReason)
......@@ -120,13 +120,6 @@ MainInterface.MainGridView {
Util.SelectableDelegateModel {
id: selectionModel
model: sourcesFilterModel
}
SortFilterProxyModel {
id: sourcesFilterModel
sourceModel: sourcesModel
searchRole: "name"
model: sourcesModel
}
}
......@@ -17,54 +17,224 @@
*****************************************************************************/
#include "servicesdiscoverymodel.hpp"
#include <vlc_addons.h>
#include "util/base_model_p.hpp"
#include "util/locallistcacheloader.hpp"
#include "medialibrary/mlhelper.hpp"
#include "playlist/media.hpp"
#include "playlist/playlist_controller.hpp"
#include <memory>
#include <QPixmap>
ServicesDiscoveryModel::ServicesDiscoveryModel( QObject* parent )
: QAbstractListModel( parent )
#include <vlc_media_source.h>
#include <vlc_addons.h>
#include <vlc_cxx_helpers.hpp>
#include <vlc_addons.h>
namespace {
using AddonPtr = vlc_shared_data_ptr_type(addon_entry_t,
addon_entry_Hold, addon_entry_Release);
class SDItem {
public:
SDItem( AddonPtr addon )
{
name = qfu( addon->psz_name );
summery = qfu( addon->psz_summary ).trimmed();
description = qfu( addon->psz_description ).trimmed();
author = qfu( addon->psz_author );
sourceUrl = QUrl( addon->psz_source_uri );
entry = addon;
if ( addon->psz_image_data ) {
char *cDir = config_GetUserDir( VLC_CACHE_DIR );
if (likely(cDir != nullptr))
{
QDir dir( cDir );
free(cDir);
dir.mkdir("art");
dir.cd("art");
dir.mkdir("qt-addon-covers");
dir.cd("qt-addon-covers");
QString id = addons_uuid_to_psz( &addon->uuid );
QString filename = QString("addon_thumbnail_%1.png").arg(id);
QString absoluteFilePath = dir.absoluteFilePath(filename);
if ( !QFileInfo::exists( absoluteFilePath )) {
QPixmap pixmap;
pixmap.loadFromData( QByteArray::fromBase64( QByteArray( addon->psz_image_data ) ),
0,
Qt::AutoColor
);
pixmap.save(absoluteFilePath);
}
artworkUrl = QUrl::fromLocalFile( absoluteFilePath );
}
}
else if ( addon->e_flags & ADDON_BROKEN )
artworkUrl = QUrl( ":/addons/addon_broken.svg" );
else
artworkUrl = QUrl( ":/addons/addon_default.svg" );
}
public:
QString name;
QString summery;
QString description;
QString author;
QUrl sourceUrl;
QUrl artworkUrl;
AddonPtr entry;
};
} //namespace
using SDItemPtr = std::shared_ptr<SDItem> ;
using SDItemList = std::vector<SDItemPtr> ;
// ListCache specialisation
template<>
bool ListCache<SDItemPtr>::compareItems(const SDItemPtr& a, const SDItemPtr& b)
{
//just compare the pointers here
return a == b;
}
ServicesDiscoveryModel::~ServicesDiscoveryModel()
// ServicesDiscoveryModelPrivate
class ServicesDiscoveryModelPrivate
: public BaseModelPrivateT<SDItemPtr>
, public LocalListCacheLoader<SDItemPtr>::ModelSource
{
if ( m_manager )
public:
Q_DECLARE_PUBLIC(ServicesDiscoveryModel)
public: //ctor/dtor
ServicesDiscoveryModelPrivate(ServicesDiscoveryModel* pub)
: BaseModelPrivateT<SDItemPtr>(pub)
{
addons_manager_Delete( m_manager );
}
~ServicesDiscoveryModelPrivate()
{
if ( m_manager )
addons_manager_Delete( m_manager );
}
public:
const SDItem* getItemForRow(int row) const
{
const SDItemPtr* ref = item(row);
if (ref)
return ref->get();
return nullptr;
}
public: //BaseModelPrivateT implementation
bool initializeModel() override;
bool loading() const override
{
return m_loading || BaseModelPrivateT<SDItemPtr>::loading();
}
std::unique_ptr<ListCacheLoader<SDItemPtr>> createLoader() const override
{
return std::make_unique<LocalListCacheLoader<SDItemPtr>>(
this, m_searchPattern,
getSortFunction()
);
}
LocalListCacheLoader<SDItemPtr>::ItemCompare getSortFunction() const
{
if (m_sortOrder == Qt::SortOrder::DescendingOrder)
return [](const SDItemPtr& a, const SDItemPtr& b){
return QString::compare(a->name, b->name) > 0;
};
else
return [](const SDItemPtr& a, const SDItemPtr& b) {
return QString::compare(a->name, b->name) < 0;
};
}
public: //discovery callbacks
void addonFound( AddonPtr addon );
void addonChanged( AddonPtr addon );
void discoveryEnded();
public: //LocalListCacheLoader implementation
virtual size_t getModelRevision() const override
{
return m_revision;
}
//return the data matching the pattern
virtual SDItemList getModelData(const QString& pattern) const override
{
if (pattern.isEmpty())
return m_items;
SDItemList items;
std::copy_if(
m_items.cbegin(), m_items.cend(),
std::back_inserter(items),
[&pattern](const SDItemPtr& item) {
return item->name.contains(pattern, Qt::CaseInsensitive);
});
return items;
}
public: // data
bool m_loading = true;
addons_manager_t* m_manager = nullptr;
size_t m_revision = 0;
SDItemList m_items;
};
ServicesDiscoveryModel::ServicesDiscoveryModel( QObject* parent )
: BaseModel( new ServicesDiscoveryModelPrivate(this), parent )
{
}
QVariant ServicesDiscoveryModel::data( const QModelIndex& index, int role ) const
{
Q_D(const ServicesDiscoveryModel);
if (!m_ctx)
return {};
auto idx = index.row();
if ( idx < 0 || (size_t)idx >= m_items.size() )
const SDItem* item = d->getItemForRow(index.row());
if (!item)
return {};
const auto& item = m_items[idx];
switch ( role )
{
case Role::SERVICE_NAME:
return item.name;
return item->name;
case Role::SERVICE_AUTHOR:
return item.author;
return item->author;
case Role::SERVICE_SUMMARY:
return item.summery;
return item->summery;
case Role::SERVICE_DESCRIPTION:
return item.description;
return item->description;
case Role::SERVICE_DOWNLOADS:
return QVariant::fromValue( item.entry->i_downloads );
return QVariant::fromValue( item->entry->i_downloads );
case Role::SERVICE_SCORE:
return item.entry->i_score / 100;
return item->entry->i_score / 100;
case Role::SERVICE_STATE:
return item.entry->e_state;
return item->entry->e_state;
case Role::SERVICE_ARTWORK:
return item.artworkUrl;
return item->artworkUrl;
default:
return {};
}
......@@ -84,62 +254,83 @@ QHash<int, QByteArray> ServicesDiscoveryModel::roleNames() const
};
}
QMap<QString, QVariant> ServicesDiscoveryModel::getDataAt(int idx)
{
QMap<QString, QVariant> dataDict;
QHash<int,QByteArray> roles = roleNames();
for (auto role: roles.keys()) {
dataDict[roles[role]] = data(index(idx), role);
}
return dataDict;
}
void ServicesDiscoveryModel::installService(int idx)
{
if ( idx < 0 || idx >= (int)m_items.size() )
Q_D(ServicesDiscoveryModel);
const SDItem* item = d->getItemForRow(idx);
if (!item)
return;
addon_uuid_t uuid;
memcpy( uuid, m_items[idx].entry->uuid, sizeof( uuid ) );
addons_manager_Install( m_manager, uuid );
memcpy( uuid, item->entry->uuid, sizeof( uuid ) );
addons_manager_Install( d->m_manager, uuid );
}
void ServicesDiscoveryModel::removeService(int idx)
{
if ( idx < 0 || idx >= (int)m_items.size() )
Q_D(ServicesDiscoveryModel);
const SDItem* item = d->getItemForRow(idx);
if (!item)
return;
addon_uuid_t uuid;
memcpy( uuid, m_items[idx].entry->uuid, sizeof( uuid ) );
addons_manager_Remove( m_manager, uuid );
memcpy( uuid, item->entry->uuid, sizeof( uuid ) );
addons_manager_Remove( d->m_manager, uuid );
}
int ServicesDiscoveryModel::rowCount(const QModelIndex& parent) const
void ServicesDiscoveryModel::setCtx(MainCtx* ctx)
{
if ( parent.isValid() )
return 0;
return getCount();
Q_D(ServicesDiscoveryModel);
if (ctx == m_ctx)
return;
assert(ctx);
m_ctx = ctx;
d->initializeModel();
emit ctxChanged();
}
int ServicesDiscoveryModel::getCount() const
static void addonFoundCallback( addons_manager_t *manager, addon_entry_t *entry )
{
assert( m_items.size() < INT32_MAX );
return static_cast<int>( m_items.size() );
if (entry->e_type != ADDON_SERVICE_DISCOVERY)
return;
ServicesDiscoveryModelPrivate* d = (ServicesDiscoveryModelPrivate*) manager->owner.sys;
QMetaObject::invokeMethod( d->q_func(), [d, entryPtr = AddonPtr(entry)]()
{
d->addonFound( std::move( entryPtr ) );
}, Qt::QueuedConnection);
}
void ServicesDiscoveryModel::setCtx(MainCtx* ctx)
static void addonsDiscoveryEndedCallback( addons_manager_t *manager )
{
if (ctx) {
m_ctx = ctx;
}
if (m_ctx) {
initializeManager();
}
emit ctxChanged();
ServicesDiscoveryModelPrivate* d = (ServicesDiscoveryModelPrivate*) manager->owner.sys;
QMetaObject::invokeMethod( d->q_func(), [d]()
{
d->discoveryEnded();
}, Qt::QueuedConnection);
}
void ServicesDiscoveryModel::initializeManager()
static void addonChangedCallback( addons_manager_t *manager, addon_entry_t *entry )
{
if (entry->e_type != ADDON_SERVICE_DISCOVERY)
return;
ServicesDiscoveryModelPrivate* d = (ServicesDiscoveryModelPrivate*) manager->owner.sys;
QMetaObject::invokeMethod( d->q_func(), [d, entryPtr = AddonPtr(entry)]()
{
d->addonChanged( std::move( entryPtr ) );
}, Qt::QueuedConnection);
}
bool ServicesDiscoveryModelPrivate::initializeModel()
{
Q_Q(ServicesDiscoveryModel);
if (m_qmlInitializing || !q->m_ctx)
return false;
if ( m_manager )
addons_manager_Delete( m_manager );
......@@ -151,119 +342,42 @@ void ServicesDiscoveryModel::initializeManager()
addonChangedCallback,
};
m_manager = addons_manager_New( VLC_OBJECT( m_ctx->getIntf() ), &owner );
m_manager = addons_manager_New( VLC_OBJECT( q->m_ctx->getIntf() ), &owner );
assert( m_manager );
m_loading = true;
emit loadingChanged();
emit q->loadingChanged();
addons_manager_LoadCatalog( m_manager );
addons_manager_Gather( m_manager, "repo://" );
return true;
}
void ServicesDiscoveryModel::addonFoundCallback( addons_manager_t *manager,
addon_entry_t *entry )
{
if (entry->e_type != ADDON_SERVICE_DISCOVERY)
return;
ServicesDiscoveryModel *me = (ServicesDiscoveryModel *) manager->owner.sys;
QMetaObject::invokeMethod( me, [me, entryPtr = AddonPtr(entry)]()
{
me->addonFound( std::move( entryPtr ) );
}, Qt::QueuedConnection);
}
void ServicesDiscoveryModel::addonsDiscoveryEndedCallback( addons_manager_t *manager )
{
ServicesDiscoveryModel *me = (ServicesDiscoveryModel *) manager->owner.sys;
QMetaObject::invokeMethod( me, [me]()
{
me->discoveryEnded();
}, Qt::QueuedConnection);
}
void ServicesDiscoveryModel::addonChangedCallback( addons_manager_t *manager,
addon_entry_t *entry )
{
if (entry->e_type != ADDON_SERVICE_DISCOVERY)
return;
ServicesDiscoveryModel *me = (ServicesDiscoveryModel *) manager->owner.sys;
QMetaObject::invokeMethod( me, [me, entryPtr = AddonPtr(entry)]()
{
me->addonChanged( std::move( entryPtr ) );
}, Qt::QueuedConnection);
}
void ServicesDiscoveryModel::addonFound( ServicesDiscoveryModel::AddonPtr addon )
void ServicesDiscoveryModelPrivate::addonFound( AddonPtr addon )
{
beginInsertRows( QModelIndex(), getCount(), getCount() );
m_items.emplace_back(addon);
endInsertRows();
emit countChanged();
m_items.emplace_back(std::make_shared<SDItem>(addon));
m_revision++;
invalidateCache();
}
void ServicesDiscoveryModel::addonChanged( ServicesDiscoveryModel::AddonPtr addon )
void ServicesDiscoveryModelPrivate::addonChanged( AddonPtr addon )
{
for ( int r = 0; r < getCount(); ++r )
for ( size_t r = 0; r < m_items.size(); ++r )
{
if ( memcmp( m_items[r].entry->uuid, addon->uuid, sizeof( addon->uuid ) ) )
if ( memcmp( m_items[r]->entry->uuid, addon->uuid, sizeof( addon->uuid ) ) )
continue;
m_items[r] = addon;
emit dataChanged( index( r, 0 ), index( r, 0 ) );
m_items[r] = std::make_shared<SDItem>(addon);
break;
}
m_revision++;
invalidateCache();
}
void ServicesDiscoveryModel::discoveryEnded()
void ServicesDiscoveryModelPrivate::discoveryEnded()
{
Q_Q(ServicesDiscoveryModel);
assert( m_loading );
m_loading = false;
emit loadingChanged();
}
ServicesDiscoveryModel::Item::Item( ServicesDiscoveryModel::AddonPtr addon )
{
*this = addon;
}
ServicesDiscoveryModel::Item &ServicesDiscoveryModel::Item::operator=( ServicesDiscoveryModel::AddonPtr addon )
{
name = qfu( addon->psz_name );
summery = qfu( addon->psz_summary ).trimmed();
description = qfu( addon->psz_description ).trimmed();
author = qfu( addon->psz_author );
sourceUrl = QUrl( addon->psz_source_uri );
entry = addon;
if ( addon->psz_image_data ) {
char *cDir = config_GetUserDir( VLC_CACHE_DIR );
if (likely(cDir != nullptr))
{
QDir dir( cDir );
free(cDir);
dir.mkdir("art");
dir.cd("art");
dir.mkdir("qt-addon-covers");
dir.cd("qt-addon-covers");
QString id = addons_uuid_to_psz( &addon->uuid );
QString filename = QString("addon_thumbnail_%1.png").arg(id);
QString absoluteFilePath = dir.absoluteFilePath(filename);
if ( !QFileInfo::exists( absoluteFilePath )) {
QPixmap pixmap;
pixmap.loadFromData( QByteArray::fromBase64( QByteArray( addon->psz_image_data ) ),
0,
Qt::AutoColor
);
pixmap.save(absoluteFilePath);
}
artworkUrl = QUrl::fromLocalFile( absoluteFilePath );
}
}
else if ( addon->e_flags & ADDON_BROKEN )
artworkUrl = QUrl( ":/addons/addon_broken.svg" );
else
artworkUrl = QUrl( ":/addons/addon_default.svg" );
return *this;
emit q->loadingChanged();
}
......@@ -23,25 +23,17 @@
#include "config.h"
#endif
#include <QAbstractListModel>
#include "util/base_model.hpp"
#include "maininterface/mainctx.hpp"
#include <vlc_media_source.h>
#include <vlc_addons.h>
#include <vlc_cxx_helpers.hpp>
#include <maininterface/mainctx.hpp>
#include <memory>
class ServicesDiscoveryModel : public QAbstractListModel
struct ServicesDiscoveryModelPrivate;
class ServicesDiscoveryModel : public BaseModel
{
Q_OBJECT
public:
Q_PROPERTY(MainCtx* ctx READ getCtx WRITE setCtx NOTIFY ctxChanged FINAL)
Q_PROPERTY(bool loading READ isLoading NOTIFY loadingChanged FINAL)
Q_PROPERTY(int count READ getCount NOTIFY countChanged FINAL)
enum State // equivalent to addon_state_t
{
......@@ -65,58 +57,26 @@ public:
Q_ENUM(Role)
explicit ServicesDiscoveryModel(QObject* parent = nullptr);
~ServicesDiscoveryModel() override;
public: //QAbstractListModel override
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);
inline MainCtx* getCtx() const { return m_ctx; }
inline bool isLoading() const { return m_loading; }
int getCount() const;
Q_INVOKABLE QMap<QString, QVariant> getDataAt(int idx);
public: //invokable functions
Q_INVOKABLE void installService(int idx);
Q_INVOKABLE void removeService(int idx);
public: // properties
void setCtx(MainCtx* ctx);
inline MainCtx* getCtx() const { return m_ctx; }
signals:
void loadingChanged();
void countChanged();
void ctxChanged();
private:
using AddonPtr = vlc_shared_data_ptr_type(addon_entry_t,
addon_entry_Hold, addon_entry_Release);
void initializeManager();
static void addonFoundCallback( addons_manager_t *, struct addon_entry_t * );
static void addonsDiscoveryEndedCallback( addons_manager_t * );
static void addonChangedCallback( addons_manager_t *, struct addon_entry_t * );
void addonFound( AddonPtr addon );
void addonChanged( AddonPtr addon );
void discoveryEnded();
struct Item
{
QString name;
QString summery;
QString description;
QString author;
QUrl sourceUrl;
QUrl artworkUrl;
AddonPtr entry;
Item( AddonPtr addon );
Item& operator =( AddonPtr addon );
};
std::vector<Item> m_items;
MainCtx* m_ctx = nullptr;
addons_manager_t* m_manager = nullptr;
bool m_loading = false;
Q_DECLARE_PRIVATE(ServicesDiscoveryModel);
};
#endif // MLServicesDiscoveryModel_HPP
/*****************************************************************************
* Copyright (C) 2020 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* ( at your option ) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "sortfilterproxymodel.hpp"
#include <QRegularExpression>
#include <cassert>
SortFilterProxyModel::SortFilterProxyModel( QObject *parent )
: QSortFilterProxyModel( parent )
{
setFilterCaseSensitivity(Qt::CaseInsensitive);
connect( this, &QAbstractListModel::rowsInserted, this, &SortFilterProxyModel::countChanged );
connect( this, &QAbstractListModel::rowsRemoved, this, &SortFilterProxyModel::countChanged );
connect( this, &QAbstractItemModel::modelReset, this, &SortFilterProxyModel::countChanged );
connect( this, &QAbstractItemModel::layoutChanged, this, &SortFilterProxyModel::countChanged );
connect( this, &QAbstractProxyModel::sourceModelChanged, this, &SortFilterProxyModel::updateFilterRole );
connect( this, &QAbstractProxyModel::sourceModelChanged, this, &SortFilterProxyModel::updateSortRole );
}
QString SortFilterProxyModel::searchPattern() const
{
return filterRegularExpression().pattern();
}
void SortFilterProxyModel::setSearchPattern( const QString &searchPattern )
{
setFilterRegularExpression(searchPattern);
}
QByteArray SortFilterProxyModel::searchRole() const
{
return m_searchRole;
}
void SortFilterProxyModel::setSearchRole( const QByteArray &searchRole )
{
m_searchRole = searchRole;
emit searchRoleChanged();
updateFilterRole();
}
QString SortFilterProxyModel::sortCriteria() const
{
return m_sortCriteria;
}
void SortFilterProxyModel::setSortCriteria(const QString &sortCriteria)
{
if (m_sortCriteria == sortCriteria)
return;
m_sortCriteria = sortCriteria;
updateSortRole();
emit sortCriteriaChanged();
}
Qt::SortOrder SortFilterProxyModel::sortOrder() const
{
return QSortFilterProxyModel::sortOrder();
}
void SortFilterProxyModel::setSortOrder(Qt::SortOrder sortOrder)
{
if (this->sortOrder() == sortOrder)
return;
this->sort(0, sortOrder);
emit sortOrderChanged();
}
int SortFilterProxyModel::count() const
{
return rowCount();
}
QMap<QString, QVariant> SortFilterProxyModel::getDataAt( int idx )
{
QMap<QString, QVariant> dataDict;
QHash<int,QByteArray> roles = roleNames();
for( const auto role: roles.keys() ) {
dataDict[roles[role]] = data( index( idx, 0 ), role );
}
return dataDict;
}
QModelIndexList SortFilterProxyModel::mapIndexesToSource( const QModelIndexList &indexes )
{
QModelIndexList sourceIndexes;
sourceIndexes.reserve( indexes.size() );
for( const auto &proxyIndex : indexes ) {
sourceIndexes.push_back( mapToSource(proxyIndex) );
}
return sourceIndexes;
}
int SortFilterProxyModel::mapIndexToSource(int idx)
{
return mapToSource( index( idx, 0 ) ).row();
}
void SortFilterProxyModel::updateFilterRole()
{
setFilterRole( roleNames().key( m_searchRole ) );
}
void SortFilterProxyModel::updateSortRole()
{
setSortRole( roleNames().key( m_sortCriteria.toUtf8() ) );
}
/*****************************************************************************
* Copyright (C) 2020 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* ( at your option ) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef SORT_FILTER_PROXY_MODEL
#define SORT_FILTER_PROXY_MODEL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "qt.hpp"
#include <QSortFilterProxyModel>
class SortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
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)
Q_PROPERTY( Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged FINAL)
Q_PROPERTY( int count READ count NOTIFY countChanged FINAL)
public:
SortFilterProxyModel( QObject * parent = nullptr );
QString searchPattern() const;
void setSearchPattern( const QString &searchPattern );
QByteArray searchRole() const;
void setSearchRole( const QByteArray &searchRole );
QString sortCriteria() const;
void setSortCriteria( const QString &sortCriteria );
Qt::SortOrder sortOrder() const;
void setSortOrder(Qt::SortOrder sortOrder);
int count() const;
Q_INVOKABLE QMap<QString, QVariant> getDataAt( int idx );
Q_INVOKABLE QModelIndexList mapIndexesToSource( const QModelIndexList &indexes );
Q_INVOKABLE int mapIndexToSource( int idx );
signals:
void searchPatternChanged();
void searchRoleChanged();
void countChanged();
void sortCriteriaChanged();
void sortOrderChanged();
private slots:
void updateFilterRole();
void updateSortRole();
private:
QByteArray m_searchRole;
QString m_sortCriteria;
};
#endif // SORT_FILTER_PROXY_MODEL