File indexing completed on 2024-12-22 05:16:04
0001 /* 0002 SPDX-FileCopyrightText: 2016-2018 Jan Grulich <jgrulich@redhat.com> 0003 SPDX-FileCopyrightText: 2019 Nicolas Fella <nicolas.fella@gmx.de> 0004 SPDX-FileCopyrightText: 2020 Carson Black <uhhadd@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "kcm.h" 0010 0011 // KDE 0012 #include <KLocalizedString> 0013 #include <KPluginFactory> 0014 // Qt 0015 #include <QApplication> 0016 #include <QFileDialog> 0017 #include <QFontMetrics> 0018 #include <QImage> 0019 #include <QQmlProperty> 0020 #include <QQuickItemGrabResult> 0021 #include <QTemporaryFile> 0022 #include <QTimer> 0023 #include <QtQuick/QQuickItem> 0024 0025 #include "accounts_interface.h" 0026 #include "maskmousearea.h" 0027 #include "user.h" 0028 0029 Q_LOGGING_CATEGORY(kcm_users, "kcm_users") 0030 0031 K_PLUGIN_CLASS_WITH_JSON(KCMUser, "kcm_users.json") 0032 0033 // Work around QTBUG-100458 0034 inline auto asyncCall(OrgFreedesktopAccountsInterface *ptr, const QString &method, const QVariantList &arguments) 0035 { 0036 auto mc = QDBusMessage::createMethodCall(ptr->service(), ptr->path(), ptr->interface(), method); 0037 mc.setArguments(arguments); 0038 mc.setInteractiveAuthorizationAllowed(true); 0039 return QDBusConnection::systemBus().asyncCall(mc); 0040 } 0041 0042 KCMUser::KCMUser(QObject *parent, const KPluginMetaData &data) 0043 : KQuickConfigModule(parent, data) 0044 , m_dbusInterface(new OrgFreedesktopAccountsInterface(QStringLiteral("org.freedesktop.Accounts"), 0045 QStringLiteral("/org/freedesktop/Accounts"), 0046 QDBusConnection::systemBus(), 0047 this)) 0048 , m_model(new UserModel(this)) 0049 , m_fingerprintModel(new FingerprintModel(this)) 0050 { 0051 constexpr const char *uri = "org.kde.plasma.kcm.users"; 0052 0053 qmlRegisterUncreatableType<UserModel>(uri, 1, 0, "UserModel", QStringLiteral("Registered for enum access only")); 0054 qmlRegisterUncreatableType<User>(uri, 1, 0, "User", QStringLiteral("Use kcm.userModel to access User objects")); 0055 qmlRegisterType<MaskMouseArea>(uri, 1, 0, "MaskMouseArea"); 0056 0057 constexpr const char *uri_fm = "FingerprintModel"; 0058 0059 qmlRegisterUncreatableType<FprintDevice>(uri_fm, 1, 0, "FprintDevice", QStringLiteral("Only for enum access")); 0060 qmlRegisterType<Finger>(uri_fm, 1, 0, "Finger"); 0061 0062 setButtons(Apply); 0063 auto font = QApplication::font("QLabel"); 0064 auto fm = QFontMetrics(font); 0065 setColumnWidth(fm.capHeight() * 30); 0066 0067 const auto dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("plasma/avatars"), QStandardPaths::LocateDirectory); 0068 for (const auto &dir : dirs) { 0069 QDirIterator it(dir, QStringList{QStringLiteral("*.jpg"), QStringLiteral("*.png")}, QDir::Files, QDirIterator::Subdirectories); 0070 0071 while (it.hasNext()) { 0072 m_avatarFiles << it.next(); 0073 } 0074 } 0075 } 0076 0077 bool KCMUser::createUser(const QString &name, const QString &realName, const QString &password, bool isAdmin) 0078 { 0079 QDBusPendingReply<QDBusObjectPath> reply = asyncCall(m_dbusInterface, "CreateUser", {name, realName, static_cast<qint32>(isAdmin)}); 0080 reply.waitForFinished(); 0081 if (reply.isValid()) { 0082 User *createdUser = new User(this); 0083 createdUser->setPath(reply.value()); 0084 createdUser->setPassword(password); 0085 delete createdUser; 0086 return true; 0087 } 0088 return false; 0089 } 0090 0091 bool KCMUser::deleteUser(qint64 id, bool deleteHome) 0092 { 0093 QDBusPendingReply<> reply = asyncCall(m_dbusInterface, "DeleteUser", {id, deleteHome}); 0094 reply.waitForFinished(); 0095 if (reply.isError()) { 0096 return false; 0097 } else { 0098 return true; 0099 } 0100 } 0101 0102 KCMUser::~KCMUser() 0103 { 0104 } 0105 0106 void KCMUser::save() 0107 { 0108 KQuickConfigModule::save(); 0109 Q_EMIT apply(); 0110 } 0111 0112 // Grab the initials of a string 0113 QString KCMUser::initializeString(const QString &stringToGrabInitialsOf) 0114 { 0115 if (stringToGrabInitialsOf.isEmpty()) 0116 return ""; 0117 0118 auto normalized = stringToGrabInitialsOf.normalized(QString::NormalizationForm_D); 0119 if (normalized.contains(" ")) { 0120 QStringList split = normalized.split(" "); 0121 auto first = split.first(); 0122 auto last = split.last(); 0123 if (first.isEmpty()) { 0124 return QString(last.front()); 0125 } 0126 if (last.isEmpty()) { 0127 return QString(first.front()); 0128 } 0129 return QString(first.front()) + last.front(); 0130 } else { 0131 return QString(normalized.front()); 0132 } 0133 } 0134 0135 QString KCMUser::plonkImageInTempfile(const QImage &image) 0136 { 0137 auto file = new QTemporaryFile(qApp); 0138 if (file->open()) { 0139 image.save(file, "PNG"); 0140 } 0141 return file->fileName(); 0142 } 0143 0144 QUrl KCMUser::recolorSVG(const QUrl &url, const QColor &color) 0145 { 0146 static QMap<QUrl, QString> s_cache; 0147 0148 if (!s_cache.contains(url)) { 0149 QFile at(url.toString().sliced(QLatin1String("qrc").size())); 0150 if (at.fileName().isEmpty() || !at.open(QFile::ReadOnly)) { 0151 return QUrl(); 0152 } 0153 s_cache[url] = QString::fromUtf8(at.readAll()); 0154 } 0155 0156 auto str = s_cache[url]; 0157 str.replace("fill:#000000", "fill:" + color.name()); 0158 return QUrl("data:image/svg+xml;utf8," + QUrl::toPercentEncoding(str)); 0159 } 0160 0161 void KCMUser::load() 0162 { 0163 Q_EMIT reset(); 0164 } 0165 0166 #include "kcm.moc"