~ubuntu-branches/ubuntu/raring/jovie/raring-proposed

« back to all changes in this revision

Viewing changes to .pc/jovie_scroll_when_add.diff/kcmkttsmgr/kcmkttsmgr.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2011-12-15 15:32:24 UTC
  • Revision ID: package-import@ubuntu.com-20111215153224-vp8bggrjqt6430xn
Tags: 4:4.7.90-0ubuntu1
Initial package

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************** vim:set ts=4 sw=4 sts=4:
 
2
  KControl module for KTTSD configuration and Job Management
 
3
  -------------------
 
4
  Copyright 2002-2003 by José Pablo Ezequiel "Pupeno" Fernández <pupeno@kde.org>
 
5
  Copyright 2004-2005 by Gary Cramblitt <garycramblitt@comcast.net>
 
6
  Copyright 2009 by Jeremy Whiting <jpwhiting@kde.org>
 
7
  -------------------
 
8
  Original author: José Pablo Ezequiel "Pupeno" Fernández <pupeno@kde.org>
 
9
  Current Maintainer: Jeremy Whiting <jpwhiting@kde.org>
 
10
 
 
11
  This program is free software; you can redistribute it and/or modify
 
12
  it under the terms of the GNU General Public License as published by
 
13
  the Free Software Foundation; either version 2 of the License, or
 
14
  (at your option) any later version.
 
15
 
 
16
  This program is distributed in the hope that it will be useful,
 
17
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
  GNU General Public License for more details.
 
20
 
 
21
  You should have received a copy of the GNU General Public License
 
22
  along with this program; if not, write to the Free Software
 
23
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
24
 ***************************************************************************/
 
25
 
 
26
// Note to programmers.  There is a subtle difference between a plugIn name and a
 
27
// synthesizer name.  The latter is a translated name, for example, "Festival Interactivo",
 
28
// while the former is alway an English name, example "Festival Interactive".
 
29
 
 
30
// KCMKttsMgr includes.
 
31
#include "kcmkttsmgr.h"
 
32
#include "kcmkttsmgr.moc"
 
33
 
 
34
// C++ includes.
 
35
#include <math.h>
 
36
 
 
37
// Qt includes.
 
38
#include <QtGui/QWidget>
 
39
#include <QtGui/QTabWidget>
 
40
#include <QtGui/QCheckBox>
 
41
#include <QtGui/QLayout>
 
42
#include <QtGui/QRadioButton>
 
43
#include <QtGui/QSlider>
 
44
#include <QtGui/QLabel>
 
45
#include <QtGui/QTreeWidget>
 
46
#include <QtGui/QHeaderView>
 
47
#include <QtCore/QTextStream>
 
48
#include <QtGui/QMenu>
 
49
 
 
50
// KDE includes.
 
51
#include <kparts/componentfactory.h>
 
52
#include <klineedit.h>
 
53
#include <kurlrequester.h>
 
54
#include <kicon.h>
 
55
#include <kstandarddirs.h>
 
56
#include <kaboutdata.h>
 
57
#include <kconfig.h>
 
58
#include <knuminput.h>
 
59
#include <kcombobox.h>
 
60
#include <kinputdialog.h>
 
61
#include <kmessagebox.h>
 
62
#include <kfiledialog.h>
 
63
#include <ktoolinvocation.h>
 
64
#include <kdialog.h>
 
65
#include <kspeech.h>
 
66
#include <kpluginfactory.h>
 
67
#include <kpluginloader.h>
 
68
 
 
69
// KTTS includes.
 
70
#include "talkercode.h"
 
71
#include "filterconf.h"
 
72
#include "selecttalkerdlg.h"
 
73
#include "selectlanguagedlg.h"
 
74
#include "utils.h"
 
75
#include "kttsjobmgr.h"
 
76
 
 
77
// Some constants.
 
78
// Defaults set when clicking Defaults button.
 
79
const bool autostartMgrCheckBoxValue = true;
 
80
const bool autoexitMgrCheckBoxValue = true;
 
81
 
 
82
 
 
83
// Make this a plug in.
 
84
K_PLUGIN_FACTORY (KCMKttsMgrFactory, registerPlugin<KCMKttsMgr>();)
 
85
K_EXPORT_PLUGIN (KCMKttsMgrFactory ("jovie"))
 
86
 
 
87
 
 
88
// ----------------------------------------------------------------------------
 
89
 
 
90
FilterListModel::FilterListModel (FilterList filters, QObject *parent)
 
91
        : QAbstractListModel (parent), m_filters (filters)
 
92
{
 
93
}
 
94
 
 
95
int FilterListModel::rowCount (const QModelIndex &parent) const
 
96
{
 
97
    if (!parent.isValid())
 
98
        return m_filters.count();
 
99
    else
 
100
        return 0;
 
101
}
 
102
 
 
103
int FilterListModel::columnCount (const QModelIndex &parent) const
 
104
{
 
105
    Q_UNUSED (parent);
 
106
    return 2;
 
107
}
 
108
 
 
109
QModelIndex FilterListModel::index (int row, int column, const QModelIndex &parent) const
 
110
{
 
111
    if (!parent.isValid())
 
112
        return createIndex (row, column, 0);
 
113
    else
 
114
        return QModelIndex();
 
115
}
 
116
 
 
117
QModelIndex FilterListModel::parent (const QModelIndex &index) const
 
118
{
 
119
    Q_UNUSED (index);
 
120
    return QModelIndex();
 
121
}
 
122
 
 
123
QVariant FilterListModel::data (const QModelIndex &index, int role) const
 
124
{
 
125
    if (!index.isValid())
 
126
        return QVariant();
 
127
 
 
128
    if (index.row() < 0 || index.row() >= m_filters.count())
 
129
        return QVariant();
 
130
 
 
131
    if (index.column() < 0 || index.column() >= 2)
 
132
        return QVariant();
 
133
 
 
134
    if (role == Qt::DisplayRole || role == Qt::EditRole)
 
135
        switch (index.column()) {
 
136
        case 0:
 
137
            return QVariant();
 
138
            break;
 
139
        case 1:
 
140
            return m_filters.at (index.row()).userFilterName;
 
141
            break;
 
142
        }
 
143
 
 
144
    if (role == Qt::CheckStateRole)
 
145
        switch (index.column()) {
 
146
        case 0:
 
147
            if (m_filters.at (index.row()).enabled)
 
148
                return Qt::Checked;
 
149
            else
 
150
                return Qt::Unchecked;
 
151
            break;
 
152
        case 1:
 
153
            return QVariant();
 
154
            break;
 
155
        }
 
156
 
 
157
    return QVariant();
 
158
}
 
159
 
 
160
Qt::ItemFlags FilterListModel::flags (const QModelIndex &index) const
 
161
{
 
162
    if (!index.isValid())
 
163
        return Qt::ItemIsEnabled;
 
164
 
 
165
    switch (index.column()) {
 
166
    case 0:
 
167
        return QAbstractItemModel::flags (index) | Qt::ItemIsEnabled |
 
168
               Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
 
169
        break;
 
170
    case 1:
 
171
        return QAbstractItemModel::flags (index) | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
 
172
        break;
 
173
    }
 
174
    return QAbstractItemModel::flags (index) | Qt::ItemIsEnabled;
 
175
}
 
176
 
 
177
QVariant FilterListModel::headerData (int section, Qt::Orientation orientation, int role) const
 
178
{
 
179
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
 
180
        switch (section) {
 
181
        case 0:
 
182
            return QLatin1String( "" );
 
183
        case 1:
 
184
            return i18n ("Filter");
 
185
        };
 
186
    return QVariant();
 
187
}
 
188
 
 
189
bool FilterListModel::removeRow (int row, const QModelIndex & parent)
 
190
{
 
191
    beginRemoveRows (parent, row, row);
 
192
    m_filters.removeAt (row);
 
193
    endRemoveRows();
 
194
    return true;
 
195
}
 
196
 
 
197
FilterItem FilterListModel::getRow (int row) const
 
198
{
 
199
    if (row < 0 || row >= rowCount()) return FilterItem();
 
200
    return m_filters[row];
 
201
}
 
202
 
 
203
bool FilterListModel::appendRow (FilterItem& filter)
 
204
{
 
205
    beginInsertRows (QModelIndex(), m_filters.count(), m_filters.count());
 
206
    m_filters.append (filter);
 
207
    endInsertRows();
 
208
    return true;
 
209
}
 
210
 
 
211
bool FilterListModel::updateRow (int row, FilterItem& filter)
 
