Solid

frontend/devicemanager.cpp
1/*
2 SPDX-FileCopyrightText: 2005-2007 Kevin Ottens <ervin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "devicemanager_p.h" //krazy:exclude=includes (devicenotifier.h is the header file for this class)
8#include "devicenotifier.h"
9
10#include "device.h"
11#include "device_p.h"
12#include "devices_debug.h"
13#include "predicate.h"
14#include "storageaccess.h"
15#include "storagevolume.h"
16
17#include "ifaces/device.h"
18#include "ifaces/devicemanager.h"
19
20#include "soliddefs_p.h"
21
22#include <QLoggingCategory>
23
24#include <set>
25
26Q_GLOBAL_STATIC(Solid::DeviceManagerStorage, globalDeviceStorage)
27
28Solid::DeviceManagerPrivate::DeviceManagerPrivate()
29 : m_nullDevice(new DevicePrivate(QString()))
30{
31 loadBackends();
32
33 const QList<QObject *> backends = managerBackends();
34 for (QObject *backend : backends) {
35 connect(backend, SIGNAL(deviceAdded(QString)), this, SLOT(_k_deviceAdded(QString)));
36 connect(backend, SIGNAL(deviceRemoved(QString)), this, SLOT(_k_deviceRemoved(QString)));
37 }
38}
39
40Solid::DeviceManagerPrivate::~DeviceManagerPrivate()
41{
42 const QList<QObject *> backends = managerBackends();
43 for (QObject *backend : backends) {
44 disconnect(backend, nullptr, this, nullptr);
45 }
46
47 // take a copy as m_devicesMap is changed by Solid::DeviceManagerPrivate::_k_destroyed
48 const auto deviceMap = m_devicesMap;
49 for (QPointer<DevicePrivate> dev : deviceMap) {
50 if (!dev.data()->ref.deref()) {
51 delete dev.data();
52 }
53 }
54
55 m_devicesMap.clear();
56}
57
59{
60 QList<Device> list;
61 const QList<QObject *> backends = globalDeviceStorage->managerBackends();
62
63 for (QObject *backendObj : backends) {
64 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj);
65
66 if (backend == nullptr) {
67 continue;
68 }
69
70 const QStringList udis = backend->allDevices();
71 for (const QString &udi : udis) {
72 list.append(Device(udi));
73 }
74 }
75
76 return list;
77}
78
80{
81 Predicate p = Predicate::fromString(predicate);
82
83 if (p.isValid()) {
84 return listFromQuery(p, parentUdi);
85 } else {
86 return QList<Device>();
87 }
88}
89
91{
92 QList<Device> list;
93 const QList<QObject *> backends = globalDeviceStorage->managerBackends();
94
95 for (QObject *backendObj : backends) {
96 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj);
97
98 if (backend == nullptr) {
99 continue;
100 }
101 if (!backend->supportedInterfaces().contains(type)) {
102 continue;
103 }
104
105 const QStringList udis = backend->devicesFromQuery(parentUdi, type);
106 for (const QString &udi : udis) {
107 list.append(Device(udi));
108 }
109 }
110
111 return list;
112}
113
115{
116 QList<Device> list;
117 const QSet<DeviceInterface::Type> usedTypes = predicate.usedTypes();
118 const QList<QObject *> backends = globalDeviceStorage->managerBackends();
119 for (QObject *backendObj : backends) {
120 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj);
121
122 if (backend == nullptr) {
123 continue;
124 }
125
126 QStringList udis;
127 if (predicate.isValid()) {
128 QSet<DeviceInterface::Type> supportedTypes = backend->supportedInterfaces();
129 if (supportedTypes.intersect(usedTypes).isEmpty()) {
130 continue;
131 }
132
133 QList<DeviceInterface::Type> sortedTypes = supportedTypes.values();
134 std::sort(sortedTypes.begin(), sortedTypes.end());
135 for (DeviceInterface::Type type : std::as_const(sortedTypes)) {
136 udis += backend->devicesFromQuery(parentUdi, type);
137 }
138 } else {
139 udis += backend->allDevices();
140 }
141
142 std::set<QString> seen;
143 for (const QString &udi : std::as_const(udis)) {
144 const auto [it, isInserted] = seen.insert(udi);
145 if (!isInserted) {
146 continue;
147 }
148 Device dev(udi);
149
150 bool matches = false;
151
152 if (!predicate.isValid()) {
153 matches = true;
154 } else {
155 matches = predicate.matches(dev);
156 }
157
158 if (matches) {
159 list.append(dev);
160 }
161 }
162 }
163
164 return list;
165}
166
168{
169 const QList<Device> list = Solid::Device::listFromType(DeviceInterface::Type::StorageAccess);
170 Device match;
171 int match_length = 0;
172 for (const Device &device : list) {
173 auto storageVolume = device.as<StorageVolume>();
174 if (storageVolume && storageVolume->usage() != StorageVolume::UsageType::FileSystem) {
175 continue;
176 }
177
178 auto storageAccess = device.as<StorageAccess>();
179 QString mountPath = storageAccess->filePath();
180
181 if (mountPath.size() <= match_length || !path.startsWith(mountPath)) {
182 continue;
183 }
184
185 const auto realLength = mountPath.back() == '/' ? mountPath.size() - 1 : mountPath.size();
186
187 // `startsWith` implies `path.size() >= mountPath.size()`
188 if (path.size() == realLength || path[realLength] == '/') {
189 match_length = realLength;
190 match = device;
191 }
192 }
193 return match;
194}
195
196Solid::DeviceNotifier *Solid::DeviceNotifier::instance()
197{
198 return globalDeviceStorage->notifier();
199}
200
201void Solid::DeviceManagerPrivate::_k_deviceAdded(const QString &udi)
202{
203 if (m_devicesMap.contains(udi)) {
204 DevicePrivate *dev = m_devicesMap[udi].data();
205
206 // Ok, this one was requested somewhere was invalid
207 // and now becomes magically valid!
208
209 if (dev && dev->backendObject() == nullptr) {
210 dev->setBackendObject(createBackendObject(udi));
211 Q_ASSERT(dev->backendObject() != nullptr);
212 }
213 }
214
215 Q_EMIT deviceAdded(udi);
216}
217
218void Solid::DeviceManagerPrivate::_k_deviceRemoved(const QString &udi)
219{
220 if (m_devicesMap.contains(udi)) {
221 DevicePrivate *dev = m_devicesMap[udi].data();
222
223 // Ok, this one was requested somewhere was valid
224 // and now becomes magically invalid!
225
226 if (dev) {
227 dev->setBackendObject(nullptr);
228 Q_ASSERT(dev->backendObject() == nullptr);
229 }
230 }
231
232 Q_EMIT deviceRemoved(udi);
233}
234
235void Solid::DeviceManagerPrivate::_k_destroyed(QObject *object)
236{
237 QString udi = m_reverseMap.take(object);
238
239 if (!udi.isEmpty()) {
240 m_devicesMap.remove(udi);
241 }
242}
243
244Solid::DevicePrivate *Solid::DeviceManagerPrivate::findRegisteredDevice(const QString &udi)
245{
246 if (udi.isEmpty()) {
247 return m_nullDevice.data();
248 } else if (m_devicesMap.contains(udi)) {
249 return m_devicesMap[udi].data();
250 } else {
251 Ifaces::Device *iface = createBackendObject(udi);
252
253 DevicePrivate *devData = new DevicePrivate(udi);
254 devData->setBackendObject(iface);
255
256 QPointer<DevicePrivate> ptr(devData);
257 m_devicesMap[udi] = ptr;
258 m_reverseMap[devData] = udi;
259
260 connect(devData, SIGNAL(destroyed(QObject *)), this, SLOT(_k_destroyed(QObject *)));
261
262 return devData;
263 }
264}
265
266Solid::Ifaces::Device *Solid::DeviceManagerPrivate::createBackendObject(const QString &udi)
267{
268 const QList<QObject *> backends = globalDeviceStorage->managerBackends();
269
270 for (QObject *backendObj : backends) {
271 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj);
272
273 if (backend == nullptr) {
274 continue;
275 }
276 if (!udi.startsWith(backend->udiPrefix())) {
277 continue;
278 }
279
280 Ifaces::Device *iface = nullptr;
281
282 QObject *object = backend->createDevice(udi);
283 iface = qobject_cast<Ifaces::Device *>(object);
284
285 if (iface == nullptr) {
286 delete object;
287 }
288
289 return iface;
290 }
291
292 return nullptr;
293}
294
295Solid::DeviceManagerStorage::DeviceManagerStorage()
296{
297}
298
299QList<QObject *> Solid::DeviceManagerStorage::managerBackends()
300{
301 ensureManagerCreated();
302 return m_storage.localData()->managerBackends();
303}
304
305Solid::DeviceNotifier *Solid::DeviceManagerStorage::notifier()
306{
307 ensureManagerCreated();
308 return m_storage.localData();
309}
310
311void Solid::DeviceManagerStorage::ensureManagerCreated()
312{
313 if (!m_storage.hasLocalData()) {
314 m_storage.setLocalData(new DeviceManagerPrivate());
315 }
316}
317
318#include "moc_devicemanager_p.cpp"
319#include "moc_devicenotifier.cpp"
Type
This enum type defines the type of device interface that a Device can have.
This class allow to query the underlying system to obtain information about the hardware available.
This class allows applications to deal with devices available in the underlying system.
static QList< Device > listFromType(const DeviceInterface::Type &type, const QString &parentUdi=QString())
Retrieves a list of devices of the system given matching the given constraints (parent and device int...
QString udi() const
Retrieves the Universal Device Identifier (UDI).
static QList< Device > allDevices()
Retrieves all the devices available in the underlying system.
static Device storageAccessFromPath(const QString &path)
Returns the Device containing the filesystem for the given path.
Device(const QString &udi=QString())
Constructs a device for a given Universal Device Identifier (UDI).
static QList< Device > listFromQuery(const Predicate &predicate, const QString &parentUdi=QString())
Retrieves a list of devices of the system given matching the given constraints (parent and predicate)
This class specifies the interface a backend will have to implement in order to be used in the system...
virtual QStringList allDevices()=0
Retrieves the Universal Device Identifier (UDI) of all the devices available in the system.
virtual QSet< Solid::DeviceInterface::Type > supportedInterfaces() const =0
Retrieves a set of interfaces the backend supports.
virtual QStringList devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type=Solid::DeviceInterface::Unknown)=0
Retrieves the Universal Device Identifier (UDI) of all the devices matching the given constraints (pa...
This class specifies the interface a device will have to comply to in order to be used in the system.
This class implements predicates for devices.
Definition predicate.h:67
bool matches(const Device &device) const
Checks if a device matches the predicate.
bool isValid() const
Indicates if the predicate is valid.
QSet< DeviceInterface::Type > usedTypes() const
Retrieves the device interface types used in this predicate.
static Predicate fromString(const QString &predicate)
Converts a string to a predicate.
This device interface is available on volume devices to access them (i.e.
This device interface is available on volume devices.
void append(QList< T > &&value)
iterator begin()
iterator end()
iterator insert(const_iterator before, parameter_type value)
bool contains(const QSet< T > &other) const const
QSet< T > & intersect(const QSet< T > &other)
QList< T > values() const const
QChar & back()
QChar * data()
bool isEmpty() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:47:59 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.