diff --git a/src/card.cpp b/src/card.cpp index 7cff602..77d88c3 100644 --- a/src/card.cpp +++ b/src/card.cpp @@ -1,134 +1,158 @@ /* Copyright 2014-2015 Harald Sitter This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "card.h" #include "card_p.h" #include "debug.h" #include "context.h" #include "pulseobject.h" #include "pulseobject_p.h" #include "cardport.h" #include "profile_p.h" namespace PulseAudioQt { Card::Card(QObject *parent) : PulseObject(parent) , d(new CardPrivate(this)) { } Card::~Card(){ delete d; } CardPrivate::CardPrivate(Card* q) : q(q) { } CardPrivate::~CardPrivate() { } void CardPrivate::update(const pa_card_info *info) { q->PulseObject::d->updatePulseObject(info); QString infoName = QString::fromUtf8(info->name); if (m_name != infoName) { m_name = infoName; Q_EMIT q->nameChanged(); } QStringList newProfiles; for (auto **it = info->profiles2; it && *it != nullptr; ++it) { const QString name = QString::fromUtf8((*it)->name); newProfiles << name; if (!m_profiles.contains(name)) { m_profiles[name] = new Profile(q); } Profile *profile = m_profiles[name]; profile->d->setInfo(*it); if (info->active_profile2 == *it) { m_activeProfileIndex = m_profiles.size() - 1; } } const QList profileKeys = m_profiles.keys(); for (const QString &profileKey : profileKeys) { if (!newProfiles.contains(profileKey)) { delete m_profiles.take(profileKey); } } Q_EMIT q->profilesChanged(); Q_EMIT q->activeProfileIndexChanged(); QStringList newPorts; for (auto **it = info->ports; it && *it != nullptr; ++it) { const QString name = QString::fromUtf8((*it)->name); newPorts << name; if (!m_ports.contains(name)) { m_ports[name] = new CardPort(q); } CardPort *port = m_ports[name]; port->update(*it); } const QList portKeys = m_ports.keys(); for (const QString &portKey : profileKeys) { if (!newPorts.contains(portKey)) { delete m_ports.take(portKey); } } Q_EMIT q->portsChanged(); } QString Card::name() const { return d->m_name; } QVector Card::profiles() const { return QVector::fromList(d->m_profiles.values()); } +QList Card::profilesQml() const +{ + QList out; + out.reserve(d->m_profiles.size()); + + for (Profile* profile : d->m_profiles.values()) { + out.append(static_cast(profile)); + } + + return out; +} + quint32 Card::activeProfileIndex() const { return d->m_activeProfileIndex; } void Card::setActiveProfileIndex(quint32 profileIndex) { const Profile *profile = qobject_cast(profiles().at(profileIndex)); context()->setCardProfile(index(), profile->name()); } QVector Card::ports() const { return QVector::fromList(d->m_ports.values()); } +QList Card::portsQml() const +{ + QList out; + out.reserve(d->m_ports.size()); + + for (CardPort* port : d->m_ports.values()) { + out.append(static_cast(port)); + } + + return out; +} + } // PulseAudioQt diff --git a/src/card.h b/src/card.h index 6869462..6a47668 100644 --- a/src/card.h +++ b/src/card.h @@ -1,66 +1,68 @@ /* Copyright 2014-2015 Harald Sitter This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef CARD_H #define CARD_H #include "pulseobject.h" struct pa_card_info; namespace PulseAudioQt { class CardPort; class Profile; class Card : public PulseObject { Q_OBJECT Q_PROPERTY(QString name READ name NOTIFY nameChanged) - Q_PROPERTY(QVector profiles READ profiles NOTIFY profilesChanged) + Q_PROPERTY(QList profiles READ profilesQml NOTIFY profilesChanged) Q_PROPERTY(quint32 activeProfileIndex READ activeProfileIndex WRITE setActiveProfileIndex NOTIFY activeProfileIndexChanged) - Q_PROPERTY(QVector ports READ ports NOTIFY portsChanged) + Q_PROPERTY(QList ports READ portsQml NOTIFY portsChanged) public: ~Card(); QString name() const; QVector profiles() const; + QList profilesQml() const; quint32 activeProfileIndex() const; void setActiveProfileIndex(quint32 profileIndex); QVector ports() const; + QList portsQml() const; Q_SIGNALS: void nameChanged(); void profilesChanged(); void activeProfileIndexChanged(); void portsChanged(); private: explicit Card(QObject *parent); class CardPrivate *const d; friend class MapBase; }; } // PulseAudioQt #endif // CARD_H diff --git a/src/device.cpp b/src/device.cpp index 5a7ef17..027e848 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -1,92 +1,104 @@ /* Copyright 2014-2015 Harald Sitter This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "device.h" #include "device_p.h" namespace PulseAudioQt { Device::State Device::state() const { return d->m_state; } QString Device::name() const { return d->m_name; } QString Device::description() const { return d->m_description; } QString Device::formFactor() const { return d->m_formFactor; } quint32 Device::cardIndex() const { return d->m_cardIndex; } QVector Device::ports() const { return QVector::fromList(d->m_ports.values()); } +QList Device::portsQml() const +{ + QList out; + out.reserve(d->m_ports.size()); + + for (Port* port : d->m_ports.values()) { + out.append(static_cast(port)); + } + + return out; +} + quint32 Device::activePortIndex() const { return d->m_activePortIndex; } Device::Device(QObject *parent) : VolumeObject(parent) , d(new DevicePrivate(this)) { } DevicePrivate::DevicePrivate(Device *q) : q(q) { } Device::State DevicePrivate::stateFromPaState(int value) const { switch (value) { case -1: // PA_X_INVALID_STATE return Device::InvalidState; case 0: // PA_X_RUNNING return Device::RunningState; case 1: // PA_X_IDLE return Device::IdleState; case 2: // PA_X_SUSPENDED return Device::SuspendedState; default: return Device::UnknownState; } } Device::~Device(){ delete d; } } // namespace PulseAudioQt diff --git a/src/device.h b/src/device.h index fc7ed4b..39437ef 100644 --- a/src/device.h +++ b/src/device.h @@ -1,90 +1,91 @@ /* Copyright 2014-2015 Harald Sitter This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef PA_DEVICE_H #define PA_DEVICE_H #include #include "volumeobject.h" namespace PulseAudioQt { class Port; class DevicePrivate; class KF5PULSEAUDIOQT_EXPORT Device : public VolumeObject { Q_OBJECT Q_PROPERTY(State state READ state NOTIFY stateChanged) Q_PROPERTY(QString name READ name NOTIFY nameChanged) Q_PROPERTY(QString description READ description NOTIFY descriptionChanged) Q_PROPERTY(QString formFactor READ formFactor NOTIFY formFactorChanged) Q_PROPERTY(quint32 cardIndex READ cardIndex NOTIFY cardIndexChanged) - Q_PROPERTY(QVector ports READ ports NOTIFY portsChanged) + Q_PROPERTY(QList ports READ portsQml NOTIFY portsChanged) Q_PROPERTY(quint32 activePortIndex READ activePortIndex WRITE setActivePortIndex NOTIFY activePortIndexChanged) Q_PROPERTY(bool default READ isDefault WRITE setDefault NOTIFY defaultChanged) public: enum State { InvalidState = 0, RunningState, IdleState, SuspendedState, UnknownState }; Q_ENUM(State); ~Device(); State state() const; QString name() const; QString description() const; QString formFactor() const; quint32 cardIndex() const; QVector ports() const; + QList portsQml() const; quint32 activePortIndex() const; virtual void setActivePortIndex(quint32 port_index) = 0; virtual bool isDefault() const = 0; virtual void setDefault(bool enable) = 0; Q_SIGNALS: void stateChanged(); void nameChanged(); void descriptionChanged(); void formFactorChanged(); void cardIndexChanged(); void portsChanged(); void activePortIndexChanged(); void defaultChanged(); protected: explicit Device(QObject *parent); DevicePrivate *d; private: friend class SinkPrivate; friend class SourcePrivate; }; } // PulseAudioQt #endif // DEVICE_H diff --git a/src/models.cpp b/src/models.cpp index a24506b..5f57450 100644 --- a/src/models.cpp +++ b/src/models.cpp @@ -1,416 +1,416 @@ /* Copyright 2014-2015 Harald Sitter Copyright 2016 David Rosca This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "models.h" #include "maps.h" #include "debug.h" #include "card.h" #include "sink.h" #include "sinkinput.h" #include "source.h" #include "sourceoutput.h" #include "server.h" #include "streamrestore.h" #include "module.h" #include "context.h" #include "context_p.h" #include #include "models_p.h" namespace PulseAudioQt { AbstractModel::AbstractModel(const MapBaseQObject *map, QObject *parent) : QAbstractListModel(parent) , d(new AbstractModelPrivate(this, map)) { Context::instance()->ref(); connect(d->m_map, &MapBaseQObject::aboutToBeAdded, this, [this](int index) { beginInsertRows(QModelIndex(), index, index); }); connect(d->m_map, &MapBaseQObject::added, this, [this](int index) { onDataAdded(index); endInsertRows(); }); connect(d->m_map, &MapBaseQObject::aboutToBeRemoved, this, [this](int index) { beginRemoveRows(QModelIndex(), index, index); }); connect(d->m_map, &MapBaseQObject::removed, this, [this](int index) { Q_UNUSED(index); endRemoveRows(); }); } AbstractModel::~AbstractModel() { //deref context after we've deleted this object //see https://bugs.kde.org/show_bug.cgi?id=371215 Context::instance()->unref(); delete d; } AbstractModelPrivate::AbstractModelPrivate(AbstractModel *q, const MapBaseQObject *map) : q(q) , m_map(map) { } AbstractModelPrivate::~AbstractModelPrivate() { } QHash AbstractModel::roleNames() const { if (!d->m_roles.empty()) { qCDebug(PULSEAUDIOQT) << "returning roles" << d->m_roles; return d->m_roles; } Q_UNREACHABLE(); return QHash(); } int AbstractModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return d->m_map->count(); } QVariant AbstractModel::data(const QModelIndex &index, int role) const { if (!hasIndex(index.row(), index.column())) { return QVariant(); } QObject *data = d->m_map->objectAt(index.row()); Q_ASSERT(data); if (role == PulseObjectRole) { return QVariant::fromValue(data); } else if (role == Qt::DisplayRole) { return static_cast(data)->properties().value(QStringLiteral("name")).toString(); } int property = d->m_objectProperties.value(role, -1); if (property == -1) { return QVariant(); } return data->metaObject()->property(property).read(data); } bool AbstractModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!hasIndex(index.row(), index.column())) { return false; } int propertyIndex = d->m_objectProperties.value(role, -1); if (propertyIndex == -1) { return false; } QObject *data = d->m_map->objectAt(index.row()); auto property = data->metaObject()->property(propertyIndex); return property.write(data, value); } int AbstractModel::role(const QByteArray &roleName) const { - qCDebug(PULSEAUDIOQT) << roleName << d->m_roles.key(roleName, -1); + qDebug() << roleName << d->m_roles.key(roleName, -1); return d->m_roles.key(roleName, -1); } Context *AbstractModel::context() const { return Context::instance(); } void AbstractModel::initRoleNames(const QMetaObject &qobjectMetaObject) { d->m_roles[PulseObjectRole] = QByteArrayLiteral("PulseObject"); QMetaEnum enumerator; for (int i = 0; i < metaObject()->enumeratorCount(); ++i) { if (metaObject()->enumerator(i).name() == QLatin1String("ItemRole")) { enumerator = metaObject()->enumerator(i); break; } } for (int i = 0; i < enumerator.keyCount(); ++i) { // Clip the Role suffix and glue it in the hash. const int roleLength = 4; QByteArray key(enumerator.key(i)); // Enum values must end in Role or the enum is crap Q_ASSERT(key.right(roleLength) == QByteArrayLiteral("Role")); key.chop(roleLength); d->m_roles[enumerator.value(i)] = key; } int maxEnumValue = -1; for (auto it = d->m_roles.constBegin(); it != d->m_roles.constEnd(); ++it) { if (it.key() > maxEnumValue) { maxEnumValue = it.key(); } } Q_ASSERT(maxEnumValue != -1); auto mo = qobjectMetaObject; for (int i = 0; i < mo.propertyCount(); ++i) { QMetaProperty property = mo.property(i); QString name(property.name()); name.replace(0, 1, name.at(0).toUpper()); d->m_roles[++maxEnumValue] = name.toLatin1(); d->m_objectProperties.insert(maxEnumValue, i); if (!property.hasNotifySignal()) { continue; } d->m_signalIndexToProperties.insert(property.notifySignalIndex(), i); } qCDebug(PULSEAUDIOQT) << d->m_roles; // Connect to property changes also with objects already in model for (int i = 0; i < d->m_map->count(); ++i) { onDataAdded(i); } } void AbstractModel::propertyChanged() { if (!sender() || senderSignalIndex() == -1) { return; } int propertyIndex = d->m_signalIndexToProperties.value(senderSignalIndex(), -1); if (propertyIndex == -1) { return; } int role = d->m_objectProperties.key(propertyIndex, -1); if (role == -1) { return; } int index = d->m_map->indexOfObject(sender()); qCDebug(PULSEAUDIOQT) << "PROPERTY CHANGED (" << index << ") :: " << role << roleNames().value(role); Q_EMIT dataChanged(createIndex(index, 0), createIndex(index, 0), {role}); } void AbstractModel::onDataAdded(int index) { QObject *data = d->m_map->objectAt(index); const QMetaObject *mo = data->metaObject(); // We have all the data changed notify signals already stored auto keys = d->m_signalIndexToProperties.keys(); foreach (int index, keys) { QMetaMethod meth = mo->method(index); connect(data, meth, this, propertyChangedMetaMethod()); } } QMetaMethod AbstractModel::propertyChangedMetaMethod() const { auto mo = metaObject(); int methodIndex = mo->indexOfMethod("propertyChanged()"); if (methodIndex == -1) { return QMetaMethod(); } return mo->method(methodIndex); } SinkModel::SinkModel(QObject *parent) : AbstractModel(&context()->d->m_sinks, parent) , d(new SinkModelPrivate(this)) { initRoleNames(Sink::staticMetaObject); for (int i = 0; i < context()->d->m_sinks.count(); ++i) { sinkAdded(i); } connect(&context()->d->m_sinks, &MapBaseQObject::added, this, &SinkModel::sinkAdded); connect(&context()->d->m_sinks, &MapBaseQObject::removed, this, &SinkModel::sinkRemoved); connect(context()->server(), &Server::defaultSinkChanged, this, [this]() { updatePreferredSink(); Q_EMIT defaultSinkChanged(); }); } SinkModel::~SinkModel() { delete d; } SinkModelPrivate::SinkModelPrivate(SinkModel *q) : q(q) , m_preferredSink(nullptr) { } SinkModelPrivate::~SinkModelPrivate() { } Sink *SinkModel::defaultSink() const { return context()->server()->defaultSink(); } Sink *SinkModel::preferredSink() const { return d->m_preferredSink; } QVariant SinkModel::data(const QModelIndex &index, int role) const { if (role == SortByDefaultRole) { // Workaround QTBUG-1548 const QString pulseIndex = data(index, AbstractModel::role(QByteArrayLiteral("Index"))).toString(); const QString defaultDevice = data(index, AbstractModel::role(QByteArrayLiteral("Default"))).toString(); return defaultDevice + pulseIndex; } return AbstractModel::data(index, role); } void SinkModel::sinkAdded(int index) { Q_ASSERT(qobject_cast(context()->d->m_sinks.objectAt(index))); Sink *sink = static_cast(context()->d->m_sinks.objectAt(index)); connect(sink, &Sink::stateChanged, this, &SinkModel::updatePreferredSink); updatePreferredSink(); } void SinkModel::sinkRemoved(int index) { Q_UNUSED(index); updatePreferredSink(); } void SinkModel::updatePreferredSink() { Sink *sink = findPreferredSink(); if (sink != d->m_preferredSink) { qCDebug(PULSEAUDIOQT) << "Changing preferred sink to" << sink << (sink ? sink->name() : ""); d->m_preferredSink = sink; Q_EMIT preferredSinkChanged(); } } Sink *SinkModel::findPreferredSink() const { const auto &sinks = context()->d->m_sinks; // Only one sink is the preferred one if (sinks.count() == 1) { return static_cast(sinks.objectAt(0)); } auto lookForState = [&](Device::State state) { Sink *ret = nullptr; const auto data = sinks.data(); for (Sink *sink : data) { if (sink->state() != state) { continue; } if (!ret) { ret = sink; } else if (sink == defaultSink()) { ret = sink; break; } } return ret; }; Sink *preferred = nullptr; // Look for playing sinks + prefer default sink preferred = lookForState(Device::RunningState); if (preferred) { return preferred; } // Look for idle sinks + prefer default sink preferred = lookForState(Device::IdleState); if (preferred) { return preferred; } // Fallback to default sink return defaultSink(); } SourceModel::SourceModel(QObject *parent) : AbstractModel(&context()->d->m_sources, parent) { initRoleNames(Source::staticMetaObject); connect(context()->server(), &Server::defaultSourceChanged, this, &SourceModel::defaultSourceChanged); } Source *SourceModel::defaultSource() const { return context()->server()->defaultSource(); } QVariant SourceModel::data(const QModelIndex &index, int role) const { if (role == SortByDefaultRole) { // Workaround QTBUG-1548 const QString pulseIndex = data(index, AbstractModel::role(QByteArrayLiteral("Index"))).toString(); const QString defaultDevice = data(index, AbstractModel::role(QByteArrayLiteral("Default"))).toString(); return defaultDevice + pulseIndex; } return AbstractModel::data(index, role); } SinkInputModel::SinkInputModel(QObject *parent) : AbstractModel(&context()->d->m_sinkInputs, parent) { initRoleNames(SinkInput::staticMetaObject); } SourceOutputModel::SourceOutputModel(QObject *parent) : AbstractModel(&context()->d->m_sourceOutputs, parent) { initRoleNames(SourceOutput::staticMetaObject); } CardModel::CardModel(QObject *parent) : AbstractModel(&context()->d->m_cards, parent) { initRoleNames(Card::staticMetaObject); } StreamRestoreModel::StreamRestoreModel(QObject *parent) : AbstractModel(&context()->d->m_streamRestores, parent) { initRoleNames(StreamRestore::staticMetaObject); } ModuleModel::ModuleModel(QObject *parent) : AbstractModel(&context()->d->m_modules, parent) { initRoleNames(Module::staticMetaObject); } } // PulseAudioQt diff --git a/src/models.h b/src/models.h index 3b1a56d..e72815e 100644 --- a/src/models.h +++ b/src/models.h @@ -1,172 +1,172 @@ /* Copyright 2014-2015 Harald Sitter Copyright 2016 David Rosca This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef PULSEAUDIO_H #define PULSEAUDIO_H #include #include "kf5pulseaudioqt_export.h" namespace PulseAudioQt { class Context; class MapBaseQObject; class Sink; class Source; class AbstractModelPrivate; class SinkModelPrivate; class KF5PULSEAUDIOQT_EXPORT AbstractModel : public QAbstractListModel { Q_OBJECT public: enum ItemRole { PulseObjectRole = Qt::UserRole + 1 }; ~AbstractModel() override; QHash roleNames() const final override; int rowCount(const QModelIndex &parent = QModelIndex()) const final override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) final override; - int role(const QByteArray &roleName) const; + Q_SCRIPTABLE int role(const QByteArray &roleName) const; protected: AbstractModel(const MapBaseQObject *map, QObject *parent); void initRoleNames(const QMetaObject &qobjectMetaObject); Context *context() const; private Q_SLOTS: void propertyChanged(); private: void onDataAdded(int index); void onDataRemoved(int index); QMetaMethod propertyChangedMetaMethod() const; AbstractModelPrivate *d; // Prevent leaf-classes from default constructing as we want to enforce // them passing us a context or explicit nullptrs. AbstractModel() {} }; class KF5PULSEAUDIOQT_EXPORT CardModel : public AbstractModel { Q_OBJECT public: CardModel(QObject *parent = nullptr); private: void *d; }; class KF5PULSEAUDIOQT_EXPORT SinkModel : public AbstractModel { Q_OBJECT Q_PROPERTY(PulseAudioQt::Sink *defaultSink READ defaultSink NOTIFY defaultSinkChanged) Q_PROPERTY(PulseAudioQt::Sink *preferredSink READ preferredSink NOTIFY preferredSinkChanged) public: enum ItemRole { SortByDefaultRole = PulseObjectRole + 1 }; Q_ENUM(ItemRole) SinkModel(QObject *parent = nullptr); virtual ~SinkModel(); Sink *defaultSink() const; Sink *preferredSink() const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; Q_SIGNALS: void defaultSinkChanged(); void preferredSinkChanged(); private: void sinkAdded(int index); void sinkRemoved(int index); void updatePreferredSink(); Sink *findPreferredSink() const; SinkModelPrivate *d; }; class KF5PULSEAUDIOQT_EXPORT SinkInputModel : public AbstractModel { Q_OBJECT public: SinkInputModel(QObject *parent = nullptr); private: void *d; }; class KF5PULSEAUDIOQT_EXPORT SourceModel : public AbstractModel { Q_OBJECT Q_PROPERTY(PulseAudioQt::Source *defaultSource READ defaultSource NOTIFY defaultSourceChanged) public: enum ItemRole { SortByDefaultRole = PulseObjectRole + 1 }; Q_ENUM(ItemRole) SourceModel(QObject *parent = nullptr); Source *defaultSource() const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; Q_SIGNALS: void defaultSourceChanged(); private: void *d; }; class KF5PULSEAUDIOQT_EXPORT SourceOutputModel : public AbstractModel { Q_OBJECT public: SourceOutputModel(QObject *parent = nullptr); private: void *d; }; class KF5PULSEAUDIOQT_EXPORT StreamRestoreModel : public AbstractModel { Q_OBJECT public: StreamRestoreModel(QObject *parent = nullptr); private: void *d; }; class KF5PULSEAUDIOQT_EXPORT ModuleModel : public AbstractModel { Q_OBJECT public: ModuleModel(QObject *parent = nullptr); private: void *d; }; } // PulseAudioQt #endif // PULSEAUDIO_H