212
{
 
213
    m_filters.replace (row, filter);
 
214
    emit dataChanged (index (row, 0, QModelIndex()), index (row, columnCount() - 1, QModelIndex()));
 
215
    return true;
 
216
}
 
217
 
 
218
bool FilterListModel::swap (int i, int j)
 
219
{
 
220
    m_filters.swap (i, j);
 
221
    emit dataChanged (index (i, 0, QModelIndex()), index (j, columnCount() - 1, QModelIndex()));
 
222
    return true;
 
223
}
 
224
 
 
225
void FilterListModel::clear()
 
226
{
 
227
    m_filters.clear();
 
228
    emit reset();
 
229
}
 
230
 
 
231
// ----------------------------------------------------------------------------
 
232
 
 
233
/**
 
234
* Constructor.
 
235
*/
 
236
KCMKttsMgr::KCMKttsMgr (QWidget *parent, const QVariantList &) :
 
237
        KCModule (KCMKttsMgrFactory::componentData(), parent/*, name*/),
 
238
        m_kspeech (0)
 
239
{
 
240
 
 
241
    // kDebug() << "KCMKttsMgr constructor running.";
 
242
 
 
243
    // Initialize some variables.
 
244
    m_config = 0;
 
245
    m_jobMgrWidget = 0;
 
246
    m_configDlg = 0;
 
247
    m_changed = false;
 
248
    m_suppressConfigChanged = false;
 
249
 
 
250
    // Add the KTTS Manager widget
 
251
    setupUi (this);
 
252
 
 
253
    // Connect Views to Models and set row selection mode.
 
254
    talkersView->setModel (&m_talkerListModel);
 
255
    filtersView->setModel (&m_filterListModel);
 
256
    talkersView->setSelectionBehavior (QAbstractItemView::SelectRows);
 
257
    filtersView->setSelectionBehavior (QAbstractItemView::SelectRows);
 
258
    talkersView->setRootIsDecorated (false);
 
259
    filtersView->setRootIsDecorated (false);
 
260
    talkersView->setItemsExpandable (false);
 
261
    filtersView->setItemsExpandable (false);
 
262
 
 
263
    // Give buttons icons.
 
264
    // Talkers tab.
 
265
    higherTalkerPriorityButton->setIcon (KIcon ( QLatin1String( "go-up" )));
 
266
    lowerTalkerPriorityButton->setIcon (KIcon ( QLatin1String( "go-down" )));
 
267
    removeTalkerButton->setIcon (KIcon ( QLatin1String( "user-trash" )));
 
268
    configureTalkerButton->setIcon (KIcon ( QLatin1String( "configure" )));
 
269
 
 
270
    // Filters tab.
 
271
    higherFilterPriorityButton->setIcon (KIcon ( QLatin1String( "go-up" )));
 
272
    lowerFilterPriorityButton->setIcon (KIcon ( QLatin1String( "go-down" )));
 
273
    removeFilterButton->setIcon (KIcon ( QLatin1String( "user-trash" )));
 
274
    configureFilterButton->setIcon (KIcon ( QLatin1String( "configure" )));
 
275
 
 
276
    // Object for the KTTSD configuration.
 
277
    m_config = new KConfig (QLatin1String( "kttsdrc" ));
 
278
 
 
279
    // Connect the signals from the KCMKtssMgrWidget to this class.
 
280
 
 
281
    // General tab.
 
282
    connect (enableJovieCheckBox, SIGNAL (toggled(bool)),
 
283
             SLOT (slotEnableJovie_toggled(bool)));
 
284
 
 
285
    // Talker tab.
 
286
    connect (addTalkerButton, SIGNAL (clicked()),
 
287
             this, SLOT (slotAddTalkerButton_clicked()));
 
288
    connect (higherTalkerPriorityButton, SIGNAL (clicked()),
 
289
             this, SLOT (slotHigherTalkerPriorityButton_clicked()));
 
290
    connect (lowerTalkerPriorityButton, SIGNAL (clicked()),
 
291
             this, SLOT (slotLowerTalkerPriorityButton_clicked()));
 
292
    connect (removeTalkerButton, SIGNAL (clicked()),
 
293
             this, SLOT (slotRemoveTalkerButton_clicked()));
 
294
    connect (configureTalkerButton, SIGNAL (clicked()),
 
295
             this, SLOT (slotConfigureTalkerButton_clicked()));
 
296
    connect (talkersView, SIGNAL (clicked(QModelIndex)),
 
297
             this, SLOT (updateTalkerButtons()));
 
298
 
 
299
    // Filter tab.
 
300
    connect (addFilterButton, SIGNAL (clicked()),
 
301
             this, SLOT (slotAddFilterButton_clicked()));
 
302
    connect (higherFilterPriorityButton, SIGNAL (clicked()),
 
303
             this, SLOT (slotHigherFilterPriorityButton_clicked()));
 
304
    connect (lowerFilterPriorityButton, SIGNAL (clicked()),
 
305
             this, SLOT (slotLowerFilterPriorityButton_clicked()));
 
306
    connect (removeFilterButton, SIGNAL (clicked()),
 
307
             this, SLOT (slotRemoveFilterButton_clicked()));
 
308
    connect (configureFilterButton, SIGNAL (clicked()),
 
309
             this, SLOT (slotConfigureFilterButton_clicked()));
 
310
    connect (filtersView, SIGNAL (clicked(QModelIndex)),
 
311
             this, SLOT (updateFilterButtons()));
 
312
    connect (filtersView, SIGNAL (clicked(QModelIndex)),
 
313
             this, SLOT (slotFilterListView_clicked(QModelIndex)));
 
314
 
 
315
 
 
316
    // Others.
 
317
    connect (mainTab, SIGNAL (currentChanged(int)),
 
318
             this, SLOT (slotTabChanged()));
 
319
 
 
320
    // See if Jovie is already running, and if so, create jobs tab.
 
321
    if (QDBusConnection::sessionBus().interface()->isServiceRegistered (QLatin1String( "org.kde.jovie" )))
 
322
        jovieStarted();
 
323
    else
 
324
        // Start Jovie if check box is checked.
 
325
        slotEnableJovie_toggled (enableJovieCheckBox->isChecked());
 
326
 
 
327
    // Adjust view column sizes.
 
328
    // TODO: To work properly, this needs to be done after the widgets are shown.
 
329
    // Possibly in Resize event?
 
330
    for (int i = 0; i < m_filterListModel.columnCount(); ++i)
 
331
        filtersView->resizeColumnToContents (i);
 
332
    for (int i = 0; i < m_talkerListModel.columnCount(); ++i)
 
333
        talkersView->resizeColumnToContents (i);
 
334
 
 
335
    // Switch to Talkers tab if none configured,
 
336
    // otherwise switch to Jobs tab if it is active.
 
337
    if (m_talkerListModel.rowCount() == 0)
 
338
        mainTab->setCurrentIndex (wpTalkers);
 
339
    else if (enableJovieCheckBox->isChecked())
 
340
        mainTab->setCurrentIndex (wpJobs);
 
341
}
 
342
 
 
343
/**
 
344
* Destructor.
 
345
*/
 
346
KCMKttsMgr::~KCMKttsMgr()
 
347
{
 
348
    // kDebug() << "KCMKttsMgr::~KCMKttsMgr: Running";
 
349
    delete m_config;
 
350
}
 
351
 
 
352
/**
 
353
* This method is invoked whenever the module should read its
 
354
* configuration (most of the times from a config file) and update the
 
355
* user interface. This happens when the user clicks the "Reset" button in
 
356
* the control center, to undo all of his changes and restore the currently
 
357
* valid settings. NOTE that this is not called after the modules is loaded,
 
358
* so you probably want to call this method in the constructor.
 
359
*/
 
360
void KCMKttsMgr::load()
 
