SVN_SILENT made messages (.desktop file)
[kdeaccessibility.git] / kttsd / kcmkttsmgr / kcmkttsmgr.cpp
blob0c1a562a638153c2bf0b1fc71ef16d381c400c1f
1 /***************************************************** vim:set ts=4 sw=4 sts=4:
2 KControl module for KTTSD configuration and Job Management
3 -------------------
4 Copyright : (C) 2002-2003 by José Pablo Ezequiel "Pupeno" Fernández <pupeno@kde.org>
5 Copyright : (C) 2004-2005 by Gary Cramblitt <garycramblitt@comcast.net>
6 -------------------
7 Original author: José Pablo Ezequiel "Pupeno" Fernández <pupeno@kde.org>
8 Current Maintainer: Gary Cramblitt <garycramblitt@comcast.net>
9 ******************************************************************************/
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; version 2 of the License. *
16 * *
17 ***************************************************************************/
19 // Note to programmers. There is a subtle difference between a plugIn name and a
20 // synthesizer name. The latter is a translated name, for example, "Festival Interactivo",
21 // while the former is alway an English name, example "Festival Interactive".
23 // KCMKttsMgr includes.
24 #include "kcmkttsmgr.h"
25 #include "kcmkttsmgr.moc"
27 // C++ includes.
28 #include <math.h>
30 // Qt includes.
31 #include <QtGui/QWidget>
32 #include <QtGui/QTabWidget>
33 #include <QtGui/QCheckBox>
34 #include <QtGui/QLayout>
35 #include <QtGui/QRadioButton>
36 #include <QtGui/QSlider>
37 #include <QtGui/QLabel>
38 #include <QtGui/QTreeWidget>
39 #include <QtGui/QHeaderView>
40 #include <QtCore/QTextStream>
41 #include <QtGui/QMenu>
43 // KDE includes.
44 #include <kparts/componentfactory.h>
45 #include <klineedit.h>
46 #include <kurlrequester.h>
47 #include <kicon.h>
48 #include <kstandarddirs.h>
49 #include <kaboutdata.h>
50 #include <kconfig.h>
51 #include <knuminput.h>
52 #include <kcombobox.h>
53 #include <kinputdialog.h>
54 #include <kmessagebox.h>
55 #include <kfiledialog.h>
56 #include <ktoolinvocation.h>
57 #include <kdialog.h>
58 #include <kspeech.h>
59 #include <kpluginfactory.h>
60 #include <kpluginloader.h>
63 // KTTS includes.
64 #include "talkercode.h"
65 #include "pluginconf.h"
66 #include "filterconf.h"
67 #include "testplayer.h"
68 #include "player.h"
69 #include "selecttalkerdlg.h"
70 #include "selectlanguagedlg.h"
71 #include "utils.h"
73 // Some constants.
74 // Defaults set when clicking Defaults button.
75 const bool autostartMgrCheckBoxValue = true;
76 const bool autoexitMgrCheckBoxValue = true;
79 const bool textPreMsgCheckValue = true;
80 const QString textPreMsgValue = i18n("Text interrupted. Message.");
82 const bool textPreSndCheckValue = false;
83 const QString textPreSndValue = "";
85 const bool textPostMsgCheckValue = true;
86 const QString textPostMsgValue = i18n("Resuming text.");
88 const bool textPostSndCheckValue = false;
89 const QString textPostSndValue = "";
91 const int timeBoxValue = 100;
93 const bool keepAudioCheckBoxValue = false;
95 // Make this a plug in.
96 K_PLUGIN_FACTORY(KCMKttsMgrFactory, registerPlugin<KCMKttsMgr>();)
97 K_EXPORT_PLUGIN(KCMKttsMgrFactory("kttsd"))
100 // ----------------------------------------------------------------------------
102 FilterListModel::FilterListModel(FilterList filters, QObject *parent)
103 : QAbstractListModel(parent), m_filters(filters)
107 int FilterListModel::rowCount(const QModelIndex &parent) const
109 if (!parent.isValid())
110 return m_filters.count();
111 else
112 return 0;
115 int FilterListModel::columnCount(const QModelIndex &parent) const
117 Q_UNUSED(parent);
118 return 2;
121 QModelIndex FilterListModel::index(int row, int column, const QModelIndex &parent) const
123 if (!parent.isValid())
124 return createIndex(row, column, 0);
125 else
126 return QModelIndex();
129 QModelIndex FilterListModel::parent(const QModelIndex &index ) const
131 Q_UNUSED(index);
132 return QModelIndex();
135 QVariant FilterListModel::data(const QModelIndex &index, int role) const
137 if (!index.isValid())
138 return QVariant();
140 if (index.row() < 0 || index.row() >= m_filters.count())
141 return QVariant();
143 if (index.column() < 0 || index.column() >= 2)
144 return QVariant();
146 if (role == Qt::DisplayRole || role == Qt::EditRole)
147 switch (index.column()) {
148 case 0: return QVariant(); break;
149 case 1: return m_filters.at(index.row()).userFilterName; break;
152 if (role == Qt::CheckStateRole)
153 switch (index.column()) {
154 case 0: if (m_filters.at(index.row()).enabled)
155 return Qt::Checked;
156 else
157 return Qt::Unchecked;
158 break;
159 case 1: return QVariant(); break;
162 return QVariant();
165 Qt::ItemFlags FilterListModel::flags(const QModelIndex &index) const
167 if (!index.isValid())
168 return Qt::ItemIsEnabled;
170 switch (index.column()) {
171 case 0: return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled |
172 Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; break;
173 case 1: return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled | Qt::ItemIsSelectable; break;
175 return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled;
178 QVariant FilterListModel::headerData(int section, Qt::Orientation orientation, int role) const
180 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
181 switch (section) {
182 case 0: return "";
183 case 1: return i18n("Filter");
185 return QVariant();
188 bool FilterListModel::removeRow(int row, const QModelIndex & parent)
190 beginRemoveRows(parent, row, row);
191 m_filters.removeAt(row);
192 endRemoveRows();
193 return true;
196 FilterItem FilterListModel::getRow(int row) const
198 if (row < 0 || row >= rowCount()) return FilterItem();
199 return m_filters[row];
202 bool FilterListModel::appendRow(FilterItem& filter)
204 beginInsertRows(QModelIndex(), m_filters.count(), m_filters.count());
205 m_filters.append(filter);
206 endInsertRows();
207 return true;
210 bool FilterListModel::updateRow(int row, FilterItem& filter)
212 m_filters.replace(row, filter);
213 emit dataChanged(index(row, 0, QModelIndex()), index(row, columnCount()-1, QModelIndex()));
214 return true;
217 bool FilterListModel::swap(int i, int j)
219 m_filters.swap(i, j);
220 emit dataChanged(index(i, 0, QModelIndex()), index(j, columnCount()-1, QModelIndex()));
221 return true;
224 void FilterListModel::clear()
226 m_filters.clear();
227 emit reset();
230 // ----------------------------------------------------------------------------
232 SbdFilterListModel::SbdFilterListModel(FilterList filters, QObject *parent)
233 : FilterListModel(filters, parent)
237 int SbdFilterListModel::columnCount(const QModelIndex &parent) const
239 Q_UNUSED(parent);
240 return 1;
243 QVariant SbdFilterListModel::data(const QModelIndex &index, int role) const
245 if (!index.isValid())
246 return QVariant();
248 if (index.row() < 0 || index.row() >= m_filters.count())
249 return QVariant();
251 if (index.column() != 0)
252 return QVariant();
254 if (role == Qt::DisplayRole)
255 return m_filters.at(index.row()).userFilterName;
256 else
257 return QVariant();
260 Qt::ItemFlags SbdFilterListModel::flags(const QModelIndex &index) const
262 if (!index.isValid())
263 return Qt::ItemIsEnabled;
265 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
268 QVariant SbdFilterListModel::headerData(int section, Qt::Orientation orientation, int role) const
270 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
271 switch (section) {
272 case 0: return i18n("Sentence Boundary Detector");
274 return QVariant();
277 // ----------------------------------------------------------------------------
280 * Constructor.
282 KCMKttsMgr::KCMKttsMgr(QWidget *parent, const QVariantList &) :
283 KCModule(KCMKttsMgrFactory::componentData(), parent/*, name*/),
284 m_kspeech(0)
287 // kDebug() << "KCMKttsMgr constructor running.";
289 // Initialize some variables.
290 m_config = 0;
291 m_jobMgrPart = 0;
292 m_configDlg = 0;
293 m_changed = false;
294 m_suppressConfigChanged = false;
296 // Add the KTTS Manager widget
297 setupUi(this);
299 // Connect Views to Models and set row selection mode.
300 talkersView->setModel(&m_talkerListModel);
301 filtersView->setModel(&m_filterListModel);
302 sbdsView->setModel(&m_sbdFilterListModel);
303 talkersView->setSelectionBehavior(QAbstractItemView::SelectRows);
304 filtersView->setSelectionBehavior(QAbstractItemView::SelectRows);
305 sbdsView->setSelectionBehavior(QAbstractItemView::SelectRows);
306 talkersView->setRootIsDecorated(false);
307 filtersView->setRootIsDecorated(false);
308 sbdsView->setRootIsDecorated(false);
309 talkersView->setItemsExpandable(false);
310 filtersView->setItemsExpandable(false);
311 sbdsView->setItemsExpandable(false);
313 // Give buttons icons.
314 // Talkers tab.
315 higherTalkerPriorityButton->setIcon(KIcon("go-up"));
316 lowerTalkerPriorityButton->setIcon(KIcon("go-down"));
317 removeTalkerButton->setIcon(KIcon("user-trash"));
318 configureTalkerButton->setIcon(KIcon("configure"));
320 // Filters tab.
321 higherFilterPriorityButton->setIcon(KIcon("go-up"));
322 lowerFilterPriorityButton->setIcon(KIcon("go-down"));
323 removeFilterButton->setIcon(KIcon("user-trash"));
324 configureFilterButton->setIcon(KIcon("configure"));
326 // Construct a popup menu for the Sentence Boundary Detector buttons on Filter tab.
327 QMenu* sbdPopmenu = new QMenu( this );
328 sbdPopmenu->setObjectName( "SbdPopupMenu" );
329 m_sbdBtnEdit = sbdPopmenu->addAction(
330 i18n("&Edit..."), this, SLOT(slotConfigureSbdFilterButton_clicked()), 0 );
331 m_sbdBtnUp = sbdPopmenu->addAction( KIcon("go-up"),
332 i18n("U&p"), this, SLOT(slotHigherSbdFilterPriorityButton_clicked()), 0 );
333 m_sbdBtnDown = sbdPopmenu->addAction( KIcon("go-down"),
334 i18n("Do&wn"), this, SLOT(slotLowerSbdFilterPriorityButton_clicked()), 0 );
335 m_sbdBtnAdd = sbdPopmenu->addAction(
336 i18n("&Add..."), this, SLOT(slotAddSbdFilterButton_clicked()), 0 );
337 m_sbdBtnRemove = sbdPopmenu->addAction(
338 i18n("&Remove"), this, SLOT(slotRemoveSbdFilterButton_clicked()), 0 );
339 sbdButton->setMenu( sbdPopmenu );
341 TestPlayer* testPlayer;
342 Player* player;
344 // If Phonon is available, enable its radio button.
345 // Determine if available by loading its plugin. If it fails, not available.
346 testPlayer = new TestPlayer();
347 player = testPlayer->createPlayerObject(0);
348 if (player)
350 phononRadioButton->setEnabled(true);
352 delete player;
353 delete testPlayer;
355 // If ALSA is available, enable its radio button.
356 // Determine if available by loading its plugin. If it fails, not available.
357 testPlayer = new TestPlayer();
358 player = testPlayer->createPlayerObject(2);
359 if (player)
361 alsaRadioButton->setEnabled(true);
362 pcmLabel->setEnabled(true);
363 pcmComboBox->setEnabled(true);
364 pcmCustom->setEnabled(pcmComboBox->currentText() == "custom");
365 QStringList pcmList = player->getPluginList("");
366 pcmList.append("custom");
367 kDebug() << "KCMKttsMgr::KCMKttsMgr: ALSA pcmList = " << pcmList;
368 pcmComboBox->clear();
369 pcmComboBox->addItems(pcmList);
371 delete player;
372 delete testPlayer;
374 // Set up Keep Audio Path KURLRequestor.
375 keepAudioPath->setMode(KFile::Directory);
376 keepAudioPath->setUrl(KUrl::fromPath(
377 KStandardDirs::locateLocal("data", "kttsd/audio/")));
379 // Object for the KTTSD configuration.
380 m_config = new KConfig("kttsdrc");
382 // Load configuration.
383 load();
385 // Connect the signals from the KCMKtssMgrWidget to this class.
387 // General tab.
388 connect(enableKttsdCheckBox, SIGNAL(toggled(bool)),
389 SLOT(slotEnableKttsd_toggled(bool)));
390 connect(autostartMgrCheckBox, SIGNAL(toggled(bool)),
391 SLOT(slotAutoStartMgrCheckBox_toggled(bool)));
392 connect(autoexitMgrCheckBox, SIGNAL(toggled(bool)),
393 SLOT(configChanged()));
395 // Talker tab.
396 connect(addTalkerButton, SIGNAL(clicked()),
397 this, SLOT(slotAddTalkerButton_clicked()));
398 connect(higherTalkerPriorityButton, SIGNAL(clicked()),
399 this, SLOT(slotHigherTalkerPriorityButton_clicked()));
400 connect(lowerTalkerPriorityButton, SIGNAL(clicked()),
401 this, SLOT(slotLowerTalkerPriorityButton_clicked()));
402 connect(removeTalkerButton, SIGNAL(clicked()),
403 this, SLOT(slotRemoveTalkerButton_clicked()));
404 connect(configureTalkerButton, SIGNAL(clicked()),
405 this, SLOT(slotConfigureTalkerButton_clicked()));
406 connect(talkersView, SIGNAL(clicked(const QModelIndex &)),
407 this, SLOT(updateTalkerButtons()));
409 // Filter tab.
410 connect(addFilterButton, SIGNAL(clicked()),
411 this, SLOT(slotAddNormalFilterButton_clicked()));
412 connect(higherFilterPriorityButton, SIGNAL(clicked()),
413 this, SLOT(slotHigherNormalFilterPriorityButton_clicked()));
414 connect(lowerFilterPriorityButton, SIGNAL(clicked()),
415 this, SLOT(slotLowerNormalFilterPriorityButton_clicked()));
416 connect(removeFilterButton, SIGNAL(clicked()),
417 this, SLOT(slotRemoveNormalFilterButton_clicked()));
418 connect(configureFilterButton, SIGNAL(clicked()),
419 this, SLOT(slotConfigureNormalFilterButton_clicked()));
420 connect(filtersView, SIGNAL(clicked(const QModelIndex &)),
421 this, SLOT(updateFilterButtons()));
422 connect(sbdsView, SIGNAL(clicked(const QModelIndex &)),
423 this, SLOT(updateSbdButtons()));
424 connect(filtersView, SIGNAL(clicked(const QModelIndex &)),
425 this, SLOT(slotFilterListView_clicked(const QModelIndex &)));
428 // Interruption tab.
429 connect(textPreMsgCheck, SIGNAL(toggled(bool)),
430 this, SLOT(slotTextPreMsgCheck_toggled(bool)));
431 connect(textPreMsg, SIGNAL(textChanged(const QString&)),
432 this, SLOT(configChanged()));
433 connect(textPreSndCheck, SIGNAL(toggled(bool)),
434 this, SLOT(slotTextPreSndCheck_toggled(bool)));
435 connect(textPreSnd, SIGNAL(textChanged(const QString&)),
436 this, SLOT(configChanged()));
437 connect(textPostMsgCheck, SIGNAL(toggled(bool)),
438 this, SLOT(slotTextPostMsgCheck_toggled(bool)));
439 connect(textPostMsg, SIGNAL(textChanged(const QString&)),
440 this, SLOT(configChanged()));
441 connect(textPostSndCheck, SIGNAL(toggled(bool)),
442 this, SLOT(slotTextPostSndCheck_toggled(bool)));
443 connect(textPostSnd, SIGNAL(textChanged(const QString&)),
444 this, SLOT(configChanged()));
446 // Audio tab.
447 connect(phononRadioButton, SIGNAL(toggled(bool)),
448 this, SLOT(slotPhononRadioButton_toggled(bool)));
449 connect(alsaRadioButton, SIGNAL(toggled(bool)),
450 this, SLOT(slotAlsaRadioButton_toggled(bool)));
451 connect(pcmComboBox, SIGNAL(activated(int)),
452 this, SLOT(slotPcmComboBox_activated()));
453 connect(pcmComboBox, SIGNAL(activated(int)),
454 this, SLOT(configChanged()));
455 connect(timeBox, SIGNAL(valueChanged(int)),
456 this, SLOT(timeBox_valueChanged(int)));
457 connect(timeSlider, SIGNAL(valueChanged(int)),
458 this, SLOT(timeSlider_valueChanged(int)));
459 connect(timeBox, SIGNAL(valueChanged(int)),
460 this, SLOT(configChanged()));
461 connect(timeSlider, SIGNAL(valueChanged(int)),
462 this, SLOT(configChanged()));
463 connect(keepAudioCheckBox, SIGNAL(toggled(bool)),
464 this, SLOT(keepAudioCheckBox_toggled(bool)));
465 connect(keepAudioPath, SIGNAL(textChanged(const QString&)),
466 this, SLOT(configChanged()));
468 // Others.
469 connect(mainTab, SIGNAL(currentChanged(int)),
470 this, SLOT(slotTabChanged()));
472 // See if KTTSD is already running, and if so, create jobs tab.
473 if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kttsd"))
474 kttsdStarted();
475 else
476 // Start KTTSD if check box is checked.
477 slotEnableKttsd_toggled(enableKttsdCheckBox->isChecked());
479 // Adjust view column sizes.
480 // TODO: To work properly, this needs to be done after the widgets are shown.
481 // Possibly in Resize event?
482 for (int i = 0; i < m_filterListModel.columnCount(); ++i)
483 filtersView->resizeColumnToContents(i);
484 for (int i = 0; i < m_talkerListModel.columnCount(); ++i)
485 talkersView->resizeColumnToContents(i);
487 // Switch to Talkers tab if none configured,
488 // otherwise switch to Jobs tab if it is active.
489 if (m_talkerListModel.rowCount() == 0)
490 mainTab->setCurrentIndex(wpTalkers);
491 else if (enableKttsdCheckBox->isChecked())
492 mainTab->setCurrentIndex(wpJobs);
496 * Destructor.
498 KCMKttsMgr::~KCMKttsMgr(){
499 // kDebug() << "KCMKttsMgr::~KCMKttsMgr: Running";
500 delete m_config;
504 * This method is invoked whenever the module should read its
505 * configuration (most of the times from a config file) and update the
506 * user interface. This happens when the user clicks the "Reset" button in
507 * the control center, to undo all of his changes and restore the currently
508 * valid settings. NOTE that this is not called after the modules is loaded,
509 * so you probably want to call this method in the constructor.
511 void KCMKttsMgr::load()
513 // kDebug() << "KCMKttsMgr::load: Running";
515 m_changed = false;
516 // Don't emit changed() signal while loading.
517 m_suppressConfigChanged = true;
519 // Set the group general for the configuration of kttsd itself (no plug ins)
520 KConfigGroup generalConfig(m_config, "General");
522 // Load the configuration of the text interruption messages and sound
523 textPreMsgCheck->setChecked(generalConfig.readEntry("TextPreMsgEnabled", textPreMsgCheckValue));
524 textPreMsg->setText(generalConfig.readEntry("TextPreMsg", textPreMsgValue));
525 textPreMsg->setEnabled(textPreMsgCheck->isChecked());
527 textPreSndCheck->setChecked(generalConfig.readEntry("TextPreSndEnabled", textPreSndCheckValue));
528 textPreSnd->setUrl(KUrl::fromPath(generalConfig.readEntry("TextPreSnd", textPreSndValue)));
529 textPreSnd->setEnabled(textPreSndCheck->isChecked());
531 textPostMsgCheck->setChecked(generalConfig.readEntry("TextPostMsgEnabled", textPostMsgCheckValue));
532 textPostMsg->setText(generalConfig.readEntry("TextPostMsg", textPostMsgValue));
533 textPostMsg->setEnabled(textPostMsgCheck->isChecked());
535 textPostSndCheck->setChecked(generalConfig.readEntry("TextPostSndEnabled", textPostSndCheckValue));
536 textPostSnd->setUrl(KUrl::fromPath(generalConfig.readEntry("TextPostSnd", textPostSndValue)));
537 textPostSnd->setEnabled(textPostSndCheck->isChecked());
539 // Overall settings.
540 enableKttsdCheckBox->setChecked(generalConfig.readEntry("EnableKttsd",
541 enableKttsdCheckBox->isChecked()));
543 autostartMgrCheckBox->setChecked(generalConfig.readEntry("AutoStartManager", true));
544 autoexitMgrCheckBox->setChecked(generalConfig.readEntry("AutoExitManager", true));
547 // Audio Output.
548 // Default to Phonon.
549 int audioOutputMethod = 0;
550 // if (gstreamerRadioButton->isChecked()) audioOutputMethod = 1;
551 if (alsaRadioButton->isChecked()) audioOutputMethod = 2;
552 audioOutputMethod = generalConfig.readEntry("AudioOutputMethod", audioOutputMethod);
553 switch (audioOutputMethod)
555 case 0:
556 phononRadioButton->setChecked(true);
557 break;
558 case 2:
559 alsaRadioButton->setChecked(true);
560 break;
561 default:
562 phononRadioButton->setChecked(true);
564 timeBox->setValue(generalConfig.readEntry("AudioStretchFactor", timeBoxValue));
565 timeBox_valueChanged(timeBox->value());
566 keepAudioCheckBox->setChecked(
567 generalConfig.readEntry("KeepAudio", keepAudioCheckBox->isChecked()));
568 keepAudioPath->setUrl(KUrl::fromPath(
569 generalConfig.readEntry("KeepAudioPath",
570 keepAudioPath->url().path())));
571 keepAudioPath->setEnabled(keepAudioCheckBox->isChecked());
573 // Last filter ID. Used to generate a new ID for an added filter.
574 m_lastFilterID = 0;
576 // Load existing Talkers into Talker List.
577 m_talkerListModel.loadTalkerCodesFromConfig(m_config);
579 // Last talker ID. Used to generate a new ID for an added talker.
580 m_lastTalkerID = m_talkerListModel.highestTalkerId();
582 // Dictionary mapping languages to language codes.
583 m_languagesToCodes.clear();
584 for (int i = 0; i < m_talkerListModel.rowCount(); ++i) {
585 QString fullLanguageCode = m_talkerListModel.getRow(i).fullLanguageCode();
586 QString language = TalkerCode::languageCodeToLanguage(fullLanguageCode);
587 m_languagesToCodes[language] = fullLanguageCode;
590 // Query for all the KCMKTTSD SynthPlugins and store the list in offers.
591 KService::List offers = KServiceTypeTrader::self()->query("KTTSD/SynthPlugin");
593 // Iterate thru the possible plug ins getting their language support codes.
594 for(int i=0; i < offers.count() ; ++i)
596 QString synthName = offers[i]->name();
597 QStringList languageCodes = offers[i]->property("X-KDE-Languages").toStringList();
598 // Add language codes to the language-to-language code map.
599 QStringList::ConstIterator endLanguages(languageCodes.constEnd());
600 for( QStringList::ConstIterator it = languageCodes.constBegin(); it != endLanguages; ++it )
602 QString language = TalkerCode::languageCodeToLanguage(*it);
603 m_languagesToCodes[language] = *it;
606 // All plugins support "Other".
607 // TODO: Eventually, this should not be necessary, since all plugins will know
608 // the languages they support and report them in call to getSupportedLanguages().
609 if (!languageCodes.contains("other")) languageCodes.append("other");
611 // Add supported language codes to synthesizer-to-language map.
612 m_synthToLangMap[synthName] = languageCodes;
615 // Add "Other" language.
616 m_languagesToCodes[i18n("Other")] = "other";
618 // Load Filters.
619 m_filterListModel.clear();
620 m_sbdFilterListModel.clear();
621 QStringList filterIDsList = generalConfig.readEntry("FilterIDs", QStringList());
622 // kDebug() << "KCMKttsMgr::load: FilterIDs = " << filterIDsList;
623 if (!filterIDsList.isEmpty())
625 QStringList::ConstIterator itEnd = filterIDsList.constEnd();
626 for (QStringList::ConstIterator it = filterIDsList.constBegin(); it != itEnd; ++it)
628 QString filterID = *it;
629 // kDebug() << "KCMKttsMgr::load: filterID = " << filterID;
630 KConfigGroup filterConfig(m_config, "Filter_" + filterID);
631 QString desktopEntryName = filterConfig.readEntry("DesktopEntryName", QString());
632 // If a DesktopEntryName is not in the config file, it was configured before
633 // we started using them, when we stored translated plugin names instead.
634 // Try to convert the translated plugin name to a DesktopEntryName.
635 // DesktopEntryNames are better because user can change their desktop language
636 // and DesktopEntryName won't change.
637 QString filterPlugInName;
638 filterPlugInName = FilterDesktopEntryNameToName(desktopEntryName);
639 if (!filterPlugInName.isEmpty())
641 FilterItem fi;
642 fi.id = filterID;
643 fi.plugInName = filterPlugInName;
644 fi.desktopEntryName = desktopEntryName;
645 fi.userFilterName = filterConfig.readEntry("UserFilterName", filterPlugInName);
646 fi.multiInstance = filterConfig.readEntry("MultiInstance", false);
647 fi.enabled = filterConfig.readEntry("Enabled", false);
648 // Determine if this filter is a Sentence Boundary Detector (SBD).
649 bool isSbd = filterConfig.readEntry("IsSBD", false);
650 if (isSbd)
651 m_sbdFilterListModel.appendRow(fi);
652 else
653 m_filterListModel.appendRow(fi);
654 if (filterID.toInt() > m_lastFilterID) m_lastFilterID = filterID.toInt();
659 // Add at least one unchecked instance of each available filter plugin if there is
660 // not already at least one instance and the filter can autoconfig itself.
661 offers = KServiceTypeTrader::self()->query("KTTSD/FilterPlugin");
662 for (int i=0; i < offers.count() ; ++i)
664 QString filterPlugInName = offers[i]->name();
665 QString desktopEntryName = FilterNameToDesktopEntryName(filterPlugInName);
666 if (!desktopEntryName.isEmpty() && (countFilterPlugins(filterPlugInName) == 0))
668 // Must load plugin to determine if it supports multiple instances
669 // and to see if it can autoconfigure itself.
670 KttsFilterConf* filterPlugIn = loadFilterPlugin(desktopEntryName);
671 if (filterPlugIn)
673 ++m_lastFilterID;
674 QString filterID = QString::number(m_lastFilterID);
675 QString groupName = "Filter_" + filterID;
676 filterPlugIn->load(m_config, groupName);
677 QString userFilterName = filterPlugIn->userPlugInName();
678 if (!userFilterName.isEmpty())
680 kDebug() << "KCMKttsMgr::load: auto-configuring filter " << userFilterName;
681 bool multiInstance = filterPlugIn->supportsMultiInstance();
682 FilterItem fi;
683 fi.id = filterID;
684 fi.userFilterName = userFilterName;
685 fi.plugInName = filterPlugInName;
686 fi.desktopEntryName = desktopEntryName;
687 fi.enabled = true;
688 fi.multiInstance = multiInstance;
689 // Determine if plugin is an SBD filter.
690 bool isSbd = filterPlugIn->isSBD();
691 if (isSbd)
692 m_sbdFilterListModel.appendRow(fi);
693 else
694 m_filterListModel.appendRow(fi);
695 KConfigGroup filterConfig(m_config, groupName);
696 filterPlugIn->save(m_config, groupName);
697 filterConfig.writeEntry("DesktopEntryName", desktopEntryName);
698 filterConfig.writeEntry("UserFilterName", userFilterName);
699 filterConfig.writeEntry("Enabled", isSbd);
700 filterConfig.writeEntry("MultiInstance", multiInstance);
701 filterConfig.writeEntry("IsSBD", isSbd);
702 filterIDsList.append(filterID);
703 } else m_lastFilterID--;
704 } else
705 kDebug() << "KCMKttsMgr::load: Unable to load filter plugin " << filterPlugInName
706 << " DesktopEntryName " << desktopEntryName << endl;
707 delete filterPlugIn;
710 // Rewrite list of FilterIDs in case we added any.
711 QString filterIDs = filterIDsList.join(",");
712 generalConfig.writeEntry("FilterIDs", filterIDs);
713 m_config->sync();
715 // Uncheck and disable KTTSD checkbox if no Talkers are configured.
716 if (m_talkerListModel.rowCount() == 0)
718 enableKttsdCheckBox->setChecked(false);
719 enableKttsdCheckBox->setEnabled(false);
720 slotEnableKttsd_toggled(false);
723 // Phonon settings.
724 // None.
726 // ALSA settings.
727 KConfigGroup alsaConfig(m_config, "ALSAPlayer");
728 KttsUtils::setCbItemFromText(pcmComboBox, alsaConfig.readEntry("PcmName", "default"));
729 pcmCustom->setText(alsaConfig.readEntry("CustomPcmName", ""));
731 // Update controls based on new states.
732 updateTalkerButtons();
733 updateFilterButtons();
734 updateSbdButtons();
735 slotPhononRadioButton_toggled(phononRadioButton->isChecked());
736 slotAlsaRadioButton_toggled(alsaRadioButton->isChecked());
738 m_changed = false;
739 m_suppressConfigChanged = false;
743 * This function gets called when the user wants to save the settings in
744 * the user interface, updating the config files or wherever the
745 * configuration is stored. The method is called when the user clicks "Apply"
746 * or "Ok".
748 void KCMKttsMgr::save()
750 // kDebug() << "KCMKttsMgr::save: Running";
751 m_changed = false;
753 // Clean up config.
754 m_config->deleteGroup("General", 0);
756 // Set the group general for the configuration of kttsd itself (no plug ins)
757 KConfigGroup generalConfig(m_config, "General");
759 // Set text interrumption messages and paths
760 generalConfig.writeEntry("TextPreMsgEnabled", textPreMsgCheck->isChecked());
761 generalConfig.writeEntry("TextPreMsg", textPreMsg->text());
763 generalConfig.writeEntry("TextPreSndEnabled", textPreSndCheck->isChecked());
764 generalConfig.writeEntry("TextPreSnd", PlugInConf::realFilePath(textPreSnd->url().path()));
766 generalConfig.writeEntry("TextPostMsgEnabled", textPostMsgCheck->isChecked());
767 generalConfig.writeEntry("TextPostMsg", textPostMsg->text());
769 generalConfig.writeEntry("TextPostSndEnabled", textPostSndCheck->isChecked());
770 generalConfig.writeEntry("TextPostSnd", PlugInConf::realFilePath(textPostSnd->url().path()));
772 // Overall settings.
773 generalConfig.writeEntry("AutoStartManager", autostartMgrCheckBox->isChecked());
774 generalConfig.writeEntry("AutoExitManager", autoexitMgrCheckBox->isChecked());
776 // Uncheck and disable KTTSD checkbox if no Talkers are configured.
777 // Enable checkbox if at least one Talker is configured.
778 bool enableKttsdWasToggled = false;
779 if (m_talkerListModel.rowCount() == 0)
781 enableKttsdWasToggled = enableKttsdCheckBox->isChecked();
782 enableKttsdCheckBox->setChecked(false);
783 enableKttsdCheckBox->setEnabled(false);
784 // Might as well zero LastTalkerID as well.
785 m_lastTalkerID = 0;
787 else
788 enableKttsdCheckBox->setEnabled(true);
790 generalConfig.writeEntry("EnableKttsd", enableKttsdCheckBox->isChecked());
793 // Audio Output.
794 int audioOutputMethod = 0;
795 // if (gstreamerRadioButton->isChecked()) audioOutputMethod = 1;
796 if (alsaRadioButton->isChecked()) audioOutputMethod = 2;
797 generalConfig.writeEntry("AudioOutputMethod", audioOutputMethod);
798 generalConfig.writeEntry("AudioStretchFactor", timeBox->value());
799 generalConfig.writeEntry("KeepAudio", keepAudioCheckBox->isChecked());
800 generalConfig.writeEntry("KeepAudioPath", keepAudioPath->url().path());
802 // Get ordered list of all talker IDs.
803 QStringList talkerIDsList;
804 for (int i = 0; i < m_talkerListModel.rowCount(); ++i)
805 talkerIDsList.append(m_talkerListModel.getRow(i).id());
806 QString talkerIDs = talkerIDsList.join(",");
807 generalConfig.writeEntry("TalkerIDs", talkerIDs);
809 // Erase obsolete Talker_nn sections.
810 QStringList groupList = m_config->groupList();
811 int groupListCount = groupList.count();
812 for (int groupNdx = 0; groupNdx < groupListCount; ++groupNdx)
814 QString groupName = groupList[groupNdx];
815 if (groupName.left(7) == "Talker_")
817 QString groupTalkerID = groupName.mid(7);
818 if (!talkerIDsList.contains(groupTalkerID))
819 m_config->deleteGroup(groupName, 0);
823 // Get ordered list of all filter IDs. Record enabled state of each filter.
824 QStringList filterIDsList;
825 for (int i = 0; i < m_filterListModel.rowCount(); ++i) {
826 FilterItem fi = m_filterListModel.getRow(i);
827 filterIDsList.append(fi.id);
828 KConfigGroup filterConfig(m_config, "Filter_" + fi.id);
829 filterConfig.writeEntry("Enabled", fi.enabled);
830 filterConfig.writeEntry("IsSBD", false);
832 for (int i = 0; i < m_sbdFilterListModel.rowCount(); ++i) {
833 FilterItem fi = m_sbdFilterListModel.getRow(i);
834 filterIDsList.append(fi.id);
835 KConfigGroup filterConfig(m_config, "Filter_" + fi.id);
836 filterConfig.writeEntry("Enabled", fi.enabled);
837 filterConfig.writeEntry("IsSBD", true);
839 QString filterIDs = filterIDsList.join(",");
840 generalConfig.writeEntry("FilterIDs", filterIDs);
842 // Erase obsolete Filter_nn sections.
843 for (int groupNdx = 0; groupNdx < groupListCount; ++groupNdx)
845 QString groupName = groupList[groupNdx];
846 if (groupName.left(7) == "Filter_")
848 QString groupFilterID = groupName.mid(7);
849 if (!filterIDsList.contains(groupFilterID))
850 m_config->deleteGroup(groupName, 0);
854 // ALSA settings.
855 KConfigGroup alsaConfig(m_config, "ALSAPlayer");
856 alsaConfig.writeEntry("PcmName", pcmComboBox->currentText());
857 alsaConfig.writeEntry("CustomPcmName", pcmCustom->text());
859 m_config->sync();
861 // If we automatically unchecked the Enable KTTSD checkbox, stop KTTSD.
862 if (enableKttsdWasToggled)
863 slotEnableKttsd_toggled(false);
864 else
866 // If KTTSD is running, reinitialize it.
867 if (m_kspeech)
869 kDebug() << "Restarting KTTSD";
870 m_kspeech->reinit();
875 void KCMKttsMgr::slotTabChanged()
877 // TODO: Commentting this out to avoid a crash. It seems there is a bug in
878 // KDialog. The workaround is to call setDefaultButton(), but that method
879 // is not available to a KCModule. Uncomment this when bug is fixed.
880 // setButtons(buttons());
881 int currentPageIndex = mainTab->currentIndex();
882 if (currentPageIndex == wpJobs)
884 if (m_changed)
886 KMessageBox::information(this,
887 i18n("You have made changes to the configuration but have not saved them yet. "
888 "Click Apply to save the changes or Cancel to abandon the changes."));
894 * This function is called to set the settings in the module to sensible
895 * default values. It gets called when hitting the "Default" button. The
896 * default values should probably be the same as the ones the application
897 * uses when started without a config file.
899 void KCMKttsMgr::defaults() {
900 // kDebug() << "Running: KCMKttsMgr::defaults: Running";
902 int currentPageIndex = mainTab->currentIndex();
903 bool changed = false;
904 switch (currentPageIndex)
906 case wpGeneral:
907 if (autostartMgrCheckBox->isChecked() != autostartMgrCheckBoxValue)
909 changed = true;
910 autostartMgrCheckBox->setChecked(
911 autostartMgrCheckBoxValue);
913 if (autoexitMgrCheckBox->isChecked() != autoexitMgrCheckBoxValue)
915 changed = true;
916 autoexitMgrCheckBox->setChecked(
917 autoexitMgrCheckBoxValue);
919 break;
921 case wpInterruption:
922 if (textPreMsgCheck->isChecked() != textPreMsgCheckValue)
924 changed = true;
925 textPreMsgCheck->setChecked(textPreMsgCheckValue);
927 if (textPreMsg->text() != i18n(textPreMsgValue.toUtf8()))
929 changed = true;
930 textPreMsg->setText(i18n(textPreMsgValue.toUtf8()));
932 if (textPreSndCheck->isChecked() != textPreSndCheckValue)
934 changed = true;
935 textPreSndCheck->setChecked(textPreSndCheckValue);
937 if (textPreSnd->url().path() != textPreSndValue)
939 changed = true;
940 textPreSnd->setUrl(KUrl::fromPath(textPreSndValue));
942 if (textPostMsgCheck->isChecked() != textPostMsgCheckValue)
944 changed = true;
945 textPostMsgCheck->setChecked(textPostMsgCheckValue);
947 if (textPostMsg->text() != i18n(textPostMsgValue.toUtf8()))
949 changed = true;
950 textPostMsg->setText(i18n(textPostMsgValue.toUtf8()));
952 if (textPostSndCheck->isChecked() != textPostSndCheckValue)
954 changed = true;
955 textPostSndCheck->setChecked(textPostSndCheckValue);
957 if (textPostSnd->url().path() != textPostSndValue)
959 changed = true;
960 textPostSnd->setUrl(KUrl::fromPath(textPostSndValue));
962 break;
964 case wpAudio:
965 // Default to Phonon.
966 if (!phononRadioButton->isChecked())
968 changed = true;
969 phononRadioButton->setChecked(true);
971 if (timeBox->value() != timeBoxValue)
973 changed = true;
974 timeBox->setValue(timeBoxValue);
976 if (keepAudioCheckBox->isChecked() !=
977 keepAudioCheckBoxValue)
979 changed = true;
980 keepAudioCheckBox->setChecked(keepAudioCheckBoxValue);
982 if (keepAudioPath->url().path() != KStandardDirs::locateLocal("data", "kttsd/audio/"))
984 changed = true;
985 keepAudioPath->setUrl(KUrl::fromPath(
986 KStandardDirs::locateLocal("data", "kttsd/audio/")));
988 keepAudioPath->setEnabled(keepAudioCheckBox->isEnabled());
990 if (changed) configChanged();
994 * This is a static method which gets called to realize the modules settings
995 * during the startup of KDE. NOTE that most modules do not implement this
996 * method, but modules like the keyboard and mouse modules, which directly
997 * interact with the X-server, need this method. As this method is static,
998 * it can avoid to create an instance of the user interface, which is often
999 * not needed in this case.
1001 void KCMKttsMgr::init(){
1002 // kDebug() << "KCMKttsMgr::init: Running";
1006 * This function returns the small quickhelp.
1007 * That is displayed in the sidebar in the KControl
1009 QString KCMKttsMgr::quickHelp() const{
1010 // kDebug() << "KCMKttsMgr::quickHelp: Running";
1011 return i18n(
1012 "<h1>Text-to-Speech</h1>"
1013 "<p>This is the configuration for the text-to-speech dcop service</p>"
1014 "<p>This allows other applications to access text-to-speech resources</p>"
1015 "<p>Be sure to configure a default language for the language you are using as this will be the language used by most of the applications</p>");
1018 const KAboutData* KCMKttsMgr::aboutData() const{
1019 KAboutData *about =
1020 new KAboutData(I18N_NOOP("kttsd"), 0, ki18n("KCMKttsMgr"),
1021 0, KLocalizedString(), KAboutData::License_GPL,
1022 ki18n("(c) 2002, José Pablo Ezequiel Fernández"));
1024 about->addAuthor(ki18n("José Pablo Ezequiel Fernández"), ki18n("Author") , "pupeno@kde.org");
1025 about->addAuthor(ki18n("Gary Cramblitt"), ki18n("Maintainer") , "garycramblitt@comcast.net");
1026 about->addAuthor(ki18n("Olaf Schmidt"), ki18n("Contributor"), "ojschmidt@kde.org");
1027 about->addAuthor(ki18n("Paul Giannaros"), ki18n("Contributor"), "ceruleanblaze@gmail.com");
1029 return about;
1033 * Loads the configuration plug in for a named talker plug in and type.
1034 * @param name DesktopEntryName of the Synthesizer.
1035 * @return Pointer to the configuration plugin for the Talker.
1037 PlugInConf* KCMKttsMgr::loadTalkerPlugin(const QString& name)
1039 // kDebug() << "KCMKttsMgr::loadPlugin: Running";
1041 // Find the plugin.
1042 KService::List offers = KServiceTypeTrader::self()->query("KTTSD/SynthPlugin",
1043 QString("DesktopEntryName == '%1'").arg(name));
1045 if (offers.count() == 1)
1047 // When the entry is found, load the plug in
1048 // First create a factory for the library
1049 KLibFactory *factory = KLibLoader::self()->factory(offers[0]->library().toLatin1());
1050 if(factory){
1051 // If the factory is created successfully, instantiate the PlugInConf class for the
1052 // specific plug in to get the plug in configuration object.
1053 PlugInConf *plugIn = KLibLoader::createInstance<PlugInConf>(
1054 offers[0]->library().toLatin1(), NULL, QStringList(offers[0]->library().toLatin1()));
1055 if(plugIn){
1056 // If everything went ok, return the plug in pointer.
1057 return plugIn;
1058 } else {
1059 // Something went wrong, returning null.
1060 kDebug() << "KCMKttsMgr::loadTalkerPlugin: Unable to instantiate PlugInConf class for plugin " << name;
1061 return NULL;
1063 } else {
1064 // Something went wrong, returning null.
1065 kDebug() << "KCMKttsMgr::loadTalkerPlugin: Unable to create Factory object for plugin "
1066 << name << endl;
1067 return NULL;
1070 // The plug in was not found (unexpected behaviour, returns null).
1071 kDebug() << "KCMKttsMgr::loadTalkerPlugin: KTrader did not return an offer for plugin "
1072 << name << endl;
1073 return NULL;
1077 * Loads the configuration plug in for a named filter plug in.
1078 * @param plugInName DesktopEntryName of the plugin.
1079 * @return Pointer to the configuration plugin for the Filter.
1081 KttsFilterConf* KCMKttsMgr::loadFilterPlugin(const QString& plugInName)
1083 // kDebug() << "KCMKttsMgr::loadPlugin: Running";
1085 // Find the plugin.
1086 KService::List offers = KServiceTypeTrader::self()->query("KTTSD/FilterPlugin",
1087 QString("DesktopEntryName == '%1'").arg(plugInName));
1089 if (offers.count() == 1)
1091 // When the entry is found, load the plug in
1092 // First create a factory for the library
1093 KLibFactory *factory = KLibLoader::self()->factory(offers[0]->library().toLatin1());
1094 if(factory){
1095 // If the factory is created successfully, instantiate the KttsFilterConf class for the
1096 // specific plug in to get the plug in configuration object.
1097 int errorNo = 0;
1098 KttsFilterConf *plugIn =
1099 KLibLoader::createInstance<KttsFilterConf>(
1100 offers[0]->library().toLatin1(), NULL, QStringList(offers[0]->library().toLatin1()),
1101 &errorNo);
1102 if(plugIn){
1103 // If everything went ok, return the plug in pointer.
1104 return plugIn;
1105 } else {
1106 // Something went wrong, returning null.
1107 kDebug() << "KCMKttsMgr::loadFilterPlugin: Unable to instantiate KttsFilterConf class for plugin " << plugInName << " error: " << errorNo;
1108 return NULL;
1110 } else {
1111 // Something went wrong, returning null.
1112 kDebug() << "KCMKttsMgr::loadFilterPlugin: Unable to create Factory object for plugin " << plugInName;
1113 return NULL;
1116 // The plug in was not found (unexpected behaviour, returns null).
1117 kDebug() << "KCMKttsMgr::loadFilterPlugin: KTrader did not return an offer for plugin " << plugInName;
1118 return NULL;
1122 * Add a talker.
1124 void KCMKttsMgr::slotAddTalkerButton_clicked()
1126 KDialog* dlg = new KDialog(this);
1127 dlg->setCaption(i18n("Add Talker"));
1128 dlg->setButtons(KDialog::Help|KDialog::Ok|KDialog::Cancel);
1129 dlg->setDefaultButton(KDialog::Cancel);
1130 AddTalker* addTalkerWidget = new AddTalker(m_synthToLangMap, dlg, "AddTalker_widget");
1131 dlg->setMainWidget(addTalkerWidget);
1132 dlg->setHelp("select-plugin", "kttsd");
1133 int dlgResult = dlg->exec();
1134 QString languageCode = addTalkerWidget->getLanguageCode();
1135 QString synthName = addTalkerWidget->getSynthesizer();
1136 delete dlg;
1137 // TODO: Also delete addTalkerWidget?
1138 if (dlgResult != QDialog::Accepted) return;
1140 // If user chose "Other", must now get a language from him.
1141 if(languageCode == "other")
1143 SelectLanguageDlg* dlg = new SelectLanguageDlg(
1144 this,
1145 i18n("Select Language"),
1146 QStringList(),
1147 SelectLanguageDlg::SingleSelect,
1148 SelectLanguageDlg::BlankNotAllowed);
1149 int dlgResult = dlg->exec();
1150 languageCode = dlg->selectedLanguageCode();
1151 delete dlg;
1152 // TODO: Also delete QTableWidget and hBox?
1153 if (dlgResult != QDialog::Accepted) return;
1156 if (languageCode.isEmpty()) return;
1157 QString language = TalkerCode::languageCodeToLanguage(languageCode);
1158 if (language.isEmpty()) return;
1160 m_languagesToCodes[language] = languageCode;
1162 // Assign a new Talker ID for the talker. Wraps around to 1.
1163 QString talkerID = QString::number(m_lastTalkerID + 1);
1165 // Erase extraneous Talker configuration entries that might be there.
1166 m_config->deleteGroup(QString("Talker_")+talkerID, 0);
1167 m_config->sync();
1169 // Convert translated plugin name to DesktopEntryName.
1170 QString desktopEntryName = TalkerCode::TalkerNameToDesktopEntryName(synthName);
1171 // This shouldn't happen, but just in case.
1172 if (desktopEntryName.isEmpty()) return;
1174 // Load the plugin.
1175 m_loadedTalkerPlugIn = loadTalkerPlugin(desktopEntryName);
1176 if (!m_loadedTalkerPlugIn) return;
1178 // Give plugin the user's language code and permit plugin to autoconfigure itself.
1179 m_loadedTalkerPlugIn->setDesiredLanguage(languageCode);
1180 m_loadedTalkerPlugIn->load(m_config, QString("Talker_")+talkerID);
1182 // If plugin was able to configure itself, it returns a full talker code.
1183 // If not, display configuration dialog for user to configure the plugin.
1184 QString talkerCode = m_loadedTalkerPlugIn->getTalkerCode();
1185 if (talkerCode.isEmpty())
1187 // Display configuration dialog.
1188 configureTalker();
1189 // Did user Cancel?
1190 if (!m_loadedTalkerPlugIn)
1192 delete m_configDlg;
1193 m_configDlg = 0;
1194 return;
1196 talkerCode = m_loadedTalkerPlugIn->getTalkerCode();
1199 // If still no Talker Code, abandon.
1200 if (!talkerCode.isEmpty())
1202 // Let plugin save its configuration.
1203 m_loadedTalkerPlugIn->save(m_config, QString("Talker_"+talkerID));
1205 // Record last Talker ID used for next add.
1206 m_lastTalkerID = talkerID.toInt();
1208 // Record configuration data. Note, might as well do this now.
1209 KConfigGroup talkerConfig(m_config, QString("Talker_")+talkerID);
1210 talkerConfig.writeEntry("DesktopEntryName", desktopEntryName);
1211 talkerCode = TalkerCode::normalizeTalkerCode(talkerCode, languageCode);
1212 talkerConfig.writeEntry("TalkerCode", talkerCode);
1213 m_config->sync();
1215 // Add to list of Talkers.
1216 TalkerCode tc = TalkerCode(talkerCode);
1217 tc.setId(talkerID);
1218 tc.setDesktopEntryName(desktopEntryName);
1219 m_talkerListModel.appendRow(tc);
1221 // Make sure visible.
1222 const QModelIndex modelIndex = m_talkerListModel.index(m_talkerListModel.rowCount(),
1223 0, QModelIndex());
1224 talkersView->scrollTo(modelIndex);
1226 // Select the new item, update buttons.
1227 talkersView->setCurrentIndex(modelIndex);
1228 updateTalkerButtons();
1230 // Inform Control Center that change has been made.
1231 configChanged();
1234 // Don't need plugin in memory anymore.
1235 delete m_loadedTalkerPlugIn;
1236 m_loadedTalkerPlugIn = 0;
1237 if (m_configDlg)
1239 delete m_configDlg;
1240 m_configDlg = 0;
1243 // kDebug() << "KCMKttsMgr::addTalker: done.";
1246 void KCMKttsMgr::slotAddNormalFilterButton_clicked()
1248 addFilter( false );
1251 void KCMKttsMgr:: slotAddSbdFilterButton_clicked()
1253 addFilter( true );
1257 * Add a filter.
1259 void KCMKttsMgr::addFilter( bool sbd)
1261 QTreeView* lView = filtersView;
1262 if (sbd) lView = sbdsView;
1263 FilterListModel* model = qobject_cast<FilterListModel *>(lView->model());
1265 // Build a list of filters that support multiple instances and let user choose.
1266 QStringList filterPlugInNames;
1267 for (int i = 0; i < model->rowCount(); ++i) {
1268 FilterItem fi = model->getRow(i);
1269 if (fi.multiInstance)
1271 if (!filterPlugInNames.contains(fi.plugInName))
1272 filterPlugInNames.append(fi.plugInName);
1275 // Append those available plugins not yet in the list at all.
1276 KService::List offers = KServiceTypeTrader::self()->query("KTTSD/FilterPlugin");
1277 for (int i=0; i < offers.count() ; ++i)
1279 QString filterPlugInName = offers[i]->name();
1280 if (countFilterPlugins(filterPlugInName) == 0)
1282 QString desktopEntryName = FilterNameToDesktopEntryName(filterPlugInName);
1283 KttsFilterConf* filterConf = loadFilterPlugin( desktopEntryName );
1284 if (filterConf)
1286 if (filterConf->isSBD() == sbd)
1287 filterPlugInNames.append(filterPlugInName);
1288 delete filterConf;
1293 // If no choice (shouldn't happen), bail out.
1294 // kDebug() << "KCMKttsMgr::addFilter: filterPluginNames = " << filterPlugInNames;
1295 if (filterPlugInNames.count() == 0) return;
1297 // If exactly one choice, skip selection dialog, otherwise display list to user to select from.
1298 bool okChosen = false;
1299 QString filterPlugInName;
1300 if (filterPlugInNames.count() > 1)
1302 filterPlugInName = KInputDialog::getItem(
1303 i18n("Select Filter"),
1304 i18n("Filter"),
1305 filterPlugInNames,
1307 false,
1308 &okChosen,
1309 this);
1310 if (!okChosen) return;
1311 } else
1312 filterPlugInName = filterPlugInNames[0];
1314 // kDebug() << "KCMKttsMgr::addFilter: filterPlugInName = " << filterPlugInName;
1316 // Assign a new Filter ID for the filter. Wraps around to 1.
1317 QString filterID = QString::number(m_lastFilterID + 1);
1319 // Erase extraneous Filter configuration entries that might be there.
1320 m_config->deleteGroup(QString("Filter_")+filterID, 0);
1321 m_config->sync();
1323 // Get DesktopEntryName from the translated name.
1324 QString desktopEntryName = FilterNameToDesktopEntryName(filterPlugInName);
1325 // This shouldn't happen, but just in case.
1326 if (desktopEntryName.isEmpty()) return;
1328 // Load the plugin.
1329 m_loadedFilterPlugIn = loadFilterPlugin(desktopEntryName);
1330 if (!m_loadedFilterPlugIn) return;
1332 // Permit plugin to autoconfigure itself.
1333 m_loadedFilterPlugIn->load(m_config, QString("Filter_")+filterID);
1335 // Display configuration dialog for user to configure the plugin.
1336 configureFilter();
1338 // Did user Cancel?
1339 if (!m_loadedFilterPlugIn)
1341 delete m_configDlg;
1342 m_configDlg = 0;
1343 return;
1346 // Get user's name for Filter.
1347 QString userFilterName = m_loadedFilterPlugIn->userPlugInName();
1349 // If user properly configured the plugin, save its configuration.
1350 if ( !userFilterName.isEmpty() )
1352 // Let plugin save its configuration.
1353 m_loadedFilterPlugIn->save(m_config, QString("Filter_"+filterID));
1355 // Record last Filter ID used for next add.
1356 m_lastFilterID = filterID.toInt();
1358 // Determine if filter supports multiple instances.
1359 bool multiInstance = m_loadedFilterPlugIn->supportsMultiInstance();
1361 // Record configuration data. Note, might as well do this now.
1362 KConfigGroup filterConfig(m_config, QString("Filter_"+filterID));
1363 filterConfig.writeEntry("DesktopEntryName", desktopEntryName);
1364 filterConfig.writeEntry("UserFilterName", userFilterName);
1365 filterConfig.writeEntry("MultiInstance", multiInstance);
1366 filterConfig.writeEntry("Enabled", true);
1367 filterConfig.writeEntry("IsSBD", sbd);
1368 m_config->sync();
1370 // Add listview item.
1371 FilterItem fi;
1372 fi.id = filterID;
1373 fi.plugInName = filterPlugInName;
1374 fi.userFilterName = userFilterName;
1375 fi.desktopEntryName = desktopEntryName;
1376 fi.multiInstance = multiInstance;
1377 fi.enabled = true;
1378 model->appendRow(fi);
1380 // Make sure visible.
1381 QModelIndex modelIndex = model->index(model->rowCount() - 1, 0, QModelIndex());
1382 lView->scrollTo(modelIndex);
1384 // Select the new item, update buttons.
1385 lView->setCurrentIndex(modelIndex);
1386 if (sbd)
1387 updateSbdButtons();
1388 else
1389 updateFilterButtons();
1391 // Inform Control Center that change has been made.
1392 configChanged();
1395 // Don't need plugin in memory anymore.
1396 delete m_loadedFilterPlugIn;
1397 m_loadedFilterPlugIn = 0;
1398 delete m_configDlg;
1399 m_configDlg = 0;
1401 // kDebug() << "KCMKttsMgr::addFilter: done.";
1405 * Remove talker.
1407 void KCMKttsMgr::slotRemoveTalkerButton_clicked(){
1408 // kDebug() << "KCMKttsMgr::removeTalker: Running";
1410 // Get the selected talker.
1411 QModelIndex modelIndex = talkersView->currentIndex();
1412 if (!modelIndex.isValid()) return;
1414 // Delete the talker from configuration file?
1415 QString talkerID = m_talkerListModel.getRow(modelIndex.row()).id();
1416 m_config->deleteGroup(QString("Talker_")+talkerID, 0);
1418 // Delete the talker from the list of Talkers.
1419 m_talkerListModel.removeRow(modelIndex.row());
1421 updateTalkerButtons();
1423 // Emit configuration changed.
1424 configChanged();
1427 void KCMKttsMgr::slotRemoveNormalFilterButton_clicked()
1429 removeFilter( false );
1432 void KCMKttsMgr::slotRemoveSbdFilterButton_clicked()
1434 removeFilter( true );
1438 * Remove filter.
1440 void KCMKttsMgr::removeFilter( bool sbd )
1442 // kDebug() << "KCMKttsMgr::removeFilter: Running";
1444 FilterListModel* model;
1445 QTreeView* lView;
1446 if (sbd)
1447 lView = sbdsView;
1448 else
1449 lView = filtersView;
1450 model = qobject_cast<FilterListModel *>(lView->model());
1451 QModelIndex modelIndex = lView->currentIndex();
1452 if (!modelIndex.isValid()) return;
1453 QString filterID = model->getRow(modelIndex.row()).id;
1454 // Delete the filter from list view.
1455 model->removeRow(modelIndex.row());
1456 if (sbd)
1457 updateSbdButtons();
1458 else
1459 updateFilterButtons();
1461 // Delete the filter from the configuration file?
1462 kDebug() << "KCMKttsMgr::removeFilter: removing FilterID = " << filterID << " from config file.";
1463 m_config->deleteGroup(QString("Filter_")+filterID, 0);
1465 // Emit configuration changed.
1466 configChanged();
1469 void KCMKttsMgr::slotHigherTalkerPriorityButton_clicked()
1471 QModelIndex modelIndex = talkersView->currentIndex();
1472 if (!modelIndex.isValid()) return;
1473 m_talkerListModel.swap(modelIndex.row(), modelIndex.row() - 1);
1474 modelIndex = m_talkerListModel.index(modelIndex.row() - 1, 0, QModelIndex());
1475 talkersView->scrollTo(modelIndex);
1476 talkersView->setCurrentIndex(modelIndex);
1477 updateTalkerButtons();
1478 configChanged();
1481 void KCMKttsMgr::slotHigherNormalFilterPriorityButton_clicked()
1483 QModelIndex modelIndex = filtersView->currentIndex();
1484 if (!modelIndex.isValid()) return;
1485 m_filterListModel.swap(modelIndex.row(), modelIndex.row() - 1);
1486 modelIndex = m_filterListModel.index(modelIndex.row() - 1, 0, QModelIndex());
1487 filtersView->scrollTo(modelIndex);
1488 filtersView->setCurrentIndex(modelIndex);
1489 updateFilterButtons();
1490 configChanged();
1493 void KCMKttsMgr::slotHigherSbdFilterPriorityButton_clicked()
1495 QModelIndex modelIndex = sbdsView->currentIndex();
1496 if (!modelIndex.isValid()) return;
1497 m_sbdFilterListModel.swap(modelIndex.row(), modelIndex.row() - 1);
1498 modelIndex = m_sbdFilterListModel.index(modelIndex.row() - 1, 0, QModelIndex());
1499 sbdsView->scrollTo(modelIndex);
1500 sbdsView->setCurrentIndex(modelIndex);
1501 updateSbdButtons();
1502 configChanged();
1505 void KCMKttsMgr::slotLowerTalkerPriorityButton_clicked()
1507 QModelIndex modelIndex = talkersView->currentIndex();
1508 if (!modelIndex.isValid()) return;
1509 m_talkerListModel.swap(modelIndex.row(), modelIndex.row() + 1);
1510 modelIndex = m_talkerListModel.index(modelIndex.row() + 1, 0, QModelIndex());
1511 talkersView->scrollTo(modelIndex);
1512 talkersView->setCurrentIndex(modelIndex);
1513 updateTalkerButtons();
1514 configChanged();
1517 void KCMKttsMgr::slotLowerNormalFilterPriorityButton_clicked()
1519 QModelIndex modelIndex = filtersView->currentIndex();
1520 if (!modelIndex.isValid()) return;
1521 m_filterListModel.swap(modelIndex.row(), modelIndex.row() + 1);
1522 modelIndex = m_filterListModel.index(modelIndex.row() + 1, 0, QModelIndex());
1523 filtersView->scrollTo(modelIndex);
1524 filtersView->setCurrentIndex(modelIndex);
1525 updateFilterButtons();
1526 configChanged();
1529 void KCMKttsMgr::slotLowerSbdFilterPriorityButton_clicked()
1531 QModelIndex modelIndex = sbdsView->currentIndex();
1532 if (!modelIndex.isValid()) return;
1533 m_sbdFilterListModel.swap(modelIndex.row(), modelIndex.row() + 1);
1534 modelIndex = m_sbdFilterListModel.index(modelIndex.row() + 1, 0, QModelIndex());
1535 sbdsView->scrollTo(modelIndex);
1536 sbdsView->setCurrentIndex(modelIndex);
1537 updateSbdButtons();
1538 configChanged();
1542 * Update the status of the Talker buttons.
1544 void KCMKttsMgr::updateTalkerButtons(){
1545 // kDebug() << "KCMKttsMgr::updateTalkerButtons: Running";
1546 QModelIndex modelIndex = talkersView->currentIndex();
1547 if (modelIndex.isValid()) {
1548 removeTalkerButton->setEnabled(true);
1549 configureTalkerButton->setEnabled(true);
1550 higherTalkerPriorityButton->setEnabled(modelIndex.row() != 0);
1551 lowerTalkerPriorityButton->setEnabled(modelIndex.row() < (m_talkerListModel.rowCount() - 1));
1552 } else {
1553 removeTalkerButton->setEnabled(false);
1554 configureTalkerButton->setEnabled(false);
1555 higherTalkerPriorityButton->setEnabled(false);
1556 lowerTalkerPriorityButton->setEnabled(false);
1558 // kDebug() << "KCMKttsMgr::updateTalkerButtons: Exiting";
1562 * Update the status of the normal Filter buttons.
1564 void KCMKttsMgr::updateFilterButtons(){
1565 // kDebug() << "KCMKttsMgr::updateFilterButtons: Running";
1566 QModelIndex modelIndex = filtersView->currentIndex();
1567 if (modelIndex.isValid()) {
1568 removeFilterButton->setEnabled(true);
1569 configureFilterButton->setEnabled(true);
1570 higherFilterPriorityButton->setEnabled(modelIndex.row() != 0);
1571 lowerFilterPriorityButton->setEnabled(modelIndex.row() < (m_filterListModel.rowCount() - 1));
1572 } else {
1573 removeFilterButton->setEnabled(false);
1574 configureFilterButton->setEnabled(false);
1575 higherFilterPriorityButton->setEnabled(false);
1576 lowerFilterPriorityButton->setEnabled(false);
1578 // kDebug() << "KCMKttsMgr::updateFilterButtons: Exiting";
1582 * Update the status of the SBD buttons.
1584 void KCMKttsMgr::updateSbdButtons(){
1585 // kDebug() << "KCMKttsMgr::updateSbdButtons: Running";
1586 QModelIndex modelIndex = sbdsView->currentIndex();
1587 if (modelIndex.isValid()) {
1588 m_sbdBtnEdit->setEnabled( true );
1589 m_sbdBtnUp->setEnabled( modelIndex.row() != 0 );
1590 m_sbdBtnDown->setEnabled( modelIndex.row() < (m_sbdFilterListModel.rowCount() -1));
1591 m_sbdBtnRemove->setEnabled( true );
1592 } else {
1593 m_sbdBtnEdit->setEnabled( false );
1594 m_sbdBtnUp->setEnabled( false );
1595 m_sbdBtnDown->setEnabled( false );
1596 m_sbdBtnRemove->setEnabled( false );
1598 // kDebug() << "KCMKttsMgr::updateSbdButtons: Exiting";
1602 * This signal is emitted whenever user checks/unchecks the Enable TTS System check box.
1604 void KCMKttsMgr::slotEnableKttsd_toggled(bool)
1606 // Prevent re-entrancy.
1607 static bool reenter;
1608 if (reenter) return;
1609 reenter = true;
1610 // See if KTTSD is running.
1611 bool kttsdRunning = (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kttsd"));
1613 // kDebug() << "KCMKttsMgr::slotEnableKttsd_toggled: kttsdRunning = " << kttsdRunning;
1614 // If Enable KTTSD check box is checked and it is not running, then start KTTSD.
1615 if (enableKttsdCheckBox->isChecked())
1617 if (!kttsdRunning)
1619 // kDebug() << "KCMKttsMgr::slotEnableKttsd_toggled:: Starting KTTSD";
1620 QString error;
1621 if (KToolInvocation::startServiceByDesktopName("kttsd", QStringList(), &error))
1623 kDebug() << "Starting KTTSD failed with message " << error;
1624 enableKttsdCheckBox->setChecked(false);
1626 } else {
1627 configChanged();
1628 kttsdStarted();
1632 else
1633 // If check box is not checked and it is running, then stop KTTSD.
1635 if (kttsdRunning)
1637 // kDebug() << "KCMKttsMgr::slotEnableKttsd_toggled:: Stopping KTTSD";
1638 m_kspeech->kttsdExit();
1639 configChanged();
1642 reenter = false;
1645 void KCMKttsMgr::slotAutoStartMgrCheckBox_toggled(bool checked)
1647 autoexitMgrCheckBox->setEnabled(checked);
1648 configChanged();
1651 void KCMKttsMgr::slotTextPreMsgCheck_toggled(bool checked)
1653 textPreMsg->setEnabled(checked);
1654 configChanged();
1657 void KCMKttsMgr::slotTextPreSndCheck_toggled(bool checked)
1659 textPreSnd->setEnabled(checked);
1660 configChanged();
1663 void KCMKttsMgr::slotTextPostMsgCheck_toggled(bool checked)
1665 textPostMsg->setEnabled(checked);
1666 configChanged();
1669 void KCMKttsMgr::slotTextPostSndCheck_toggled(bool checked)
1671 textPostSnd->setEnabled(checked);
1672 configChanged();
1676 * This signal is emitted whenever user checks/unchecks the Phonon radio button.
1678 void KCMKttsMgr::slotPhononRadioButton_toggled(bool state)
1680 Q_UNUSED(state);
1681 configChanged();
1685 * This signal is emitted whenever user checks/unchecks the ALSA radio button.
1687 void KCMKttsMgr::slotAlsaRadioButton_toggled(bool state)
1689 pcmLabel->setEnabled(state);
1690 pcmComboBox->setEnabled(state);
1691 pcmCustom->setEnabled(state && pcmComboBox->currentText() == "custom");
1692 configChanged();
1696 * This is emitted whenever user activates the ALSA pcm combobox.
1698 void KCMKttsMgr::slotPcmComboBox_activated()
1700 pcmCustom->setEnabled(pcmComboBox->currentText() == "custom");
1704 * This slot is called whenever KTTSD starts or restarts.
1706 void KCMKttsMgr::kttsdStarted()
1708 // kDebug() << "KCMKttsMgr::kttsdStarted: Running";
1709 bool kttsdLoaded = (m_jobMgrPart != 0);
1710 // Load Job Manager Part library.
1711 if (!kttsdLoaded)
1713 m_jobMgrPart = KParts::ComponentFactory::createPartInstanceFromLibrary<KParts::ReadOnlyPart>(
1714 "libkttsjobmgrpart", mainTab, this);
1715 if (m_jobMgrPart)
1717 // Add the Job Manager part as a new tab.
1718 mainTab->addTab(m_jobMgrPart->widget(), i18n("Jobs"));
1719 kttsdLoaded = true;
1721 else
1722 kDebug() << "KCMKttsMgr::kttsdStarted: Could not create kttsjobmgr part.";
1724 // Check/Uncheck the Enable KTTSD check box.
1725 if (kttsdLoaded)
1727 enableKttsdCheckBox->setChecked(true);
1728 m_kspeech = new OrgKdeKSpeechInterface("org.kde.kttsd", "/KSpeech", QDBusConnection::sessionBus());
1729 m_kspeech->setParent(this);
1730 m_kspeech->setApplicationName("KCMKttsMgr");
1731 m_kspeech->setIsSystemManager(true);
1732 // Connect KTTSD DBUS signals to our slots.
1733 connect(m_kspeech, SIGNAL(kttsdStarted()),
1734 this, SLOT(kttsdStarted()));
1735 connect(m_kspeech, SIGNAL(kttsdExiting()),
1736 this, SLOT(kttsdExiting()));
1737 kttsdVersion->setText(i18n("KTTSD Version: %1", m_kspeech->version()));
1739 } else {
1740 enableKttsdCheckBox->setChecked(false);
1741 delete m_kspeech;
1742 m_kspeech = 0;
1747 * This slot is called whenever KTTSD is about to exit.
1749 void KCMKttsMgr::kttsdExiting()
1751 // kDebug() << "KCMKttsMgr::kttsdExiting: Running";
1752 if (m_jobMgrPart)
1754 mainTab->removeTab(wpJobs);
1755 delete m_jobMgrPart;
1756 m_jobMgrPart = 0;
1758 enableKttsdCheckBox->setChecked(false);
1759 delete m_kspeech;
1760 m_kspeech = 0;
1761 kttsdVersion->setText(i18n("KTTSD not running"));
1765 * User has requested display of talker configuration dialog.
1767 void KCMKttsMgr::slotConfigureTalkerButton_clicked()
1769 // Get highlighted plugin from Talker ListView and load into memory.
1770 QModelIndex modelIndex = talkersView->currentIndex();
1771 if (!modelIndex.isValid()) return;
1772 TalkerCode tc = m_talkerListModel.getRow(modelIndex.row());
1773 QString talkerID = tc.id();
1774 QString synthName = tc.plugInName();
1775 QString desktopEntryName = tc.desktopEntryName();
1776 QString languageCode = tc.fullLanguageCode();
1777 m_loadedTalkerPlugIn = loadTalkerPlugin(desktopEntryName);
1778 if (!m_loadedTalkerPlugIn) return;
1779 // kDebug() << "KCMKttsMgr::slotConfigureTalkerButton_clicked: plugin for " << synthName << " loaded successfully.";
1781 // Tell plugin to load its configuration.
1782 m_loadedTalkerPlugIn->setDesiredLanguage(languageCode);
1783 // kDebug() << "KCMKttsMgr::slotConfigureTalkerButton_clicked: about to call plugin load() method with Talker ID = " << talkerID;
1784 m_loadedTalkerPlugIn->load(m_config, QString("Talker_")+talkerID);
1786 // Display configuration dialog.
1787 configureTalker();
1789 // Did user Cancel?
1790 if (!m_loadedTalkerPlugIn)
1792 delete m_configDlg;
1793 m_configDlg = 0;
1794 return;
1797 // Get Talker Code. Note that plugin may return a code different from before.
1798 QString talkerCode = m_loadedTalkerPlugIn->getTalkerCode();
1800 // If plugin was successfully configured, save its configuration.
1801 if (!talkerCode.isEmpty())
1803 m_loadedTalkerPlugIn->save(m_config, QString("Talker_")+talkerID);
1804 talkerCode = TalkerCode::normalizeTalkerCode(talkerCode, languageCode);
1805 KConfigGroup talkerConfig(m_config, QString("Talker_")+talkerID);
1806 talkerConfig.writeEntry("TalkerCode", talkerCode);
1807 m_config->sync();
1809 // Update display.
1810 tc.setTalkerCode(talkerCode);
1811 m_talkerListModel.updateRow(modelIndex.row(), tc);
1812 // Inform Control Center that configuration has changed.
1813 configChanged();
1816 delete m_loadedTalkerPlugIn;
1817 m_loadedTalkerPlugIn = 0;
1818 delete m_configDlg;
1819 m_configDlg = 0;
1822 void KCMKttsMgr::slotConfigureNormalFilterButton_clicked()
1824 configureFilterItem( false );
1827 void KCMKttsMgr::slotConfigureSbdFilterButton_clicked()
1829 configureFilterItem( true );
1833 * User has requested display of filter configuration dialog.
1835 void KCMKttsMgr::configureFilterItem( bool sbd )
1837 // Get highlighted plugin from Filter ListView and load into memory.
1838 QTreeView* lView;
1839 FilterListModel* model;
1840 if (sbd) {
1841 lView = sbdsView;
1842 model = &m_sbdFilterListModel;
1843 } else {
1844 lView = filtersView;
1845 model = &m_filterListModel;
1847 QModelIndex modelIndex = lView->currentIndex();
1848 if (!modelIndex.isValid()) return;
1849 FilterItem fi = model->getRow(modelIndex.row());
1850 QString filterID = fi.id;
1851 QString filterPlugInName = fi.plugInName;
1852 QString desktopEntryName = fi.desktopEntryName;
1853 if (desktopEntryName.isEmpty()) return;
1854 m_loadedFilterPlugIn = loadFilterPlugin(desktopEntryName);
1855 if (!m_loadedFilterPlugIn) return;
1856 // kDebug() << "KCMKttsMgr::slot_configureFilter: plugin for " << filterPlugInName << " loaded successfully.";
1858 // Tell plugin to load its configuration.
1859 // kDebug() << "KCMKttsMgr::slot_configureFilter: about to call plugin load() method with Filter ID = " << filterID;
1860 m_loadedFilterPlugIn->load(m_config, QString("Filter_")+filterID);
1862 // Display configuration dialog.
1863 configureFilter();
1865 // Did user Cancel?
1866 if (!m_loadedFilterPlugIn)
1868 delete m_configDlg;
1869 m_configDlg = 0;
1870 return;
1873 // Get user's name for the plugin.
1874 QString userFilterName = m_loadedFilterPlugIn->userPlugInName();
1876 // If user properly configured the plugin, save the configuration.
1877 if ( !userFilterName.isEmpty() )
1879 // Let plugin save its configuration.
1880 m_loadedFilterPlugIn->save(m_config, QString("Filter_")+filterID);
1882 // Save configuration.
1883 KConfigGroup filterConfig(m_config, QString("Filter_")+filterID);
1884 filterConfig.writeEntry("DesktopEntryName", desktopEntryName);
1885 filterConfig.writeEntry("UserFilterName", userFilterName);
1886 filterConfig.writeEntry("Enabled", true);
1887 filterConfig.writeEntry("MultiInstance", m_loadedFilterPlugIn->supportsMultiInstance());
1888 filterConfig.writeEntry("IsSBD", sbd);
1890 m_config->sync();
1892 // Update display.
1893 FilterItem fi;
1894 fi.id = filterID;
1895 fi.desktopEntryName = desktopEntryName;
1896 fi.userFilterName = userFilterName;
1897 fi.enabled = true;
1898 fi.multiInstance = m_loadedFilterPlugIn->supportsMultiInstance();
1899 model->updateRow(modelIndex.row(), fi);
1900 // Inform Control Center that configuration has changed.
1901 configChanged();
1904 delete m_loadedFilterPlugIn;
1905 m_loadedFilterPlugIn = 0;
1906 delete m_configDlg;
1907 m_configDlg = 0;
1911 * Display talker configuration dialog. The plugin is assumed already loaded into
1912 * memory referenced by m_loadedTalkerPlugIn.
1914 void KCMKttsMgr::configureTalker()
1916 if (!m_loadedTalkerPlugIn) return;
1917 m_configDlg = new KDialog(this);
1918 m_configDlg->setCaption(i18n("Talker Configuration"));
1919 m_configDlg->setButtons(KDialog::Help|KDialog::Default|KDialog::Ok|KDialog::Cancel);
1920 m_configDlg->setDefaultButton(KDialog::Cancel);
1921 m_configDlg->setMainWidget(m_loadedTalkerPlugIn);
1922 m_configDlg->setHelp("configure-plugin", "kttsd");
1923 m_configDlg->enableButtonOk(false);
1924 connect(m_loadedTalkerPlugIn, SIGNAL( changed(bool) ), this, SLOT( slotConfigTalkerDlg_ConfigChanged() ));
1925 connect(m_configDlg, SIGNAL( defaultClicked() ), this, SLOT( slotConfigTalkerDlg_DefaultClicked() ));
1926 connect(m_configDlg, SIGNAL( cancelClicked() ), this, SLOT (slotConfigTalkerDlg_CancelClicked() ));
1927 // Create a Player object for the plugin to use for testing.
1928 int playerOption = 0;
1929 QString sinkName;
1930 if (phononRadioButton->isChecked()) {
1931 playerOption = 0;
1933 if (alsaRadioButton->isChecked()) {
1934 playerOption = 2;
1935 sinkName = pcmComboBox->currentText();
1937 float audioStretchFactor = 1.0/(float(timeBox->value())/100.0);
1938 // kDebug() << "KCMKttsMgr::configureTalker: playerOption = " << playerOption << " audioStretchFactor = " << audioStretchFactor << " sink name = " << sinkName;
1939 TestPlayer* testPlayer = new TestPlayer(this, "ktts_testplayer",
1940 playerOption, audioStretchFactor, sinkName);
1941 m_loadedTalkerPlugIn->setPlayer(testPlayer);
1942 // Display the dialog.
1943 m_configDlg->exec();
1944 // Done with Player object.
1945 if (m_loadedTalkerPlugIn)
1947 delete testPlayer;
1948 m_loadedTalkerPlugIn->setPlayer(0);
1953 * Display filter configuration dialog. The plugin is assumed already loaded into
1954 * memory referenced by m_loadedFilterPlugIn.
1956 void KCMKttsMgr::configureFilter()
1958 if (!m_loadedFilterPlugIn) return;
1959 m_configDlg = new KDialog(this);
1960 m_configDlg->setCaption(i18n("Filter Configuration"));
1961 m_configDlg->setButtons(KDialog::Help|KDialog::Default|KDialog::Ok|KDialog::Cancel);
1962 m_configDlg->setDefaultButton(KDialog::Cancel);
1963 m_loadedFilterPlugIn->setMinimumSize(m_loadedFilterPlugIn->minimumSizeHint());
1964 m_loadedFilterPlugIn->show();
1965 m_configDlg->setMainWidget(m_loadedFilterPlugIn);
1966 m_configDlg->setHelp("configure-filter", "kttsd");
1967 m_configDlg->enableButtonOk(false);
1968 connect(m_loadedFilterPlugIn, SIGNAL( changed(bool) ), this, SLOT( slotConfigFilterDlg_ConfigChanged() ));
1969 connect(m_configDlg, SIGNAL( defaultClicked() ), this, SLOT( slotConfigFilterDlg_DefaultClicked() ));
1970 connect(m_configDlg, SIGNAL( cancelClicked() ), this, SLOT (slotConfigFilterDlg_CancelClicked() ));
1971 // Display the dialog.
1972 m_configDlg->exec();
1976 * Count number of configured Filters with the specified plugin name.
1978 int KCMKttsMgr::countFilterPlugins(const QString& filterPlugInName)
1980 int cnt = 0;
1981 for (int i = 0; i < m_filterListModel.rowCount(); ++i) {
1982 FilterItem fi = m_filterListModel.getRow(i);
1983 if (fi.plugInName == filterPlugInName) ++cnt;
1985 for (int i = 0; i < m_sbdFilterListModel.rowCount(); ++i) {
1986 FilterItem fi = m_sbdFilterListModel.getRow(i);
1987 if (fi.plugInName == filterPlugInName) ++cnt;
1989 return cnt;
1992 void KCMKttsMgr::keepAudioCheckBox_toggled(bool checked)
1994 keepAudioPath->setEnabled(checked);
1995 configChanged();
1998 // Basically the slider values are logarithmic (0,...,1000) whereas percent
1999 // values are linear (50%,...,200%).
2001 // slider = alpha * (log(percent)-log(50))
2002 // with alpha = 1000/(log(200)-log(50))
2004 int KCMKttsMgr::percentToSlider(int percentValue) {
2005 double alpha = 1000 / (log(200.0) - log(50.0));
2006 return (int)floor (0.5 + alpha * (log((float)percentValue)-log(50.0)));
2009 int KCMKttsMgr::sliderToPercent(int sliderValue) {
2010 double alpha = 1000 / (log(200.0) - log(50.0));
2011 return (int)floor(0.5 + exp (sliderValue/alpha + log(50.0)));
2014 void KCMKttsMgr::timeBox_valueChanged(int percentValue) {
2015 timeSlider->setValue (percentToSlider (percentValue));
2018 void KCMKttsMgr::timeSlider_valueChanged(int sliderValue) {
2019 timeBox->setValue (sliderToPercent (sliderValue));
2022 void KCMKttsMgr::slotConfigTalkerDlg_ConfigChanged()
2024 m_configDlg->enableButtonOk(!m_loadedTalkerPlugIn->getTalkerCode().isEmpty());
2027 void KCMKttsMgr::slotConfigFilterDlg_ConfigChanged()
2029 m_configDlg->enableButtonOk( !m_loadedFilterPlugIn->userPlugInName().isEmpty() );
2032 void KCMKttsMgr::slotConfigTalkerDlg_DefaultClicked()
2034 m_loadedTalkerPlugIn->defaults();
2037 void KCMKttsMgr::slotConfigFilterDlg_DefaultClicked()
2039 m_loadedFilterPlugIn->defaults();
2042 void KCMKttsMgr::slotConfigTalkerDlg_CancelClicked()
2044 delete m_loadedTalkerPlugIn;
2045 m_loadedTalkerPlugIn = 0;
2048 void KCMKttsMgr::slotConfigFilterDlg_CancelClicked()
2050 delete m_loadedFilterPlugIn;
2051 m_loadedFilterPlugIn = 0;
2055 * Uses KTrader to convert a translated Filter Plugin Name to DesktopEntryName.
2056 * @param name The translated plugin name. From Name= line in .desktop file.
2057 * @return DesktopEntryName. The name of the .desktop file (less .desktop).
2058 * QString() if not found.
2060 QString KCMKttsMgr::FilterNameToDesktopEntryName(const QString& name)
2062 if (name.isEmpty()) return QString();
2063 KService::List offers = KServiceTypeTrader::self()->query("KTTSD/FilterPlugin");
2064 for (int ndx = 0; ndx < offers.count(); ++ndx)
2065 if (offers[ndx]->name() == name) return offers[ndx]->desktopEntryName();
2066 return QString();
2070 * Uses KTrader to convert a DesktopEntryName into a translated Filter Plugin Name.
2071 * @param desktopEntryName The DesktopEntryName.
2072 * @return The translated Name of the plugin, from Name= line in .desktop file.
2074 QString KCMKttsMgr::FilterDesktopEntryNameToName(const QString& desktopEntryName)
2076 if (desktopEntryName.isEmpty()) return QString();
2077 KService::List offers = KServiceTypeTrader::self()->query("KTTSD/FilterPlugin",
2078 QString("DesktopEntryName == '%1'").arg(desktopEntryName));
2080 if (offers.count() == 1)
2081 return offers[0]->name();
2082 else
2083 return QString();
2087 void KCMKttsMgr::slotFilterListView_clicked(const QModelIndex & index)
2089 if (!index.isValid()) return;
2090 if (index.column() != 0) return;
2091 if (index.row() < 0 || index.row() >= m_filterListModel.rowCount()) return;
2092 FilterItem fi = m_filterListModel.getRow(index.row());
2093 fi.enabled = !fi.enabled;
2094 m_filterListModel.updateRow(index.row(), fi);
2095 configChanged();