1 /*
2 SPDX-FileCopyrightText: 2015 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
3
4 SPDX-License-Identifier: LGPL-3.0-or-later
5 */
6
7 #include "upnpcontentdirectorymodel.h"
8
9 #include "musiclistenersmanager.h"
10
11 #include "upnpLogging.h"
12
13 #include "didlparser.h"
14 #include "upnpcontrolcontentdirectory.h"
15 #include "upnpdiscoverallmusic.h"
16
17 #include <UpnpDeviceDescription>
18 #include <UpnpServiceDescription>
19 #include <UpnpActionDescription>
20
21 #include <QDomDocument>
22 #include <QDomElement>
23 #include <QDomNode>
24
25 #include <QHash>
26 #include <QString>
27 #include <QList>
28 #include <QLoggingCategory>
29 #include <QPointer>
30 #include <QUrl>
31
32 class UpnpContentDirectoryModelPrivate
33 {
34 public:
35
36 UpnpControlContentDirectory *mContentDirectory;
37
38 DidlParser mDidlParser;
39
40 QString mParentId = QStringLiteral("0");
41
42 QString mBrowseFlag = QStringLiteral("BrowseDirectChildren");
43
44 QString mFilter = QStringLiteral("*");
45
46 QString mSortCriteria;
47
48 quintptr mLastInternalId;
49
50 QHash<QString, quintptr> mUpnpIds;
51
52 QHash<quintptr, QVector<quintptr> > mChilds;
53
54 QHash<quintptr, DataTypes::UpnpTrackDataType> mAllTrackData;
55
56 int mCurrentUpdateId;
57
58 bool mUseLocalIcons = false;
59
60 bool mIsBusy = false;
61
62 };
63
UpnpContentDirectoryModel(QObject * parent)64 UpnpContentDirectoryModel::UpnpContentDirectoryModel(QObject *parent)
65 : QAbstractItemModel(parent), d(new UpnpContentDirectoryModelPrivate)
66 {
67 d->mContentDirectory = nullptr;
68
69 connect(&d->mDidlParser, &DidlParser::isDataValidChanged, this, &UpnpContentDirectoryModel::contentChanged);
70 }
71
72 UpnpContentDirectoryModel::~UpnpContentDirectoryModel()
73 = default;
74
rowCount(const QModelIndex & parent) const75 int UpnpContentDirectoryModel::rowCount(const QModelIndex &parent) const
76 {
77 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::rowCount" << parent;
78
79 int result = 0;
80
81 auto currentInternalId = parent.internalId();
82
83 if (!parent.isValid()) {
84 currentInternalId = d->mUpnpIds[parentId()];
85 }
86
87 if (!d->mChilds.contains(currentInternalId)) {
88 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::rowCount" << parent << currentInternalId << "unknown child" << result;
89
90 if (d->mAllTrackData.contains(currentInternalId)) {
91 result = d->mAllTrackData[currentInternalId][DataTypes::ChildCountRole].toInt();
92
93 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::rowCount" << parent << currentInternalId << result;
94 }
95
96 return result;
97 }
98
99 result = d->mChilds[currentInternalId].size();
100
101 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::rowCount" << parent << currentInternalId << result;
102
103 return result;
104 }
105
roleNames() const106 QHash<int, QByteArray> UpnpContentDirectoryModel::roleNames() const
107 {
108 auto roles = QAbstractItemModel::roleNames();
109
110 roles[static_cast<int>(DataTypes::TitleRole)] = "title";
111 roles[static_cast<int>(DataTypes::SecondaryTextRole)] = "secondaryText";
112 roles[static_cast<int>(DataTypes::ImageUrlRole)] = "imageUrl";
113 roles[static_cast<int>(DataTypes::DatabaseIdRole)] = "databaseId";
114 roles[static_cast<int>(DataTypes::ElementTypeRole)] = "dataType";
115 roles[static_cast<int>(DataTypes::ResourceRole)] = "url";
116
117 roles[static_cast<int>(DataTypes::ArtistRole)] = "artist";
118 roles[static_cast<int>(DataTypes::AllArtistsRole)] = "allArtists";
119 roles[static_cast<int>(DataTypes::HighestTrackRating)] = "highestTrackRating";
120 roles[static_cast<int>(DataTypes::GenreRole)] = "genre";
121
122 roles[static_cast<int>(DataTypes::AlbumRole)] = "album";
123 roles[static_cast<int>(DataTypes::AlbumArtistRole)] = "albumArtist";
124 roles[static_cast<int>(DataTypes::DurationRole)] = "duration";
125 roles[static_cast<int>(DataTypes::TrackNumberRole)] = "trackNumber";
126 roles[static_cast<int>(DataTypes::DiscNumberRole)] = "discNumber";
127 roles[static_cast<int>(DataTypes::RatingRole)] = "rating";
128 roles[static_cast<int>(DataTypes::IsSingleDiscAlbumRole)] = "isSingleDiscAlbum";
129 roles[static_cast<int>(DataTypes::FullDataRole)] = "fullData";
130 roles[static_cast<int>(DataTypes::HasModelChildrenRole)] = "hasModelChildren";
131
132 return roles;
133 }
134
flags(const QModelIndex & index) const135 Qt::ItemFlags UpnpContentDirectoryModel::flags(const QModelIndex &index) const
136 {
137 if (!index.isValid()) {
138 return Qt::NoItemFlags;
139 }
140
141 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
142 }
143
data(const QModelIndex & index,int role) const144 QVariant UpnpContentDirectoryModel::data(const QModelIndex &index, int role) const
145 {
146 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::data" << index << role;
147
148 QVariant result;
149
150 if (!index.isValid()) {
151 return result;
152 }
153
154 if (index.column() != 0) {
155 return result;
156 }
157
158 if (index.row() < 0) {
159 return result;
160 }
161
162 if (!d->mAllTrackData.contains(index.internalId())) {
163 return result;
164 }
165
166 auto convertedRole = static_cast<DataTypes::ColumnsRoles>(role);
167
168 switch(role)
169 {
170 case Qt::DisplayRole:
171 result = d->mAllTrackData[index.internalId()][DataTypes::TitleRole];
172 break;
173 case DataTypes::ElementTypeRole:
174 case DataTypes::IdRole:
175 case DataTypes::ParentIdRole:
176 case DataTypes::TitleRole:
177 case DataTypes::DurationRole:
178 case DataTypes::ArtistRole:
179 case DataTypes::AlbumRole:
180 result = d->mAllTrackData[index.internalId()][convertedRole];
181 break;
182 case DataTypes::RatingRole:
183 result = 0;
184 break;
185 case DataTypes::ResourceRole:
186 result = QUrl{};
187 break;
188 case DataTypes::ImageUrlRole:
189 switch (d->mAllTrackData[index.internalId()][DataTypes::ElementTypeRole].value<ElisaUtils::PlayListEntryType>())
190 {
191 case ElisaUtils::Album:
192 if (!d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole].toString().isEmpty()) {
193 result = d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole].toUrl();
194 } else {
195 if (d->mUseLocalIcons) {
196 result = QUrl(QStringLiteral("qrc:/media-optical-audio.svg"));
197 } else {
198 result = QUrl(QStringLiteral("image://icon/media-optical-audio"));
199 }
200 }
201 break;
202 case ElisaUtils::Container:
203 case ElisaUtils::UpnpMediaServer:
204 if (!d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole].toString().isEmpty()) {
205 result = d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole].toUrl();
206 } else {
207 if (d->mUseLocalIcons) {
208 return QUrl(QStringLiteral("qrc:/folder.svg"));
209 } else {
210 return QUrl(QStringLiteral("image://icon/folder"));
211 }
212 }
213 break;
214 case ElisaUtils::Track:
215 result = d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole];
216 break;
217 case ElisaUtils::Artist:
218 case ElisaUtils::Composer:
219 case ElisaUtils::FileName:
220 case ElisaUtils::Genre:
221 case ElisaUtils::Lyricist:
222 case ElisaUtils::Radio:
223 case ElisaUtils::Unknown:
224 break;
225 }
226 break;
227 case DataTypes::HasModelChildrenRole:
228 result = rowCount(index);
229 break;
230 case DataTypes::FullDataRole:
231 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::data" << d->mAllTrackData[index.internalId()];
232 result = QVariant::fromValue(static_cast<DataTypes::MusicDataType>(d->mAllTrackData[index.internalId()]));
233 break;
234 }
235
236 return result;
237 }
238
index(int row,int column,const QModelIndex & parent) const239 QModelIndex UpnpContentDirectoryModel::index(int row, int column, const QModelIndex &parent) const
240 {
241 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent;
242
243 QModelIndex result;
244
245 auto currentInternalId = parent.internalId();
246
247 if (!parent.isValid()) {
248 currentInternalId = d->mUpnpIds[parentId()];
249 }
250
251 if (!d->mChilds.contains(currentInternalId)) {
252 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent << result;
253
254 return result;
255 }
256
257 if (row < 0 || row >= d->mChilds[currentInternalId].size()) {
258 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent << result;
259
260 return result;
261 }
262
263 if (column != 0) {
264 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent << result;
265
266 return result;
267 }
268
269 result = createIndex(row, column, d->mChilds[currentInternalId][row]);
270
271 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent << result;
272
273 return result;
274 }
275
parent(const QModelIndex & child) const276 QModelIndex UpnpContentDirectoryModel::parent(const QModelIndex &child) const
277 {
278 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::parent" << child;
279
280 QModelIndex result;
281
282 // child is valid
283 if (!child.isValid()) {
284 return result;
285 }
286
287 // data knows child internal id
288 if (!d->mAllTrackData.contains(child.internalId())) {
289 return result;
290 }
291
292 const auto &childData = d->mAllTrackData[child.internalId()];
293
294 // child data has upnp id of parent
295 if (!childData.contains(DataTypes::ParentIdRole)) {
296 return result;
297 }
298
299 const auto &parentStringId = childData[DataTypes::ParentIdRole].toString();
300
301 // upnp ids has the internal id of parent
302 if (!d->mUpnpIds.contains(parentStringId)) {
303 return result;
304 }
305
306 // special case if we are already at top of model
307 if (parentStringId == QLatin1Char('0')) {
308 return result;
309 }
310
311 auto parentInternalId = d->mUpnpIds[parentStringId];
312
313 // data knows parent internal id
314 if (!d->mAllTrackData.contains(parentInternalId)) {
315 return result;
316 }
317
318 const auto &parentData = d->mAllTrackData[parentInternalId];
319
320 // parent data has upnp id of parent
321 if (!parentData.contains(DataTypes::ParentIdRole)) {
322 return result;
323 }
324
325 const auto &grandParentStringId = parentData[DataTypes::ParentIdRole].toString();
326
327 // upnp ids has the internal id of grand parent
328 if (!d->mUpnpIds.contains(grandParentStringId)) {
329 return result;
330 }
331
332 auto grandParentInternalId = d->mUpnpIds[grandParentStringId];
333
334 // childs of grand parent are known
335 if (!d->mChilds.contains(grandParentInternalId)) {
336 return result;
337 }
338
339 const auto &allUncles = d->mChilds[grandParentInternalId];
340
341 // look for my parent
342 for (int i = 0; i < allUncles.size(); ++i) {
343 if (allUncles[i] == parentInternalId) {
344 result = createIndex(i, 0, parentInternalId);
345 break;
346 }
347 }
348
349 return result;
350 }
351
columnCount(const QModelIndex & parent) const352 int UpnpContentDirectoryModel::columnCount(const QModelIndex &parent) const
353 {
354 Q_UNUSED(parent)
355
356 return 1;
357 }
358
canFetchMore(const QModelIndex & parent) const359 bool UpnpContentDirectoryModel::canFetchMore(const QModelIndex &parent) const
360 {
361 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::canFetchMore" << parent;
362
363 bool result = false;
364
365 auto parentInternalId = parent.internalId();
366
367 if (!parent.isValid()) {
368 parentInternalId = d->mUpnpIds[parentId()];
369 }
370
371 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::canFetchMore" << parent
372 << parentInternalId << !d->mChilds.contains(parentInternalId)
373 << d->mChilds[parentInternalId].isEmpty();
374
375 result = !d->mChilds.contains(parentInternalId) || d->mChilds[parentInternalId].isEmpty();
376
377 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::canFetchMore" << parent << result;
378
379 return result;
380 }
381
fetchMore(const QModelIndex & parent)382 void UpnpContentDirectoryModel::fetchMore(const QModelIndex &parent)
383 {
384 if (d->mIsBusy) {
385 return;
386 }
387
388 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent;
389
390 d->mIsBusy = true;
391 Q_EMIT isBusyChanged();
392
393 if (!d->mContentDirectory) {
394 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << "no content directory";
395
396 d->mIsBusy = false;
397 Q_EMIT isBusyChanged();
398
399 return;
400 }
401
402 auto parentInternalId = parent.internalId();
403
404 if (!parent.isValid()) {
405 parentInternalId = d->mUpnpIds[parentId()];
406 }
407
408 if (!d->mAllTrackData.contains(parentInternalId)) {
409 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << "no parent internal id";
410
411 d->mIsBusy = false;
412 Q_EMIT isBusyChanged();
413
414 return;
415 }
416
417 if (!d->mAllTrackData[parentInternalId].contains(DataTypes::IdRole)) {
418 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << "no id role";
419
420 d->mIsBusy = false;
421 Q_EMIT isBusyChanged();
422
423 return;
424 }
425
426 if (parentId().isEmpty()) {
427 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << d->mAllTrackData[parentInternalId][DataTypes::IdRole].toString();
428
429 d->mDidlParser.setParentId(d->mAllTrackData[parentInternalId][DataTypes::IdRole].toString());
430 } else {
431 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << parentId();
432
433 d->mDidlParser.setParentId(parentId());
434 }
435 d->mDidlParser.browse();
436 }
437
parentId() const438 const QString &UpnpContentDirectoryModel::parentId() const
439 {
440 return d->mParentId;
441 }
442
browseFlag() const443 const QString &UpnpContentDirectoryModel::browseFlag() const
444 {
445 return d->mBrowseFlag;
446 }
447
setBrowseFlag(const QString & flag)448 void UpnpContentDirectoryModel::setBrowseFlag(const QString &flag)
449 {
450 d->mBrowseFlag = flag;
451 Q_EMIT browseFlagChanged();
452 }
453
filter() const454 const QString &UpnpContentDirectoryModel::filter() const
455 {
456 return d->mFilter;
457 }
458
setFilter(const QString & flag)459 void UpnpContentDirectoryModel::setFilter(const QString &flag)
460 {
461 d->mFilter = flag;
462 Q_EMIT filterChanged();
463 }
464
sortCriteria() const465 const QString &UpnpContentDirectoryModel::sortCriteria() const
466 {
467 return d->mSortCriteria;
468 }
469
setSortCriteria(const QString & criteria)470 void UpnpContentDirectoryModel::setSortCriteria(const QString &criteria)
471 {
472 d->mSortCriteria = criteria;
473 Q_EMIT sortCriteriaChanged();
474 }
475
contentDirectory() const476 UpnpControlContentDirectory *UpnpContentDirectoryModel::contentDirectory() const
477 {
478 return d->mContentDirectory;
479 }
480
setContentDirectory(UpnpControlContentDirectory * directory)481 void UpnpContentDirectoryModel::setContentDirectory(UpnpControlContentDirectory *directory)
482 {
483 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::setContentDirectory" << directory;
484 if (directory) {
485 beginResetModel();
486 }
487 if (d->mContentDirectory) {
488 }
489
490 d->mContentDirectory = directory;
491
492 if (!d->mContentDirectory) {
493 Q_EMIT contentDirectoryChanged();
494 return;
495 }
496
497 d->mDidlParser.setContentDirectory(d->mContentDirectory);
498 d->mDidlParser.setBrowseFlag(browseFlag());
499 d->mDidlParser.setFilter(filter());
500 d->mDidlParser.setSortCriteria(sortCriteria());
501 d->mDidlParser.setParentId(parentId());
502
503 endResetModel();
504
505 Q_EMIT contentDirectoryChanged();
506 }
507
useLocalIcons() const508 bool UpnpContentDirectoryModel::useLocalIcons() const
509 {
510 return d->mUseLocalIcons;
511 }
512
setUseLocalIcons(bool value)513 void UpnpContentDirectoryModel::setUseLocalIcons(bool value)
514 {
515 d->mUseLocalIcons = value;
516 Q_EMIT useLocalIconsChanged();
517 }
518
isBusy() const519 bool UpnpContentDirectoryModel::isBusy() const
520 {
521 return d->mIsBusy;
522 }
523
initializeByData(MusicListenersManager * manager,DatabaseInterface * database,ElisaUtils::PlayListEntryType modelType,ElisaUtils::FilterType filter,const DataTypes::DataType & dataFilter)524 void UpnpContentDirectoryModel::initializeByData(MusicListenersManager *manager, DatabaseInterface *database,
525 ElisaUtils::PlayListEntryType modelType, ElisaUtils::FilterType filter,
526 const DataTypes::DataType &dataFilter)
527 {
528 Q_UNUSED(database)
529 Q_UNUSED(modelType)
530 Q_UNUSED(filter)
531
532 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::initializeByData" << modelType << filter << dataFilter << dataFilter[DataTypes::UUIDRole].toString() << dataFilter[DataTypes::IdRole].toString();
533
534 if (manager && manager->ssdpEngine() && manager->upnpServiceDiscovery()) {
535 auto *newContentDirectory = new UpnpControlContentDirectory;
536
537 const auto &deviceDescription = manager->upnpServiceDiscovery()->deviceDescriptionByUdn(dataFilter[DataTypes::UUIDRole].toString());
538 newContentDirectory->setDescription(deviceDescription.serviceById(QStringLiteral("urn:upnp-org:serviceId:ContentDirectory")));
539 setParentId(dataFilter[DataTypes::IdRole].toString());
540 setContentDirectory(newContentDirectory);
541 d->mDidlParser.setDeviceUUID(dataFilter[DataTypes::UUIDRole].toString());
542 }
543 }
544
setParentId(QString parentId)545 void UpnpContentDirectoryModel::setParentId(QString parentId)
546 {
547 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::setParentId" << parentId;
548
549 if (d->mParentId == parentId) {
550 return;
551 }
552
553 if (parentId.isEmpty()) {
554 parentId = QStringLiteral("0");
555 }
556
557 d->mParentId = std::move(parentId);
558 d->mDidlParser.setParentId(d->mParentId);
559
560 Q_EMIT parentIdChanged();
561
562 beginResetModel();
563 d->mLastInternalId = 1;
564
565 d->mUpnpIds[d->mParentId] = d->mLastInternalId;
566
567 d->mChilds[d->mLastInternalId] = QVector<quintptr>();
568
569 d->mAllTrackData[d->mLastInternalId] = {{DataTypes::IdRole, d->mParentId},
570 {DataTypes::ElementTypeRole, QVariant::fromValue(ElisaUtils::Container)},
571 {DataTypes::TitleRole, QStringLiteral("Root")},};
572
573 ++d->mLastInternalId;
574
575 d->mCurrentUpdateId = -1;
576 endResetModel();
577 }
578
indexFromInternalId(quintptr internalId) const579 QModelIndex UpnpContentDirectoryModel::indexFromInternalId(quintptr internalId) const
580 {
581 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId;
582
583 QModelIndex result;
584
585 if (internalId == 1) {
586 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << result;
587
588 return result;
589 }
590
591 // data knows child internal id
592 if (!d->mAllTrackData.contains(internalId)) {
593 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << "unknown children id" << result;
594
595 return result;
596 }
597
598 const auto &childData = d->mAllTrackData[internalId];
599
600 // child data has upnp id of parent
601 if (!childData.contains(DataTypes::ParentIdRole)) {
602 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << "unknown parent" << result;
603
604 return result;
605 }
606
607 const auto &parentStringId = childData[DataTypes::ParentIdRole].toString();
608
609 // upnp ids has the internal id of parent
610 if (!d->mUpnpIds.contains(parentStringId)) {
611 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << "unknown parent from ids list" << result;
612
613 return result;
614 }
615
616 auto parentInternalId = d->mUpnpIds[parentStringId];
617
618 // childs of parent are known
619 if (!d->mChilds.contains(parentInternalId)) {
620 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << "unknown parent id" << result;
621
622 return result;
623 }
624
625 const auto &allUncles = d->mChilds[parentInternalId];
626
627 // look for my parent
628 for (int i = 0; i < allUncles.size(); ++i) {
629 if (allUncles[i] == internalId) {
630 result = createIndex(i, 0, internalId);
631 break;
632 }
633 }
634
635 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << result;
636
637 return result;
638 }
639
contentChanged(const QString & parentId)640 void UpnpContentDirectoryModel::contentChanged(const QString &parentId)
641 {
642 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::contentChanged" << parentId;
643
644 auto parentInternalId = d->mUpnpIds[parentId];
645
646 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::contentChanged" << parentId
647 << parentInternalId
648 << indexFromInternalId(parentInternalId)
649 << 0 << d->mDidlParser.newMusicTracks().size() - 1;
650 beginInsertRows(indexFromInternalId(parentInternalId), 0, d->mDidlParser.newMusicTracks().size() - 1);
651
652 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::contentChanged" << parentId << parentInternalId;
653
654 for(const auto &oneUpnpTrack : std::as_const(d->mDidlParser.newMusicTracks())) {
655 d->mAllTrackData[d->mLastInternalId] = oneUpnpTrack;
656 d->mUpnpIds[oneUpnpTrack[DataTypes::IdRole].toString()] = d->mLastInternalId;
657 d->mChilds[parentInternalId].push_back(d->mLastInternalId);
658 ++d->mLastInternalId;
659 }
660
661 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::contentChanged" << parentId << d->mChilds[parentInternalId].size();
662
663 endInsertRows();
664
665 d->mIsBusy = false;
666 Q_EMIT isBusyChanged();
667 }
668
669 #include "moc_upnpcontentdirectorymodel.cpp"
670