361
{
 
362
    // kDebug() << "KCMKttsMgr::load: Running";
 
363
 
 
364
    m_changed = false;
 
365
    // Don't emit changed() signal while loading.
 
366
    m_suppressConfigChanged = true;
 
367
 
 
368
    // Set the group general for the configuration of kttsd itself (no plug ins)
 
369
    KConfigGroup generalConfig (m_config, "General");
 
370
 
 
371
    // Overall settings.
 
372
    enableJovieCheckBox->setChecked (generalConfig.readEntry ("EnableJovie",
 
373
                                     enableJovieCheckBox->isChecked()));
 
374
 
 
375
    // Last filter ID.  Used to generate a new ID for an added filter.
 
376
    m_lastFilterID = 0;
 
377
 
 
378
    // Load existing Talkers into Talker List.
 
379
    m_talkerListModel.loadTalkerCodesFromConfig (m_config);
 
380
 
 
381
    // Last talker ID.  Used to generate a new ID for an added talker.
 
382
    //m_lastTalkerID = m_talkerListModel.highestTalkerId();
 
383
 
 
384
    // Dictionary mapping languages to language codes.
 
385
    m_languagesToCodes.clear();
 
386
    for (int i = 0; i < m_talkerListModel.rowCount(); ++i) {
 
387
        QString language = m_talkerListModel.getRow (i).language();
 
388
        m_languagesToCodes[language] = language;
 
389
    }
 
390
 
 
391
    // Iterate thru the possible plug ins getting their language support codes.
 
392
    //for(int i=0; i < offers.count() ; ++i)
 
393
    //{
 
394
    //    QString synthName = offers[i]->name();
 
395
    //    QStringList languageCodes = offers[i]->property("X-KDE-Languages").toStringList();
 
396
    //    // Add language codes to the language-to-language code map.
 
397
    //    QStringList::ConstIterator endLanguages(languageCodes.constEnd());
 
398
    //    for( QStringList::ConstIterator it = languageCodes.constBegin(); it != endLanguages; ++it )
 
399
    //    {
 
400
    //        QString language = TalkerCode::languageCodeToLanguage(*it);
 
401
    //        m_languagesToCodes[language] = *it;
 
402
    //    }
 
403
 
 
404
    //    // All plugins support "Other".
 
405
    //    // TODO: Eventually, this should not be necessary, since all plugins will know
 
406
    //    // the languages they support and report them in call to getSupportedLanguages().
 
407
    //    if (!languageCodes.contains("other")) languageCodes.append("other");
 
408
 
 
409
    //    // Add supported language codes to synthesizer-to-language map.
 
410
    //    m_synthToLangMap[synthName] = languageCodes;
 
411
    //}
 
412
 
 
413
    // Add "Other" language.
 
414
    //m_languagesToCodes[i18nc("Other language", "Other")] = "other";
 
415
 
 
416
    // Load Filters.
 
417
    m_filterListModel.clear();
 
418
    QStringList filterIDsList = generalConfig.readEntry ("FilterIDs", QStringList());
 
419
    // kDebug() << "KCMKttsMgr::load: FilterIDs = " << filterIDsList;
 
420
    if (!filterIDsList.isEmpty()) {
 
421
        QStringList::ConstIterator itEnd = filterIDsList.constEnd();
 
422
        for (QStringList::ConstIterator it = filterIDsList.constBegin(); it != itEnd; ++it) {
 
423
            QString filterID = *it;
 
424
            // kDebug() << "KCMKttsMgr::load: filterID = " << filterID;
 
425
            KConfigGroup filterConfig (m_config, QLatin1String( "Filter_" ) + filterID);
 
426
            QString desktopEntryName = filterConfig.readEntry ("DesktopEntryName", QString());
 
427
            // If a DesktopEntryName is not in the config file, it was configured before
 
428
            // we started using them, when we stored translated plugin names instead.
 
429
            // Try to convert the translated plugin name to a DesktopEntryName.
 
430
            // DesktopEntryNames are better because user can change their desktop language
 
431
            // and DesktopEntryName won't change.
 
432
            QString filterPlugInName;
 
433
            filterPlugInName = FilterDesktopEntryNameToName (desktopEntryName);
 
434
            if (!filterPlugInName.isEmpty()) {
 
435
                FilterItem fi;
 
436
                fi.id = filterID;
 
437
                fi.plugInName = filterPlugInName;
 
438
                fi.desktopEntryName = desktopEntryName;
 
439
                fi.userFilterName = filterConfig.readEntry ("UserFilterName", filterPlugInName);
 
440
                fi.multiInstance = filterConfig.readEntry ("MultiInstance", false);
 
441
                fi.enabled = filterConfig.readEntry ("Enabled", false);
 
442
                // Determine if this filter is a Sentence Boundary Detector (SBD).
 
443
                m_filterListModel.appendRow (fi);
 
444
                if (filterID.toInt() > m_lastFilterID) m_lastFilterID = filterID.toInt();
 
445
            }
 
446
        }
 
447
    }
 
448
 
 
449
    // Add at least one unchecked instance of each available filter plugin if there is
 
450
    // not already at least one instance and the filter can autoconfig itself.
 
451
    //offers = KServiceTypeTrader::self()->query("KTTSD/FilterPlugin");
 
452
    //for (int i=0; i < offers.count() ; ++i)
 
453
    //{
 
454
    //    QString filterPlugInName = offers[i]->name();
 
455
    //    QString desktopEntryName = FilterNameToDesktopEntryName(filterPlugInName);
 
456
    //    if (!desktopEntryName.isEmpty() && (countFilterPlugins(filterPlugInName) == 0))
 
457
    //    {
 
458
    //        // Must load plugin to determine if it supports multiple instances
 
459
    //        // and to see if it can autoconfigure itself.
 
460
    //        KttsFilterConf* filterPlugIn = loadFilterPlugin(desktopEntryName);
 
461
    //        if (filterPlugIn)
 
462
    //        {
 
463
    //            ++m_lastFilterID;
 
464
    //            QString filterID = QString::number(m_lastFilterID);
 
465
    //            QString groupName = "Filter_" + filterID;
 
466
    //            filterPlugIn->load(m_config, groupName);
 
467
    //            QString userFilterName = filterPlugIn->userPlugInName();
 
468
    //            if (!userFilterName.isEmpty())
 
469
    //            {
 
470
    //                kDebug() << "KCMKttsMgr::load: auto-configuring filter " << userFilterName;
 
471
    //                bool multiInstance = filterPlugIn->supportsMultiInstance();
 
472
    //                FilterItem fi;
 
473
    //                fi.id = filterID;
 
474
    //                fi.userFilterName = userFilterName;
 
475
    //                fi.plugInName = filterPlugInName;
 
476
    //                fi.desktopEntryName = desktopEntryName;
 
477
    //                fi.enabled = true;
 
478
    //                fi.multiInstance = multiInstance;
 
479
    //                // Determine if plugin is an SBD filter.
 
480
    //                bool isSbd = filterPlugIn->isSBD();
 
481
    //                if (isSbd)
 
482
    //                    m_sbdFilterListModel.appendRow(fi);
 
483
    //                else
 
484
    //                    m_filterListModel.appendRow(fi);
 
485
    //                KConfigGroup filterConfig(m_config, groupName);
 
486
    //                filterPlugIn->save(m_config, groupName);
 
487
    //                filterConfig.writeEntry("DesktopEntryName", desktopEntryName);
 
488
    //                filterConfig.writeEntry("UserFilterName", userFilterName);
 
489
    //                filterConfig.writeEntry("Enabled", isSbd);
 
490
    //                filterConfig.writeEntry("MultiInstance", multiInstance);
 
491
    //                filterConfig.writeEntry("IsSBD", isSbd);
 
492
    //                filterIDsList.append(filterID);
 
493
    //            } else m_lastFilterID--;
 
494
    //        } else
 
495
    //            kDebug() << "KCMKttsMgr::load: Unable to load filter plugin " << filterPlugInName
 
496
    //                << " DesktopEntryName " << desktopEntryName << endl;
 
497
    //        delete filterPlugIn;
 
498
    //    }
 
499
    //}
 
500
    // Rewrite list of FilterIDs in case we added any.
 
501
    QString filterIDs = filterIDsList.join (QLatin1String( "," ));
 
502
    generalConfig.writeEntry ("FilterIDs", filterIDs);
 
503
    m_config->sync();
 
504
 
 
505
    // Update controls based on new states.
 
506
    updateTalkerButtons();
 
507
    updateFilterButtons();
 
508
 
 
509
    m_changed = false;
 
510
    m_suppressConfigChanged = false;
 
511
}
 
512
 
 
513
/**
 
514
* This function gets called when the user wants to save the settings in
 
515
* the user interface, updating the config files or wherever the
 
516
* configuration is stored. The method is called when the user clicks "Apply"
 
517
* or "Ok".
 
518
*/
 
519
void KCMKttsMgr::save()
 
