File indexing completed on 2024-04-28 04:49:05
0001 /* 0002 SPDX-FileCopyrightText: 2015 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr> 0003 0004 SPDX-License-Identifier: LGPL-3.0-or-later 0005 */ 0006 0007 #include "upnpcontentdirectorymodel.h" 0008 0009 #include "musiclistenersmanager.h" 0010 0011 #include "upnpLogging.h" 0012 0013 #include "didlparser.h" 0014 #include "upnpcontrolcontentdirectory.h" 0015 #include "upnpdiscoverallmusic.h" 0016 0017 #include <UpnpDeviceDescription> 0018 #include <UpnpServiceDescription> 0019 #include <UpnpActionDescription> 0020 0021 0022 #include <QHash> 0023 #include <QString> 0024 #include <QUrl> 0025 0026 class UpnpContentDirectoryModelPrivate 0027 { 0028 public: 0029 0030 UpnpControlContentDirectory *mContentDirectory; 0031 0032 DidlParser mDidlParser; 0033 0034 QString mParentId = QStringLiteral("0"); 0035 0036 QString mBrowseFlag = QStringLiteral("BrowseDirectChildren"); 0037 0038 QString mFilter = QStringLiteral("*"); 0039 0040 QString mSortCriteria; 0041 0042 quintptr mLastInternalId; 0043 0044 QHash<QString, quintptr> mUpnpIds; 0045 0046 QHash<quintptr, QVector<quintptr> > mChilds; 0047 0048 QHash<quintptr, DataTypes::UpnpTrackDataType> mAllTrackData; 0049 0050 int mCurrentUpdateId; 0051 0052 bool mUseLocalIcons = false; 0053 0054 bool mIsBusy = false; 0055 0056 }; 0057 0058 UpnpContentDirectoryModel::UpnpContentDirectoryModel(QObject *parent) 0059 : QAbstractItemModel(parent), d(new UpnpContentDirectoryModelPrivate) 0060 { 0061 d->mContentDirectory = nullptr; 0062 0063 connect(&d->mDidlParser, &DidlParser::isDataValidChanged, this, &UpnpContentDirectoryModel::contentChanged); 0064 } 0065 0066 UpnpContentDirectoryModel::~UpnpContentDirectoryModel() 0067 = default; 0068 0069 int UpnpContentDirectoryModel::rowCount(const QModelIndex &parent) const 0070 { 0071 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::rowCount" << parent; 0072 0073 int result = 0; 0074 0075 auto currentInternalId = parent.internalId(); 0076 0077 if (!parent.isValid()) { 0078 currentInternalId = d->mUpnpIds[parentId()]; 0079 } 0080 0081 if (!d->mChilds.contains(currentInternalId)) { 0082 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::rowCount" << parent << currentInternalId << "unknown child" << result; 0083 0084 if (d->mAllTrackData.contains(currentInternalId)) { 0085 result = d->mAllTrackData[currentInternalId][DataTypes::ChildCountRole].toInt(); 0086 0087 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::rowCount" << parent << currentInternalId << result; 0088 } 0089 0090 return result; 0091 } 0092 0093 result = d->mChilds[currentInternalId].size(); 0094 0095 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::rowCount" << parent << currentInternalId << result; 0096 0097 return result; 0098 } 0099 0100 QHash<int, QByteArray> UpnpContentDirectoryModel::roleNames() const 0101 { 0102 auto roles = QAbstractItemModel::roleNames(); 0103 0104 roles[static_cast<int>(DataTypes::TitleRole)] = "title"; 0105 roles[static_cast<int>(DataTypes::SecondaryTextRole)] = "secondaryText"; 0106 roles[static_cast<int>(DataTypes::ImageUrlRole)] = "imageUrl"; 0107 roles[static_cast<int>(DataTypes::DatabaseIdRole)] = "databaseId"; 0108 roles[static_cast<int>(DataTypes::ElementTypeRole)] = "dataType"; 0109 roles[static_cast<int>(DataTypes::ResourceRole)] = "url"; 0110 0111 roles[static_cast<int>(DataTypes::ArtistRole)] = "artist"; 0112 roles[static_cast<int>(DataTypes::AllArtistsRole)] = "allArtists"; 0113 roles[static_cast<int>(DataTypes::HighestTrackRating)] = "highestTrackRating"; 0114 roles[static_cast<int>(DataTypes::GenreRole)] = "genre"; 0115 0116 roles[static_cast<int>(DataTypes::AlbumRole)] = "album"; 0117 roles[static_cast<int>(DataTypes::AlbumArtistRole)] = "albumArtist"; 0118 roles[static_cast<int>(DataTypes::DurationRole)] = "duration"; 0119 roles[static_cast<int>(DataTypes::TrackNumberRole)] = "trackNumber"; 0120 roles[static_cast<int>(DataTypes::DiscNumberRole)] = "discNumber"; 0121 roles[static_cast<int>(DataTypes::RatingRole)] = "rating"; 0122 roles[static_cast<int>(DataTypes::IsSingleDiscAlbumRole)] = "isSingleDiscAlbum"; 0123 roles[static_cast<int>(DataTypes::FullDataRole)] = "fullData"; 0124 roles[static_cast<int>(DataTypes::HasModelChildrenRole)] = "hasModelChildren"; 0125 0126 return roles; 0127 } 0128 0129 Qt::ItemFlags UpnpContentDirectoryModel::flags(const QModelIndex &index) const 0130 { 0131 if (!index.isValid()) { 0132 return Qt::NoItemFlags; 0133 } 0134 0135 return Qt::ItemIsSelectable | Qt::ItemIsEnabled; 0136 } 0137 0138 QVariant UpnpContentDirectoryModel::data(const QModelIndex &index, int role) const 0139 { 0140 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::data" << index << role; 0141 0142 QVariant result; 0143 0144 if (!index.isValid()) { 0145 return result; 0146 } 0147 0148 if (index.column() != 0) { 0149 return result; 0150 } 0151 0152 if (index.row() < 0) { 0153 return result; 0154 } 0155 0156 if (!d->mAllTrackData.contains(index.internalId())) { 0157 return result; 0158 } 0159 0160 auto convertedRole = static_cast<DataTypes::ColumnsRoles>(role); 0161 0162 switch(role) 0163 { 0164 case Qt::DisplayRole: 0165 result = d->mAllTrackData[index.internalId()][DataTypes::TitleRole]; 0166 break; 0167 case DataTypes::ElementTypeRole: 0168 case DataTypes::IdRole: 0169 case DataTypes::ParentIdRole: 0170 case DataTypes::TitleRole: 0171 case DataTypes::DurationRole: 0172 case DataTypes::ArtistRole: 0173 case DataTypes::AlbumRole: 0174 result = d->mAllTrackData[index.internalId()][convertedRole]; 0175 break; 0176 case DataTypes::RatingRole: 0177 result = 0; 0178 break; 0179 case DataTypes::ResourceRole: 0180 result = QUrl{}; 0181 break; 0182 case DataTypes::ImageUrlRole: 0183 switch (d->mAllTrackData[index.internalId()][DataTypes::ElementTypeRole].value<ElisaUtils::PlayListEntryType>()) 0184 { 0185 case ElisaUtils::Album: 0186 if (!d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole].toString().isEmpty()) { 0187 result = d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole].toUrl(); 0188 } else { 0189 if (d->mUseLocalIcons) { 0190 result = QUrl(QStringLiteral("qrc:/media-default-album.svg")); 0191 } else { 0192 result = QUrl(QStringLiteral("image://icon/media-default-album")); 0193 } 0194 } 0195 break; 0196 case ElisaUtils::Container: 0197 case ElisaUtils::UpnpMediaServer: 0198 if (!d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole].toString().isEmpty()) { 0199 result = d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole].toUrl(); 0200 } else { 0201 if (d->mUseLocalIcons) { 0202 return QUrl(QStringLiteral("qrc:/folder.svg")); 0203 } else { 0204 return QUrl(QStringLiteral("image://icon/folder")); 0205 } 0206 } 0207 break; 0208 case ElisaUtils::Track: 0209 result = d->mAllTrackData[index.internalId()][DataTypes::ImageUrlRole]; 0210 break; 0211 case ElisaUtils::Artist: 0212 case ElisaUtils::Composer: 0213 case ElisaUtils::FileName: 0214 case ElisaUtils::Genre: 0215 case ElisaUtils::Lyricist: 0216 case ElisaUtils::Radio: 0217 case ElisaUtils::Unknown: 0218 break; 0219 } 0220 break; 0221 case DataTypes::HasModelChildrenRole: 0222 result = rowCount(index); 0223 break; 0224 case DataTypes::FullDataRole: 0225 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::data" << d->mAllTrackData[index.internalId()]; 0226 result = QVariant::fromValue(static_cast<DataTypes::MusicDataType>(d->mAllTrackData[index.internalId()])); 0227 break; 0228 } 0229 0230 return result; 0231 } 0232 0233 QModelIndex UpnpContentDirectoryModel::index(int row, int column, const QModelIndex &parent) const 0234 { 0235 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent; 0236 0237 QModelIndex result; 0238 0239 auto currentInternalId = parent.internalId(); 0240 0241 if (!parent.isValid()) { 0242 currentInternalId = d->mUpnpIds[parentId()]; 0243 } 0244 0245 if (!d->mChilds.contains(currentInternalId)) { 0246 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent << result; 0247 0248 return result; 0249 } 0250 0251 if (row < 0 || row >= d->mChilds[currentInternalId].size()) { 0252 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent << result; 0253 0254 return result; 0255 } 0256 0257 if (column != 0) { 0258 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent << result; 0259 0260 return result; 0261 } 0262 0263 result = createIndex(row, column, d->mChilds[currentInternalId][row]); 0264 0265 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::index" << row << column << parent << result; 0266 0267 return result; 0268 } 0269 0270 QModelIndex UpnpContentDirectoryModel::parent(const QModelIndex &child) const 0271 { 0272 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::parent" << child; 0273 0274 QModelIndex result; 0275 0276 // child is valid 0277 if (!child.isValid()) { 0278 return result; 0279 } 0280 0281 // data knows child internal id 0282 if (!d->mAllTrackData.contains(child.internalId())) { 0283 return result; 0284 } 0285 0286 const auto &childData = d->mAllTrackData[child.internalId()]; 0287 0288 // child data has upnp id of parent 0289 if (!childData.contains(DataTypes::ParentIdRole)) { 0290 return result; 0291 } 0292 0293 const auto &parentStringId = childData[DataTypes::ParentIdRole].toString(); 0294 0295 // upnp ids has the internal id of parent 0296 if (!d->mUpnpIds.contains(parentStringId)) { 0297 return result; 0298 } 0299 0300 // special case if we are already at top of model 0301 if (parentStringId == QLatin1Char('0')) { 0302 return result; 0303 } 0304 0305 auto parentInternalId = d->mUpnpIds[parentStringId]; 0306 0307 // data knows parent internal id 0308 if (!d->mAllTrackData.contains(parentInternalId)) { 0309 return result; 0310 } 0311 0312 const auto &parentData = d->mAllTrackData[parentInternalId]; 0313 0314 // parent data has upnp id of parent 0315 if (!parentData.contains(DataTypes::ParentIdRole)) { 0316 return result; 0317 } 0318 0319 const auto &grandParentStringId = parentData[DataTypes::ParentIdRole].toString(); 0320 0321 // upnp ids has the internal id of grand parent 0322 if (!d->mUpnpIds.contains(grandParentStringId)) { 0323 return result; 0324 } 0325 0326 auto grandParentInternalId = d->mUpnpIds[grandParentStringId]; 0327 0328 // childs of grand parent are known 0329 if (!d->mChilds.contains(grandParentInternalId)) { 0330 return result; 0331 } 0332 0333 const auto &allUncles = d->mChilds[grandParentInternalId]; 0334 0335 // look for my parent 0336 for (int i = 0; i < allUncles.size(); ++i) { 0337 if (allUncles[i] == parentInternalId) { 0338 result = createIndex(i, 0, parentInternalId); 0339 break; 0340 } 0341 } 0342 0343 return result; 0344 } 0345 0346 int UpnpContentDirectoryModel::columnCount(const QModelIndex &parent) const 0347 { 0348 Q_UNUSED(parent) 0349 0350 return 1; 0351 } 0352 0353 bool UpnpContentDirectoryModel::canFetchMore(const QModelIndex &parent) const 0354 { 0355 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::canFetchMore" << parent; 0356 0357 bool result = false; 0358 0359 auto parentInternalId = parent.internalId(); 0360 0361 if (!parent.isValid()) { 0362 parentInternalId = d->mUpnpIds[parentId()]; 0363 } 0364 0365 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::canFetchMore" << parent 0366 << parentInternalId << !d->mChilds.contains(parentInternalId) 0367 << d->mChilds[parentInternalId].isEmpty(); 0368 0369 result = !d->mChilds.contains(parentInternalId) || d->mChilds[parentInternalId].isEmpty(); 0370 0371 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::canFetchMore" << parent << result; 0372 0373 return result; 0374 } 0375 0376 void UpnpContentDirectoryModel::fetchMore(const QModelIndex &parent) 0377 { 0378 if (d->mIsBusy) { 0379 return; 0380 } 0381 0382 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent; 0383 0384 d->mIsBusy = true; 0385 Q_EMIT isBusyChanged(); 0386 0387 if (!d->mContentDirectory) { 0388 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << "no content directory"; 0389 0390 d->mIsBusy = false; 0391 Q_EMIT isBusyChanged(); 0392 0393 return; 0394 } 0395 0396 auto parentInternalId = parent.internalId(); 0397 0398 if (!parent.isValid()) { 0399 parentInternalId = d->mUpnpIds[parentId()]; 0400 } 0401 0402 if (!d->mAllTrackData.contains(parentInternalId)) { 0403 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << "no parent internal id"; 0404 0405 d->mIsBusy = false; 0406 Q_EMIT isBusyChanged(); 0407 0408 return; 0409 } 0410 0411 if (!d->mAllTrackData[parentInternalId].contains(DataTypes::IdRole)) { 0412 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << "no id role"; 0413 0414 d->mIsBusy = false; 0415 Q_EMIT isBusyChanged(); 0416 0417 return; 0418 } 0419 0420 if (parentId().isEmpty()) { 0421 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << d->mAllTrackData[parentInternalId][DataTypes::IdRole].toString(); 0422 0423 d->mDidlParser.setParentId(d->mAllTrackData[parentInternalId][DataTypes::IdRole].toString()); 0424 } else { 0425 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::fetchMore" << parent << parentId(); 0426 0427 d->mDidlParser.setParentId(parentId()); 0428 } 0429 d->mDidlParser.browse(); 0430 } 0431 0432 const QString &UpnpContentDirectoryModel::parentId() const 0433 { 0434 return d->mParentId; 0435 } 0436 0437 const QString &UpnpContentDirectoryModel::browseFlag() const 0438 { 0439 return d->mBrowseFlag; 0440 } 0441 0442 void UpnpContentDirectoryModel::setBrowseFlag(const QString &flag) 0443 { 0444 d->mBrowseFlag = flag; 0445 Q_EMIT browseFlagChanged(); 0446 } 0447 0448 const QString &UpnpContentDirectoryModel::filter() const 0449 { 0450 return d->mFilter; 0451 } 0452 0453 void UpnpContentDirectoryModel::setFilter(const QString &flag) 0454 { 0455 d->mFilter = flag; 0456 Q_EMIT filterChanged(); 0457 } 0458 0459 const QString &UpnpContentDirectoryModel::sortCriteria() const 0460 { 0461 return d->mSortCriteria; 0462 } 0463 0464 void UpnpContentDirectoryModel::setSortCriteria(const QString &criteria) 0465 { 0466 d->mSortCriteria = criteria; 0467 Q_EMIT sortCriteriaChanged(); 0468 } 0469 0470 UpnpControlContentDirectory *UpnpContentDirectoryModel::contentDirectory() const 0471 { 0472 return d->mContentDirectory; 0473 } 0474 0475 void UpnpContentDirectoryModel::setContentDirectory(UpnpControlContentDirectory *directory) 0476 { 0477 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::setContentDirectory" << directory; 0478 if (directory) { 0479 beginResetModel(); 0480 } 0481 if (d->mContentDirectory) { 0482 } 0483 0484 d->mContentDirectory = directory; 0485 0486 if (!d->mContentDirectory) { 0487 Q_EMIT contentDirectoryChanged(); 0488 return; 0489 } 0490 0491 d->mDidlParser.setContentDirectory(d->mContentDirectory); 0492 d->mDidlParser.setBrowseFlag(browseFlag()); 0493 d->mDidlParser.setFilter(filter()); 0494 d->mDidlParser.setSortCriteria(sortCriteria()); 0495 d->mDidlParser.setParentId(parentId()); 0496 0497 endResetModel(); 0498 0499 Q_EMIT contentDirectoryChanged(); 0500 } 0501 0502 bool UpnpContentDirectoryModel::useLocalIcons() const 0503 { 0504 return d->mUseLocalIcons; 0505 } 0506 0507 void UpnpContentDirectoryModel::setUseLocalIcons(bool value) 0508 { 0509 d->mUseLocalIcons = value; 0510 Q_EMIT useLocalIconsChanged(); 0511 } 0512 0513 bool UpnpContentDirectoryModel::isBusy() const 0514 { 0515 return d->mIsBusy; 0516 } 0517 0518 void UpnpContentDirectoryModel::initializeByData(MusicListenersManager *manager, DatabaseInterface *database, 0519 ElisaUtils::PlayListEntryType modelType, ElisaUtils::FilterType filter, 0520 const DataTypes::DataType &dataFilter) 0521 { 0522 Q_UNUSED(database) 0523 Q_UNUSED(modelType) 0524 Q_UNUSED(filter) 0525 0526 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::initializeByData" << modelType << filter << dataFilter << dataFilter[DataTypes::UUIDRole].toString() << dataFilter[DataTypes::IdRole].toString(); 0527 0528 if (manager && manager->ssdpEngine() && manager->upnpServiceDiscovery()) { 0529 auto *newContentDirectory = new UpnpControlContentDirectory; 0530 0531 const auto &deviceDescription = manager->upnpServiceDiscovery()->deviceDescriptionByUdn(dataFilter[DataTypes::UUIDRole].toString()); 0532 newContentDirectory->setDescription(deviceDescription.serviceById(QStringLiteral("urn:upnp-org:serviceId:ContentDirectory"))); 0533 setParentId(dataFilter[DataTypes::IdRole].toString()); 0534 setContentDirectory(newContentDirectory); 0535 d->mDidlParser.setDeviceUUID(dataFilter[DataTypes::UUIDRole].toString()); 0536 } 0537 } 0538 0539 void UpnpContentDirectoryModel::setParentId(QString parentId) 0540 { 0541 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::setParentId" << parentId; 0542 0543 if (d->mParentId == parentId) { 0544 return; 0545 } 0546 0547 if (parentId.isEmpty()) { 0548 parentId = QStringLiteral("0"); 0549 } 0550 0551 d->mParentId = std::move(parentId); 0552 d->mDidlParser.setParentId(d->mParentId); 0553 0554 Q_EMIT parentIdChanged(); 0555 0556 beginResetModel(); 0557 d->mLastInternalId = 1; 0558 0559 d->mUpnpIds[d->mParentId] = d->mLastInternalId; 0560 0561 d->mChilds[d->mLastInternalId] = QVector<quintptr>(); 0562 0563 d->mAllTrackData[d->mLastInternalId] = {{DataTypes::IdRole, d->mParentId}, 0564 {DataTypes::ElementTypeRole, QVariant::fromValue(ElisaUtils::Container)}, 0565 {DataTypes::TitleRole, QStringLiteral("Root")},}; 0566 0567 ++d->mLastInternalId; 0568 0569 d->mCurrentUpdateId = -1; 0570 endResetModel(); 0571 } 0572 0573 QModelIndex UpnpContentDirectoryModel::indexFromInternalId(quintptr internalId) const 0574 { 0575 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId; 0576 0577 QModelIndex result; 0578 0579 if (internalId == 1) { 0580 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << result; 0581 0582 return result; 0583 } 0584 0585 // data knows child internal id 0586 if (!d->mAllTrackData.contains(internalId)) { 0587 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << "unknown children id" << result; 0588 0589 return result; 0590 } 0591 0592 const auto &childData = d->mAllTrackData[internalId]; 0593 0594 // child data has upnp id of parent 0595 if (!childData.contains(DataTypes::ParentIdRole)) { 0596 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << "unknown parent" << result; 0597 0598 return result; 0599 } 0600 0601 const auto &parentStringId = childData[DataTypes::ParentIdRole].toString(); 0602 0603 // upnp ids has the internal id of parent 0604 if (!d->mUpnpIds.contains(parentStringId)) { 0605 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << "unknown parent from ids list" << result; 0606 0607 return result; 0608 } 0609 0610 auto parentInternalId = d->mUpnpIds[parentStringId]; 0611 0612 // childs of parent are known 0613 if (!d->mChilds.contains(parentInternalId)) { 0614 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << "unknown parent id" << result; 0615 0616 return result; 0617 } 0618 0619 const auto &allUncles = d->mChilds[parentInternalId]; 0620 0621 // look for my parent 0622 for (int i = 0; i < allUncles.size(); ++i) { 0623 if (allUncles[i] == internalId) { 0624 result = createIndex(i, 0, internalId); 0625 break; 0626 } 0627 } 0628 0629 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::indexFromInternalId" << internalId << result; 0630 0631 return result; 0632 } 0633 0634 void UpnpContentDirectoryModel::contentChanged(const QString &parentId) 0635 { 0636 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::contentChanged" << parentId; 0637 0638 auto parentInternalId = d->mUpnpIds[parentId]; 0639 0640 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::contentChanged" << parentId 0641 << parentInternalId 0642 << indexFromInternalId(parentInternalId) 0643 << 0 << d->mDidlParser.newMusicTracks().size() - 1; 0644 beginInsertRows(indexFromInternalId(parentInternalId), 0, d->mDidlParser.newMusicTracks().size() - 1); 0645 0646 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::contentChanged" << parentId << parentInternalId; 0647 0648 for(const auto &oneUpnpTrack : std::as_const(d->mDidlParser.newMusicTracks())) { 0649 d->mAllTrackData[d->mLastInternalId] = oneUpnpTrack; 0650 d->mUpnpIds[oneUpnpTrack[DataTypes::IdRole].toString()] = d->mLastInternalId; 0651 d->mChilds[parentInternalId].push_back(d->mLastInternalId); 0652 ++d->mLastInternalId; 0653 } 0654 0655 qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::contentChanged" << parentId << d->mChilds[parentInternalId].size(); 0656 0657 endInsertRows(); 0658 0659 d->mIsBusy = false; 0660 Q_EMIT isBusyChanged(); 0661 } 0662 0663 #include "moc_upnpcontentdirectorymodel.cpp"