File indexing completed on 2024-04-28 15:34:03

0001 /*
0002     SPDX-FileCopyrightText: 2013 Ivan Cukic <ivan.cukic(at)kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "devices.h"
0008 #include "devices_p.h"
0009 
0010 #include <solid/device.h>
0011 #include <solid/devicenotifier.h>
0012 #include <solid/genericinterface.h>
0013 
0014 namespace Solid
0015 {
0016 // Maps queries to the handler objects
0017 QHash<QString, QWeakPointer<DevicesQueryPrivate>> DevicesQueryPrivate::handlers;
0018 
0019 QSharedPointer<DevicesQueryPrivate> DevicesQueryPrivate::forQuery(const QString &query)
0020 {
0021     if (handlers.contains(query)) {
0022         return handlers[query].toStrongRef();
0023     }
0024 
0025     // Creating a new shared backend instance
0026     QSharedPointer<DevicesQueryPrivate> backend(new DevicesQueryPrivate(query));
0027 
0028     // Storing a weak pointer to the backend
0029     handlers[query] = backend;
0030 
0031     // Returns the newly created backend
0032     // TODO: It would be nicer with std::move and STL's smart pointers,
0033     // but RVO should optimize this out.
0034     return backend;
0035 }
0036 
0037 DevicesQueryPrivate::DevicesQueryPrivate(const QString &query)
0038     : query(query)
0039     , predicate(Solid::Predicate::fromString(query))
0040     , notifier(Solid::DeviceNotifier::instance())
0041 {
0042     connect(notifier, &Solid::DeviceNotifier::deviceAdded, this, &DevicesQueryPrivate::addDevice);
0043     connect(notifier, &Solid::DeviceNotifier::deviceRemoved, this, &DevicesQueryPrivate::removeDevice);
0044 
0045     if (!query.isEmpty() && !predicate.isValid()) {
0046         return;
0047     }
0048 
0049     const QList<Solid::Device> deviceList = Solid::Device::listFromQuery(predicate);
0050     for (const Solid::Device &device : deviceList) {
0051         matchingDevices << device.udi();
0052     }
0053 }
0054 
0055 DevicesQueryPrivate::~DevicesQueryPrivate()
0056 {
0057     handlers.remove(query);
0058 }
0059 
0060 void DevicesQueryPrivate::addDevice(const QString &udi)
0061 {
0062     if (predicate.isValid() && predicate.matches(Solid::Device(udi))) {
0063         matchingDevices << udi;
0064         Q_EMIT deviceAdded(udi);
0065     }
0066 }
0067 
0068 void DevicesQueryPrivate::removeDevice(const QString &udi)
0069 {
0070     if (predicate.isValid() && matchingDevices.contains(udi)) {
0071         matchingDevices.removeAll(udi);
0072         Q_EMIT deviceRemoved(udi);
0073     }
0074 }
0075 
0076 const QStringList &DevicesQueryPrivate::devices() const
0077 {
0078     return matchingDevices;
0079 }
0080 
0081 void Devices::initialize() const
0082 {
0083     if (m_backend) {
0084         return;
0085     }
0086 
0087     m_backend = DevicesQueryPrivate::forQuery(m_query);
0088 
0089     connect(m_backend.data(), &DevicesQueryPrivate::deviceAdded, this, &Devices::addDevice);
0090     connect(m_backend.data(), &DevicesQueryPrivate::deviceAdded, this, &Devices::addDevice);
0091     connect(m_backend.data(), &DevicesQueryPrivate::deviceRemoved, this, &Devices::removeDevice);
0092 
0093     const int matchesCount = m_backend->devices().count();
0094 
0095     if (matchesCount != 0) {
0096         Q_EMIT emptyChanged(false);
0097         Q_EMIT countChanged(matchesCount);
0098         Q_EMIT devicesChanged(m_backend->devices());
0099     }
0100 }
0101 
0102 void Devices::reset()
0103 {
0104     if (!m_backend) {
0105         return;
0106     }
0107 
0108     m_backend->disconnect(this);
0109     m_backend.reset();
0110 
0111     Q_EMIT emptyChanged(true);
0112     Q_EMIT countChanged(0);
0113     Q_EMIT devicesChanged(QStringList());
0114 }
0115 
0116 void Devices::addDevice(const QString &udi)
0117 {
0118     if (!m_backend) {
0119         return;
0120     }
0121 
0122     const int count = m_backend->devices().count();
0123 
0124     if (count == 1) {
0125         Q_EMIT emptyChanged(false);
0126     }
0127 
0128     Q_EMIT countChanged(count);
0129     Q_EMIT devicesChanged(m_backend->devices());
0130     Q_EMIT deviceAdded(udi);
0131 }
0132 
0133 void Devices::removeDevice(const QString &udi)
0134 {
0135     if (!m_backend) {
0136         return;
0137     }
0138 
0139     const int count = m_backend->devices().count();
0140 
0141     if (count == 0) {
0142         Q_EMIT emptyChanged(true);
0143     }
0144 
0145     Q_EMIT countChanged(count);
0146     Q_EMIT devicesChanged(m_backend->devices());
0147     Q_EMIT deviceRemoved(udi);
0148 }
0149 
0150 Devices::Devices(QObject *parent)
0151     : QObject(parent)
0152 {
0153 }
0154 
0155 Devices::~Devices()
0156 {
0157 }
0158 
0159 bool Devices::isEmpty() const
0160 {
0161     initialize();
0162     return count() == 0;
0163 }
0164 
0165 int Devices::count() const
0166 {
0167     initialize();
0168     return devices().count();
0169 }
0170 
0171 QStringList Devices::devices() const
0172 {
0173     initialize();
0174     return m_backend->devices();
0175 }
0176 
0177 QString Devices::query() const
0178 {
0179     return m_backend->query;
0180 }
0181 
0182 void Devices::setQuery(const QString &query)
0183 {
0184     if (m_query == query) {
0185         return;
0186     }
0187 
0188     m_query = query;
0189 
0190     reset();
0191     initialize();
0192 
0193     Q_EMIT queryChanged(query);
0194 }
0195 
0196 QObject *Devices::device(const QString &udi, const QString &_type)
0197 {
0198     Solid::DeviceInterface::Type type = Solid::DeviceInterface::stringToType(_type);
0199 
0200     return Solid::Device(udi).asDeviceInterface(type);
0201 }
0202 } // namespace Solid
0203 
0204 #include "moc_devices.cpp"
0205 #include "moc_devices_p.cpp"