520
{
 
521
    // kDebug() << "KCMKttsMgr::save: Running";
 
522
    m_changed = false;
 
523
 
 
524
    // Clean up config.
 
525
    m_config->deleteGroup ("General", 0);
 
526
 
 
527
    // Set the group general for the configuration of kttsd itself (no plug ins)
 
528
    KConfigGroup generalConfig (m_config, "General");
 
529
 
 
530
    // Uncheck and disable KTTSD checkbox if no Talkers are configured.
 
531
    // Enable checkbox if at least one Talker is configured.
 
532
    bool enableJovieWasToggled = false;
 
533
    //if (m_talkerListModel.rowCount() == 0)
 
534
    //{
 
535
    //enableKttsdWasToggled = enableKttsdCheckBox->isChecked();
 
536
    //enableKttsdCheckBox->setChecked(false);
 
537
    //enableKttsdCheckBox->setEnabled(false);
 
538
    // Might as well zero LastTalkerID as well.
 
539
    //m_lastTalkerID = 0;
 
540
    //}
 
541
    //else
 
542
    enableJovieCheckBox->setEnabled (true);
 
543
 
 
544
    generalConfig.writeEntry ("EnableKttsd", enableJovieCheckBox->isChecked());
 
545
 
 
546
    // Get ordered list of all talker IDs.
 
547
    QList<TalkerCode> talkers;
 
548
    QStringList talkerIDsList;
 
549
    KConfigGroup talkerGroup (m_config, "Talkers");
 
550
    talkerGroup.deleteGroup();
 
551
    for (int i = 0; i < m_talkerListModel.rowCount(); ++i) {
 
552
        TalkerCode talker = m_talkerListModel.getRow (i);
 
553
        talkers << talker;
 
554
        talkerGroup.writeEntry (talker.name(), talker.getTalkerCode());
 
555
        talkerIDsList << talker.name();
 
556
    }
 
557
 
 
558
    QString talkerIDs = talkerIDsList.join (QLatin1String( "," ));
 
559
    generalConfig.writeEntry ("TalkerIDs", talkerIDs);
 
560
 
 
561
    // Erase obsolete Talker_nn sections.
 
562
    QStringList groupList = m_config->groupList();
 
563
    int groupListCount = groupList.count();
 
564
    for (int groupNdx = 0; groupNdx < groupListCount; ++groupNdx) {
 
565
        QString groupName = groupList[groupNdx];
 
566
        if (groupName.left (7) == QLatin1String( "Talker_" )) {
 
567
            QString groupTalkerID = groupName.mid (7);
 
568
            if (!talkerIDsList.contains (groupTalkerID))
 
569
                m_config->deleteGroup (groupName, 0);
 
570
        }
 
571
    }
 
572
 
 
573
    // Get ordered list of all filter IDs.  Record enabled state of each filter.
 
574
    QStringList filterIDsList;
 
575
    for (int i = 0; i < m_filterListModel.rowCount(); ++i) {
 
576
        FilterItem fi = m_filterListModel.getRow (i);
 
577
        filterIDsList.append (fi.id);
 
578
        KConfigGroup filterConfig (m_config, QLatin1String( "Filter_" ) + fi.id);
 
579
        filterConfig.writeEntry ("Enabled", fi.enabled);
 
580
    }
 
581
    QString filterIDs = filterIDsList.join (QLatin1String( "," ));
 
582
    generalConfig.writeEntry ("FilterIDs", filterIDs);
 
583
 
 
584
    // Erase obsolete Filter_nn sections.
 
585
    for (int groupNdx = 0; groupNdx < groupListCount; ++groupNdx) {
 
586
        QString groupName = groupList[groupNdx];
 
587
        if (groupName.left (7) == QLatin1String( "Filter_" )) {
 
588
            QString groupFilterID = groupName.mid (7);
 
589
            if (!filterIDsList.contains (groupFilterID))
 
590
                m_config->deleteGroup (groupName, 0);
 
591
        }
 
592
    }
 
593
 
 
594
    m_config->sync();
 
595
 
 
596
    // apply changes in the jobs page if it exists
 
597
    if (m_jobMgrWidget) {
 
598
        m_jobMgrWidget->save();
 
599
    }
 
600
 
 
601
    // If we automatically unchecked the Enable KTTSD checkbox, stop KTTSD.
 
602
    if (enableJovieWasToggled)
 
603
        slotEnableJovie_toggled (false);
 
604
    else {
 
605
        // If Jovie is running, reinitialize it.
 
606
        if (m_kspeech) {
 
607
            kDebug() << "Restarting Jovie";
 
608
            m_kspeech->reinit();
 
609
        }
 
610
    }
 
611
}
 
612
 
 
613
void KCMKttsMgr::slotTabChanged()
 
614
{
 
615
    // TODO: Commentting this out to avoid a crash.  It seems there is a bug in
 
616
    // KDialog.  The workaround is to call setDefaultButton(), but that method
 
617
    // is not available to a KCModule.  Uncomment this when bug is fixed.
 
618
    // setButtons(buttons());
 
619
    int currentPageIndex = mainTab->currentIndex();
 
620
    if (currentPageIndex == wpJobs) {
 
621
        if (m_changed) {
 
622
            KMessageBox::information (this,
 
623
                                      i18n ("You have made changes to the configuration but have not saved them yet.  "
 
624
                                            "Click Apply to save the changes or Cancel to abandon the changes."));
 
625
        }
 
626
    }
 
627
}
 
628
 
 
629
/**
 
630
* This function is called to set the settings in the module to sensible
 
631
* default values. It gets called when hitting the "Default" button. The
 
632
* default values should probably be the same as the ones the application
 
633
* uses when started without a config file.
 
634
*/
 
635
void KCMKttsMgr::defaults()
 
636
{
 
637
    // kDebug() << "Running: KCMKttsMgr::defaults: Running";
 
638
 
 
639
    int currentPageIndex = mainTab->currentIndex();
 
640
    // configChanged();
 
641
}
 
642
 
 
643
/**
 
644
* This is a static method which gets called to realize the modules settings
 
645
* during the startup of KDE. NOTE that most modules do not implement this
 
646
* method, but modules like the keyboard and mouse modules, which directly
 
647
* interact with the X-server, need this method. As this method is static,
 
648
* it can avoid to create an instance of the user interface, which is often
 
649
* not needed in this case.
 
650
*/
 
651
void KCMKttsMgr::init()
 
652
{
 
653
    // kDebug() << "KCMKttsMgr::init: Running";
 
654
}
 
655
 
 
656
/**
 
657
* This function returns the small quickhelp.
 
658
* That is displayed in the sidebar in the KControl
 
659
*/
 
660
QString KCMKttsMgr::quickHelp() const
 
661
{
 
662
    // kDebug() << "KCMKttsMgr::quickHelp: Running";
 
663
    return i18n (
 
664
               "<h1>Text-to-Speech</h1>"
 
665
               "<p>This is the configuration for the text-to-speech D-Bus service</p>"
 
666
               "<p>This allows other applications to access text-to-speech resources</p>"
 
667
               "<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>");
 
668
}
 
669
 
 
670
const KAboutData* KCMKttsMgr::aboutData() const
 
671
{
 
672
    KAboutData *about =
 
673
        new KAboutData (I18N_NOOP ("jovie"), 0, ki18n ("KCMKttsMgr"),
 
674
                        0, KLocalizedString(), KAboutData::License_GPL,
 
675
                        ki18n ("(c) 2010, Jeremy Whiting"));
 
676
 
 
677
    about->addAuthor (ki18n ("José Pablo Ezequiel Fernández"), ki18n ("Author") , "pupeno@kde.org");
 
678
    about->addAuthor (ki18n ("Gary Cramblitt"), ki18n ("Maintainer") , "garycramblitt@comcast.net");
 
679
    about->addAuthor (ki18n ("Olaf Schmidt"), ki18n ("Contributor"), "ojschmidt@kde.org");
 
680
    about->addAuthor (ki18n ("Paul Giannaros"), ki18n ("Contributor"), "ceruleanblaze@gmail.com");
 
681
 
 
682
    return about;
 
683
}
 
684
 
 
685
/**
 
686
 * Loads the configuration plug in for a named filter plug in.
 
687
 * @param plugInName       DesktopEntryName of the plugin.
 
688
 * @return                 Pointer to the configuration plugin for the Filter.
 
689
 */
 
690
KttsFilterConf* KCMKttsMgr::loadFilterPlugin (const QString& plugInName)
 
