File indexing completed on 2024-04-21 15:08:50
0001 /*************************************************************************** 0002 * Copyright (C) 2012-2016 by Daniel Nicoletti <dantti12@gmail.com> * 0003 * 2022 by Han Young <hanyoung@protonmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; see the file COPYING. If not, write to * 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0018 * Boston, MA 02110-1301, USA. * 0019 ***************************************************************************/ 0020 0021 #include "ProfileModel.h" 0022 #include "Profile.h" 0023 0024 #include "CdInterface.h" 0025 #include "CdProfileInterface.h" 0026 0027 #include <QDBusConnection> 0028 #include <QDBusMetaType> 0029 #include <QDateTime> 0030 #include <QDebug> 0031 #include <QFileInfo> 0032 #include <QIcon> 0033 0034 #include <KLocalizedString> 0035 0036 typedef QList<QDBusObjectPath> ObjectPathList; 0037 0038 ProfileModel::ProfileModel(CdInterface *cdInterface, QObject *parent) 0039 : QStandardItemModel(parent) 0040 { 0041 qDBusRegisterMetaType<ObjectPathList>(); 0042 qDBusRegisterMetaType<CdStringMap>(); 0043 0044 // listen to colord for events 0045 connect(cdInterface, &CdInterface::ProfileAdded, this, &ProfileModel::profileAddedEmit); 0046 connect(cdInterface, &CdInterface::ProfileRemoved, this, &ProfileModel::profileRemoved); 0047 connect(cdInterface, &CdInterface::ProfileChanged, this, &ProfileModel::profileChanged); 0048 0049 // Ask for profiles 0050 auto async = cdInterface->GetProfiles(); 0051 auto watcher = new QDBusPendingCallWatcher(async, this); 0052 connect(watcher, &QDBusPendingCallWatcher::finished, this, &ProfileModel::gotProfiles); 0053 } 0054 0055 void ProfileModel::gotProfiles(QDBusPendingCallWatcher *call) 0056 { 0057 QDBusPendingReply<ObjectPathList> reply = *call; 0058 if (reply.isError()) { 0059 qWarning() << "Unexpected message" << reply.error().message(); 0060 } else { 0061 const ObjectPathList profiles = reply.argumentAt<0>(); 0062 for (const QDBusObjectPath &profile : profiles) { 0063 profileAdded(profile, false); 0064 } 0065 Q_EMIT changed(); 0066 } 0067 call->deleteLater(); 0068 } 0069 0070 void ProfileModel::profileChanged(const QDBusObjectPath &objectPath) 0071 { 0072 int row = findItem(objectPath); 0073 if (row == -1) { 0074 qWarning() << "Profile not found" << objectPath.path(); 0075 return; 0076 } 0077 0078 Q_EMIT dataChanged(index(row, 0), index(row, 0)); 0079 } 0080 0081 void ProfileModel::profileAdded(const QDBusObjectPath &objectPath, bool emitChanged) 0082 { 0083 if (findItem(objectPath) != -1) { 0084 qWarning() << "Profile is already on the list" << objectPath.path(); 0085 return; 0086 } 0087 0088 CdProfileInterface profile(QStringLiteral("org.freedesktop.ColorManager"), objectPath.path(), QDBusConnection::systemBus()); 0089 if (!profile.isValid()) { 0090 return; 0091 } 0092 0093 // Verify if the profile has a filename 0094 QString filename = profile.filename(); 0095 if (filename.isEmpty()) { 0096 return; 0097 } 0098 0099 // Check if we can read the profile 0100 QFileInfo fileInfo(filename); 0101 if (!fileInfo.isReadable()) { 0102 return; 0103 } 0104 0105 const QString dataSource = getProfileDataSource(profile.metadata()); 0106 const QString profileId = profile.profileId(); 0107 QString title = profile.title(); 0108 const QString kind = profile.kind(); 0109 const QString colorspace = profile.colorspace(); 0110 const qlonglong created = profile.created(); 0111 0112 QStandardItem *item = new QStandardItem; 0113 item->setData(colorspace, ColorspaceRole); 0114 // Choose a nice icon 0115 if (kind == QLatin1String("display-device")) { 0116 item->setData(QStringLiteral("video-display"), Qt::DecorationRole); 0117 } else if (kind == QLatin1String("input-device")) { 0118 item->setData(QStringLiteral("scanner"), Qt::DecorationRole); 0119 } else if (kind == QLatin1String("output-device")) { 0120 if (colorspace == QLatin1String("gray")) { 0121 item->setData(QStringLiteral("printer-laser"), Qt::DecorationRole); 0122 } else { 0123 item->setData(QStringLiteral("printer"), Qt::DecorationRole); 0124 } 0125 } else if (kind == QLatin1String("colorspace-conversion")) { 0126 item->setData(QStringLiteral("view-refresh"), Qt::DecorationRole); 0127 } else if (kind == QLatin1String("abstract")) { 0128 item->setData(QStringLiteral("insert-link"), Qt::DecorationRole); 0129 } else if (kind == QLatin1String("named-color")) { 0130 item->setData(QStringLiteral("view-preview"), Qt::DecorationRole); 0131 } else { 0132 item->setData(QStringLiteral("image-missing"), Qt::DecorationRole); 0133 } 0134 0135 // Sets the profile title 0136 if (title.isEmpty()) { 0137 title = profileId; 0138 } else { 0139 QDateTime createdDT; 0140 createdDT.setSecsSinceEpoch(created); 0141 title = Profile::profileWithSource(dataSource, title, createdDT); 0142 } 0143 item->setText(title); 0144 0145 item->setData(QVariant::fromValue(objectPath), ObjectPathRole); 0146 item->setData(QString(getSortChar(kind) + title), SortRole); 0147 item->setData(filename, FilenameRole); 0148 item->setData(kind, ProfileKindRole); 0149 0150 bool canRemoveProfile = false; 0151 if (!filename.isNull() && fileInfo.isWritable() && dataSource != QLatin1String(CD_PROFILE_METADATA_DATA_SOURCE_EDID)) { 0152 // if we can write we can also remove the profile 0153 canRemoveProfile = true; 0154 } 0155 item->setData(canRemoveProfile, CanRemoveProfileRole); 0156 0157 appendRow(item); 0158 0159 if (emitChanged) { 0160 Q_EMIT changed(); 0161 } 0162 } 0163 0164 void ProfileModel::profileAddedEmit(const QDBusObjectPath &objectPath) 0165 { 0166 profileAdded(objectPath); 0167 } 0168 0169 void ProfileModel::profileRemoved(const QDBusObjectPath &objectPath) 0170 { 0171 int row = findItem(objectPath); 0172 if (row != -1) { 0173 removeRow(row); 0174 } 0175 0176 Q_EMIT changed(); 0177 } 0178 0179 void ProfileModel::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner) 0180 { 0181 Q_UNUSED(serviceName) 0182 if (newOwner.isEmpty() || oldOwner != newOwner) { 0183 // colord has quit or restarted 0184 removeRows(0, rowCount()); 0185 Q_EMIT changed(); 0186 } 0187 } 0188 0189 int ProfileModel::findItem(const QDBusObjectPath &objectPath) 0190 { 0191 for (int i = 0; i < rowCount(); ++i) { 0192 if (item(i)->data(ObjectPathRole).value<QDBusObjectPath>() == objectPath) { 0193 return i; 0194 } 0195 } 0196 return -1; 0197 } 0198 0199 QChar ProfileModel::getSortChar(const QString &kind) 0200 { 0201 if (kind == QLatin1String("display-device")) { 0202 return QLatin1Char('1'); 0203 } 0204 if (kind == QLatin1String("input-device")) { 0205 return QLatin1Char('2'); 0206 } 0207 if (kind == QLatin1String("output-device")) { 0208 return QLatin1Char('3'); 0209 } 0210 return QLatin1Char('4'); 0211 } 0212 0213 QString ProfileModel::getProfileDataSource(const CdStringMap &metadata) 0214 { 0215 QString dataSource; 0216 auto it = metadata.constFind(QStringLiteral("DATA_source")); 0217 if (it != metadata.constEnd()) { 0218 dataSource = it.value(); 0219 } 0220 return dataSource; 0221 } 0222 0223 QVariant ProfileModel::headerData(int section, Qt::Orientation orientation, int role) const 0224 { 0225 if (section == 0 && orientation == Qt::Horizontal && role == Qt::DisplayRole) { 0226 return i18n("Profiles"); 0227 } 0228 return QVariant(); 0229 } 0230 0231 Qt::ItemFlags ProfileModel::flags(const QModelIndex &index) const 0232 { 0233 QStandardItem *stdItem = itemFromIndex(index); 0234 if (stdItem && stdItem->isCheckable() && stdItem->checkState() == Qt::Unchecked) { 0235 return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; 0236 } 0237 return Qt::ItemIsSelectable | Qt::ItemIsEnabled; 0238 } 0239 0240 QHash<int, QByteArray> ProfileModel::roleNames() const 0241 { 0242 return {{Qt::DisplayRole, "title"}, 0243 {ObjectPathRole, "objectPath"}, 0244 {ParentObjectPathRole, "parentObjectPath"}, 0245 {FilenameRole, "fileName"}, 0246 {ProfileKindRole, "profileKind"}, 0247 {CanRemoveProfileRole, "canRemove"}, 0248 {SortRole, "sortString"}, 0249 {ColorspaceRole, "colorspace"}, 0250 {Qt::DecorationRole, "iconName"}}; 0251 } 0252 0253 #include "moc_ProfileModel.cpp"