1 /* This file is part of the KDE project
2 Copyright (C) 2006-2008 Matthias Kretz <kretz@kde.org>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) version 3.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
21 #include "devicepreference.h"
23 #include <QtCore/QList>
24 #include <QtDBus/QDBusConnection>
25 #include <QtDBus/QDBusReply>
26 #include <QtDBus/QDBusInterface>
27 #include <QtDBus/QDBusMessage>
28 #include <QtGui/QApplication>
29 #include <QtGui/QPainter>
30 #include <QtGui/QItemDelegate>
31 #include <QtGui/QLabel>
32 #include <QtGui/QVBoxLayout>
33 #include <QtGui/QHeaderView>
35 #include <Phonon/AudioOutput>
36 #include <Phonon/MediaObject>
37 #include <phonon/backendcapabilities.h>
38 #include <phonon/objectdescription.h>
39 #include <phonon/phononnamespace.h>
40 #include "qsettingsgroup_p.h"
41 #include "globalconfig_p.h"
42 #include <kfadewidgeteffect.h>
45 #include <klistwidget.h>
48 #include <kmessagebox.h>
49 #include <kstandarddirs.h>
52 #ifndef METATYPE_QLIST_INT_DEFINED
53 #define METATYPE_QLIST_INT_DEFINED
54 // Want this exactly once, see phonondefs_p.h kcm/devicepreference.cpp
55 Q_DECLARE_METATYPE(QList
<int>)
58 using Phonon::QSettingsGroup
;
60 static const Phonon::Category captureCategories
[] = {
62 Phonon::CommunicationCategory
,
63 Phonon::AccessibilityCategory
65 static const int captureCategoriesCount
= sizeof(captureCategories
)/sizeof(Phonon::Category
);
67 void operator++(Phonon::Category
&c
)
69 c
= static_cast<Phonon::Category
>(1 + static_cast<int>(c
));
70 //Q_ASSERT(c <= Phonon::LastCategory);
73 class CategoryItem
: public QStandardItem
{
75 CategoryItem(Phonon::Category cat
, bool output
= true)
76 : QStandardItem(cat
== Phonon::NoCategory
? (output
? i18n("Audio Output") : i18n("Audio Capture")) : Phonon::categoryToString(cat
)),
82 int type() const { return 1001; }
83 Phonon::Category
category() const { return m_cat
; }
84 const bool isOutputItem
;
87 Phonon::Category m_cat
;
91 * Need this to change the colors of the ListView if the Palette changed. With CSS set this won't
92 * change automatically
94 void DevicePreference::changeEvent(QEvent
*e
)
96 QWidget::changeEvent(e
);
97 if (e
->type() == QEvent::PaletteChange
) {
98 //deviceList->viewport()->setStyleSheet(deviceList->viewport()->styleSheet());
99 deviceList
->setStyleSheet(deviceList
->styleSheet());
103 DevicePreference::DevicePreference(QWidget
*parent
)
105 m_headerModel(0, 1, 0),
106 m_showingOutputModel(true),
107 m_media(0), m_output(0)
110 testPlaybackButton
->setIcon(KIcon("media-playback-start"));
111 testPlaybackButton
->setEnabled(false);
112 testPlaybackButton
->setToolTip(i18n("Play a test sound on the selected device"));
113 removeButton
->setIcon(KIcon("list-remove"));
114 deferButton
->setIcon(KIcon("go-down"));
115 preferButton
->setIcon(KIcon("go-up"));
116 deviceList
->setDragDropMode(QAbstractItemView::InternalMove
);
117 //deviceList->viewport()->setStyleSheet(QString("QWidget#qt_scrollarea_viewport {"
118 deviceList
->setStyleSheet(QString("QTreeView {"
119 "background-color: palette(base);"
120 "background-image: url(%1);"
121 "background-position: bottom left;"
122 "background-attachment: fixed;"
123 "background-repeat: no-repeat;"
125 .arg(KStandardDirs::locate("data", "kcm_phonon/listview-background.png")));
126 deviceList
->setAlternatingRowColors(false);
127 QStandardItem
*parentItem
= m_categoryModel
.invisibleRootItem();
129 // Audio Output Parent
130 QStandardItem
*outputItem
= new CategoryItem(Phonon::NoCategory
);
131 m_outputModel
[Phonon::NoCategory
] = new Phonon::AudioOutputDeviceModel
;
132 outputItem
->setEditable(false);
133 outputItem
->setToolTip(i18n("Defines the default ordering of devices which can be overridden by individual categories."));
134 parentItem
->appendRow(outputItem
);
136 // Audio Capture Parent
137 QStandardItem
*captureItem
= new CategoryItem(Phonon::NoCategory
, false);
138 m_captureModel
[Phonon::NoCategory
] = new Phonon::AudioCaptureDeviceModel
;
139 captureItem
->setEditable(false);
140 captureItem
->setToolTip(i18n("Defines the default ordering of devices which can be overridden by individual categories."));
141 parentItem
->appendRow(captureItem
);
143 // Audio Output Children
144 parentItem
= outputItem
;
145 for (int i
= 0; i
<= Phonon::LastCategory
; ++i
) {
146 m_outputModel
[i
] = new Phonon::AudioOutputDeviceModel
;
147 QStandardItem
*item
= new CategoryItem(static_cast<Phonon::Category
>(i
));
148 item
->setEditable(false);
149 parentItem
->appendRow(item
);
152 // Audio Capture Children
153 parentItem
= captureItem
;
154 for (int i
= 1; i
< captureCategoriesCount
; ++i
) { // i == 1 to skip NoCategory
155 m_captureModel
[captureCategories
[i
]] = new Phonon::AudioCaptureDeviceModel
;
156 QStandardItem
*item
= new CategoryItem(captureCategories
[i
], false);
157 item
->setEditable(false);
158 parentItem
->appendRow(item
);
161 categoryTree
->setModel(&m_categoryModel
);
162 if (categoryTree
->header()) {
163 categoryTree
->header()->hide();
165 categoryTree
->expandAll();
167 connect(categoryTree
->selectionModel(),
168 SIGNAL(currentChanged(const QModelIndex
&,const QModelIndex
&)),
169 SLOT(updateDeviceList()));
171 for (int i
= -1; i
<= Phonon::LastCategory
; ++i
) {
172 connect(m_outputModel
[i
], SIGNAL(rowsInserted(const QModelIndex
&, int, int)), this, SIGNAL(changed()));
173 connect(m_outputModel
[i
], SIGNAL(rowsRemoved(const QModelIndex
&, int, int)), this, SIGNAL(changed()));
174 connect(m_outputModel
[i
], SIGNAL(layoutChanged()), this, SIGNAL(changed()));
175 connect(m_outputModel
[i
], SIGNAL(dataChanged(const QModelIndex
&, const QModelIndex
&)), this, SIGNAL(changed()));
176 if (m_captureModel
.contains(i
)) {
177 connect(m_captureModel
[i
], SIGNAL(rowsInserted(const QModelIndex
&, int, int)), this, SIGNAL(changed()));
178 connect(m_captureModel
[i
], SIGNAL(rowsRemoved(const QModelIndex
&, int, int)), this, SIGNAL(changed()));
179 connect(m_captureModel
[i
], SIGNAL(layoutChanged()), this, SIGNAL(changed()));
180 connect(m_captureModel
[i
], SIGNAL(dataChanged(const QModelIndex
&, const QModelIndex
&)), this, SIGNAL(changed()));
183 connect(showCheckBox
, SIGNAL(stateChanged (int)), this, SIGNAL(changed()));
184 connect(Phonon::BackendCapabilities::notifier(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(updateAudioOutputDevices()));
185 connect(Phonon::BackendCapabilities::notifier(), SIGNAL(availableAudioCaptureDevicesChanged()), SLOT(updateAudioCaptureDevices()));
186 connect(Phonon::BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), SLOT(updateAudioOutputDevices()));
187 connect(Phonon::BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), SLOT(updateAudioCaptureDevices()));
189 if (!categoryTree
->currentIndex().isValid()) {
190 categoryTree
->setCurrentIndex(m_categoryModel
.index(0, 0).child(1, 0));
194 void DevicePreference::updateDeviceList()
196 QStandardItem
*currentItem
= m_categoryModel
.itemFromIndex(categoryTree
->currentIndex());
197 KFadeWidgetEffect
*animation
= new KFadeWidgetEffect(deviceList
);
198 if (deviceList
->selectionModel()) {
199 disconnect(deviceList
->selectionModel(),
200 SIGNAL(currentRowChanged(const QModelIndex
&,const QModelIndex
&)),
201 this, SLOT(updateButtonsEnabled()));
203 if (currentItem
&& currentItem
->type() == 1001) {
204 CategoryItem
*catItem
= static_cast<CategoryItem
*>(currentItem
);
205 const Phonon::Category cat
= catItem
->category();
206 if (catItem
->isOutputItem
) {
207 deviceList
->setModel(m_outputModel
[cat
]);
209 deviceList
->setModel(m_captureModel
[cat
]);
211 m_showingOutputModel
= catItem
->isOutputItem
;
212 if (cat
== Phonon::NoCategory
) {
213 if (catItem
->isOutputItem
) {
214 m_headerModel
.setHeaderData(0, Qt::Horizontal
, i18n("Default Output Device Preference"), Qt::DisplayRole
);
216 m_headerModel
.setHeaderData(0, Qt::Horizontal
, i18n("Default Capture Device Preference"), Qt::DisplayRole
);
219 if (catItem
->isOutputItem
) {
220 m_headerModel
.setHeaderData(0, Qt::Horizontal
, i18n("Output Device Preference for the '%1' Category", Phonon::categoryToString(cat
)), Qt::DisplayRole
);
222 m_headerModel
.setHeaderData(0, Qt::Horizontal
, i18n("Capture Device Preference for the '%1' Category", Phonon::categoryToString(cat
)), Qt::DisplayRole
);
226 m_showingOutputModel
= false;
227 m_headerModel
.setHeaderData(0, Qt::Horizontal
, QString(), Qt::DisplayRole
);
228 deviceList
->setModel(0);
230 deviceList
->header()->setModel(&m_headerModel
);
231 updateButtonsEnabled();
232 if (deviceList
->selectionModel()) {
233 connect(deviceList
->selectionModel(),
234 SIGNAL(currentRowChanged(const QModelIndex
&,const QModelIndex
&)),
235 this, SLOT(updateButtonsEnabled()));
237 deviceList
->resizeColumnToContents(0);
241 void DevicePreference::updateAudioCaptureDevices()
244 const QList
<Phonon::AudioCaptureDevice
> list
= availableAudioCaptureDevices();
245 QHash
<int, Phonon::AudioCaptureDevice
> hash
;
246 foreach (const Phonon::AudioCaptureDevice
&dev
, list
) {
247 hash
.insert(dev
.index(), dev
);
249 for (int ii
= 0; ii
< captureCategoriesCount
; ++ii
) {
250 const int i
= captureCategories
[ii
];
251 Phonon::AudioCaptureDeviceModel
*model
= m_captureModel
.value(i
);
254 QHash
<int, Phonon::AudioCaptureDevice
> hashCopy(hash
);
255 QList
<Phonon::AudioCaptureDevice
> orderedList
;
256 if (model
->rowCount() > 0) {
257 QList
<int> order
= model
->tupleIndexOrder();
258 foreach (int idx
, order
) {
259 if (hashCopy
.contains(idx
)) {
260 orderedList
<< hashCopy
.take(idx
);
263 if (hashCopy
.size() > 1) {
264 // keep the order of the original list
265 foreach (const Phonon::AudioCaptureDevice
&dev
, list
) {
266 if (hashCopy
.contains(dev
.index())) {
267 orderedList
<< hashCopy
.take(dev
.index());
270 } else if (hashCopy
.size() == 1) {
271 orderedList
+= hashCopy
.values();
273 model
->setModelData(orderedList
);
275 model
->setModelData(list
);
278 deviceList
->resizeColumnToContents(0);
281 void DevicePreference::updateAudioOutputDevices()
283 const QList
<Phonon::AudioOutputDevice
> list
= availableAudioOutputDevices();
284 QHash
<int, Phonon::AudioOutputDevice
> hash
;
285 foreach (const Phonon::AudioOutputDevice
&dev
, list
) {
286 hash
.insert(dev
.index(), dev
);
288 for (int i
= -1; i
<= Phonon::LastCategory
; ++i
) {
289 Phonon::AudioOutputDeviceModel
*model
= m_outputModel
.value(i
);
292 QHash
<int, Phonon::AudioOutputDevice
> hashCopy(hash
);
293 QList
<Phonon::AudioOutputDevice
> orderedList
;
294 if (model
->rowCount() > 0) {
295 QList
<int> order
= model
->tupleIndexOrder();
296 foreach (int idx
, order
) {
297 if (hashCopy
.contains(idx
)) {
298 orderedList
<< hashCopy
.take(idx
);
301 if (hashCopy
.size() > 1) {
302 // keep the order of the original list
303 foreach (const Phonon::AudioOutputDevice
&dev
, list
) {
304 if (hashCopy
.contains(dev
.index())) {
305 orderedList
<< hashCopy
.take(dev
.index());
308 } else if (hashCopy
.size() == 1) {
309 orderedList
+= hashCopy
.values();
311 model
->setModelData(orderedList
);
313 model
->setModelData(list
);
316 deviceList
->resizeColumnToContents(0);
319 QList
<Phonon::AudioOutputDevice
> DevicePreference::availableAudioOutputDevices() const
321 QList
<Phonon::AudioOutputDevice
> ret
;
322 const QList
<int> deviceIndexes
= Phonon::GlobalConfig().audioOutputDeviceListFor(Phonon::NoCategory
,
323 showCheckBox
->isChecked()
324 ? Phonon::GlobalConfig::ShowAdvancedDevices
325 : Phonon::GlobalConfig::HideAdvancedDevices
);
326 foreach (int i
, deviceIndexes
) {
327 ret
.append(Phonon::AudioOutputDevice::fromIndex(i
));
332 QList
<Phonon::AudioCaptureDevice
> DevicePreference::availableAudioCaptureDevices() const
334 QList
<Phonon::AudioCaptureDevice
> ret
;
335 const QList
<int> deviceIndexes
= Phonon::GlobalConfig().audioCaptureDeviceListFor(Phonon::NoCategory
,
336 showCheckBox
->isChecked()
337 ? Phonon::GlobalConfig::ShowAdvancedDevices
338 : Phonon::GlobalConfig::HideAdvancedDevices
);
339 kDebug() << deviceIndexes
;
340 foreach (int i
, deviceIndexes
) {
341 ret
.append(Phonon::AudioCaptureDevice::fromIndex(i
));
346 void DevicePreference::load()
348 QSettings
phononConfig(QLatin1String("kde.org"), QLatin1String("libphonon"));
349 QSettingsGroup
outputDeviceGroup(&phononConfig
, QLatin1String("AudioOutputDevice"));
350 QSettingsGroup
captureDeviceGroup(&phononConfig
, QLatin1String("AudioCaptureDevice"));
351 QSettingsGroup
generalGroup(&phononConfig
, QLatin1String("General"));
352 showCheckBox
->setChecked(!generalGroup
.value(QLatin1String("HideAdvancedDevices"), true));
355 // the following call returns ordered according to NoCategory
356 const QList
<Phonon::AudioOutputDevice
> list
= availableAudioOutputDevices();
357 m_outputModel
[Phonon::NoCategory
]->setModelData(list
);
359 QHash
<int, Phonon::AudioOutputDevice
> hash
;
360 foreach (const Phonon::AudioOutputDevice
&dev
, list
) {
361 hash
.insert(dev
.index(), dev
);
363 for (int i
= 0; i
<= Phonon::LastCategory
; ++i
) {
364 const QString
configKey(QLatin1String("Category_") + QString::number(i
));
365 if (!outputDeviceGroup
.hasKey(configKey
)) {
366 m_outputModel
[i
]->setModelData(list
); // use the NoCategory order
369 QHash
<int, Phonon::AudioOutputDevice
> hashCopy(hash
);
370 const QList
<int> order
= outputDeviceGroup
.value(configKey
, QList
<int>());
371 QList
<Phonon::AudioOutputDevice
> orderedList
;
372 foreach (int idx
, order
) {
373 if (hashCopy
.contains(idx
)) {
374 orderedList
<< hashCopy
.take(idx
);
377 if (hashCopy
.size() > 1) {
378 // keep the order of the original list
379 foreach (const Phonon::AudioOutputDevice
&dev
, list
) {
380 if (hashCopy
.contains(dev
.index())) {
381 orderedList
<< hashCopy
.take(dev
.index());
384 } else if (hashCopy
.size() == 1) {
385 orderedList
+= hashCopy
.values();
387 m_outputModel
[i
]->setModelData(orderedList
);
391 // the following call returns ordered according to NoCategory
392 QList
<Phonon::AudioCaptureDevice
> list
= availableAudioCaptureDevices();
393 m_captureModel
[Phonon::NoCategory
]->setModelData(list
);
395 QHash
<int, Phonon::AudioCaptureDevice
> hash
;
396 foreach (const Phonon::AudioCaptureDevice
&dev
, list
) {
397 hash
.insert(dev
.index(), dev
);
399 for (int i
= 1; i
< captureCategoriesCount
; ++i
) { // i == 1 to skip NoCategory
400 const Phonon::Category cat
= captureCategories
[i
];
401 const QString
configKey(QLatin1String("Category_") + QString::number(cat
));
402 if (!captureDeviceGroup
.hasKey(configKey
)) {
403 m_captureModel
[cat
]->setModelData(list
); // use the NoCategory order
406 QHash
<int, Phonon::AudioCaptureDevice
> hashCopy(hash
);
407 const QList
<int> order
= captureDeviceGroup
.value(configKey
, QList
<int>());
408 QList
<Phonon::AudioCaptureDevice
> orderedList
;
409 foreach (int idx
, order
) {
410 if (hashCopy
.contains(idx
)) {
411 orderedList
<< hashCopy
.take(idx
);
414 if (hashCopy
.size() > 1) {
415 // keep the order of the original list
416 foreach (const Phonon::AudioCaptureDevice
&dev
, list
) {
417 if (hashCopy
.contains(dev
.index())) {
418 orderedList
<< hashCopy
.take(dev
.index());
421 } else if (hashCopy
.size() == 1) {
422 orderedList
+= hashCopy
.values();
424 m_captureModel
[cat
]->setModelData(orderedList
);
428 deviceList
->resizeColumnToContents(0);
431 void DevicePreference::save()
433 QSettings
config(QLatin1String("kde.org"), QLatin1String("libphonon"));
435 QSettingsGroup
generalGroup(&config
, QLatin1String("General"));
436 generalGroup
.setValue(QLatin1String("HideAdvancedDevices"), !showCheckBox
->isChecked());
438 if (!m_removeOnApply
.isEmpty()) {
439 QDBusMessage msg
= QDBusMessage::createMethodCall("org.kde.kded", "/modules/phononserver",
440 "org.kde.PhononServer", "removeAudioDevices");
441 msg
<< QVariant::fromValue(m_removeOnApply
);
442 QDBusConnection::sessionBus().send(msg
);
443 m_removeOnApply
.clear();
446 QSettingsGroup
globalGroup(&config
, QLatin1String("AudioOutputDevice"));
447 const QList
<int> noCategoryOrder
= m_outputModel
.value(Phonon::NoCategory
)->tupleIndexOrder();
448 globalGroup
.setValue(QLatin1String("Category_") + QString::number(Phonon::NoCategory
), noCategoryOrder
);
449 for (int i
= 0; i
<= Phonon::LastCategory
; ++i
) {
450 Q_ASSERT(m_outputModel
.value(i
));
451 const QList
<int> order
= m_outputModel
.value(i
)->tupleIndexOrder();
452 if (order
== noCategoryOrder
) {
453 globalGroup
.removeEntry(QLatin1String("Category_") + QString::number(i
));
455 globalGroup
.setValue(QLatin1String("Category_") + QString::number(i
), order
);
460 QSettingsGroup
globalGroup(&config
, QLatin1String("AudioCaptureDevice"));
461 const QList
<int> noCategoryOrder
= m_captureModel
.value(Phonon::NoCategory
)->tupleIndexOrder();
462 globalGroup
.setValue(QLatin1String("Category_") + QString::number(Phonon::NoCategory
), noCategoryOrder
);
463 for (int i
= 1; i
< captureCategoriesCount
; ++i
) {
464 const Phonon::Category cat
= captureCategories
[i
];
465 Q_ASSERT(m_captureModel
.value(cat
));
466 const QList
<int> order
= m_captureModel
.value(cat
)->tupleIndexOrder();
467 if (order
== noCategoryOrder
) {
468 globalGroup
.removeEntry(QLatin1String("Category_") + QString::number(cat
));
470 globalGroup
.setValue(QLatin1String("Category_") + QString::number(cat
), order
);
476 void DevicePreference::defaults()
479 QList
<Phonon::AudioOutputDevice
> list
= availableAudioOutputDevices();
480 for (int i
= -1; i
<= Phonon::LastCategory
; ++i
) {
481 m_outputModel
[i
]->setModelData(list
);
485 QList
<Phonon::AudioCaptureDevice
> list
= availableAudioCaptureDevices();
486 for (int i
= 0; i
< captureCategoriesCount
; ++i
) {
487 m_captureModel
[captureCategories
[i
]]->setModelData(list
);
491 deviceList
->resizeColumnToContents(0);
494 void DevicePreference::on_preferButton_clicked()
496 QAbstractItemModel
*model
= deviceList
->model();
498 Phonon::AudioOutputDeviceModel
*deviceModel
= qobject_cast
<Phonon::AudioOutputDeviceModel
*>(model
);
500 deviceModel
->moveUp(deviceList
->currentIndex());
501 updateButtonsEnabled();
506 Phonon::AudioCaptureDeviceModel
*deviceModel
= qobject_cast
<Phonon::AudioCaptureDeviceModel
*>(model
);
508 deviceModel
->moveUp(deviceList
->currentIndex());
509 updateButtonsEnabled();
515 void DevicePreference::on_deferButton_clicked()
517 QAbstractItemModel
*model
= deviceList
->model();
519 Phonon::AudioOutputDeviceModel
*deviceModel
= qobject_cast
<Phonon::AudioOutputDeviceModel
*>(model
);
521 deviceModel
->moveDown(deviceList
->currentIndex());
522 updateButtonsEnabled();
527 Phonon::AudioCaptureDeviceModel
*deviceModel
= qobject_cast
<Phonon::AudioCaptureDeviceModel
*>(model
);
529 deviceModel
->moveDown(deviceList
->currentIndex());
530 updateButtonsEnabled();
536 template<Phonon::ObjectDescriptionType T
>
537 void DevicePreference::removeDevice(const Phonon::ObjectDescription
<T
> &deviceToRemove
,
538 QMap
<int, Phonon::ObjectDescriptionModel
<T
> *> *modelMap
)
540 QDBusInterface
phononServer(QLatin1String("org.kde.kded"), QLatin1String("/modules/phononserver"),
541 QLatin1String("org.kde.PhononServer"));
542 QDBusReply
<bool> reply
= phononServer
.call(QLatin1String("isAudioDeviceRemovable"), deviceToRemove
.index());
543 if (!reply
.isValid()) {
544 kError(600) << reply
.error();
547 if (!reply
.value()) {
550 m_removeOnApply
<< deviceToRemove
.index();
552 // remove from all models, idx.row() is only correct for the current model
553 foreach (Phonon::ObjectDescriptionModel
<T
> *model
, *modelMap
) {
554 QList
<Phonon::ObjectDescription
<T
> > data
= model
->modelData();
555 for (int row
= 0; row
< data
.size(); ++row
) {
556 if (data
[row
] == deviceToRemove
) {
557 model
->removeRows(row
, 1);
562 updateButtonsEnabled();
566 void DevicePreference::on_removeButton_clicked()
568 const QModelIndex idx
= deviceList
->currentIndex();
570 QAbstractItemModel
*model
= deviceList
->model();
571 Phonon::AudioOutputDeviceModel
*playbackModel
= qobject_cast
<Phonon::AudioOutputDeviceModel
*>(model
);
572 if (playbackModel
&& idx
.isValid()) {
573 removeDevice(playbackModel
->modelData(idx
), &m_outputModel
);
575 Phonon::AudioCaptureDeviceModel
*captureModel
= qobject_cast
<Phonon::AudioCaptureDeviceModel
*>(model
);
576 if (captureModel
&& idx
.isValid()) {
577 removeDevice(captureModel
->modelData(idx
), &m_captureModel
);
581 deviceList
->resizeColumnToContents(0);
584 void DevicePreference::on_applyPreferencesButton_clicked()
586 const QModelIndex idx
= categoryTree
->currentIndex();
587 const QStandardItem
*item
= m_categoryModel
.itemFromIndex(idx
);
590 Q_ASSERT(item
->type() == 1001);
591 const CategoryItem
*catItem
= static_cast<const CategoryItem
*>(item
);
592 const QList
<Phonon::AudioOutputDevice
> modelData
= m_outputModel
.value(catItem
->category())->modelData();
594 KDialog
dialog(this);
595 dialog
.setButtons(KDialog::Ok
| KDialog::Cancel
);
596 dialog
.setDefaultButton(KDialog::Ok
);
598 QWidget
mainWidget(&dialog
);
599 dialog
.setMainWidget(&mainWidget
);
601 QLabel
label(&mainWidget
);
602 label
.setText(i18n("Apply the currently shown device preference list to the following other "
603 "audio output categories:"));
604 label
.setWordWrap(true);
606 KListWidget
list(&mainWidget
);
607 for (Phonon::Category cat
= Phonon::NoCategory
; cat
<= Phonon::LastCategory
; ++cat
) {
608 QListWidgetItem
*item
= new QListWidgetItem(cat
== Phonon::NoCategory
609 ? i18n("Default/Unspecified Category") : Phonon::categoryToString(cat
), &list
, cat
);
610 item
->setCheckState(Qt::Checked
);
611 if (cat
== catItem
->category()) {
612 item
->setFlags(item
->flags() & ~Qt::ItemIsEnabled
);
616 QVBoxLayout
layout(&mainWidget
);
618 layout
.addWidget(&label
);
619 layout
.addWidget(&list
);
621 switch (dialog
.exec()) {
622 case QDialog::Accepted
:
623 for (Phonon::Category cat
= Phonon::NoCategory
; cat
<= Phonon::LastCategory
; ++cat
) {
624 if (cat
!= catItem
->category()) {
625 QListWidgetItem
*item
= list
.item(static_cast<int>(cat
) + 1);
626 Q_ASSERT(item
->type() == cat
);
627 if (item
->checkState() == Qt::Checked
) {
628 m_outputModel
.value(cat
)->setModelData(modelData
);
633 case QDialog::Rejected
:
639 void DevicePreference::on_showCheckBox_toggled()
642 // the following call returns ordered according to NoCategory
643 const QList
<Phonon::AudioOutputDevice
> list
= availableAudioOutputDevices();
644 m_outputModel
[Phonon::NoCategory
]->setModelData(list
);
646 QHash
<int, Phonon::AudioOutputDevice
> hash
;
647 foreach (const Phonon::AudioOutputDevice
&dev
, list
) {
648 hash
.insert(dev
.index(), dev
);
650 for (int i
= 0; i
<= Phonon::LastCategory
; ++i
) {
651 QHash
<int, Phonon::AudioOutputDevice
> hashCopy(hash
);
652 const QList
<int> order
= m_outputModel
[i
]->tupleIndexOrder();
653 QList
<Phonon::AudioOutputDevice
> orderedList
;
654 foreach (int idx
, order
) {
655 if (hashCopy
.contains(idx
)) {
656 orderedList
<< hashCopy
.take(idx
);
659 if (hashCopy
.size() > 1) {
660 // keep the order of the original list
661 foreach (const Phonon::AudioOutputDevice
&dev
, list
) {
662 if (hashCopy
.contains(dev
.index())) {
663 orderedList
<< hashCopy
.take(dev
.index());
666 } else if (hashCopy
.size() == 1) {
667 orderedList
+= hashCopy
.values();
669 m_outputModel
[i
]->setModelData(orderedList
);
673 // the following call returns ordered according to NoCategory
674 const QList
<Phonon::AudioCaptureDevice
> list
= availableAudioCaptureDevices();
675 m_captureModel
[Phonon::NoCategory
]->setModelData(list
);
677 QHash
<int, Phonon::AudioCaptureDevice
> hash
;
678 foreach (const Phonon::AudioCaptureDevice
&dev
, list
) {
679 hash
.insert(dev
.index(), dev
);
681 for (int i
= 1; i
< captureCategoriesCount
; ++i
) {
682 const Phonon::Category cat
= captureCategories
[i
];
683 QHash
<int, Phonon::AudioCaptureDevice
> hashCopy(hash
);
684 const QList
<int> order
= m_captureModel
[cat
]->tupleIndexOrder();
685 QList
<Phonon::AudioCaptureDevice
> orderedList
;
686 foreach (int idx
, order
) {
687 if (hashCopy
.contains(idx
)) {
688 orderedList
<< hashCopy
.take(idx
);
691 if (hashCopy
.size() > 1) {
692 // keep the order of the original list
693 foreach (const Phonon::AudioCaptureDevice
&dev
, list
) {
694 if (hashCopy
.contains(dev
.index())) {
695 orderedList
<< hashCopy
.take(dev
.index());
698 } else if (hashCopy
.size() == 1) {
699 orderedList
+= hashCopy
.values();
701 m_captureModel
[cat
]->setModelData(orderedList
);
704 deviceList
->resizeColumnToContents(0);
707 void DevicePreference::on_testPlaybackButton_toggled(bool down
)
710 QModelIndex idx
= deviceList
->currentIndex();
711 if (!idx
.isValid() || !m_showingOutputModel
) {
714 const Phonon::AudioOutputDeviceModel
*model
= static_cast<const Phonon::AudioOutputDeviceModel
*>(idx
.model());
715 const Phonon::AudioOutputDevice
&device
= model
->modelData(idx
);
716 m_media
= new Phonon::MediaObject(this);
717 m_output
= new Phonon::AudioOutput(this);
718 m_output
->setOutputDevice(device
);
720 // just to be very sure that nothing messes our test sound up
721 m_output
->setVolume(1.0);
722 m_output
->setMuted(false);
724 Phonon::createPath(m_media
, m_output
);
725 connect(m_media
, SIGNAL(finished()), testPlaybackButton
, SLOT(toggle()));
726 m_media
->setCurrentSource(KStandardDirs::locate("sound", "KDE-Sys-Log-In.ogg"));
729 disconnect(m_media
, SIGNAL(finished()), testPlaybackButton
, SLOT(toggle()));
737 void DevicePreference::updateButtonsEnabled()
740 if (deviceList
->model()) {
741 //kDebug() << "model available";
742 QModelIndex idx
= deviceList
->currentIndex();
743 preferButton
->setEnabled(idx
.isValid() && idx
.row() > 0);
744 deferButton
->setEnabled(idx
.isValid() && idx
.row() < deviceList
->model()->rowCount() - 1);
745 removeButton
->setEnabled(idx
.isValid() && !(idx
.flags() & Qt::ItemIsEnabled
));
746 testPlaybackButton
->setEnabled(m_showingOutputModel
&& idx
.isValid() &&
747 (idx
.flags() & Qt::ItemIsEnabled
));
749 preferButton
->setEnabled(false);
750 deferButton
->setEnabled(false);
751 removeButton
->setEnabled(false);
752 testPlaybackButton
->setEnabled(false);
756 #include "moc_devicepreference.cpp"