691
{
 
692
    // kDebug() << "KCMKttsMgr::loadPlugin: Running";
 
693
 
 
694
    // Find the plugin.
 
695
    KService::List offers = KServiceTypeTrader::self()->query (QLatin1String( "Jovie/FilterPlugin" ),
 
696
                            QString (QLatin1String( "DesktopEntryName == '%1'" )).arg (plugInName));
 
697
 
 
698
    if (offers.count() == 1) {
 
699
        // When the entry is found, load the plug in
 
700
        // First create a factory for the library
 
701
        KLibFactory *factory = KLibLoader::self()->factory (QLatin1String( offers[0]->library().toLatin1() ));
 
702
        if (factory) {
 
703
            // If the factory is created successfully, instantiate the KttsFilterConf class for the
 
704
            // specific plug in to get the plug in configuration object.
 
705
            int errorNo = 0;
 
706
            KttsFilterConf *plugIn =
 
707
                KLibLoader::createInstance<KttsFilterConf> (
 
708
                    QLatin1String( offers[0]->library().toLatin1() ), NULL, QStringList ( QLatin1String( offers[0]->library().toLatin1() )),
 
709
                    &errorNo);
 
710
            if (plugIn) {
 
711
                // If everything went ok, return the plug in pointer.
 
712
                return plugIn;
 
713
            } else {
 
714
                // Something went wrong, returning null.
 
715
                kDebug() << "KCMKttsMgr::loadFilterPlugin: Unable to instantiate KttsFilterConf class for plugin " << plugInName << " error: " << errorNo;
 
716
                return NULL;
 
717
            }
 
718
        } else {
 
719
            // Something went wrong, returning null.
 
720
            kDebug() << "KCMKttsMgr::loadFilterPlugin: Unable to create Factory object for plugin " << plugInName;
 
721
            return NULL;
 
722
        }
 
723
    }
 
724
    // The plug in was not found (unexpected behaviour, returns null).
 
725
    kDebug() << "KCMKttsMgr::loadFilterPlugin: KTrader did not return an offer for plugin " << plugInName;
 
726
    return NULL;
 
727
}
 
728
 
 
729
/**
 
730
 * Add a talker.
 
731
 */
 
732
void KCMKttsMgr::slotAddTalkerButton_clicked()
 
733
{
 
734
    QPointer<AddTalker> dlg = new AddTalker (this);
 
735
    if (dlg->exec() == QDialog::Accepted) {
 
736
        TalkerCode code = dlg->getTalkerCode();
 
737
 
 
738
        // Add to list of Talkers.
 
739
        m_talkerListModel.appendRow (code);
 
740
 
 
741
        // Make sure visible.
 
742
        const QModelIndex modelIndex = m_talkerListModel.index (m_talkerListModel.rowCount(),
 
743
                                       0, QModelIndex());
 
744
        talkersView->scrollTo (modelIndex);
 
745
 
 
746
        // Select the new item, update buttons.
 
747
        talkersView->setCurrentIndex (modelIndex);
 
748
        updateTalkerButtons();
 
749
 
 
750
        // Inform Control Center that change has been made.
 
751
        configChanged();
 
752
    }
 
753
    delete dlg;
 
754
 
 
755
    kDebug() << "KCMKttsMgr::addTalker: done.";
 
756
}
 
757
 
 
758
void KCMKttsMgr::slotAddFilterButton_clicked()
 
759
{
 
760
    addFilter();
 
761
}
 
762
 
 
763
/**
 
764
* Add a filter.
 
765
*/
 
766
void KCMKttsMgr::addFilter()
 
767
{
 
768
    QTreeView* lView = filtersView;
 
769
    FilterListModel* model = qobject_cast<FilterListModel *> (lView->model());
 
770
 
 
771
    // Build a list of filters that support multiple instances and let user choose.
 
772
    QStringList filterPlugInNames;
 
773
    for (int i = 0; i < model->rowCount(); ++i) {
 
774
        FilterItem fi = model->getRow (i);
 
775
        if (fi.multiInstance) {
 
776
            if (!filterPlugInNames.contains (fi.plugInName))
 
777
                filterPlugInNames.append (fi.plugInName);
 
778
        }
 
779
    }
 
780
    // Append those available plugins not yet in the list at all.
 
781
    KService::List offers = KServiceTypeTrader::self()->query (QLatin1String( "Jovie/FilterPlugin" ));
 
782
    for (int i = 0; i < offers.count() ; ++i) {
 
783
        QString filterPlugInName = offers[i]->name();
 
784
        if (countFilterPlugins (filterPlugInName) == 0) {
 
785
            QString desktopEntryName = FilterNameToDesktopEntryName (filterPlugInName);
 
786
            KttsFilterConf* filterConf = loadFilterPlugin (desktopEntryName);
 
787
            if (filterConf) {
 
788
                filterPlugInNames.append (filterPlugInName);
 
789
                delete filterConf;
 
790
            }
 
791
        }
 
792
    }
 
793
 
 
794
    // If no choice (shouldn't happen), bail out.
 
795
    // kDebug() << "KCMKttsMgr::addFilter: filterPluginNames = " << filterPlugInNames;
 
796
    if (filterPlugInNames.count() == 0) return;
 
797
 
 
798
    // If exactly one choice, skip selection dialog, otherwise display list to user to select from.
 
799
    bool okChosen = false;
 
800
    QString filterPlugInName;
 
801
    if (filterPlugInNames.count() > 1) {
 
802
        filterPlugInName = KInputDialog::getItem (
 
803
                               i18n ("Select Filter"),
 
804
                               i18n ("Filter"),
 
805
                               filterPlugInNames,
 
806
                               0,
 
807
                               false,
 
808
                               &okChosen,
 
809
                               this);
 
810
        if (!okChosen) return;
 
811
    } else
 
812
        filterPlugInName = filterPlugInNames[0];
 
813
 
 
814
    // kDebug() << "KCMKttsMgr::addFilter: filterPlugInName = " << filterPlugInName;
 
815
 
 
816
    // Assign a new Filter ID for the filter.  Wraps around to 1.
 
817
    QString filterID = QString::number (m_lastFilterID + 1);
 
818
 
 
819
    // Erase extraneous Filter configuration entries that might be there.
 
820
    m_config->deleteGroup (QLatin1String ("Filter_") + filterID, 0);
 
821
    m_config->sync();
 
822
 
 
823
    // Get DesktopEntryName from the translated name.
 
824
    QString desktopEntryName = FilterNameToDesktopEntryName (filterPlugInName);
 
825
    // This shouldn't happen, but just in case.
 
826
    if (desktopEntryName.isEmpty()) return;
 
827
 
 
828
    // Load the plugin.
 
829
    m_loadedFilterPlugIn = loadFilterPlugin (desktopEntryName);
 
830
    if (!m_loadedFilterPlugIn) return;
 
831
 
 
832
    // Permit plugin to autoconfigure itself.
 
833
    m_loadedFilterPlugIn->load (m_config, QLatin1String ("Filter_") + filterID);
 
834
 
 
835
    // Display configuration dialog for user to configure the plugin.
 
836
    configureFilter();
 
837
 
 
838
    // Did user Cancel?
 
839
    if (!m_loadedFilterPlugIn) {
 
840
        delete m_configDlg;
 
841
        m_configDlg = 0;
 
842
        return;
 
843
    }
 
844
 
 
845
    // Get user's name for Filter.
 
846
    QString userFilterName = m_loadedFilterPlugIn->userPlugInName();
 
847
 
 
848
    // If user properly configured the plugin, save its configuration.
 
849
    if (!userFilterName.isEmpty()) {
 
850
        // Let plugin save its configuration.
 
851
        m_loadedFilterPlugIn->save (m_config, QLatin1String ("Filter_" ) + filterID);
 
852
 
 
853
        // Record last Filter ID used for next add.
 
854
        m_lastFilterID = filterID.toInt();
 
855
 
 
856
        // Determine if filter supports multiple instances.
 
857
        bool multiInstance = m_loadedFilterPlugIn->supportsMultiInstance();
 
858
 
 
859
        // Record configuration data.  Note, might as well do this now.
 
860
        KConfigGroup filterConfig (m_config, QLatin1String ("Filter_" ) + filterID);
 
861
        filterConfig.writeEntry ("DesktopEntryName", desktopEntryName);
 
862
        filterConfig.writeEntry ("UserFilterName", userFilterName);
 
863
        filterConfig.writeEntry ("MultiInstance", multiInstance);
 
864
        filterConfig.writeEntry ("Enabled", true);
 
865
        m_config->sync();
 
866
 
 
867
        // Add listview item.
 
868
        FilterItem fi;
 
869
        fi.id = filterID;
 
870
        fi.plugInName = filterPlugInName;
 
871
        fi.userFilterName = userFilterName;
 
872
        fi.desktopEntryName = desktopEntryName;
 
873
        fi.multiInstance = multiInstance;
 
874
        fi.enabled = true;
 
875
        model->appendRow (fi);
 
876
 
 
877
        // Make sure visible.
 
878
        QModelIndex modelIndex = model->index (model->rowCount() - 1, 0, QModelIndex());
 
879
        lView->scrollTo (modelIndex);
 
880
 
 
881
        // Select the new item, update buttons.
 
882
        lView->setCurrentIndex (modelIndex);
 
883
        updateFilterButtons();
 
884
 
 
885
        // Inform Control Center that change has been made.
 
886
        configChanged();
 
887
    }
 
888
 
 
889
    // Don't need plugin in memory anymore.
 
890
    delete m_loadedFilterPlugIn;
 
891
    m_loadedFilterPlugIn = 0;
 
892
    delete m_configDlg;
 
893
    m_configDlg = 0;
 
894
 
 
895
    // kDebug() << "KCMKttsMgr::addFilter: done.";
 
896
}
 
