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 <QDir>
23#include <QFileInfo>
24#include <QLoggingCategory>
25
26#include <set>
27
28Q_GLOBAL_STATIC(Solid::DeviceManagerStorage, globalDeviceStorage)
29
30Solid::DeviceManagerPrivate::DeviceManagerPrivate()
31 : m_nullDevice(new DevicePrivate(QString()))
32{
33 loadBackends();
34
35 const QList<QObject *> backends = managerBackends();
36 for (QObject *backend : backends) {
37 connect(backend, SIGNAL(deviceAdded(QString)), this, SLOT(_k_deviceAdded(QString)));
38 connect(backend, SIGNAL(deviceRemoved(QString)), this, SLOT(_k_deviceRemoved(QString)));
39 }
40}
41
42Solid::DeviceManagerPrivate::~DeviceManagerPrivate()
43{
44 const QList<QObject *> backends = managerBackends();
45 for (QObject *backend : backends) {
46 disconnect(backend, nullptr, this, nullptr);
47 }
48
49 // take a copy as m_devicesMap is changed by Solid::DeviceManagerPrivate::_k_destroyed
50 const auto deviceMap = m_devicesMap;
51 for (QPointer<DevicePrivate> dev : deviceMap) {
52 if (!dev.data()->ref.deref()) {
53 delete dev.data();
54 }
55 }
56
57 m_devicesMap.clear();
58}
59
61{
62 QList<Device> list;
63 const QList<QObject *> backends = globalDeviceStorage->managerBackends();
64
65 for (QObject *backendObj : backends) {
66 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj);
67
68 if (backend == nullptr) {
69 continue;
70 }
71
72 const QStringList udis = backend->allDevices();
73 for (const QString &udi : udis) {
74 list.append(Device(udi));
75 }
76 }
77
78 return list;
79}
80
82{
83 Predicate p = Predicate::fromString(predicate);
84
85 if (p.isValid()) {
86 return listFromQuery(p, parentUdi);
87 } else {
88 return QList<Device>();
89 }
90}
91
93{
94 QList<Device> list;
95 const QList<QObject *> backends = globalDeviceStorage->managerBackends();
96
97 for (QObject *backendObj : backends) {
98 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj);
99
100 if (backend == nullptr) {
101 continue;
102 }
103 if (!backend->supportedInterfaces().contains(type)) {
104 continue;
105 }
106
107 const QStringList udis = backend->devicesFromQuery(parentUdi, type);
108 for (const QString &udi : udis) {
109 list.append(Device(udi));
110 }
111 }
112
113 return list;
114}
115
117{
118 QList<Device> list;
119 const QSet<DeviceInterface::Type> usedTypes = predicate.usedTypes();
120 const QList<QObject *> backends = globalDeviceStorage->managerBackends();
121 for (QObject *backendObj : backends) {
122 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj);
123
124 if (backend == nullptr) {
125 continue;
126 }
127
128 QStringList udis;
129 if (predicate.isValid()) {
130 QSet<DeviceInterface::Type> supportedTypes = backend->supportedInterfaces();
131 if (supportedTypes.intersect(usedTypes).isEmpty()) {
132 continue;
133 }
134
135 QList<DeviceInterface::Type> sortedTypes = supportedTypes.values();
136 std::sort(sortedTypes.begin(), sortedTypes.end());
137 for (DeviceInterface::Type type : std::as_const(sortedTypes)) {
138 udis += backend->devicesFromQuery(parentUdi, type);
139 }
140 } else {
141 udis += backend->allDevices();
142 }
143
144 std::set<QString> seen;
145 for (const QString &udi : std::as_const(udis)) {
146 const auto [it, isInserted] = seen.insert(udi);
147 if (!isInserted) {
148 continue;
149 }
150 Device dev(udi);
151
152 bool matches = false;
153
154 if (!predicate.isValid()) {
155 matches = true;
156 } else {
157 matches = predicate.matches(dev);
158 }
159
160 if (matches) {
161 list.append(dev);
162 }
163 }
164 }
165
166 return list;
167}
168
170{
171 if (!QFileInfo::exists(path)) {
172 qCWarning(Frontend::DeviceManager::DEVICEMANAGER).nospace() << "Couldn't get StorageAccess for \"" << path << "\" - File doesn't exist";
173 return Device();
174 }
175 // We ensure file and all mount paths are with trailing dir separators, to avoid false positive matches later
176 QString trailing_path(path);
177 if (!trailing_path.endsWith(QDir::separator())) {
178 trailing_path.append(QDir::separator());
179 }
180
181 const QList<Device> list = Solid::Device::listFromType(DeviceInterface::Type::StorageAccess);
182 Device match;
183 int match_length = 0;
184 for (const Device &device : list) {
185 auto storageVolume = device.as<StorageVolume>();
186 if (storageVolume && storageVolume->usage() != StorageVolume::UsageType::FileSystem) {
187 continue;
188 }
189
190 auto storageAccess = device.as<StorageAccess>();
191 QString mountPath = storageAccess->filePath();
192 if (!mountPath.endsWith(QDir::separator())) {
193 mountPath.append(QDir::separator());
194 }
195 if (mountPath.size() > match_length && trailing_path.startsWith(mountPath)) {
196 match_length = mountPath.size();
197 match = device;
198 }
199 }
200 return match;
201}
202
203Solid::DeviceNotifier *Solid::DeviceNotifier::instance()
204{
205 return globalDeviceStorage->notifier();
206}
207
208void Solid::DeviceManagerPrivate::_k_deviceAdded(const QString &udi)
209{
210 if (m_devicesMap.contains(udi)) {
211 DevicePrivate *dev = m_devicesMap[udi].data();
212
213 // Ok, this one was requested somewhere was invalid
214 // and now becomes magically valid!
215
216 if (dev && dev->backendObject() == nullptr) {
217 dev->setBackendObject(createBackendObject(udi));
218 Q_ASSERT(dev->backendObject() != nullptr);
219 }
220 }
221
222 Q_EMIT deviceAdded(udi);
223}
224
225void Solid::DeviceManagerPrivate::_k_deviceRemoved(const QString &udi)
226{
227 if (m_devicesMap.contains(udi)) {
228 DevicePrivate *dev = m_devicesMap[udi].data();
229
230 // Ok, this one was requested somewhere was valid
231 // and now becomes magically invalid!
232
233 if (dev) {
234 Q_ASSERT(dev->backendObject() != nullptr);
235 dev->setBackendObject(nullptr);
236 Q_ASSERT(dev->backendObject() == nullptr);
237 }
238 }
239
240 Q_EMIT deviceRemoved(udi);
241}
242
243void Solid::DeviceManagerPrivate::_k_destroyed(QObject *object)
244{
245 QString udi = m_reverseMap.take(object);
246
247 if (!udi.isEmpty()) {
248 m_devicesMap.remove(udi);
249 }
250}
251
252Solid::DevicePrivate *Solid::DeviceManagerPrivate::findRegisteredDevice(const QString &udi)
253{
254 if (udi.isEmpty()) {
255 return m_nullDevice.data();
256 } else if (m_devicesMap.contains(udi)) {
257 return m_devicesMap[udi].data();
258 } else {
259 Ifaces::Device *iface = createBackendObject(udi);
260
261 DevicePrivate *devData = new DevicePrivate(udi);
262 devData->setBackendObject(iface);
263
264 QPointer<DevicePrivate> ptr(devData);
265 m_devicesMap[udi] = ptr;
266 m_reverseMap[devData] = udi;
267
268 connect(devData, SIGNAL(destroyed(QObject *)), this, SLOT(_k_destroyed(QObject *)));
269
270 return devData;
271 }
272}
273
274Solid::Ifaces::Device *Solid::DeviceManagerPrivate::createBackendObject(const QString &udi)
275{
276 const QList<QObject *> backends = globalDeviceStorage->managerBackends();
277
278 for (QObject *backendObj : backends) {
279 Ifaces::DeviceManager *backend = qobject_cast<Ifaces::DeviceManager *>(backendObj);
280
281 if (backend == nullptr) {
282 continue;
283 }
284 if (!udi.startsWith(backend->udiPrefix())) {
285 continue;
286 }
287
288 Ifaces::Device *iface = nullptr;
289
290 QObject *object = backend->createDevice(udi);
291 iface = qobject_cast<Ifaces::Device *>(object);
292
293 if (iface == nullptr) {
294 delete object;
295 }
296
297 return iface;
298 }
299
300 return nullptr;
301}
302
303Solid::DeviceManagerStorage::DeviceManagerStorage()
304{
305}
306
307QList<QObject *> Solid::DeviceManagerStorage::managerBackends()
308{
309 ensureManagerCreated();
310 return m_storage.localData()->managerBackends();
311}
312
313Solid::DeviceNotifier *Solid::DeviceManagerStorage::notifier()
314{
315 ensureManagerCreated();
316 return m_storage.localData();
317}
318
319void Solid::DeviceManagerStorage::ensureManagerCreated()
320{
321 if (!m_storage.hasLocalData()) {
322 m_storage.setLocalData(new DeviceManagerPrivate());
323 }
324}
325
326#include "moc_devicemanager_p.cpp"
327#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 storage volume for given canonical path to file stored on that device.
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.
QChar separator()
bool exists() const const
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
QString & append(QChar ch)
QChar * data()
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
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 Tue Mar 26 2024 11:17:12 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.