mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-24 02:42:50 +00:00
1015 lines
36 KiB
C++
1015 lines
36 KiB
C++
/* This file is part of the KDE project
|
|
Copyright (C) 2006-2008 Matthias Kretz <kretz@kde.org>
|
|
Copyright (C) 2011 Casian Andrei <skeletk13@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) version 3.
|
|
|
|
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
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
#include "devicepreference.h"
|
|
|
|
#include <QtCore/QList>
|
|
#include <QtCore/QPointer>
|
|
#include <QtDBus/QDBusConnection>
|
|
#include <QtDBus/QDBusReply>
|
|
#include <QtDBus/QDBusInterface>
|
|
#include <QtDBus/QDBusMessage>
|
|
#include <QApplication>
|
|
#include <QPainter>
|
|
#include <QItemDelegate>
|
|
#include <QLabel>
|
|
#include <QVBoxLayout>
|
|
#include <QHeaderView>
|
|
|
|
#include <Phonon/AudioOutput>
|
|
#include <Phonon/MediaObject>
|
|
#include <Phonon/VideoWidget>
|
|
#include <phonon/backendinterface.h>
|
|
#include <phonon/backendcapabilities.h>
|
|
#include <phonon/globalconfig.h>
|
|
#include <phonon/objectdescription.h>
|
|
#include <phonon/phononnamespace.h>
|
|
#include "factory_p.h"
|
|
#include <kfadewidgeteffect.h>
|
|
|
|
#include <kdialog.h>
|
|
#include <klistwidget.h>
|
|
#include <klocale.h>
|
|
#include <kmenu.h>
|
|
#include <kmessagebox.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kdebug.h>
|
|
#include <kurl.h>
|
|
|
|
#ifndef METATYPE_QLIST_INT_DEFINED
|
|
#define METATYPE_QLIST_INT_DEFINED
|
|
// Want this exactly once, see phonondefs_p.h kcm/devicepreference.cpp
|
|
Q_DECLARE_METATYPE(QList<int>)
|
|
#endif
|
|
|
|
namespace Phonon
|
|
{
|
|
|
|
/*
|
|
* Lists of categories for every device type
|
|
*/
|
|
static const Category audioOutCategories[] = {
|
|
NoCategory,
|
|
NotificationCategory,
|
|
MusicCategory,
|
|
VideoCategory,
|
|
CommunicationCategory,
|
|
GameCategory,
|
|
AccessibilityCategory,
|
|
};
|
|
|
|
static const CaptureCategory audioCapCategories[] = {
|
|
NoCaptureCategory,
|
|
CommunicationCaptureCategory,
|
|
RecordingCaptureCategory,
|
|
ControlCaptureCategory
|
|
};
|
|
|
|
static const CaptureCategory videoCapCategories[] = {
|
|
NoCaptureCategory,
|
|
CommunicationCaptureCategory,
|
|
RecordingCaptureCategory,
|
|
};
|
|
|
|
static const int audioOutCategoriesCount = sizeof(audioOutCategories) / sizeof(Category);
|
|
static const int audioCapCategoriesCount = sizeof(audioCapCategories) / sizeof(CaptureCategory);
|
|
static const int videoCapCategoriesCount = sizeof(videoCapCategories) / sizeof(CaptureCategory);
|
|
|
|
void operator++(Category &c)
|
|
{
|
|
c = static_cast<Category>(1 + static_cast<int>(c));
|
|
//Q_ASSERT(c <= LastCategory);
|
|
}
|
|
|
|
class CategoryItem : public QStandardItem {
|
|
public:
|
|
CategoryItem(Category cat)
|
|
: QStandardItem(),
|
|
m_cat(cat),
|
|
m_odtype(AudioOutputDeviceType)
|
|
{
|
|
if (cat == NoCategory) {
|
|
setText(i18n("Audio Playback"));
|
|
} else {
|
|
setText(categoryToString(cat));
|
|
}
|
|
}
|
|
|
|
CategoryItem(CaptureCategory cat, ObjectDescriptionType t = AudioCaptureDeviceType)
|
|
: QStandardItem(),
|
|
m_capcat(cat),
|
|
m_odtype(t)
|
|
{
|
|
if (cat == NoCaptureCategory) {
|
|
switch(t) {
|
|
case AudioCaptureDeviceType:
|
|
setText(i18n("Audio Recording"));
|
|
break;
|
|
case VideoCaptureDeviceType:
|
|
setText(i18n("Video Recording"));
|
|
break;
|
|
default:
|
|
setText(i18n("Invalid"));
|
|
}
|
|
} else {
|
|
setText(categoryToString(cat));
|
|
}
|
|
}
|
|
|
|
int type() const { return 1001; }
|
|
Category category() const { return m_cat; }
|
|
CaptureCategory captureCategory() const { return m_capcat; }
|
|
ObjectDescriptionType odtype() const { return m_odtype; }
|
|
|
|
private:
|
|
Category m_cat;
|
|
CaptureCategory m_capcat;
|
|
ObjectDescriptionType m_odtype;
|
|
};
|
|
|
|
/**
|
|
* Need this to change the colors of the ListView if the Palette changed. With CSS set this won't
|
|
* change automatically
|
|
*/
|
|
void DevicePreference::changeEvent(QEvent *e)
|
|
{
|
|
QWidget::changeEvent(e);
|
|
if (e->type() == QEvent::PaletteChange) {
|
|
deviceList->setStyleSheet(deviceList->styleSheet());
|
|
}
|
|
}
|
|
|
|
DevicePreference::DevicePreference(QWidget *parent)
|
|
: QWidget(parent),
|
|
m_headerModel(0, 1, 0),
|
|
m_media(NULL), m_audioOutput(NULL), m_videoWidget(NULL)
|
|
{
|
|
setupUi(this);
|
|
|
|
// Setup the buttons
|
|
testPlaybackButton->setIcon(KIcon("media-playback-start"));
|
|
testPlaybackButton->setEnabled(false);
|
|
testPlaybackButton->setToolTip(i18n("Test the selected device"));
|
|
deferButton->setIcon(KIcon("go-down"));
|
|
preferButton->setIcon(KIcon("go-up"));
|
|
|
|
// Configure the device list
|
|
deviceList->setDragDropMode(QAbstractItemView::InternalMove);
|
|
deviceList->setStyleSheet(QString("QTreeView {"
|
|
"background-color: palette(base);"
|
|
"background-image: url(%1);"
|
|
"background-position: bottom left;"
|
|
"background-attachment: fixed;"
|
|
"background-repeat: no-repeat;"
|
|
"background-clip: padding;"
|
|
"}")
|
|
.arg(KStandardDirs::locate("data", "kcm_phonon/listview-background.png")));
|
|
deviceList->setAlternatingRowColors(false);
|
|
|
|
// The root item for the categories
|
|
QStandardItem *parentItem = m_categoryModel.invisibleRootItem();
|
|
|
|
// Audio Output Parent
|
|
QStandardItem *aOutputItem = new CategoryItem(NoCategory);
|
|
m_audioOutputModel[NoCategory] = new AudioOutputDeviceModel(this);
|
|
aOutputItem->setEditable(false);
|
|
aOutputItem->setToolTip(i18n("Defines the default ordering of devices which can be overridden by individual categories."));
|
|
parentItem->appendRow(aOutputItem);
|
|
|
|
// Audio Capture Parent
|
|
QStandardItem *aCaptureItem = new CategoryItem(NoCaptureCategory, AudioCaptureDeviceType);
|
|
m_audioCaptureModel[NoCaptureCategory] = new AudioCaptureDeviceModel(this);
|
|
aCaptureItem->setEditable(false);
|
|
aCaptureItem->setToolTip(i18n("Defines the default ordering of devices which can be overridden by individual categories."));
|
|
parentItem->appendRow(aCaptureItem);
|
|
|
|
// Video Capture Parent
|
|
QStandardItem *vCaptureItem = new CategoryItem(NoCaptureCategory, VideoCaptureDeviceType);
|
|
m_videoCaptureModel[NoCaptureCategory] = new VideoCaptureDeviceModel(this);
|
|
vCaptureItem->setEditable(false);
|
|
vCaptureItem->setToolTip(i18n("Defines the default ordering of devices which can be overridden by individual categories."));
|
|
parentItem->appendRow(vCaptureItem);
|
|
|
|
// Audio Output Children
|
|
parentItem = aOutputItem;
|
|
for (int i = 1; i < audioOutCategoriesCount; ++i) { // i == 1 to skip NoCategory
|
|
m_audioOutputModel[audioOutCategories[i]] = new AudioOutputDeviceModel(this);
|
|
QStandardItem *item = new CategoryItem(audioOutCategories[i]);
|
|
item->setEditable(false);
|
|
parentItem->appendRow(item);
|
|
}
|
|
|
|
// Audio Capture Children
|
|
parentItem = aCaptureItem;
|
|
for (int i = 1; i < audioCapCategoriesCount; ++i) { // i == 1 to skip NoCategory
|
|
m_audioCaptureModel[audioCapCategories[i]] = new AudioCaptureDeviceModel(this);
|
|
QStandardItem *item = new CategoryItem(audioCapCategories[i], AudioCaptureDeviceType);
|
|
item->setEditable(false);
|
|
parentItem->appendRow(item);
|
|
}
|
|
|
|
// Video Capture Children
|
|
parentItem = vCaptureItem;
|
|
for (int i = 1; i < videoCapCategoriesCount; ++i) { // i == 1 to skip NoCategory
|
|
m_videoCaptureModel[videoCapCategories[i]] = new VideoCaptureDeviceModel(this);
|
|
QStandardItem *item = new CategoryItem(videoCapCategories[i], VideoCaptureDeviceType);
|
|
item->setEditable(false);
|
|
parentItem->appendRow(item);
|
|
}
|
|
|
|
// Configure the category tree
|
|
categoryTree->setModel(&m_categoryModel);
|
|
if (categoryTree->header()) {
|
|
categoryTree->header()->hide();
|
|
}
|
|
categoryTree->expandAll();
|
|
|
|
connect(categoryTree->selectionModel(),
|
|
SIGNAL(currentChanged(const QModelIndex &,const QModelIndex &)),
|
|
SLOT(updateDeviceList()));
|
|
|
|
// Connect all model data change signals to the changed slot
|
|
for (int i = -1; i <= LastCategory; ++i) {
|
|
connect(m_audioOutputModel[i], SIGNAL(rowsInserted(QModelIndex, int, int)), this, SIGNAL(changed()));
|
|
connect(m_audioOutputModel[i], SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SIGNAL(changed()));
|
|
connect(m_audioOutputModel[i], SIGNAL(layoutChanged()), this, SIGNAL(changed()));
|
|
connect(m_audioOutputModel[i], SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(changed()));
|
|
if (m_audioCaptureModel.contains(i)) {
|
|
connect(m_audioCaptureModel[i], SIGNAL(rowsInserted(QModelIndex, int, int)), this, SIGNAL(changed()));
|
|
connect(m_audioCaptureModel[i], SIGNAL(rowsRemoved(QModelIndex , int, int)), this, SIGNAL(changed()));
|
|
connect(m_audioCaptureModel[i], SIGNAL(layoutChanged()), this, SIGNAL(changed()));
|
|
connect(m_audioCaptureModel[i], SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(changed()));
|
|
}
|
|
if (m_videoCaptureModel.contains(i)) {
|
|
connect(m_videoCaptureModel[i], SIGNAL(rowsInserted(QModelIndex, int, int)), this, SIGNAL(changed()));
|
|
connect(m_videoCaptureModel[i], SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SIGNAL(changed()));
|
|
connect(m_videoCaptureModel[i], SIGNAL(layoutChanged()), this, SIGNAL(changed()));
|
|
connect(m_videoCaptureModel[i], SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(changed()));
|
|
}
|
|
}
|
|
|
|
connect(showAdvancedDevicesCheckBox, SIGNAL(stateChanged (int)), this, SIGNAL(changed()));
|
|
|
|
// Connect the signals from Phonon that notify changes in the device lists
|
|
connect(BackendCapabilities::notifier(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(updateAudioOutputDevices()));
|
|
connect(BackendCapabilities::notifier(), SIGNAL(availableAudioCaptureDevicesChanged()), SLOT(updateAudioCaptureDevices()));
|
|
connect(BackendCapabilities::notifier(), SIGNAL(availableVideoCaptureDevicesChanged()), SLOT(updateVideoCaptureDevices()));
|
|
connect(BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), SLOT(updateAudioOutputDevices()));
|
|
connect(BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), SLOT(updateAudioCaptureDevices()));
|
|
connect(BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), SLOT(updateVideoCaptureDevices()));
|
|
|
|
if (!categoryTree->currentIndex().isValid()) {
|
|
categoryTree->setCurrentIndex(m_categoryModel.index(0, 0).child(1, 0));
|
|
}
|
|
}
|
|
|
|
DevicePreference::~DevicePreference()
|
|
{
|
|
// Ensure that the video widget is destroyed, if it remains active
|
|
delete m_videoWidget;
|
|
}
|
|
|
|
void DevicePreference::updateDeviceList()
|
|
{
|
|
KFadeWidgetEffect *animation = new KFadeWidgetEffect(deviceList);
|
|
|
|
// Temporarily disconnect the device list selection model
|
|
if (deviceList->selectionModel()) {
|
|
disconnect(deviceList->selectionModel(),
|
|
SIGNAL(currentRowChanged(const QModelIndex &,const QModelIndex &)),
|
|
this, SLOT(updateButtonsEnabled()));
|
|
}
|
|
|
|
// Get the current selected category item
|
|
QStandardItem *currentItem = m_categoryModel.itemFromIndex(categoryTree->currentIndex());
|
|
if (currentItem && currentItem->type() == 1001) {
|
|
CategoryItem *catItem = static_cast<CategoryItem *>(currentItem);
|
|
bool cap = catItem->odtype() != AudioOutputDeviceType;
|
|
const Category cat = catItem->category();
|
|
const CaptureCategory capcat = catItem->captureCategory();
|
|
|
|
// Update the device list, by setting it's model to the one for the corresponding category
|
|
switch (catItem->odtype()) {
|
|
case AudioOutputDeviceType:
|
|
deviceList->setModel(m_audioOutputModel[cat]);
|
|
break;
|
|
case AudioCaptureDeviceType:
|
|
deviceList->setModel(m_audioCaptureModel[capcat]);
|
|
break;
|
|
case VideoCaptureDeviceType:
|
|
deviceList->setModel(m_videoCaptureModel[capcat]);
|
|
break;
|
|
default: ;
|
|
}
|
|
|
|
// Update the header
|
|
if (cap ? capcat == NoCaptureCategory : cat == NoCategory) {
|
|
switch (catItem->odtype()) {
|
|
case AudioOutputDeviceType:
|
|
m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Default Audio Playback Device Preference"), Qt::DisplayRole);
|
|
break;
|
|
case AudioCaptureDeviceType:
|
|
m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Default Audio Recording Device Preference"), Qt::DisplayRole);
|
|
break;
|
|
case VideoCaptureDeviceType:
|
|
m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Default Video Recording Device Preference"), Qt::DisplayRole);
|
|
break;
|
|
default: ;
|
|
}
|
|
} else {
|
|
switch (catItem->odtype()) {
|
|
case AudioOutputDeviceType:
|
|
m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Audio Playback Device Preference for the '%1' Category",
|
|
categoryToString(cat)), Qt::DisplayRole);
|
|
break;
|
|
case AudioCaptureDeviceType:
|
|
m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Audio Recording Device Preference for the '%1' Category",
|
|
categoryToString(capcat)), Qt::DisplayRole);
|
|
break;
|
|
case VideoCaptureDeviceType:
|
|
m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Video Recording Device Preference for the '%1' Category ",
|
|
categoryToString(capcat)), Qt::DisplayRole);
|
|
break;
|
|
default: ;
|
|
}
|
|
}
|
|
} else {
|
|
// No valid category selected
|
|
m_headerModel.setHeaderData(0, Qt::Horizontal, QString(), Qt::DisplayRole);
|
|
deviceList->setModel(0);
|
|
}
|
|
|
|
// Update the header, the buttons enabled state
|
|
deviceList->header()->setModel(&m_headerModel);
|
|
updateButtonsEnabled();
|
|
|
|
// Reconnect the device list selection model
|
|
if (deviceList->selectionModel()) {
|
|
connect(deviceList->selectionModel(),
|
|
SIGNAL(currentRowChanged(const QModelIndex &,const QModelIndex &)),
|
|
this, SLOT(updateButtonsEnabled()));
|
|
}
|
|
|
|
deviceList->resizeColumnToContents(0);
|
|
animation->start();
|
|
}
|
|
|
|
void DevicePreference::updateAudioCaptureDevices()
|
|
{
|
|
const QList<AudioCaptureDevice> list = availableAudioCaptureDevices();
|
|
QHash<int, AudioCaptureDevice> hash;
|
|
foreach (const AudioCaptureDevice &dev, list) {
|
|
hash.insert(dev.index(), dev);
|
|
}
|
|
|
|
for (int catIndex = 0; catIndex < audioCapCategoriesCount; ++ catIndex) {
|
|
const int i = audioCapCategories[catIndex];
|
|
AudioCaptureDeviceModel *model = m_audioCaptureModel.value(i);
|
|
Q_ASSERT(model);
|
|
|
|
QHash<int, AudioCaptureDevice> hashCopy(hash);
|
|
QList<AudioCaptureDevice> orderedList;
|
|
|
|
if (model->rowCount() > 0) {
|
|
QList<int> order = model->tupleIndexOrder();
|
|
foreach (int idx, order) {
|
|
if (hashCopy.contains(idx)) {
|
|
orderedList << hashCopy.take(idx);
|
|
}
|
|
}
|
|
|
|
if (hashCopy.size() > 1) {
|
|
// keep the order of the original list
|
|
foreach (const AudioCaptureDevice &dev, list) {
|
|
if (hashCopy.contains(dev.index())) {
|
|
orderedList << hashCopy.take(dev.index());
|
|
}
|
|
}
|
|
} else if (hashCopy.size() == 1) {
|
|
orderedList += hashCopy.values();
|
|
}
|
|
|
|
model->setModelData(orderedList);
|
|
} else {
|
|
model->setModelData(list);
|
|
}
|
|
}
|
|
|
|
deviceList->resizeColumnToContents(0);
|
|
}
|
|
|
|
void DevicePreference::updateVideoCaptureDevices()
|
|
{
|
|
const QList<VideoCaptureDevice> list = availableVideoCaptureDevices();
|
|
QHash<int, VideoCaptureDevice> hash;
|
|
foreach (const VideoCaptureDevice &dev, list) {
|
|
hash.insert(dev.index(), dev);
|
|
}
|
|
|
|
for (int catIndex = 0; catIndex < videoCapCategoriesCount; ++ catIndex) {
|
|
const int i = videoCapCategories[catIndex];
|
|
VideoCaptureDeviceModel *model = m_videoCaptureModel.value(i);
|
|
Q_ASSERT(model);
|
|
|
|
QHash<int, VideoCaptureDevice> hashCopy(hash);
|
|
QList<VideoCaptureDevice> orderedList;
|
|
|
|
if (model->rowCount() > 0) {
|
|
QList<int> order = model->tupleIndexOrder();
|
|
foreach (int idx, order) {
|
|
if (hashCopy.contains(idx)) {
|
|
orderedList << hashCopy.take(idx);
|
|
}
|
|
}
|
|
|
|
if (hashCopy.size() > 1) {
|
|
// keep the order of the original list
|
|
foreach (const VideoCaptureDevice &dev, list) {
|
|
if (hashCopy.contains(dev.index())) {
|
|
orderedList << hashCopy.take(dev.index());
|
|
}
|
|
}
|
|
} else if (hashCopy.size() == 1) {
|
|
orderedList += hashCopy.values();
|
|
}
|
|
|
|
model->setModelData(orderedList);
|
|
} else {
|
|
model->setModelData(list);
|
|
}
|
|
}
|
|
|
|
deviceList->resizeColumnToContents(0);
|
|
}
|
|
|
|
void DevicePreference::updateAudioOutputDevices()
|
|
{
|
|
const QList<AudioOutputDevice> list = availableAudioOutputDevices();
|
|
QHash<int, AudioOutputDevice> hash;
|
|
foreach (const AudioOutputDevice &dev, list) {
|
|
hash.insert(dev.index(), dev);
|
|
}
|
|
|
|
for (int catIndex = 0; catIndex < audioOutCategoriesCount; ++ catIndex) {
|
|
const int i = audioOutCategories[catIndex];
|
|
AudioOutputDeviceModel *model = m_audioOutputModel.value(i);
|
|
Q_ASSERT(model);
|
|
|
|
QHash<int, AudioOutputDevice> hashCopy(hash);
|
|
QList<AudioOutputDevice> orderedList;
|
|
|
|
if (model->rowCount() > 0) {
|
|
QList<int> order = model->tupleIndexOrder();
|
|
foreach (int idx, order) {
|
|
if (hashCopy.contains(idx)) {
|
|
orderedList << hashCopy.take(idx);
|
|
}
|
|
}
|
|
|
|
if (hashCopy.size() > 1) {
|
|
// keep the order of the original list
|
|
foreach (const AudioOutputDevice &dev, list) {
|
|
if (hashCopy.contains(dev.index())) {
|
|
orderedList << hashCopy.take(dev.index());
|
|
}
|
|
}
|
|
} else if (hashCopy.size() == 1) {
|
|
orderedList += hashCopy.values();
|
|
}
|
|
|
|
model->setModelData(orderedList);
|
|
} else {
|
|
model->setModelData(list);
|
|
}
|
|
}
|
|
|
|
deviceList->resizeColumnToContents(0);
|
|
}
|
|
|
|
QList<AudioOutputDevice> DevicePreference::availableAudioOutputDevices() const
|
|
{
|
|
return BackendCapabilities::availableAudioOutputDevices();
|
|
}
|
|
|
|
QList<AudioCaptureDevice> DevicePreference::availableAudioCaptureDevices() const
|
|
{
|
|
#ifndef PHONON_NO_AUDIOCAPTURE
|
|
return BackendCapabilities::availableAudioCaptureDevices();
|
|
#else
|
|
return QList<AudioCaptureDevice>();
|
|
#endif
|
|
}
|
|
|
|
QList<VideoCaptureDevice> DevicePreference::availableVideoCaptureDevices() const
|
|
{
|
|
#ifndef PHONON_NO_VIDEOCAPTURE
|
|
return BackendCapabilities::availableVideoCaptureDevices();
|
|
#else
|
|
return QList<VideoCaptureDevice>();
|
|
#endif
|
|
}
|
|
|
|
void DevicePreference::load()
|
|
{
|
|
showAdvancedDevicesCheckBox->setChecked(!GlobalConfig().hideAdvancedDevices());
|
|
loadCategoryDevices();
|
|
}
|
|
|
|
void DevicePreference::loadCategoryDevices()
|
|
{
|
|
// "Load" the settings from the backend.
|
|
for (int i = 0; i < audioOutCategoriesCount; ++ i) {
|
|
const Category cat = audioOutCategories[i];
|
|
QList<AudioOutputDevice> list;
|
|
const QList<int> deviceIndexes = GlobalConfig().audioOutputDeviceListFor(cat);
|
|
foreach (int i, deviceIndexes) {
|
|
list.append(AudioOutputDevice::fromIndex(i));
|
|
}
|
|
|
|
m_audioOutputModel[cat]->setModelData(list);
|
|
}
|
|
|
|
#ifndef PHONON_NO_AUDIOCAPTURE
|
|
for (int i = 0; i < audioCapCategoriesCount; ++ i) {
|
|
const CaptureCategory cat = audioCapCategories[i];
|
|
QList<AudioCaptureDevice> list;
|
|
const QList<int> deviceIndexes = GlobalConfig().audioCaptureDeviceListFor(cat);
|
|
foreach (int i, deviceIndexes) {
|
|
list.append(AudioCaptureDevice::fromIndex(i));
|
|
}
|
|
|
|
m_audioCaptureModel[cat]->setModelData(list);
|
|
}
|
|
#endif
|
|
|
|
#ifndef PHONON_NO_VIDEOCAPTURE
|
|
for (int i = 0; i < videoCapCategoriesCount; ++ i) {
|
|
const CaptureCategory cat = videoCapCategories[i];
|
|
QList<VideoCaptureDevice> list;
|
|
const QList<int> deviceIndexes = GlobalConfig().videoCaptureDeviceListFor(cat);
|
|
foreach (int i, deviceIndexes) {
|
|
list.append(VideoCaptureDevice::fromIndex(i));
|
|
}
|
|
|
|
m_videoCaptureModel[cat]->setModelData(list);
|
|
}
|
|
#endif
|
|
|
|
deviceList->resizeColumnToContents(0);
|
|
}
|
|
|
|
void DevicePreference::save()
|
|
{
|
|
for (int i = 0; i < audioOutCategoriesCount; ++i) {
|
|
const Category cat = audioOutCategories[i];
|
|
Q_ASSERT(m_audioOutputModel.value(cat));
|
|
const QList<int> order = m_audioOutputModel.value(cat)->tupleIndexOrder();
|
|
GlobalConfig().setAudioOutputDeviceListFor(cat, order);
|
|
}
|
|
|
|
#ifndef PHONON_NO_AUDIOCAPTURE
|
|
for (int i = 0; i < audioCapCategoriesCount; ++i) {
|
|
const CaptureCategory cat = audioCapCategories[i];
|
|
Q_ASSERT(m_audioCaptureModel.value(cat));
|
|
const QList<int> order = m_audioCaptureModel.value(cat)->tupleIndexOrder();
|
|
GlobalConfig().setAudioCaptureDeviceListFor(cat, order);
|
|
}
|
|
#endif
|
|
|
|
#ifndef PHONON_NO_VIDEOCAPTURE
|
|
for (int i = 0; i < videoCapCategoriesCount; ++i) {
|
|
const CaptureCategory cat = videoCapCategories[i];
|
|
Q_ASSERT(m_videoCaptureModel.value(cat));
|
|
const QList<int> order = m_videoCaptureModel.value(cat)->tupleIndexOrder();
|
|
GlobalConfig().setVideoCaptureDeviceListFor(cat, order);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void DevicePreference::defaults()
|
|
{
|
|
{
|
|
const QList<AudioOutputDevice> list = availableAudioOutputDevices();
|
|
for (int i = 0; i < audioOutCategoriesCount; ++i) {
|
|
m_audioOutputModel[audioOutCategories[i]]->setModelData(list);
|
|
}
|
|
}
|
|
{
|
|
const QList<AudioCaptureDevice> list = availableAudioCaptureDevices();
|
|
for (int i = 0; i < audioCapCategoriesCount; ++i) {
|
|
m_audioCaptureModel[audioCapCategories[i]]->setModelData(list);
|
|
}
|
|
}
|
|
{
|
|
const QList<VideoCaptureDevice> list = availableVideoCaptureDevices();
|
|
for (int i = 0; i < videoCapCategoriesCount; ++i) {
|
|
m_videoCaptureModel[videoCapCategories[i]]->setModelData(list);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Save this list (that contains even hidden devices) to GlobaConfig, and then
|
|
* load them back. All devices that should be hidden will be hidden
|
|
*/
|
|
save();
|
|
loadCategoryDevices();
|
|
|
|
deviceList->resizeColumnToContents(0);
|
|
}
|
|
|
|
void DevicePreference::pulseAudioEnabled()
|
|
{
|
|
showAdvancedDevicesContainer->removeItem(showAdvancedDevicesSpacer);
|
|
delete showAdvancedDevicesSpacer;
|
|
showAdvancedDevicesCheckBox->setVisible(false);
|
|
}
|
|
|
|
void DevicePreference::on_preferButton_clicked()
|
|
{
|
|
QAbstractItemModel *model = deviceList->model();
|
|
{
|
|
AudioOutputDeviceModel *deviceModel = qobject_cast<AudioOutputDeviceModel *>(model);
|
|
if (deviceModel) {
|
|
deviceModel->moveUp(deviceList->currentIndex());
|
|
updateButtonsEnabled();
|
|
emit changed();
|
|
}
|
|
}
|
|
{
|
|
AudioCaptureDeviceModel *deviceModel = qobject_cast<AudioCaptureDeviceModel *>(model);
|
|
if (deviceModel) {
|
|
deviceModel->moveUp(deviceList->currentIndex());
|
|
updateButtonsEnabled();
|
|
emit changed();
|
|
}
|
|
}
|
|
{
|
|
VideoCaptureDeviceModel *deviceModel = qobject_cast<VideoCaptureDeviceModel *>(model);
|
|
if (deviceModel) {
|
|
deviceModel->moveUp(deviceList->currentIndex());
|
|
updateButtonsEnabled();
|
|
emit changed();
|
|
}
|
|
}
|
|
}
|
|
|
|
void DevicePreference::on_deferButton_clicked()
|
|
{
|
|
QAbstractItemModel *model = deviceList->model();
|
|
{
|
|
AudioOutputDeviceModel *deviceModel = qobject_cast<AudioOutputDeviceModel *>(model);
|
|
if (deviceModel) {
|
|
deviceModel->moveDown(deviceList->currentIndex());
|
|
updateButtonsEnabled();
|
|
emit changed();
|
|
}
|
|
}
|
|
{
|
|
AudioCaptureDeviceModel *deviceModel = qobject_cast<AudioCaptureDeviceModel *>(model);
|
|
if (deviceModel) {
|
|
deviceModel->moveDown(deviceList->currentIndex());
|
|
updateButtonsEnabled();
|
|
emit changed();
|
|
}
|
|
}
|
|
{
|
|
VideoCaptureDeviceModel *deviceModel = qobject_cast<VideoCaptureDeviceModel *>(model);
|
|
if (deviceModel) {
|
|
deviceModel->moveDown(deviceList->currentIndex());
|
|
updateButtonsEnabled();
|
|
emit changed();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DevicePreference::DeviceType DevicePreference::shownModelType() const
|
|
{
|
|
const QStandardItem *item = m_categoryModel.itemFromIndex(categoryTree->currentIndex());
|
|
if (!item)
|
|
return dtInvalidDevice;
|
|
Q_ASSERT(item->type() == 1001);
|
|
|
|
const CategoryItem *catItem = static_cast<const CategoryItem *>(item);
|
|
if (!catItem)
|
|
return dtInvalidDevice;
|
|
|
|
switch (catItem->odtype()) {
|
|
case AudioOutputDeviceType:
|
|
return dtAudioOutput;
|
|
case AudioCaptureDeviceType:
|
|
return dtAudioCapture;
|
|
case VideoCaptureDeviceType:
|
|
return dtVideoCapture;
|
|
default:
|
|
return dtInvalidDevice;
|
|
}
|
|
}
|
|
|
|
void DevicePreference::on_applyPreferencesButton_clicked()
|
|
{
|
|
const QModelIndex idx = categoryTree->currentIndex();
|
|
const QStandardItem *item = m_categoryModel.itemFromIndex(idx);
|
|
if (!item)
|
|
return;
|
|
Q_ASSERT(item->type() == 1001);
|
|
|
|
const CategoryItem *catItem = static_cast<const CategoryItem *>(item);
|
|
|
|
QList<AudioOutputDevice> aoPreferredList;
|
|
QList<AudioCaptureDevice> acPreferredList;
|
|
QList<VideoCaptureDevice> vcPreferredList;
|
|
const Category *categoryList = NULL;
|
|
const CaptureCategory *capCategoryList = NULL;
|
|
int categoryListCount;
|
|
int catIndex;
|
|
bool cap = false;
|
|
|
|
switch (catItem->odtype()) {
|
|
case AudioOutputDeviceType:
|
|
aoPreferredList = m_audioOutputModel.value(catItem->category())->modelData();
|
|
categoryList = audioOutCategories;
|
|
categoryListCount = audioOutCategoriesCount;
|
|
cap = false;
|
|
break;
|
|
|
|
case AudioCaptureDeviceType:
|
|
acPreferredList = m_audioCaptureModel.value(catItem->captureCategory())->modelData();
|
|
capCategoryList = audioCapCategories;
|
|
categoryListCount = audioCapCategoriesCount;
|
|
cap = true;
|
|
break;
|
|
|
|
case VideoCaptureDeviceType:
|
|
vcPreferredList = m_videoCaptureModel.value(catItem->captureCategory())->modelData();
|
|
capCategoryList = videoCapCategories;
|
|
categoryListCount = videoCapCategoriesCount;
|
|
cap = true;
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
QPointer<KDialog> dialog = new KDialog(this);
|
|
dialog->setButtons(KDialog::Ok | KDialog::Cancel);
|
|
dialog->setDefaultButton(KDialog::Ok);
|
|
|
|
QWidget *mainWidget = new QWidget(dialog);
|
|
dialog->setMainWidget(mainWidget);
|
|
|
|
QLabel *label = new QLabel(mainWidget);
|
|
label->setText(i18n("Apply the currently shown device preference list to the following other "
|
|
"audio playback categories:"));
|
|
label->setWordWrap(true);
|
|
|
|
KListWidget *list = new KListWidget(mainWidget);
|
|
|
|
for (catIndex = 0; catIndex < categoryListCount; catIndex ++) {
|
|
Category cat = cap ? NoCategory : categoryList[catIndex];
|
|
CaptureCategory capcat = cap ? capCategoryList[catIndex] : NoCaptureCategory;
|
|
|
|
QListWidgetItem *item = NULL;
|
|
if (cap) {
|
|
if (capcat == NoCaptureCategory) {
|
|
item = new QListWidgetItem(i18n("Default/Unspecified Category"), list, capcat);
|
|
} else {
|
|
item = new QListWidgetItem(categoryToString(capcat), list, capcat);
|
|
}
|
|
} else {
|
|
if (cat == NoCategory) {
|
|
item = new QListWidgetItem(i18n("Default/Unspecified Category"), list, cat);
|
|
} else {
|
|
item = new QListWidgetItem(categoryToString(cat), list, cat);
|
|
}
|
|
}
|
|
|
|
item->setCheckState(Qt::Checked);
|
|
if (cat == catItem->category()) {
|
|
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
|
|
}
|
|
}
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout(mainWidget);
|
|
layout->setMargin(0);
|
|
layout->addWidget(label);
|
|
layout->addWidget(list);
|
|
|
|
switch (dialog->exec()) {
|
|
case QDialog::Accepted:
|
|
for (catIndex = 0; catIndex < categoryListCount; catIndex ++) {
|
|
Category cat = cap ? NoCategory : categoryList[catIndex];
|
|
CaptureCategory capcat = cap ? capCategoryList[catIndex] : NoCaptureCategory;
|
|
|
|
if (cap ? capcat != catItem->captureCategory() : cat != catItem->category()) {
|
|
QListWidgetItem *item = list->item(catIndex);
|
|
Q_ASSERT(item->type() == cap ? (int) capcat : (int) cat);
|
|
if (item->checkState() == Qt::Checked) {
|
|
switch (catItem->odtype()) {
|
|
case AudioOutputDeviceType:
|
|
m_audioOutputModel.value(cat)->setModelData(aoPreferredList);
|
|
break;
|
|
|
|
case AudioCaptureDeviceType:
|
|
m_audioCaptureModel.value(capcat)->setModelData(acPreferredList);
|
|
break;
|
|
|
|
case VideoCaptureDeviceType:
|
|
m_videoCaptureModel.value(capcat)->setModelData(vcPreferredList);
|
|
break;
|
|
|
|
default: ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
emit changed();
|
|
break;
|
|
|
|
case QDialog::Rejected:
|
|
// nothing to do
|
|
break;
|
|
}
|
|
|
|
delete dialog;
|
|
}
|
|
|
|
void DevicePreference::on_showAdvancedDevicesCheckBox_toggled()
|
|
{
|
|
// In order to get the right list from the backend, we need to update the settings now
|
|
// before calling availableAudio{Output,Capture}Devices()
|
|
GlobalConfig().setHideAdvancedDevices(!showAdvancedDevicesCheckBox->isChecked());
|
|
loadCategoryDevices();
|
|
}
|
|
|
|
void DevicePreference::on_testPlaybackButton_toggled(bool down)
|
|
{
|
|
if (down) {
|
|
QModelIndex idx = deviceList->currentIndex();
|
|
if (!idx.isValid()) {
|
|
return;
|
|
}
|
|
|
|
// Shouldn't happen, but better to be on the safe side
|
|
if (m_testingType != dtInvalidDevice) {
|
|
delete m_media;
|
|
m_media = NULL;
|
|
delete m_audioOutput;
|
|
m_audioOutput = NULL;
|
|
delete m_videoWidget;
|
|
m_videoWidget = NULL;
|
|
}
|
|
|
|
// Setup the Phonon objects according to the testing type
|
|
m_testingType = shownModelType();
|
|
switch (m_testingType) {
|
|
case dtAudioOutput: {
|
|
// Create an audio output with the selected device
|
|
m_media = new MediaObject(this);
|
|
const AudioOutputDeviceModel *model = static_cast<const AudioOutputDeviceModel *>(idx.model());
|
|
const AudioOutputDevice &device = model->modelData(idx);
|
|
m_audioOutput = new AudioOutput(this);
|
|
if (!m_audioOutput->setOutputDevice(device)) {
|
|
KMessageBox::error(this, i18n("Failed to set the selected audio output device"));
|
|
break;
|
|
}
|
|
|
|
// Just to be very sure that nothing messes our test sound up
|
|
m_audioOutput->setVolume(1.0);
|
|
m_audioOutput->setMuted(false);
|
|
|
|
createPath(m_media, m_audioOutput);
|
|
|
|
m_media->setCurrentSource(KUrl(KStandardDirs::locate("sound", "KDE-Sys-Log-In.ogg")));
|
|
connect(m_media, SIGNAL(finished()), testPlaybackButton, SLOT(toggle()));
|
|
|
|
break;
|
|
}
|
|
|
|
#ifndef PHONON_NO_AUDIOCAPTURE
|
|
case dtAudioCapture: {
|
|
// Create a media object and an audio output
|
|
m_media = new MediaObject(this);
|
|
m_audioOutput = new AudioOutput(NoCategory, this);
|
|
|
|
// Just to be very sure that nothing messes our test sound up
|
|
m_audioOutput->setVolume(1.0);
|
|
m_audioOutput->setMuted(false);
|
|
|
|
// Try to create a path
|
|
if (!createPath(m_media, m_audioOutput).isValid()) {
|
|
KMessageBox::error(this, i18n("Your backend may not support audio recording"));
|
|
break;
|
|
}
|
|
|
|
// Determine the selected device
|
|
const AudioCaptureDeviceModel *model = static_cast<const AudioCaptureDeviceModel *>(idx.model());
|
|
const AudioCaptureDevice &device = model->modelData(idx);
|
|
m_media->setCurrentSource(device);
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifndef PHONON_NO_VIDEOCAPTURE
|
|
case dtVideoCapture: {
|
|
// Create a media object and a video output
|
|
m_media = new MediaObject(this);
|
|
m_videoWidget = new VideoWidget(NULL);
|
|
|
|
// Try to create a path
|
|
if (!createPath(m_media, m_videoWidget).isValid()) {
|
|
KMessageBox::error(this, i18n("Your backend may not support video recording"));
|
|
break;
|
|
}
|
|
|
|
// Determine the selected device
|
|
const VideoCaptureDeviceModel *model = static_cast<const VideoCaptureDeviceModel *>(idx.model());
|
|
const VideoCaptureDevice &device = model->modelData(idx);
|
|
m_media->setCurrentSource(device);
|
|
|
|
// Set up the testing video widget
|
|
m_videoWidget->setWindowTitle(i18n("Testing %1", device.name()));
|
|
m_videoWidget->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint);
|
|
if (device.property("icon").canConvert(QVariant::String))
|
|
m_videoWidget->setWindowIcon(KIcon(device.property("icon").toString()));
|
|
m_videoWidget->move(QCursor::pos() - QPoint(250, 295));
|
|
m_videoWidget->resize(320, 240);
|
|
m_videoWidget->show();
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
m_media->play();
|
|
} else {
|
|
// Uninitialize the Phonon objects according to the testing type
|
|
switch (m_testingType) {
|
|
case dtAudioOutput:
|
|
disconnect(m_media, SIGNAL(finished()), testPlaybackButton, SLOT(toggle()));
|
|
delete m_media;
|
|
delete m_audioOutput;
|
|
break;
|
|
|
|
case dtAudioCapture:
|
|
delete m_media;
|
|
delete m_audioOutput;
|
|
break;
|
|
|
|
case dtVideoCapture:
|
|
delete m_media;
|
|
delete m_videoWidget;
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
m_media = NULL;
|
|
m_videoWidget = NULL;
|
|
m_audioOutput = NULL;
|
|
m_testingType = dtInvalidDevice;
|
|
}
|
|
}
|
|
|
|
void DevicePreference::updateButtonsEnabled()
|
|
{
|
|
if (deviceList->model()) {
|
|
QModelIndex idx = deviceList->currentIndex();
|
|
preferButton->setEnabled(idx.isValid() && idx.row() > 0);
|
|
deferButton->setEnabled(idx.isValid() && idx.row() < deviceList->model()->rowCount() - 1);
|
|
testPlaybackButton->setEnabled(idx.isValid() && (idx.flags() & Qt::ItemIsEnabled));
|
|
} else {
|
|
preferButton->setEnabled(false);
|
|
deferButton->setEnabled(false);
|
|
testPlaybackButton->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
} // Phonon namespace
|
|
|
|
#include "moc_devicepreference.cpp"
|
|
// vim: sw=4 ts=4
|