897
 
 
898
/**
 
899
* Remove talker.
 
900
*/
 
901
void KCMKttsMgr::slotRemoveTalkerButton_clicked()
 
902
{
 
903
    // kDebug() << "KCMKttsMgr::removeTalker: Running";
 
904
 
 
905
    // Get the selected talker.
 
906
    QModelIndex modelIndex = talkersView->currentIndex();
 
907
    if (!modelIndex.isValid()) return;
 
908
 
 
909
    // Delete the talker from configuration file?
 
910
    QString talkerID = m_talkerListModel.getRow (modelIndex.row()).name();
 
911
    m_config->deleteGroup (QLatin1String ("Talker_") + talkerID, 0);
 
912
 
 
913
    // Delete the talker from the list of Talkers.
 
914
    m_talkerListModel.removeRow (modelIndex.row());
 
915
 
 
916
    updateTalkerButtons();
 
917
 
 
918
    // Emit configuration changed.
 
919
    configChanged();
 
920
}
 
921
 
 
922
void KCMKttsMgr::slotRemoveFilterButton_clicked()
 
923
{
 
924
    removeFilter();
 
925
}
 
926
 
 
927
/**
 
928
* Remove filter.
 
929
*/
 
930
void KCMKttsMgr::removeFilter()
 
931
{
 
932
    // kDebug() << "KCMKttsMgr::removeFilter: Running";
 
933
 
 
934
    FilterListModel* model;
 
935
    QTreeView* lView = filtersView;
 
936
    model = qobject_cast<FilterListModel *> (lView->model());
 
937
    QModelIndex modelIndex = lView->currentIndex();
 
938
    if (!modelIndex.isValid()) return;
 
939
    QString filterID = model->getRow (modelIndex.row()).id;
 
940
    // Delete the filter from list view.
 
941
    model->removeRow (modelIndex.row());
 
942
    updateFilterButtons();
 
943
 
 
944
    // Delete the filter from the configuration file?
 
945
    kDebug() << "KCMKttsMgr::removeFilter: removing FilterID = " << filterID << " from config file.";
 
946
    m_config->deleteGroup (QLatin1String ("Filter_") + filterID, 0);
 
947
 
 
948
    // Emit configuration changed.
 
949
    configChanged();
 
950
}
 
951
 
 
952
void KCMKttsMgr::slotHigherTalkerPriorityButton_clicked()
 
953
{
 
954
    QModelIndex modelIndex = talkersView->currentIndex();
 
955
    if (!modelIndex.isValid()) return;
 
956
    m_talkerListModel.swap (modelIndex.row(), modelIndex.row() - 1);
 
957
    modelIndex = m_talkerListModel.index (modelIndex.row() - 1, 0, QModelIndex());
 
958
    talkersView->scrollTo (modelIndex);
 
959
    talkersView->setCurrentIndex (modelIndex);
 
960
    updateTalkerButtons();
 
961
    configChanged();
 
962
}
 
963
 
 
964
void KCMKttsMgr::slotHigherFilterPriorityButton_clicked()
 
965
{
 
966
    QModelIndex modelIndex = filtersView->currentIndex();
 
967
    if (!modelIndex.isValid()) return;
 
968
    m_filterListModel.swap (modelIndex.row(), modelIndex.row() - 1);
 
969
    modelIndex = m_filterListModel.index (modelIndex.row() - 1, 0, QModelIndex());
 
970
    filtersView->scrollTo (modelIndex);
 
971
    filtersView->setCurrentIndex (modelIndex);
 
972
    updateFilterButtons();
 
973
    configChanged();
 
974
}
 
975
 
 
976
void KCMKttsMgr::slotLowerTalkerPriorityButton_clicked()
 
977
{
 
978
    QModelIndex modelIndex = talkersView->currentIndex();
 
979
    if (!modelIndex.isValid()) return;
 
980
    m_talkerListModel.swap (modelIndex.row(), modelIndex.row() + 1);
 
981
    modelIndex = m_talkerListModel.index (modelIndex.row() + 1, 0, QModelIndex());
 
982
    talkersView->scrollTo (modelIndex);
 
983
    talkersView->setCurrentIndex (modelIndex);
 
984
    updateTalkerButtons();
 
985
    configChanged();
 
986
}
 
987
 
 
988
void KCMKttsMgr::slotLowerFilterPriorityButton_clicked()
 
989
{
 
990
    QModelIndex modelIndex = filtersView->currentIndex();
 
991
    if (!modelIndex.isValid()) return;
 
992
    m_filterListModel.swap (modelIndex.row(), modelIndex.row() + 1);
 
993
    modelIndex = m_filterListModel.index (modelIndex.row() + 1, 0, QModelIndex());
 
994
    filtersView->scrollTo (modelIndex);
 
995
    filtersView->setCurrentIndex (modelIndex);
 
996
    updateFilterButtons();
 
997
    configChanged();
 
998
}
 
999
 
 
1000
/**
 
1001
* Update the status of the Talker buttons.
 
1002
*/
 
1003
void KCMKttsMgr::updateTalkerButtons()
 
1004
{
 
1005
    // kDebug() << "KCMKttsMgr::updateTalkerButtons: Running";
 
1006
    QModelIndex modelIndex = talkersView->currentIndex();
 
1007
    if (modelIndex.isValid()) {
 
1008
        removeTalkerButton->setEnabled (true);
 
1009
        configureTalkerButton->setEnabled (true);
 
1010
        higherTalkerPriorityButton->setEnabled (modelIndex.row() != 0);
 
1011
        lowerTalkerPriorityButton->setEnabled (modelIndex.row() < (m_talkerListModel.rowCount() - 1));
 
1012
    } else {
 
1013
        removeTalkerButton->setEnabled (false);
 
1014
        configureTalkerButton->setEnabled (false);
 
1015
        higherTalkerPriorityButton->setEnabled (false);
 
1016
        lowerTalkerPriorityButton->setEnabled (false);
 
1017
    }
 
1018
    // kDebug() << "KCMKttsMgr::updateTalkerButtons: Exiting";
 
1019
}
 
1020
 
 
1021
/**
 
1022
* Update the status of the normal Filter buttons.
 
1023
*/
 
1024
void KCMKttsMgr::updateFilterButtons()
 
1025
{
 
1026
    // kDebug() << "KCMKttsMgr::updateFilterButtons: Running";
 
1027
    QModelIndex modelIndex = filtersView->currentIndex();
 
1028
    if (modelIndex.isValid()) {
 
1029
        removeFilterButton->setEnabled (true);
 
1030
        configureFilterButton->setEnabled (true);
 
1031
        higherFilterPriorityButton->setEnabled (modelIndex.row() != 0);
 
1032
        lowerFilterPriorityButton->setEnabled (modelIndex.row() < (m_filterListModel.rowCount() - 1));
 
1033
    } else {
 
1034
        removeFilterButton->setEnabled (false);
 
1035
        configureFilterButton->setEnabled (false);
 
1036
        higherFilterPriorityButton->setEnabled (false);
 
1037
        lowerFilterPriorityButton->setEnabled (false);
 
1038
    }
 
1039
    // kDebug() << "KCMKttsMgr::updateFilterButtons: Exiting";
 
1040
}
 
1041
 
 
1042
/**
 
1043
* This signal is emitted whenever user checks/unchecks the Enable TTS System check box.
 
1044
*/
 
1045
void KCMKttsMgr::slotEnableJovie_toggled (bool)
 
