From 46e23ec0f1c6d6fe552e0822105cf4a15424f030 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> Date: Tue, 24 Mar 2015 18:01:58 -0400 Subject: [PATCH] video: Offer a configuration proxy model This avoid using "if" nest in the GUI It also made possible to enable dynamic device reloading without extra client complexity. Refs #69141 --- CMakeLists.txt | 2 + src/video/configurationproxy.cpp | 277 +++++++++++++++++++++++++++++++ src/video/configurationproxy.h | 48 ++++++ src/video/devicemodel.cpp | 13 +- 4 files changed, 335 insertions(+), 5 deletions(-) create mode 100644 src/video/configurationproxy.cpp create mode 100644 src/video/configurationproxy.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3817efbd..b270fb2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,6 +212,7 @@ SET( libringclient_LIB_SRCS src/video/sourcemodel.cpp src/video/channel.cpp src/video/resolution.cpp + src/video/configurationproxy.cpp src/audio/alsapluginmodel.cpp src/audio/inputdevicemodel.cpp src/audio/managermodel.cpp @@ -333,6 +334,7 @@ SET(libringclient_video_LIB_HDRS src/video/channel.h src/video/rate.h src/video/previewmanager.h + src/video/configurationproxy.h #The renderer implementations are not exported on purpose ) diff --git a/src/video/configurationproxy.cpp b/src/video/configurationproxy.cpp new file mode 100644 index 00000000..16e7c775 --- /dev/null +++ b/src/video/configurationproxy.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** + * Copyright (C) 2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * 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) any later version. * + * * + * 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 General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#include "configurationproxy.h" + +//Qt +#include <QtCore/QIdentityProxyModel> +#include <QtCore/QAbstractItemModel> +#include <QtCore/QItemSelectionModel> + +//Ring +#include <video/sourcemodel.h> +#include <video/devicemodel.h> +#include <video/channel.h> +#include <video/resolution.h> +#include <video/rate.h> + +namespace ConfigurationProxyPrivate { + static QIdentityProxyModel* m_spDeviceModel = nullptr; + static QIdentityProxyModel* m_spChannelModel = nullptr; + static QIdentityProxyModel* m_spResolutionModel= nullptr; + static QIdentityProxyModel* m_spRateModel = nullptr; + + static QItemSelectionModel* m_spDeviceSelectionModel = nullptr; + static QItemSelectionModel* m_spChannelSelectionModel = nullptr; + static QItemSelectionModel* m_spResolutionSelectionModel= nullptr; + static QItemSelectionModel* m_spRateSelectionModel = nullptr; + + //Helper + static Video::Device* currentDevice (); + static Video::Channel* currentChannel (); + static Video::Resolution* currentResolution(); +// static Video::Rate* currentRate (); + + static void changeDevice (); + static void changeChannel (); + static void changeResolution(); + static void changeRate (); + + void updateDeviceSelection (); + void updateChannelSelection (); + void updateResolutionSelection(); + void updateRateSelection (); +} + +QAbstractItemModel* Video::ConfigurationProxy::deviceModel() +{ + if (!ConfigurationProxyPrivate::m_spDeviceModel) { + ConfigurationProxyPrivate::m_spDeviceModel = new QIdentityProxyModel(Video::SourceModel::instance()); + ConfigurationProxyPrivate::m_spDeviceModel->setSourceModel(Video::DeviceModel::instance()); + ConfigurationProxyPrivate::updateDeviceSelection(); + } + return ConfigurationProxyPrivate::m_spDeviceModel; +} + +static Video::Device* ConfigurationProxyPrivate::currentDevice() +{ + return Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice(); +} + +static Video::Channel* ConfigurationProxyPrivate::currentChannel() +{ + if (Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice() + && Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice()->activeChannel()) + return Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice()->activeChannel(); + + return nullptr; +} + +static Video::Resolution* ConfigurationProxyPrivate::currentResolution() +{ + if (Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice() + && Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice()->activeChannel() + && Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice()->activeChannel()->activeResolution() + ) + return Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice()->activeChannel()->activeResolution(); + return nullptr; +} + +/*static Video::Rate* ConfigurationProxyPrivate::currentRate() +{ + if (Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice() + && Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice()->activeChannel() + && Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice()->activeChannel()->activeResolution() + ) + return Video::DeviceModel::instance()->Video::DeviceModel::instance()->activeDevice()->activeChannel()->activeResolution()->activeRate(); + + return nullptr; +}*/ + +void ConfigurationProxyPrivate::changeDevice() +{ + Video::ConfigurationProxy::deviceSelectionModel(); + + Video::DeviceModel::instance()->setActive(ConfigurationProxyPrivate::m_spDeviceSelectionModel->currentIndex()); + + ((QIdentityProxyModel*) Video::ConfigurationProxy::channelModel())->setSourceModel(ConfigurationProxyPrivate::currentDevice()); + changeChannel(); +} + +void ConfigurationProxyPrivate::changeChannel() +{ + Video::ConfigurationProxy::channelSelectionModel(); + + Video::Device* dev = ConfigurationProxyPrivate::currentDevice(); + + if (dev) + dev->setActiveChannel(ConfigurationProxyPrivate::m_spChannelSelectionModel->currentIndex().row()); + + ((QIdentityProxyModel*) Video::ConfigurationProxy::resolutionModel())->setSourceModel(ConfigurationProxyPrivate::currentChannel()); + + updateChannelSelection(); + + changeResolution(); +} + +void ConfigurationProxyPrivate::changeResolution() +{ + Video::ConfigurationProxy::resolutionSelectionModel(); + + Video::Channel* chan = ConfigurationProxyPrivate::currentChannel(); + + if (chan) + chan->setActiveResolution(ConfigurationProxyPrivate::m_spResolutionSelectionModel->currentIndex().row()); + + ((QIdentityProxyModel*) Video::ConfigurationProxy::rateModel())->setSourceModel(ConfigurationProxyPrivate::currentResolution()); + + updateResolutionSelection(); + + changeRate(); +} + +void ConfigurationProxyPrivate::changeRate() +{ + Video::ConfigurationProxy::rateSelectionModel(); + + Video::Resolution* res = ConfigurationProxyPrivate::currentResolution(); + + if (res) + res->setActiveRate(ConfigurationProxyPrivate::m_spRateSelectionModel->currentIndex().row()); + + updateRateSelection(); +} + +void ConfigurationProxyPrivate::updateDeviceSelection() +{ + const QModelIndex& idx = ConfigurationProxyPrivate::m_spDeviceModel->index(Video::DeviceModel::instance()->activeIndex(),0); + Video::ConfigurationProxy::deviceSelectionModel()->setCurrentIndex(idx , QItemSelectionModel::ClearAndSelect); +} + +void ConfigurationProxyPrivate::updateChannelSelection() +{ + Video::Device* dev = ConfigurationProxyPrivate::currentDevice(); + if (dev) { + Video::Channel* chan = dev->activeChannel(); + if (chan) + Video::ConfigurationProxy::channelSelectionModel()->setCurrentIndex(dev->index(chan->relativeIndex(),0), QItemSelectionModel::ClearAndSelect ); + } +} + +void ConfigurationProxyPrivate::updateResolutionSelection() +{ + Video::Channel* chan = ConfigurationProxyPrivate::currentChannel(); + if (chan) { + Video::Resolution* res = chan->activeResolution(); + if (res) + Video::ConfigurationProxy::resolutionSelectionModel()->setCurrentIndex(chan->index(res->relativeIndex(),0), QItemSelectionModel::ClearAndSelect); + } +} + +void ConfigurationProxyPrivate::updateRateSelection() +{ + Video::Resolution* res = ConfigurationProxyPrivate::currentResolution(); + if (res) { + Video::Rate* rate = res->activeRate(); + if (rate) + Video::ConfigurationProxy::rateSelectionModel()->setCurrentIndex(res->index(rate->relativeIndex(),0), QItemSelectionModel::ClearAndSelect); + } +} + +QAbstractItemModel* Video::ConfigurationProxy::channelModel() +{ + if (!ConfigurationProxyPrivate::m_spChannelModel) { + ConfigurationProxyPrivate::m_spChannelModel = new QIdentityProxyModel(Video::SourceModel::instance()); + Video::Device* dev = ConfigurationProxyPrivate::currentDevice(); + if (dev) { + ConfigurationProxyPrivate::m_spChannelModel->setSourceModel(dev); + } + } + return ConfigurationProxyPrivate::m_spChannelModel; +} + +QAbstractItemModel* Video::ConfigurationProxy::resolutionModel() +{ + if (!ConfigurationProxyPrivate::m_spResolutionModel) { + ConfigurationProxyPrivate::m_spResolutionModel = new QIdentityProxyModel(Video::SourceModel::instance()); + Video::Channel* chan = ConfigurationProxyPrivate::currentChannel(); + if (chan) { + ConfigurationProxyPrivate::m_spResolutionModel->setSourceModel(chan); + } + } + return ConfigurationProxyPrivate::m_spResolutionModel; +} + +QAbstractItemModel* Video::ConfigurationProxy::rateModel() +{ + if (!ConfigurationProxyPrivate::m_spRateModel) { + ConfigurationProxyPrivate::m_spRateModel = new QIdentityProxyModel(Video::SourceModel::instance()); + ConfigurationProxyPrivate::m_spRateModel->setSourceModel(ConfigurationProxyPrivate::currentResolution()); + } + return ConfigurationProxyPrivate::m_spRateModel; +} + +QItemSelectionModel* Video::ConfigurationProxy::deviceSelectionModel() +{ + if (!ConfigurationProxyPrivate::m_spDeviceSelectionModel) { + ConfigurationProxyPrivate::m_spDeviceSelectionModel = new QItemSelectionModel(ConfigurationProxyPrivate::m_spDeviceModel); + + //Can happen if a device is removed + QObject::connect(Video::DeviceModel::instance(), &Video::DeviceModel::currentIndexChanged,[](int idx) { + ConfigurationProxyPrivate::m_spDeviceSelectionModel->setCurrentIndex(ConfigurationProxyPrivate::m_spDeviceModel->index(idx,0), QItemSelectionModel::ClearAndSelect ); + }); + + QObject::connect(ConfigurationProxyPrivate::m_spDeviceSelectionModel,&QItemSelectionModel::currentChanged, &ConfigurationProxyPrivate::changeDevice); + } + return ConfigurationProxyPrivate::m_spDeviceSelectionModel; +} + +QItemSelectionModel* Video::ConfigurationProxy::channelSelectionModel() +{ + if (!ConfigurationProxyPrivate::m_spChannelSelectionModel) { + ConfigurationProxyPrivate::m_spChannelSelectionModel = new QItemSelectionModel(ConfigurationProxyPrivate::m_spChannelModel); + + ConfigurationProxyPrivate::updateChannelSelection(); + + QObject::connect(ConfigurationProxyPrivate::m_spChannelSelectionModel,&QItemSelectionModel::currentChanged, &ConfigurationProxyPrivate::changeChannel); + } + return ConfigurationProxyPrivate::m_spChannelSelectionModel; +} + +QItemSelectionModel* Video::ConfigurationProxy::resolutionSelectionModel() +{ + if (!ConfigurationProxyPrivate::m_spResolutionSelectionModel) { + ConfigurationProxyPrivate::m_spResolutionSelectionModel = new QItemSelectionModel(ConfigurationProxyPrivate::m_spResolutionModel); + + ConfigurationProxyPrivate::updateResolutionSelection(); + + QObject::connect(ConfigurationProxyPrivate::m_spResolutionSelectionModel,&QItemSelectionModel::currentChanged, &ConfigurationProxyPrivate::changeResolution); + } + return ConfigurationProxyPrivate::m_spResolutionSelectionModel; +} + +QItemSelectionModel* Video::ConfigurationProxy::rateSelectionModel() +{ + if (!ConfigurationProxyPrivate::m_spRateSelectionModel) { + ConfigurationProxyPrivate::m_spRateSelectionModel = new QItemSelectionModel(ConfigurationProxyPrivate::m_spRateModel); + + ConfigurationProxyPrivate::updateRateSelection(); + + QObject::connect(ConfigurationProxyPrivate::m_spRateSelectionModel,&QItemSelectionModel::currentChanged, &ConfigurationProxyPrivate::changeRate); + } + return ConfigurationProxyPrivate::m_spRateSelectionModel; +} diff --git a/src/video/configurationproxy.h b/src/video/configurationproxy.h new file mode 100644 index 00000000..93985684 --- /dev/null +++ b/src/video/configurationproxy.h @@ -0,0 +1,48 @@ +/**************************************************************************** + * Copyright (C) 2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * 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) any later version. * + * * + * 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 General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifndef CONFIGURATIONPROXY_H +#define CONFIGURATIONPROXY_H + + +class QAbstractItemModel; +class QItemSelectionModel; + +namespace Video { + +/** + * This class is used to simplify the configuration process. + * Currently, every devices have their own model tree. This + * proxy flatten the three to the clients don't have to + * implement the managing logic. + */ +class ConfigurationProxy { +public: + static QAbstractItemModel* deviceModel (); + static QAbstractItemModel* channelModel (); + static QAbstractItemModel* resolutionModel(); + static QAbstractItemModel* rateModel (); + + static QItemSelectionModel* deviceSelectionModel (); + static QItemSelectionModel* channelSelectionModel (); + static QItemSelectionModel* resolutionSelectionModel(); + static QItemSelectionModel* rateSelectionModel (); +}; + +} //namespace Video + +#endif diff --git a/src/video/devicemodel.cpp b/src/video/devicemodel.cpp index db84231b..306df031 100644 --- a/src/video/devicemodel.cpp +++ b/src/video/devicemodel.cpp @@ -46,7 +46,6 @@ private Q_SLOTS: Video::DeviceModelPrivate::DeviceModelPrivate() : m_pDummyDevice(nullptr),m_pActiveDevice(nullptr) { - } /// @@ -61,6 +60,8 @@ d_ptr(new Video::DeviceModelPrivate()) { m_spInstance = this; reload(); + VideoManagerInterface& interface = DBus::VideoManager::instance(); + connect(&interface, SIGNAL(deviceEvent()), this, SLOT(reload())); } Video::DeviceModel* Video::DeviceModel::instance() @@ -84,7 +85,7 @@ QHash<int,QByteArray> Video::DeviceModel::roleNames() const ///Get data from the model QVariant Video::DeviceModel::data( const QModelIndex& idx, int role) const { - if(idx.column() == 0 && role == Qt::DisplayRole) + if(idx.isValid() && idx.column() == 0 && role == Qt::DisplayRole && d_ptr->m_lDevices.size() > idx.row()) return QVariant(d_ptr->m_lDevices[idx.row()]->id()); return QVariant(); } @@ -127,7 +128,7 @@ Video::DeviceModel::~DeviceModel() ///Save the current model over dbus void Video::DeviceModel::setActive(const QModelIndex& idx) { - if (idx.isValid()) { + if (idx.isValid() && d_ptr->m_lDevices.size() > idx.row()) { VideoManagerInterface& interface = DBus::VideoManager::instance(); interface.setDefaultDevice(d_ptr->m_lDevices[idx.row()]->id()); d_ptr->m_pActiveDevice = d_ptr->m_lDevices[idx.row()]; @@ -173,12 +174,15 @@ void Video::DeviceModel::reload() } foreach(Video::Device* dev, d_ptr->m_hDevices) { if (dev && devicesHash.key(dev).isEmpty()) { - delete dev; + dev->deleteLater(); } } + d_ptr->m_pActiveDevice = nullptr; d_ptr->m_hDevices.clear(); d_ptr->m_hDevices = devicesHash; + beginResetModel(); d_ptr->m_lDevices = d_ptr->m_hDevices.values(); + endResetModel(); emit layoutChanged(); // channelModel ()->reload(); @@ -212,7 +216,6 @@ Video::Device* Video::DeviceModel::activeDevice() const return d_ptr->m_pActiveDevice; } - int Video::DeviceModel::activeIndex() const { return d_ptr->m_lDevices.indexOf(activeDevice()); -- GitLab