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