1046
{
 
1047
    // Prevent re-entrancy.
 
1048
    static bool reenter;
 
1049
    if (reenter) return;
 
1050
    reenter = true;
 
1051
    // See if Jovie is running.
 
1052
    bool kttsdRunning = (QDBusConnection::sessionBus().interface()->isServiceRegistered (QLatin1String( "org.kde.jovie" )));
 
1053
 
 
1054
    // kDebug() << "KCMKttsMgr::slotEnableKttsd_toggled: kttsdRunning = " << kttsdRunning;
 
1055
    // If Enable Jovie check box is checked and it is not running, then start Jovie.
 
1056
    if (enableJovieCheckBox->isChecked()) {
 
1057
        if (!kttsdRunning) {
 
1058
            // kDebug() << "KCMKttsMgr::slotEnableKttsd_toggled:: Starting Jovie";
 
1059
            QString error;
 
1060
            if (KToolInvocation::startServiceByDesktopName (QLatin1String( "jovie" ), QStringList(), &error)) {
 
1061
                kDebug() << "Starting Jovie failed with message " << error;
 
1062
                enableJovieCheckBox->setChecked (false);
 
1063
 
 
1064
            } else {
 
1065
                configChanged();
 
1066
                jovieStarted();
 
1067
            }
 
1068
        }
 
1069
    } else
 
1070
        // If check box is not checked and it is running, then stop Jovie.
 
1071
    {
 
1072
        if (kttsdRunning) {
 
1073
            // kDebug() << "KCMKttsMgr::slotEnableKttsd_toggled:: Stopping Jovie";
 
1074
            if (!m_kspeech)
 
1075
                m_kspeech = new OrgKdeKSpeechInterface (QLatin1String( "org.kde.jovie" ), QLatin1String( "/KSpeech" ), QDBusConnection::sessionBus());
 
1076
            m_kspeech->kttsdExit();
 
1077
            delete m_kspeech;
 
1078
            m_kspeech = 0;
 
1079
            configChanged();
 
1080
        }
 
1081
    }
 
1082
    reenter = false;
 
1083
}
 
1084
 
 
1085
/**
 
1086
* This slot is called whenever KTTSD starts or restarts.
 
1087
*/
 
1088
void KCMKttsMgr::jovieStarted()
 
1089
{
 
1090
    // kDebug() << "KCMKttsMgr::jovieStarted: Running";
 
1091
    bool kttsdLoaded = (m_jobMgrWidget != 0);
 
1092
    // Load Job Manager Part library.
 
1093
    if (!kttsdLoaded) {
 
1094
        m_jobMgrWidget = new KttsJobMgr (this);
 
1095
        if (m_jobMgrWidget) {
 
1096
            connect (m_jobMgrWidget, SIGNAL (configChanged()), this, SLOT (configChanged()));
 
1097
            // Add the Job Manager part as a new tab.
 
1098
            mainTab->addTab (m_jobMgrWidget, i18n ("Jobs"));
 
1099
            kttsdLoaded = true;
 
1100
        } else
 
1101
            kDebug() << "KCMKttsMgr::jovieStarted: Could not create kttsjobmgr part.";
 
1102
    }
 
1103
    // Check/Uncheck the Enable KTTSD check box.
 
1104
    if (kttsdLoaded) {
 
1105
        enableJovieCheckBox->setChecked (true);
 
1106
        m_kspeech = new OrgKdeKSpeechInterface (QLatin1String( "org.kde.jovie" ), QLatin1String( "/KSpeech" ), QDBusConnection::sessionBus());
 
1107
        m_kspeech->setParent (this);
 
1108
        m_kspeech->setApplicationName (QLatin1String( "KCMKttsMgr" ));
 
1109
        m_kspeech->setIsSystemManager (true);
 
1110
        // Connect KTTSD DBUS signals to our slots.
 
1111
        connect (m_kspeech, SIGNAL (kttsdStarted()),
 
1112
                 this, SLOT (jovieStarted()));
 
1113
        connect (m_kspeech, SIGNAL (kttsdExiting()),
 
1114
                 this, SLOT (jovieExiting()));
 
1115
        connect (QDBusConnection::sessionBus().interface(), SIGNAL (serviceUnregistered(QString)),
 
1116
                 this, SLOT (slotServiceUnregistered(QString)));
 
1117
        connect (QDBusConnection::sessionBus().interface(), SIGNAL (serviceOwnerChanged(QString,QString,QString)),
 
1118
                 this, SLOT (slotServiceOwnerChanged(QString,QString,QString)));
 
1119
 
 
1120
        kttsdVersion->setText (i18n ("Jovie Version: %1", m_kspeech->version()));
 
1121
 
 
1122
    } else {
 
1123
        enableJovieCheckBox->setChecked (false);
 
1124
        delete m_kspeech;
 
1125
        m_kspeech = 0;
 
1126
    }
 
1127
}
 
1128
 
 
1129
void KCMKttsMgr::slotServiceUnregistered (const QString &service)
 
1130
{
 
1131
    if (service == QLatin1String ("org.kde.jovie")) {
 
1132
        jovieExiting();
 
1133
    }
 
1134
 
 
1135
}
 
1136
 
 
1137
void KCMKttsMgr::slotServiceOwnerChanged (const QString &service, const QString &, const QString &newOwner)
 
1138
{
 
1139
    if (service == QLatin1String ("org.kde.jovie") && newOwner.isEmpty()) {
 
1140
        jovieExiting();
 
1141
    }
 
1142
}
 
1143
 
 
1144
/**
 
1145
* This slot is called whenever KTTSD is about to exit.
 
1146
*/
 
1147
void KCMKttsMgr::jovieExiting()
 
1148
{
 
1149
    // kDebug() << "KCMKttsMgr::kttsdExiting: Running";
 
1150
    if (m_jobMgrWidget) {
 
1151
        mainTab->removeTab (wpJobs);
 
1152
        delete m_jobMgrWidget;
 
1153
        m_jobMgrWidget = 0;
 
1154
    }
 
1155
 
 
1156
    enableJovieCheckBox->setChecked (false);
 
1157
    disconnect (QDBusConnection::sessionBus().interface(), 0, this, 0);
 
1158
    delete m_kspeech;
 
1159
    m_kspeech = 0;
 
1160
    kttsdVersion->setText (i18n ("Jovie not running"));
 
1161
}
 
1162
 
 
1163
/**
 
1164
* User has requested display of talker configuration dialog.
 
1165
*/
 
1166
void KCMKttsMgr::slotConfigureTalkerButton_clicked()
 
1167
{
 
1168
    // Get highlighted Talker from ListView.
 
1169
    QModelIndex modelIndex = talkersView->currentIndex();
 
1170
 
 
1171
    if (!modelIndex.isValid())
 
1172
        return;
 
1173
 
 
1174
    TalkerCode tc = m_talkerListModel.getRow(modelIndex.row());
 
1175
 
 
1176
    QPointer<AddTalker> dlg = new AddTalker (this);
 
1177
    dlg->setTalkerCode(tc);
 
1178
    if (dlg->exec() == QDialog::Accepted) {
 
1179
        TalkerCode code = dlg->getTalkerCode();
 
1180
 
 
1181
        // Change the existing talker code to this new code.
 
1182
        m_talkerListModel.updateRow(modelIndex.row(), code);
 
1183
 
 
1184
        configChanged();
 
1185
    }
 
1186
}
 
1187
 
 
1188
void KCMKttsMgr::slotConfigureFilterButton_clicked()
 
1189
{
 
1190
    configureFilterItem();
 
1191
}
 
1192
 
 
1193
/**
 
1194
 * User has requested display of filter configuration dialog.
 
1195
 */
 
1196
void KCMKttsMgr::configureFilterItem()
 
