/* Copyright (C) 2006-2008 Matthias Kretz Copyright (C) 2011 Casian Andrei Copyright (C) 2014-2019 Harald Sitter 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 #include #include #include #include #include #include #include #include #include #include #include #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) #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(1 + static_cast(c)); //Q_ASSERT(c <= LastCategory); } class CategoryItem : public QStandardItem { public: CategoryItem(Category cat) : QStandardItem(), m_cat(cat), m_odtype(AudioOutputDeviceType) { if (cat == NoCategory) { setText(QObject::tr("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(QObject::tr("Audio Recording")); break; case VideoCaptureDeviceType: setText(QObject::tr("Video Recording")); break; default: setText(QObject::tr("Invalid")); } } else { setText(categoryToString(cat)); } } int type() const override { 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, nullptr), m_media(nullptr), m_audioOutput(nullptr), m_videoWidget(nullptr) { setupUi(this); // Setup the buttons testPlaybackButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); testPlaybackButton->setEnabled(false); testPlaybackButton->setToolTip(tr("Test the selected device")); deferButton->setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); preferButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); // Configure the device list deviceList->setDragDropMode(QAbstractItemView::InternalMove); deviceList->setStyleSheet(QStringLiteral("QTreeView {" "background-color: palette(base);" "background-image: url(:/phononsettings/listview-background.png);" "background-position: bottom left;" "background-attachment: fixed;" "background-repeat: no-repeat;" "background-clip: padding;" "}")); 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(tr("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(tr("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(tr("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, &QCheckBox::stateChanged, this, &DevicePreference::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(1, 0, m_categoryModel.index(0, 0))); } } DevicePreference::~DevicePreference() { // Ensure that the video widget is destroyed, if it remains active delete m_videoWidget; } void DevicePreference::updateDeviceList() { // 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(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, tr("Default Audio Playback Device Preference"), Qt::DisplayRole); break; case AudioCaptureDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, tr("Default Audio Recording Device Preference"), Qt::DisplayRole); break; case VideoCaptureDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, tr("Default Video Recording Device Preference"), Qt::DisplayRole); break; default: ; } } else { switch (catItem->odtype()) { case AudioOutputDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, tr("Audio Playback Device Preference for the '%1' Category").arg( categoryToString(cat)), Qt::DisplayRole); break; case AudioCaptureDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, tr("Audio Recording Device Preference for the '%1' Category").arg( categoryToString(capcat)), Qt::DisplayRole); break; case VideoCaptureDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, tr("Video Recording Device Preference for the '%1' Category ").arg( categoryToString(capcat)), Qt::DisplayRole); break; default: ; } } } else { // No valid category selected m_headerModel.setHeaderData(0, Qt::Horizontal, QString(), Qt::DisplayRole); deviceList->setModel(nullptr); } // 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); } void DevicePreference::updateAudioCaptureDevices() { const QList list = availableAudioCaptureDevices(); QHash 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 hashCopy(hash); QList orderedList; if (model->rowCount() > 0) { QList 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 list = availableVideoCaptureDevices(); QHash 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 hashCopy(hash); QList orderedList; if (model->rowCount() > 0) { QList 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 list = availableAudioOutputDevices(); QHash 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 hashCopy(hash); QList orderedList; if (model->rowCount() > 0) { QList 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 DevicePreference::availableAudioOutputDevices() const { return BackendCapabilities::availableAudioOutputDevices(); } QList DevicePreference::availableAudioCaptureDevices() const { #ifndef PHONON_NO_AUDIOCAPTURE return BackendCapabilities::availableAudioCaptureDevices(); #else return QList(); #endif } QList DevicePreference::availableVideoCaptureDevices() const { #ifndef PHONON_NO_VIDEOCAPTURE return BackendCapabilities::availableVideoCaptureDevices(); #else return QList(); #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 list; const QList 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 list; const QList 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 list; const QList 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 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 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 order = m_videoCaptureModel.value(cat)->tupleIndexOrder(); GlobalConfig().setVideoCaptureDeviceListFor(cat, order); } #endif } void DevicePreference::defaults() { { const QList list = availableAudioOutputDevices(); for (int i = 0; i < audioOutCategoriesCount; ++i) { m_audioOutputModel[audioOutCategories[i]]->setModelData(list); } } { const QList list = availableAudioCaptureDevices(); for (int i = 0; i < audioCapCategoriesCount; ++i) { m_audioCaptureModel[audioCapCategories[i]]->setModelData(list); } } { const QList 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 = dynamic_cast(model); if (deviceModel) { deviceModel->moveUp(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } { AudioCaptureDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveUp(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } { VideoCaptureDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveUp(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } } void DevicePreference::on_deferButton_clicked() { QAbstractItemModel *model = deviceList->model(); { AudioOutputDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveDown(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } { AudioCaptureDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveDown(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } { VideoCaptureDeviceModel *deviceModel = dynamic_cast(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(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(item); QList aoPreferredList; QList acPreferredList; QList vcPreferredList; const Category *categoryList = nullptr; const CaptureCategory *capCategoryList = nullptr; 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 dialog = new QDialog(this); QLabel *label = new QLabel(dialog); label->setText(tr("Apply the currently shown device preference list to the following other " "audio playback categories:")); label->setWordWrap(true); QListWidget *list = new QListWidget(dialog); for (catIndex = 0; catIndex < categoryListCount; catIndex ++) { Category cat = cap ? NoCategory : categoryList[catIndex]; CaptureCategory capcat = cap ? capCategoryList[catIndex] : NoCaptureCategory; QListWidgetItem *item = nullptr; if (cap) { if (capcat == NoCaptureCategory) { item = new QListWidgetItem(tr("Default/Unspecified Category"), list, capcat); } else { item = new QListWidgetItem(categoryToString(capcat), list, capcat); } } else { if (cat == NoCategory) { item = new QListWidgetItem(tr("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); } } QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog); connect(buttonBox, &QDialogButtonBox::accepted, dialog.data(), &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, dialog.data(), &QDialog::reject); QVBoxLayout *layout = new QVBoxLayout(dialog); layout->addWidget(label); layout->addWidget(list); layout->addWidget(buttonBox); 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 = nullptr; delete m_audioOutput; m_audioOutput = nullptr; delete m_videoWidget; m_videoWidget = nullptr; } // 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(idx.model()); const AudioOutputDevice &device = model->modelData(idx); m_audioOutput = new AudioOutput(this); if (!m_audioOutput->setOutputDevice(device)) { QMessageBox::critical(this, tr("Failed to set the selected audio output device"), tr("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); static QUrl testUrl = QUrl::fromLocalFile(QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("sounds/Oxygen-Sys-Log-In.ogg"))); m_media->setCurrentSource(testUrl); connect(m_media, &MediaObject::finished, testPlaybackButton, &QToolButton::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()) { QMessageBox::critical(this, tr("Your backend may not support audio recording"), tr("Your backend may not support audio recording")); break; } // Determine the selected device const AudioCaptureDeviceModel *model = static_cast(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(nullptr); // Try to create a path if (!createPath(m_media, m_videoWidget).isValid()) { QMessageBox::critical(this, tr("Your backend may not support video recording"), tr("Your backend may not support video recording")); break; } // Determine the selected device const VideoCaptureDeviceModel *model = static_cast(idx.model()); const VideoCaptureDevice &device = model->modelData(idx); m_media->setCurrentSource(device); // Set up the testing video widget m_videoWidget->setWindowTitle(tr("Testing %1").arg(device.name())); m_videoWidget->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint); if (device.property("icon").canConvert(QVariant::String)) m_videoWidget->setWindowIcon(QIcon::fromTheme(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, &MediaObject::finished, testPlaybackButton, &QToolButton::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 = nullptr; m_videoWidget = nullptr; m_audioOutput = nullptr; 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"