File indexing completed on 2023-09-24 08:52:41

0001 /**
0002  * SPDX-FileCopyrightText: 2018 Nicolas Fella <nicolas.fella@gmx.de>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "remotesinksmodel.h"
0008 #include "interfaces_debug.h"
0009 
0010 #include <QDebug>
0011 
0012 #include <core/qtcompat_p.h>
0013 #include <dbushelper.h>
0014 
0015 RemoteSinksModel::RemoteSinksModel(QObject *parent)
0016     : QAbstractListModel(parent)
0017     , m_dbusInterface(nullptr)
0018 {
0019     connect(this, &QAbstractItemModel::rowsInserted, this, &RemoteSinksModel::rowsChanged);
0020     connect(this, &QAbstractItemModel::rowsRemoved, this, &RemoteSinksModel::rowsChanged);
0021 
0022     QDBusServiceWatcher *watcher =
0023         new QDBusServiceWatcher(DaemonDbusInterface::activatedService(), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this);
0024     connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &RemoteSinksModel::refreshSinkList);
0025     connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, &RemoteSinksModel::refreshSinkList);
0026 }
0027 
0028 QHash<int, QByteArray> RemoteSinksModel::roleNames() const
0029 {
0030     // Role names for QML
0031     QHash<int, QByteArray> names = QAbstractItemModel::roleNames();
0032     names.insert(NameRole, "name");
0033     names.insert(DescriptionRole, "description");
0034     names.insert(MaxVolumeRole, "maxVolume");
0035     names.insert(VolumeRole, "volume");
0036     names.insert(MutedRole, "muted");
0037 
0038     return names;
0039 }
0040 
0041 RemoteSinksModel::~RemoteSinksModel()
0042 {
0043 }
0044 
0045 QString RemoteSinksModel::deviceId() const
0046 {
0047     return m_deviceId;
0048 }
0049 
0050 void RemoteSinksModel::setDeviceId(const QString &deviceId)
0051 {
0052     m_deviceId = deviceId;
0053 
0054     if (m_dbusInterface) {
0055         delete m_dbusInterface;
0056     }
0057 
0058     m_dbusInterface = new RemoteSystemVolumeDbusInterface(deviceId, this);
0059 
0060     connect(m_dbusInterface, &OrgKdeKdeconnectDeviceRemotesystemvolumeInterface::sinksChanged, this, &RemoteSinksModel::refreshSinkList);
0061 
0062     connect(m_dbusInterface, &OrgKdeKdeconnectDeviceRemotesystemvolumeInterface::volumeChanged, this, [this](const QString &name, int volume) {
0063         auto iter = std::find_if(m_sinkList.begin(), m_sinkList.end(), [&name](const Sink &s) {
0064             return s.name == name;
0065         });
0066         if (iter != m_sinkList.end()) {
0067             iter->volume = volume;
0068             int i = std::distance(m_sinkList.begin(), iter);
0069             Q_EMIT dataChanged(index(i, 0), index(i, 0), {VolumeRole});
0070         }
0071     });
0072 
0073     connect(m_dbusInterface, &OrgKdeKdeconnectDeviceRemotesystemvolumeInterface::mutedChanged, this, [this](const QString &name, bool muted) {
0074         auto iter = std::find_if(m_sinkList.begin(), m_sinkList.end(), [&name](const Sink &s) {
0075             return s.name == name;
0076         });
0077         if (iter != m_sinkList.cend()) {
0078             iter->muted = muted;
0079             int i = std::distance(m_sinkList.begin(), iter);
0080             Q_EMIT dataChanged(index(i, 0), index(i, 0), {MutedRole});
0081         }
0082     });
0083 
0084     refreshSinkList();
0085 
0086     Q_EMIT deviceIdChanged(deviceId);
0087 }
0088 
0089 void RemoteSinksModel::refreshSinkList()
0090 {
0091     if (!m_dbusInterface) {
0092         return;
0093     }
0094 
0095     if (!m_dbusInterface->isValid()) {
0096         qCWarning(KDECONNECT_INTERFACES) << "dbus interface not valid";
0097         return;
0098     }
0099 
0100     beginResetModel();
0101     m_sinkList.clear();
0102 
0103     const auto cmds = QJsonDocument::fromJson(m_dbusInterface->sinks()).array();
0104     for (const QJsonValue &cmd : cmds) {
0105         const QJsonObject cont = cmd.toObject();
0106         Sink sink;
0107         sink.name = cont.value(QStringLiteral("name")).toString();
0108         sink.description = cont.value(QStringLiteral("description")).toString();
0109         sink.maxVolume = cont.value(QStringLiteral("maxVolume")).toInt();
0110         sink.volume = cont.value(QStringLiteral("volume")).toInt();
0111         sink.muted = cont.value(QStringLiteral("muted")).toBool();
0112         m_sinkList.append(sink);
0113     }
0114 
0115     endResetModel();
0116 }
0117 
0118 QVariant RemoteSinksModel::data(const QModelIndex &index, int role) const
0119 {
0120     if (!index.isValid() || index.row() < 0 || index.row() >= m_sinkList.count()) {
0121         return QVariant();
0122     }
0123 
0124     if (!m_dbusInterface || !m_dbusInterface->isValid()) {
0125         return QVariant();
0126     }
0127 
0128     const Sink &sink = m_sinkList[index.row()];
0129 
0130     switch (role) {
0131     case NameRole:
0132         return sink.name;
0133     case DescriptionRole:
0134         return sink.description;
0135     case MaxVolumeRole:
0136         return sink.maxVolume;
0137     case VolumeRole:
0138         return sink.volume;
0139     case MutedRole:
0140         return sink.muted;
0141     default:
0142         return QVariant();
0143     }
0144 }
0145 
0146 bool RemoteSinksModel::setData(const QModelIndex &index, const QVariant &value, int role)
0147 {
0148     if (!index.isValid() || index.row() < 0 || index.row() >= m_sinkList.count()) {
0149         return false;
0150     }
0151 
0152     if (!m_dbusInterface || !m_dbusInterface->isValid()) {
0153         return false;
0154     }
0155 
0156     const QString sinkName = m_sinkList[index.row()].name;
0157     switch (role) {
0158     case VolumeRole:
0159         m_dbusInterface->sendVolume(sinkName, value.toInt());
0160         return true;
0161     case MutedRole:
0162         m_dbusInterface->sendMuted(sinkName, value.toBool());
0163         return true;
0164     default:
0165         return false;
0166     }
0167 }
0168 
0169 int RemoteSinksModel::rowCount(const QModelIndex &parent) const
0170 {
0171     if (parent.isValid()) {
0172         // Return size 0 if we are a child because this is not a tree
0173         return 0;
0174     }
0175 
0176     return m_sinkList.count();
0177 }