1 /*
2     SPDX-FileCopyrightText: 2009 Ben Cooksley <ben@eclipse.endoftheinternet.org>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "SolidActionData.h"
8 
9 #include <QDirIterator>
10 #include <QList>
11 #include <QMetaProperty>
12 
13 #include <KConfigGroup>
14 #include <KDesktopFile>
15 #include <KDesktopFileActions>
16 #include <KStringHandler>
17 
18 #include <Solid/Battery>
19 #include <Solid/Block>
20 #include <Solid/Camera>
21 #include <Solid/GenericInterface>
22 #include <Solid/OpticalDisc>
23 #include <Solid/OpticalDrive>
24 #include <Solid/PortableMediaPlayer>
25 #include <Solid/Processor>
26 #include <Solid/StorageAccess>
27 #include <Solid/StorageDrive>
28 #include <Solid/StorageVolume>
29 
30 static SolidActionData *actData = nullptr;
31 
SolidActionData(bool includeFiles)32 SolidActionData::SolidActionData(bool includeFiles)
33 {
34     const int propertyOffset = Solid::DeviceInterface::staticMetaObject.propertyOffset();
35 
36     const QList<QMetaObject> interfaceList = fillInterfaceList();
37     for (const QMetaObject &interface : interfaceList) {
38         QString ifaceName = interface.className();
39         ifaceName.remove(0, ifaceName.lastIndexOf(':') + 1);
40         Solid::DeviceInterface::Type ifaceDev = Solid::DeviceInterface::stringToType(ifaceName);
41         const QString cleanName = Solid::DeviceInterface::typeDescription(ifaceDev);
42         types.insert(ifaceDev, cleanName);
43 
44         QMap<QString, QString> deviceValues;
45         for (int doneProps = propertyOffset; interface.propertyCount() > doneProps; doneProps = doneProps + 1) {
46             QMetaProperty ifaceProp = interface.property(doneProps);
47             deviceValues.insert(ifaceProp.name(), generateUserString(ifaceProp.name()));
48         }
49         values.insert(ifaceDev, deviceValues);
50     }
51 
52     if (includeFiles) {
53         // Fill the lists of possible device types / device values
54         const QString deviceDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, //
55                                                          QStringLiteral("/solid/devices/"),
56                                                          QStandardPaths::LocateDirectory);
57         // List all the known device actions, then add their name and all values to the appropriate lists
58         QDirIterator it(deviceDir, QStringList() << QStringLiteral("*.desktop"));
59         while (it.hasNext()) {
60             it.next();
61             const QString desktop = it.filePath();
62             KDesktopFile deviceFile(desktop);
63             KConfigGroup deviceType = deviceFile.desktopGroup(); // Retrieve the configuration group where the user friendly name is
64 
65             const QString ifaceName = deviceType.readEntry("X-KDE-Solid-Actions-Type");
66             Solid::DeviceInterface::Type ifaceDev = Solid::DeviceInterface::stringToType(ifaceName);
67             const QString cleanName = Solid::DeviceInterface::typeDescription(ifaceDev);
68 
69             types.insert(ifaceDev, cleanName); // Read the user friendly name
70 
71             QMap<QString, QString> deviceValues = values.value(ifaceDev);
72             const auto actions = deviceFile.readActions();
73             for (const QString &text : actions) { // We want every single action
74                 KConfigGroup actionType = deviceFile.actionGroup(text);
75                 deviceValues.insert(text, actionType.readEntry("Name")); // Add to the type - actions map
76             }
77             values.insert(ifaceDev, deviceValues);
78         }
79     }
80 }
81 
propertyList(Solid::DeviceInterface::Type devInterface)82 QList<QString> SolidActionData::propertyList(Solid::DeviceInterface::Type devInterface)
83 {
84     return values.value(devInterface).values();
85 }
86 
propertyInternalList(Solid::DeviceInterface::Type devInterface)87 QList<QString> SolidActionData::propertyInternalList(Solid::DeviceInterface::Type devInterface)
88 {
89     return values.value(devInterface).keys();
90 }
91 
propertyInternal(Solid::DeviceInterface::Type devInterface,QString property)92 QString SolidActionData::propertyInternal(Solid::DeviceInterface::Type devInterface, QString property)
93 {
94     return values.value(devInterface).key(property);
95 }
96 
propertyName(Solid::DeviceInterface::Type devInterface,QString property)97 QString SolidActionData::propertyName(Solid::DeviceInterface::Type devInterface, QString property)
98 {
99     return values.value(devInterface).value(property);
100 }
101 
propertyPosition(Solid::DeviceInterface::Type devInterface,QString property)102 int SolidActionData::propertyPosition(Solid::DeviceInterface::Type devInterface, QString property)
103 {
104     return values.value(devInterface).keys().indexOf(property);
105 }
106 
interfaceList()107 QList<QString> SolidActionData::interfaceList()
108 {
109     return types.values();
110 }
111 
interfaceTypeList()112 QList<Solid::DeviceInterface::Type> SolidActionData::interfaceTypeList()
113 {
114     return types.keys();
115 }
116 
interfaceFromName(const QString & name)117 Solid::DeviceInterface::Type SolidActionData::interfaceFromName(const QString &name)
118 {
119     return types.key(name);
120 }
121 
nameFromInterface(Solid::DeviceInterface::Type devInterface)122 QString SolidActionData::nameFromInterface(Solid::DeviceInterface::Type devInterface)
123 {
124     return types.value(devInterface);
125 }
126 
interfacePosition(Solid::DeviceInterface::Type devInterface)127 int SolidActionData::interfacePosition(Solid::DeviceInterface::Type devInterface)
128 {
129     return types.keys().indexOf(devInterface);
130 }
131 
generateUserString(QString className)132 QString SolidActionData::generateUserString(QString className)
133 {
134     QString finalString;
135     QRegExp camelCase(QStringLiteral("([A-Z])")); // Create the split regexp
136 
137     finalString = className.remove(0, className.lastIndexOf(':') + 1); // Remove any Class information
138     finalString.replace(camelCase, QStringLiteral(" \\1")); // Use Camel Casing to add spaces
139     finalString = KStringHandler::capwords(finalString); // Capitalize everything
140     return finalString.trimmed();
141 }
142 
instance()143 SolidActionData *SolidActionData::instance()
144 {
145     if (actData == nullptr) {
146         actData = new SolidActionData(true);
147     }
148     return actData;
149 }
150 
fillInterfaceList()151 QList<QMetaObject> SolidActionData::fillInterfaceList()
152 {
153     QList<QMetaObject> interfaces;
154     interfaces.append(Solid::Battery::staticMetaObject);
155     interfaces.append(Solid::Block::staticMetaObject);
156     interfaces.append(Solid::Camera::staticMetaObject);
157     interfaces.append(Solid::PortableMediaPlayer::staticMetaObject);
158     interfaces.append(Solid::Processor::staticMetaObject);
159     interfaces.append(Solid::StorageAccess::staticMetaObject);
160     interfaces.append(Solid::StorageDrive::staticMetaObject);
161     interfaces.append(Solid::OpticalDrive::staticMetaObject);
162     interfaces.append(Solid::StorageVolume::staticMetaObject);
163     interfaces.append(Solid::OpticalDisc::staticMetaObject);
164     return interfaces;
165 }
166