qt: move network component to its own folder
[vlc.git] / modules / gui / qt / network / networkmediamodel.cpp
bloba832e0cda8eccde1b0e1aebfea2cbb2decbffe6d
1 /*****************************************************************************
2 * Copyright (C) 2019 VLC authors and VideoLAN
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17 *****************************************************************************/
19 #include "networkmediamodel.hpp"
21 #include "components/mediacenter/mlhelper.hpp"
23 #include "playlist/media.hpp"
24 #include "playlist/playlist_controller.hpp"
26 namespace {
28 enum Role {
29 NETWORK_NAME = Qt::UserRole + 1,
30 NETWORK_MRL,
31 NETWORK_INDEXED,
32 NETWORK_CANINDEX,
33 NETWORK_TYPE,
34 NETWORK_PROTOCOL,
35 NETWORK_TREE,
36 NETWORK_SOURCE,
41 NetworkMediaModel::NetworkMediaModel( QObject* parent )
42 : QAbstractListModel( parent )
43 , m_ml( nullptr )
47 QVariant NetworkMediaModel::data( const QModelIndex& index, int role ) const
49 if (!m_ctx)
50 return {};
51 auto idx = index.row();
52 if ( idx < 0 || (size_t)idx >= m_items.size() )
53 return {};
54 const auto& item = m_items[idx];
55 switch ( role )
57 case NETWORK_NAME:
58 return item.name;
59 case NETWORK_MRL:
60 return item.mainMrl;
61 case NETWORK_INDEXED:
62 return item.indexed;
63 case NETWORK_CANINDEX:
64 return item.canBeIndexed;
65 case NETWORK_TYPE:
66 return item.type;
67 case NETWORK_PROTOCOL:
68 return item.protocol;
69 case NETWORK_TREE:
70 return QVariant::fromValue( item.tree );
71 case NETWORK_SOURCE:
72 return item.mediaSource->description;
73 default:
74 return {};
78 QHash<int, QByteArray> NetworkMediaModel::roleNames() const
80 return {
81 { NETWORK_NAME, "name" },
82 { NETWORK_MRL, "mrl" },
83 { NETWORK_INDEXED, "indexed" },
84 { NETWORK_CANINDEX, "can_index" },
85 { NETWORK_TYPE, "type" },
86 { NETWORK_PROTOCOL, "protocol" },
87 { NETWORK_TREE, "tree" },
88 { NETWORK_SOURCE, "source" },
92 int NetworkMediaModel::rowCount(const QModelIndex& parent) const
94 if ( parent.isValid() )
95 return 0;
96 assert( m_items.size() < INT32_MAX );
97 return static_cast<int>( m_items.size() );
100 Qt::ItemFlags NetworkMediaModel::flags( const QModelIndex& idx ) const
102 return QAbstractListModel::flags( idx ) | Qt::ItemIsEditable;
105 bool NetworkMediaModel::setData( const QModelIndex& idx, const QVariant& value, int role )
107 printf("NetworkMediaModel::setData `\n");
108 if (!m_ml)
109 return false;
111 if ( role != NETWORK_INDEXED )
112 return false;
113 auto enabled = value.toBool();
114 if ( m_items[idx.row()].indexed == enabled )
115 return false;
116 printf("NetworkMediaModel::setData change indexed`\n");
117 int res;
118 if ( enabled )
119 res = vlc_ml_add_folder( m_ml, qtu( m_items[idx.row()].mainMrl.toString( QUrl::None ) ) );
120 else
121 res = vlc_ml_remove_folder( m_ml, qtu( m_items[idx.row()].mainMrl.toString( QUrl::None ) ) );
122 m_items[idx.row()].indexed = enabled;
123 emit dataChanged(idx, idx, { NETWORK_INDEXED });
124 return res == VLC_SUCCESS;
128 void NetworkMediaModel::setIndexed(bool indexed)
130 if (indexed == m_indexed || !m_canBeIndexed)
131 return;
132 int res;
133 if ( indexed )
134 res = vlc_ml_add_folder( m_ml, qtu( m_url.toString( QUrl::None ) ) );
135 else
136 res = vlc_ml_remove_folder( m_ml, qtu( m_url.toString( QUrl::None ) ) );
138 if (res == VLC_SUCCESS) {
139 m_indexed = indexed;
140 emit isIndexedChanged();
144 void NetworkMediaModel::setCtx(QmlMainContext* ctx)
146 if (ctx) {
147 m_ctx = ctx;
148 m_ml = vlc_ml_instance_get( m_ctx->getIntf() );
150 if (m_ctx && m_hasTree) {
151 initializeMediaSources();
153 emit ctxChanged();
156 void NetworkMediaModel::setTree(QVariant parentTree)
158 if (parentTree.canConvert<NetworkTreeItem>())
159 m_treeItem = parentTree.value<NetworkTreeItem>();
160 else
161 m_treeItem = NetworkTreeItem();
162 m_hasTree = true;
163 if (m_ctx && m_hasTree) {
164 initializeMediaSources();
166 emit treeChanged();
169 bool NetworkMediaModel::addToPlaylist(int index)
171 if (!(m_ctx && m_hasTree))
172 return false;
173 if (index < 0 || (size_t)index >= m_items.size() )
174 return false;
175 auto item = m_items[index];
176 vlc::playlist::Media media{ item.tree.media.get() };
177 m_ctx->getIntf()->p_sys->p_mainPlaylistController->append( { media }, false);
178 return true;
181 bool NetworkMediaModel::addToPlaylist(const QVariantList &itemIdList)
183 bool ret = false;
184 for (const QVariant& varValue: itemIdList)
186 if (varValue.canConvert<int>())
188 auto index = varValue.value<int>();
189 ret |= addToPlaylist(index);
192 return ret;
195 bool NetworkMediaModel::addAndPlay(int index)
197 if (!(m_ctx && m_hasTree))
198 return false;
199 if (index < 0 || (size_t)index >= m_items.size() )
200 return false;
201 auto item = m_items[index];
202 vlc::playlist::Media media{ item.tree.media.get() };
203 m_ctx->getIntf()->p_sys->p_mainPlaylistController->append( { media }, true);
204 return true;
207 bool NetworkMediaModel::addAndPlay(const QVariantList& itemIdList)
209 bool ret = false;
210 for (const QVariant& varValue: itemIdList)
212 if (varValue.canConvert<int>())
214 auto index = varValue.value<int>();
215 if (!ret)
216 ret |= addAndPlay(index);
217 else
218 ret |= addToPlaylist(index);
221 return ret;
225 bool NetworkMediaModel::initializeMediaSources()
227 auto libvlc = vlc_object_instance(m_ctx->getIntf());
229 m_listener.reset();
230 if (!m_items.empty()) {
231 beginResetModel();
232 m_items.clear();
233 endResetModel();
236 if (!m_treeItem)
237 return false;
239 auto tree = m_treeItem.source->tree;
240 std::unique_ptr<NetworkSourceListener> l{ new NetworkSourceListener( m_treeItem.source, this ) };
241 if ( l->listener == nullptr )
242 return false;
244 if (m_treeItem.media)
246 m_name = m_treeItem.media->psz_name;
247 emit nameChanged();
248 m_url = QUrl::fromEncoded( QByteArray{ m_treeItem.media->psz_uri }.append( '/' ) );
249 emit urlChanged();
250 m_type = static_cast<ItemType>(m_treeItem.media->i_type);
251 emit typeChanged();
252 m_canBeIndexed = canBeIndexed( m_url, m_type );
253 emit canBeIndexedChanged();
254 if ( vlc_ml_is_indexed( m_ml, QByteArray(m_treeItem.media->psz_uri).append('/').constData(), &m_indexed ) != VLC_SUCCESS ) {
255 m_indexed = false;
257 emit isIndexedChanged();
261 vlc_media_tree_Preparse( tree, libvlc, m_treeItem.media.get() );
262 m_parsingPending = true;
263 emit parsingPendingChanged(m_parsingPending);
265 m_listener = std::move( l );
267 return true;
270 void NetworkMediaModel::onItemCleared( MediaSourcePtr mediaSource, input_item_node_t*)
272 input_item_node_t *res;
273 input_item_node_t *parent;
274 if ( vlc_media_tree_Find( m_treeItem.source->tree, m_treeItem.media.get(),
275 &res, &parent ) == false )
276 return;
277 refreshMediaList( std::move( mediaSource ), res->pp_children, res->i_children, true );
280 void NetworkMediaModel::onItemAdded( MediaSourcePtr mediaSource, input_item_node_t* parent,
281 input_item_node_t *const children[],
282 size_t count )
284 if ( parent->p_item == m_treeItem.media.get() )
285 refreshMediaList( std::move( mediaSource ), children, count, false );
288 void NetworkMediaModel::onItemRemoved( MediaSourcePtr,
289 input_item_node_t *const children[],
290 size_t count )
292 for ( auto i = 0u; i < count; ++i )
294 input_item_t* p_item = children[i]->p_item;
295 input_item_Hold( p_item );
296 QMetaObject::invokeMethod(this, [this, p_item]() {
297 QUrl itemUri = QUrl::fromEncoded(p_item->psz_uri);
298 auto it = std::find_if( begin( m_items ), end( m_items ), [p_item, itemUri](const Item& i) {
299 return QString::compare( qfu(p_item->psz_name), i.name, Qt::CaseInsensitive ) == 0 &&
300 itemUri.scheme() == i.mainMrl.scheme();
302 if ( it == end( m_items ) )
304 input_item_Release( p_item );
305 return;
307 auto mrlIt = std::find_if( begin( (*it).mrls ), end( (*it).mrls),
308 [itemUri]( const QUrl& mrl ) {
309 return mrl == itemUri;
311 input_item_Release( p_item );
312 if ( mrlIt == end( (*it).mrls ) )
313 return;
314 (*it).mrls.erase( mrlIt );
315 if ( (*it).mrls.empty() == false )
316 return;
317 auto idx = std::distance( begin( m_items ), it );
318 beginRemoveRows({}, idx, idx );
319 m_items.erase( it );
320 endRemoveRows();
325 void NetworkMediaModel::onItemPreparseEnded(MediaSourcePtr, input_item_node_t*, enum input_item_preparse_status)
327 QMetaObject::invokeMethod(this, [this]() {
328 m_parsingPending = false;
329 emit parsingPendingChanged(false);
333 void NetworkMediaModel::refreshMediaList( MediaSourcePtr mediaSource,
334 input_item_node_t* const children[], size_t count,
335 bool clear )
337 auto items = new std::vector<Item>;
338 for ( auto i = 0u; i < count; ++i )
340 auto it = children[i]->p_item;
341 Item item;
342 item.name = it->psz_name;
343 item.protocol = "";
344 item.indexed = false;
345 item.type = static_cast<ItemType>(it->i_type);
346 item.mainMrl = (item.type == TYPE_DIRECTORY || item.type == TYPE_NODE) ?
347 QUrl::fromEncoded(QByteArray(it->psz_uri).append('/')) :
348 QUrl::fromEncoded(it->psz_uri);
350 item.canBeIndexed = canBeIndexed( item.mainMrl , item.type );
351 item.mediaSource = mediaSource;
353 if ( item.canBeIndexed == true )
355 if ( vlc_ml_is_indexed( m_ml, qtu( item.mainMrl.toString( QUrl::None ) ),
356 &item.indexed ) != VLC_SUCCESS )
357 item.indexed = false;
359 item.tree = NetworkTreeItem( mediaSource, it );
360 items->push_back( std::move( item ) );
362 QMetaObject::invokeMethod(this, [this, clear, items]() {
363 std::unique_ptr<std::vector<Item>> itemsPtr{ items };
364 if ( clear == true )
366 beginResetModel();
367 m_items.erase( begin( m_items ) , end( m_items ) );
369 else
370 beginInsertRows( {}, m_items.size(), m_items.size() + items->size() - 1 );
371 std::move( begin( *items ), end( *items ), std::back_inserter( m_items ) );
372 if ( clear == true )
373 endResetModel();
374 else
375 endInsertRows();
379 bool NetworkMediaModel::canBeIndexed(const QUrl& url , ItemType itemType )
381 return static_cast<input_item_type_e>(itemType) != ITEM_TYPE_FILE && (url.scheme() == "smb" || url.scheme() == "ftp");