File indexing completed on 2023-09-24 08:11:02
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2010 Teo Mrnjavac <teo@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.1-or-later 0006 */ 0007 0008 #include "kaboutapplicationpersonmodel_p.h" 0009 #include "debug.h" 0010 0011 #include <QNetworkAccessManager> 0012 #include <QNetworkRequest> 0013 0014 namespace KDEPrivate 0015 { 0016 KAboutApplicationPersonModel::KAboutApplicationPersonModel(const QList<KAboutPerson> &personList, QObject *parent) 0017 : QAbstractListModel(parent) 0018 , m_personList(personList) 0019 { 0020 m_profileList.reserve(m_personList.size()); 0021 bool hasAnyAvatars{false}; 0022 for (const auto &person : std::as_const(m_personList)) { 0023 KAboutApplicationPersonProfile profile = KAboutApplicationPersonProfile(person.name(), person.task(), person.emailAddress(), person.ocsUsername()); 0024 profile.setHomepage(QUrl(person.webAddress())); 0025 if (!profile.ocsUsername().isEmpty()) { 0026 hasAnyAvatars = true; 0027 profile.setOcsProfileUrl(QLatin1String{"https://store.kde.org/u/%1"}.arg(profile.ocsUsername())); 0028 } 0029 m_profileList.append(profile); 0030 } 0031 m_hasAnyAvatars = hasAnyAvatars; 0032 0033 QNetworkAccessManager *manager = new QNetworkAccessManager(this); 0034 manager->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); 0035 connect(this, &KAboutApplicationPersonModel::showRemoteAvatarsChanged, [this, manager]() { 0036 if (showRemoteAvatars()) { 0037 int i = 0; 0038 for (const auto &profile : std::as_const(m_profileList)) { 0039 if (!profile.ocsUsername().isEmpty()) { 0040 if (profile.avatar().isNull()) { 0041 QNetworkRequest request(QUrl(QLatin1String{"https://store.kde.org/avatar/%1?s=%2"}.arg(profile.ocsUsername()).arg(AVATAR_HEIGHT))); 0042 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); 0043 QNetworkReply *reply = manager->get(request); 0044 reply->setProperty("personProfile", i); 0045 connect(reply, &QNetworkReply::finished, this, &KAboutApplicationPersonModel::onAvatarJobFinished); 0046 m_ongoingAvatarFetches << reply; 0047 } else { 0048 Q_EMIT dataChanged(index(i), index(i)); 0049 } 0050 } 0051 ++i; 0052 } 0053 } else { 0054 // We keep the avatars around, no use deleting them - just hide them in the UI 0055 // This way we don't cause unnecessary crunching on the user's connection if 0056 // they do a bunch of toggling. Just stop the current fetches, and trust the 0057 // consumer to understand it should not show avatars if this property is false. 0058 for (QNetworkReply *reply : m_ongoingAvatarFetches) { 0059 reply->abort(); 0060 } 0061 m_ongoingAvatarFetches.clear(); 0062 Q_EMIT dataChanged(index(0), index(m_profileList.count() - 1)); 0063 } 0064 }); 0065 } 0066 0067 int KAboutApplicationPersonModel::rowCount(const QModelIndex &parent) const 0068 { 0069 Q_UNUSED(parent) 0070 return m_personList.count(); 0071 } 0072 0073 QVariant KAboutApplicationPersonModel::data(const QModelIndex &index, int role) const 0074 { 0075 if (!index.isValid()) { 0076 qCWarning(DEBUG_KXMLGUI) << "ERROR: invalid index"; 0077 return QVariant(); 0078 } 0079 if (index.row() >= rowCount()) { 0080 qCWarning(DEBUG_KXMLGUI) << "ERROR: index out of bounds"; 0081 return QVariant(); 0082 } 0083 if (role == Qt::DisplayRole) { 0084 // qCDebug(DEBUG_KXMLGUI) << "Spitting data for name " << m_profileList.at( index.row() ).name(); 0085 QVariant var; 0086 var.setValue(m_profileList.at(index.row())); 0087 return var; 0088 } else { 0089 return QVariant(); 0090 } 0091 } 0092 0093 Qt::ItemFlags KAboutApplicationPersonModel::flags(const QModelIndex &index) const 0094 { 0095 if (index.isValid()) { 0096 return Qt::ItemIsEnabled; 0097 } 0098 return QAbstractListModel::flags(index) | Qt::ItemIsEditable; 0099 } 0100 0101 void KAboutApplicationPersonModel::onAvatarJobFinished() // SLOT 0102 { 0103 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); 0104 if (reply) { 0105 m_ongoingAvatarFetches.removeAll(reply); 0106 if (reply->error() == QNetworkReply::NoError) { 0107 int personProfileListIndex = reply->property("personProfile").toInt(); 0108 QNetworkAccessManager *manager = reply->manager(); 0109 if (manager) { 0110 if (reply->error() != QNetworkReply::NoError) { 0111 Q_EMIT dataChanged(index(personProfileListIndex), index(personProfileListIndex)); 0112 return; 0113 } 0114 reply->waitForReadyRead(1000); 0115 QByteArray data = reply->readAll(); 0116 QPixmap pixmap; 0117 pixmap.loadFromData(data); 0118 0119 KAboutApplicationPersonProfile profile = m_profileList.value(personProfileListIndex); 0120 if (!pixmap.isNull()) { 0121 profile.setAvatar(pixmap); 0122 if (!m_hasAvatarPixmaps) { 0123 m_hasAvatarPixmaps = true; 0124 // Data has changed for all the elements now... otherwise layouts will be all wonky in our delegates 0125 Q_EMIT dataChanged(index(0), index(m_profileList.count() - 1)); 0126 } 0127 } else { 0128 // Failed to read pixmap data, so... let's load something useful maybe? 0129 } 0130 0131 m_profileList.replace(personProfileListIndex, profile); 0132 Q_EMIT dataChanged(index(personProfileListIndex), index(personProfileListIndex)); 0133 } 0134 } 0135 reply->deleteLater(); 0136 } 0137 } 0138 0139 } // namespace KDEPrivate 0140 0141 #include "moc_kaboutapplicationpersonmodel_p.cpp"