1197
{
 
1198
    // Get highlighted plugin from Filter ListView and load into memory.
 
1199
    QTreeView* lView;
 
1200
    FilterListModel* model;
 
1201
    lView = filtersView;
 
1202
    model = &m_filterListModel;
 
1203
    QModelIndex modelIndex = lView->currentIndex();
 
1204
    if (!modelIndex.isValid()) return;
 
1205
    FilterItem fi = model->getRow (modelIndex.row());
 
1206
    QString filterID = fi.id;
 
1207
    QString filterPlugInName = fi.plugInName;
 
1208
    QString desktopEntryName = fi.desktopEntryName;
 
1209
    if (desktopEntryName.isEmpty()) return;
 
1210
    m_loadedFilterPlugIn = loadFilterPlugin (desktopEntryName);
 
1211
    if (!m_loadedFilterPlugIn) return;
 
1212
    // kDebug() << "KCMKttsMgr::slot_configureFilter: plugin for " << filterPlugInName << " loaded successfully.";
 
1213
 
 
1214
    // Tell plugin to load its configuration.
 
1215
    // kDebug() << "KCMKttsMgr::slot_configureFilter: about to call plugin load() method with Filter ID = " << filterID;
 
1216
    m_loadedFilterPlugIn->load (m_config, QLatin1String ("Filter_") + filterID);
 
1217
 
 
1218
    // Display configuration dialog.
 
1219
    configureFilter();
 
1220
 
 
1221
    // Did user Cancel?
 
1222
    if (!m_loadedFilterPlugIn) {
 
1223
        delete m_configDlg;
 
1224
        m_configDlg = 0;
 
1225
        return;
 
1226
    }
 
1227
 
 
1228
    // Get user's name for the plugin.
 
1229
    QString userFilterName = m_loadedFilterPlugIn->userPlugInName();
 
1230
 
 
1231
    // If user properly configured the plugin, save the configuration.
 
1232
    if (!userFilterName.isEmpty()) {
 
1233
        // Let plugin save its configuration.
 
1234
        m_loadedFilterPlugIn->save (m_config, QLatin1String ("Filter_") + filterID);
 
1235
 
 
1236
        // Save configuration.
 
1237
        KConfigGroup filterConfig (m_config, QLatin1String ("Filter_") + filterID);
 
1238
        filterConfig.writeEntry ("DesktopEntryName", desktopEntryName);
 
1239
        filterConfig.writeEntry ("UserFilterName", userFilterName);
 
1240
        filterConfig.writeEntry ("Enabled", true);
 
1241
        filterConfig.writeEntry ("MultiInstance", m_loadedFilterPlugIn->supportsMultiInstance());
 
1242
 
 
1243
        m_config->sync();
 
1244
 
 
1245
        // Update display.
 
1246
        FilterItem fi;
 
1247
        fi.id = filterID;
 
1248
        fi.desktopEntryName = desktopEntryName;
 
1249
        fi.userFilterName = userFilterName;
 
1250
        fi.enabled = true;
 
1251
        fi.multiInstance = m_loadedFilterPlugIn->supportsMultiInstance();
 
1252
        model->updateRow (modelIndex.row(), fi);
 
1253
        // Inform Control Center that configuration has changed.
 
1254
        configChanged();
 
1255
    }
 
1256
 
 
1257
    delete m_configDlg;
 
1258
    m_configDlg = 0;
 
1259
}
 
1260
 
 
1261
/**
 
1262
* Display filter configuration dialog.  The plugin is assumed already loaded into
 
1263
* memory referenced by m_loadedFilterPlugIn.
 
1264
*/
 
1265
void KCMKttsMgr::configureFilter()
 
1266
{
 
1267
    if (!m_loadedFilterPlugIn) return;
 
1268
    m_configDlg = new KDialog (this);
 
1269
    m_configDlg->setCaption (i18n ("Filter Configuration"));
 
1270
    m_configDlg->setButtons (KDialog::Help | KDialog::Default | KDialog::Ok | KDialog::Cancel);
 
1271
    m_configDlg->setDefaultButton (KDialog::Cancel);
 
1272
    m_loadedFilterPlugIn->setMinimumSize (m_loadedFilterPlugIn->minimumSizeHint());
 
1273
    m_loadedFilterPlugIn->show();
 
1274
    m_configDlg->setMainWidget (m_loadedFilterPlugIn);
 
1275
    m_configDlg->setHelp (QLatin1String( "configure-filter" ), QLatin1String( "jovie" ));
 
1276
    m_configDlg->enableButtonOk (false);
 
1277
    connect (m_loadedFilterPlugIn, SIGNAL (changed(bool)), this, SLOT (slotConfigFilterDlg_ConfigChanged()));
 
1278
    connect (m_configDlg, SIGNAL (defaultClicked()), this, SLOT (slotConfigFilterDlg_DefaultClicked()));
 
1279
    connect (m_configDlg, SIGNAL (cancelClicked()), this, SLOT (slotConfigFilterDlg_CancelClicked()));
 
1280
    // Display the dialog.
 
1281
    m_configDlg->exec();
 
1282
}
 
1283
 
 
1284
/**
 
1285
* Count number of configured Filters with the specified plugin name.
 
1286
*/
 
1287
int KCMKttsMgr::countFilterPlugins (const QString& filterPlugInName)
 
1288
{
 
1289
    int cnt = 0;
 
1290
    for (int i = 0; i < m_filterListModel.rowCount(); ++i) {
 
1291
        FilterItem fi = m_filterListModel.getRow (i);
 
1292
        if (fi.plugInName == filterPlugInName) ++cnt;
 
1293
    }
 
1294
    return cnt;
 
1295
}
 
1296
 
 
1297
void KCMKttsMgr::slotConfigTalkerDlg_ConfigChanged()
 
1298
{
 
1299
    //m_configDlg->enableButtonOk(!m_loadedTalkerPlugIn->getTalkerCode().isEmpty());
 
1300
}
 
1301
 
 
1302
void KCMKttsMgr::slotConfigFilterDlg_ConfigChanged()
 
1303
{
 
1304
    m_configDlg->enableButtonOk (!m_loadedFilterPlugIn->userPlugInName().isEmpty());
 
1305
}
 
1306
 
 
1307
void KCMKttsMgr::slotConfigTalkerDlg_DefaultClicked()
 
1308
{
 
1309
    //m_loadedTalkerPlugIn->defaults();
 
1310
}
 
1311
 
 
1312
void KCMKttsMgr::slotConfigFilterDlg_DefaultClicked()
 
1313
{
 
1314
    m_loadedFilterPlugIn->defaults();
 
1315
}
 
1316
 
 
1317
void KCMKttsMgr::slotConfigTalkerDlg_CancelClicked()
 
1318
{
 
1319
    //delete m_loadedTalkerPlugIn;
 
1320
    //m_loadedTalkerPlugIn = 0;
 
1321
}
 
1322
 
 
1323
void KCMKttsMgr::slotConfigFilterDlg_CancelClicked()
 
1324
{
 
1325
    delete m_loadedFilterPlugIn;
 
1326
    m_loadedFilterPlugIn = 0;
 
1327
}
 
1328
 
 
1329
/**
 
1330
 * Uses KTrader to convert a translated Filter Plugin Name to DesktopEntryName.
 
1331
 * @param name                   The translated plugin name.  From Name= line in .desktop file.
 
1332
 * @return                       DesktopEntryName.  The name of the .desktop file (less .desktop).
 
1333
 *                               QString() if not found.
 
1334
 */
 
1335
QString KCMKttsMgr::FilterNameToDesktopEntryName (const QString& name)
 
1336
{
 
1337
    if (name.isEmpty()) return QString();
 
1338
    const KService::List  offers =  KServiceTypeTrader::self()->query (QLatin1String( "Jovie/FilterPlugin" ));
 
1339
    for (int ndx = 0; ndx < offers.count(); ++ndx)
 
1340
        if (offers[ndx]->name() == name)
 
1341
            return offers[ndx]->desktopEntryName();
 
1342
    return QString();
 
1343
}
 
1344
 
 
1345
/**
 
1346
 * Uses KTrader to convert a DesktopEntryName into a translated Filter Plugin Name.
 
1347
 * @param desktopEntryName       The DesktopEntryName.
 
1348
 * @return                       The translated Name of the plugin, from Name= line in .desktop file.
 
1349
 */
 
1350
QString KCMKttsMgr::FilterDesktopEntryNameToName (const QString& desktopEntryName)
 
1351
{
 
1352
    if (desktopEntryName.isEmpty()) return QString();
 
1353
    KService::List offers = KServiceTypeTrader::self()->query (QLatin1String( "Jovie/FilterPlugin" ),
 
1354
                            QString (QLatin1String( "DesktopEntryName == '%1'" )).arg (desktopEntryName));
 
1355
 
 
1356
    if (offers.count() == 1)
 
1357
        return offers[0]->name();
 
1358
    else
 
1359
        return QString();
 
1360
}
 
1361
 
 
1362
 
 
1363
void KCMKttsMgr::slotFilterListView_clicked (const QModelIndex & index)
 
1364
{
 
1365
    if (!index.isValid()) return;
 
1366
    if (index.column() != 0) return;
 
1367
    if (index.row() < 0 || index.row() >= m_filterListModel.rowCount()) return;
 
1368
    FilterItem fi = m_filterListModel.getRow (index.row());
 
1369
    fi.enabled = !fi.enabled;
 
1370
    m_filterListModel.updateRow (index.row(), fi);
 
1371
    configChanged();
 
1372
}