1 /*
2 SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "fakemanager.h"
7
8 #include "fakedevice.h"
9
10 // Qt includes
11 #include <QDebug>
12 #include <QDomDocument>
13 #include <QDomElement>
14 #include <QDomNode>
15 #include <QFile>
16 #include <QString>
17 #ifdef QT_DBUS_LIB
18 #include <QDBusConnection>
19 #endif
20
21 using namespace Solid::Backends::Fake;
22
23 class FakeManager::Private
24 {
25 public:
26 QMap<QString, FakeDevice *> loadedDevices;
27 QMap<QString, QMap<QString, QVariant>> hiddenDevices;
28 QString xmlFile;
29 QSet<Solid::DeviceInterface::Type> supportedInterfaces;
30 };
31
FakeManager(QObject * parent,const QString & xmlFile)32 FakeManager::FakeManager(QObject *parent, const QString &xmlFile)
33 : Solid::Ifaces::DeviceManager(parent)
34 , d(new Private)
35 {
36 QString machineXmlFile = xmlFile;
37 d->xmlFile = machineXmlFile;
38
39 #ifdef QT_DBUS_LIB
40 QDBusConnection::sessionBus().registerObject("/org/kde/solid/fakehw", this, QDBusConnection::ExportNonScriptableSlots);
41 #endif
42
43 parseMachineFile();
44
45 // clang-format off
46 d->supportedInterfaces << Solid::DeviceInterface::GenericInterface
47 << Solid::DeviceInterface::Processor
48 << Solid::DeviceInterface::Block
49 << Solid::DeviceInterface::StorageAccess
50 << Solid::DeviceInterface::StorageDrive
51 << Solid::DeviceInterface::OpticalDrive
52 << Solid::DeviceInterface::StorageVolume
53 << Solid::DeviceInterface::OpticalDisc
54 << Solid::DeviceInterface::Camera
55 << Solid::DeviceInterface::PortableMediaPlayer
56 << Solid::DeviceInterface::Battery
57 << Solid::DeviceInterface::NetworkShare;
58 // clang-format on
59 }
60
~FakeManager()61 FakeManager::~FakeManager()
62 {
63 #ifdef QT_DBUS_LIB
64 QDBusConnection::sessionBus().unregisterObject("/org/kde/solid/fakehw", QDBusConnection::UnregisterTree);
65 #endif
66 qDeleteAll(d->loadedDevices);
67 delete d;
68 }
69
udiPrefix() const70 QString FakeManager::udiPrefix() const
71 {
72 return "/org/kde/solid/fakehw";
73 }
74
supportedInterfaces() const75 QSet<Solid::DeviceInterface::Type> FakeManager::supportedInterfaces() const
76 {
77 return d->supportedInterfaces;
78 }
79
allDevices()80 QStringList FakeManager::allDevices()
81 {
82 QStringList deviceUdiList;
83
84 for (const FakeDevice *device : std::as_const(d->loadedDevices)) {
85 deviceUdiList.append(device->udi());
86 }
87
88 return deviceUdiList;
89 }
90
devicesFromQuery(const QString & parentUdi,Solid::DeviceInterface::Type type)91 QStringList FakeManager::devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type)
92 {
93 if (!parentUdi.isEmpty()) {
94 QStringList found = findDeviceStringMatch(QLatin1String("parent"), parentUdi);
95
96 if (type == Solid::DeviceInterface::Unknown) {
97 return found;
98 }
99
100 QStringList result;
101
102 QStringList::ConstIterator it = found.constBegin();
103 QStringList::ConstIterator end = found.constEnd();
104
105 for (; it != end; ++it) {
106 FakeDevice *device = d->loadedDevices[*it];
107
108 if (device->queryDeviceInterface(type)) {
109 result << *it;
110 }
111 }
112
113 return result;
114 } else if (type != Solid::DeviceInterface::Unknown) {
115 return findDeviceByDeviceInterface(type);
116 } else {
117 return allDevices();
118 }
119 }
120
createDevice(const QString & udi)121 QObject *FakeManager::createDevice(const QString &udi)
122 {
123 if (d->loadedDevices.contains(udi)) {
124 return new FakeDevice(*d->loadedDevices[udi]);
125 }
126
127 return nullptr;
128 }
129
findDevice(const QString & udi)130 FakeDevice *FakeManager::findDevice(const QString &udi)
131 {
132 return d->loadedDevices.value(udi);
133 }
134
findDeviceStringMatch(const QString & key,const QString & value)135 QStringList FakeManager::findDeviceStringMatch(const QString &key, const QString &value)
136 {
137 QStringList result;
138 for (const FakeDevice *device : std::as_const(d->loadedDevices)) {
139 if (device->property(key).toString() == value) {
140 result.append(device->udi());
141 }
142 }
143
144 return result;
145 }
146
findDeviceByDeviceInterface(Solid::DeviceInterface::Type type)147 QStringList FakeManager::findDeviceByDeviceInterface(Solid::DeviceInterface::Type type)
148 {
149 QStringList result;
150 for (const FakeDevice *device : std::as_const(d->loadedDevices)) {
151 if (device->queryDeviceInterface(type)) {
152 result.append(device->udi());
153 }
154 }
155
156 return result;
157 }
158
plug(const QString & udi)159 void FakeManager::plug(const QString &udi)
160 {
161 if (d->hiddenDevices.contains(udi)) {
162 QMap<QString, QVariant> properties = d->hiddenDevices.take(udi);
163 d->loadedDevices[udi] = new FakeDevice(udi, properties);
164 Q_EMIT deviceAdded(udi);
165 }
166 }
167
unplug(const QString & udi)168 void FakeManager::unplug(const QString &udi)
169 {
170 if (d->loadedDevices.contains(udi)) {
171 FakeDevice *dev = d->loadedDevices.take(udi);
172 d->hiddenDevices[udi] = dev->allProperties();
173 Q_EMIT deviceRemoved(udi);
174 delete dev;
175 }
176 }
177
parseMachineFile()178 void FakeManager::parseMachineFile()
179 {
180 QFile machineFile(d->xmlFile);
181 if (!machineFile.open(QIODevice::ReadOnly)) {
182 qWarning() << Q_FUNC_INFO << "Error while opening " << d->xmlFile;
183 return;
184 }
185
186 QDomDocument fakeDocument;
187 if (!fakeDocument.setContent(&machineFile)) {
188 qWarning() << Q_FUNC_INFO << "Error while creating the QDomDocument.";
189 machineFile.close();
190 return;
191 }
192 machineFile.close();
193
194 qDebug() << Q_FUNC_INFO << "Parsing fake computer XML: " << d->xmlFile;
195 QDomElement mainElement = fakeDocument.documentElement();
196 QDomNode node = mainElement.firstChild();
197 while (!node.isNull()) {
198 QDomElement tempElement = node.toElement();
199 if (!tempElement.isNull() && tempElement.tagName() == QLatin1String("device")) {
200 FakeDevice *tempDevice = parseDeviceElement(tempElement);
201 if (tempDevice) {
202 Q_ASSERT(!d->loadedDevices.contains(tempDevice->udi()));
203 d->loadedDevices.insert(tempDevice->udi(), tempDevice);
204 Q_EMIT deviceAdded(tempDevice->udi());
205 }
206 }
207
208 node = node.nextSibling();
209 }
210 }
211
parseDeviceElement(const QDomElement & deviceElement)212 FakeDevice *FakeManager::parseDeviceElement(const QDomElement &deviceElement)
213 {
214 FakeDevice *device = nullptr;
215 QMap<QString, QVariant> propertyMap;
216 QString udi = deviceElement.attribute("udi");
217
218 QDomNode propertyNode = deviceElement.firstChild();
219 while (!propertyNode.isNull()) {
220 QDomElement propertyElement = propertyNode.toElement();
221 if (!propertyElement.isNull() && propertyElement.tagName() == QLatin1String("property")) {
222 QString propertyKey;
223 QVariant propertyValue;
224
225 propertyKey = propertyElement.attribute("key");
226 propertyValue = QVariant(propertyElement.text());
227
228 propertyMap.insert(propertyKey, propertyValue);
229 }
230
231 propertyNode = propertyNode.nextSibling();
232 }
233
234 if (!propertyMap.isEmpty()) {
235 device = new FakeDevice(udi, propertyMap);
236 }
237
238 return device;
239 }
240