Text priority when speaking clipboard or file but msg priority when testing talkers.
[kdeaccessibility.git] / kttsd / kttsjobmgr / kttsjobmgr.cpp
blobd51d40d046d8b55221e28ad39a3c8e5b2edc2ac9
1 /***************************************************** vim:set ts=4 sw=4 sts=4:
2 A KPart to display running jobs in KTTSD and permit user to stop, rewind,
3 advance, change Talker, etc.
4 -------------------
5 Copyright : (C) 2004,2005 by Gary Cramblitt <garycramblitt@comcast.net>
6 -------------------
7 Current Maintainer: Gary Cramblitt <garycramblitt@comcast.net>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 ******************************************************************************/
24 // QT includes.
25 #include <QObject>
26 #include <QLabel>
27 #include <QSplitter>
28 #include <QClipboard>
29 #include <QPushButton>
30 #include <QList>
31 #include <QTreeView>
32 #include <QMimeData>
33 #include <QtDBus>
35 // KDE includes.
36 #include <kinstance.h>
37 #include <klocale.h>
38 #include <kaboutdata.h>
39 #include <kicon.h>
40 #include <kdebug.h>
41 #include <kencodingfiledialog.h>
42 #include <kapplication.h>
43 #include <kinputdialog.h>
44 #include <ktextedit.h>
45 #include <kvbox.h>
46 #include <kdemacros.h>
47 #include <kparts/genericfactory.h>
48 #include <kspeech.h>
50 // KTTS includes.
51 #include "talkercode.h"
52 #include "selecttalkerdlg.h"
53 #include "jobinfolistmodel.h"
55 // KttsJobMgr includes.
56 #include "kttsjobmgr.h"
57 #include "kttsjobmgr.moc"
59 typedef KParts::GenericFactory<KttsJobMgrPart> KttsJobMgrPartFactory;
60 K_EXPORT_COMPONENT_FACTORY( libkttsjobmgrpart, KttsJobMgrPartFactory )
62 KAboutData* KttsJobMgrPart::createAboutData()
64 KAboutData *about = new KAboutData("kttsjobmgr", I18N_NOOP("KttsJobMgr"), "1.99");
65 return about;
68 KttsJobMgrPart::KttsJobMgrPart(QWidget *parentWidget, QObject *parent, const QStringList& args) :
69 KParts::ReadOnlyPart(parent)
70 // m_kspeech(QDBus::sessionBus().findInterface<org::kde::KSpeech>("org.kde.kttsd", "/KSpeech"))
72 //DBusAbstractInterfacePrivate
73 Q_UNUSED(args);
74 m_kspeech = new OrgKdeKSpeechInterface("org.kde.kttsd", "/KSpeech", QDBusConnection::sessionBus());
75 m_kspeech->setParent(this);
77 // Establish ourself as a System Manager.
78 m_kspeech->setApplicationName("KCMKttsMgr");
79 m_kspeech->setIsSystemManager(true);
81 // Initialize some variables.
82 m_selectOnTextSet = false;
83 m_buttonBox = 0;
85 // All the ktts components use the same catalog.
86 KGlobal::locale()->insertCatalog("kttsd");
88 // Create a QVBox to host everything.
89 KVBox* vBox = new KVBox(parentWidget);
90 //vBox->setMargin(6);
92 // Create a splitter to contain the Job List View and the current sentence.
93 QSplitter* splitter = new QSplitter(vBox);
94 splitter->setOrientation(Qt::Vertical);
96 // Create Job List View widget and model.
97 m_jobListView = new QTreeView( splitter );
98 m_jobListModel = new JobInfoListModel();
99 m_jobListView->setModel(m_jobListModel);
101 // Select by row.
102 m_jobListView->setSelectionMode(QAbstractItemView::SingleSelection);
103 m_jobListView->setSelectionBehavior(QAbstractItemView::SelectRows);
105 // Not a tree.
106 m_jobListView->setRootIsDecorated(false);
108 // TODO: Do not sort the list.
109 // m_jobListView->setSorting(-1);
111 QString jobListViewWT = i18n(
112 "<p>These are all the text jobs. The <b>State</b> column "
113 "may be:"
114 "<ul>"
115 "<li><b>Queued</b> - the job is waiting and will not be spoken until its state "
116 "is changed to <b>Waiting</b> by clicking the <b>Resume</b> or <b>Restart</b> buttons.</li>"
117 "<li><b>Waiting</b> - the job is ready to be spoken. It will be spoken when the jobs "
118 "preceding it in the list have finished.</li>"
119 "<li><b>Speaking</b> - the job is speaking. The <b>Position</b> column shows the current "
120 "sentence of the job being spoken. You may pause a speaking job by clicking the "
121 "<b>Hold</b> button.</li>"
122 "<li><b>Paused</b> - the job is currently paused. Paused jobs prevent jobs below them "
123 "from speaking. Use the <b>Resume</b> or <b>Restart</b> buttons to resume speaking the "
124 "job, or click <b>Later</b> to move the job down in the list.</li>"
125 "<li><b>Finished</b> - the job has finished speaking. When a second job finishes, "
126 "this one will be deleted. You may click <b>Restart</b> to repeat the job.</li>"
127 "</ul>"
128 "<em>Note</em>: Messages, Warnings, and Screen Reader Output do not appear in this list. "
129 "See the Handbook for more information."
130 "</p>");
131 m_jobListView->setWhatsThis( jobListViewWT);
133 // splitter->setResizeMode(m_jobListView, QSplitter::Stretch);
135 // Create a VBox to hold buttons and current sentence.
136 KVBox* bottomBox = new KVBox(splitter);
138 // Create a box to hold buttons.
139 m_buttonBox = new KVBox(bottomBox);
140 m_buttonBox->setSpacing(6);
142 // Create 3 HBoxes to host buttons.
143 KHBox* hbox1 = new KHBox(m_buttonBox);
144 hbox1->setSpacing(6);
145 KHBox* hbox2 = new KHBox(m_buttonBox);
146 hbox2->setSpacing(6);
147 KHBox* hbox3 = new KHBox(m_buttonBox);
148 hbox3->setSpacing(6);
150 // Do not let button box stretch vertically.
151 m_buttonBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
153 // All the buttons with "job_" at start of their names will be enabled/disabled when a job is
154 // selected in the Job List View.
156 QPushButton* btn;
157 QString wt;
158 btn = new QPushButton(KIcon("stop"), i18n("Hold"), hbox1);
159 btn->setObjectName("job_hold");
160 wt = i18n(
161 "<p>Changes a job to Paused state. If currently speaking, the job stops speaking. "
162 "Paused jobs prevent jobs that follow them from speaking, so either click "
163 "<b>Resume</b> to make the job speakable, or click <b>Later</b> to move it "
164 "down in the list.</p>");
165 btn->setWhatsThis(wt);
166 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_hold()));
167 btn = new QPushButton(KIcon("exec"), i18n("Resume"), hbox1);
168 btn->setObjectName("job_resume");
169 wt = i18n(
170 "<p>Resumes a paused job or changes a Queued job to Waiting. If the job is the "
171 "top speakable job in the list, it begins speaking.</p>");
172 btn->setWhatsThis(wt);
173 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_resume()));
174 btn = new QPushButton(KIcon("redo"), i18n("R&estart"), hbox1);
175 btn->setObjectName("job_restart");
176 wt = i18n(
177 "<p>Rewinds a job to the beginning and changes its state to Waiting. If the job "
178 "is the top speakable job in the list, it begins speaking.</p>");
179 btn->setWhatsThis(wt);
180 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_restart()));
181 btn = new QPushButton(KIcon("edittrash"), i18n("Re&move"), hbox1);
182 btn->setObjectName("job_remove");
183 wt = i18n(
184 "<p>Deletes the job. If it is currently speaking, it stops speaking. The next "
185 "speakable job in the list begins speaking.</p>");
186 btn->setWhatsThis(wt);
187 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_remove()));
188 btn = new QPushButton(KIcon("down"), i18n("&Later"), hbox1);
189 btn->setObjectName("job_later");
190 wt = i18n(
191 "<p>Moves a job downward in the list so that it will be spoken later. If the job "
192 "is currently speaking, its state changes to Paused.</p>");
193 btn->setWhatsThis(wt);
194 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_move()));
196 btn = new QPushButton(KIcon("1leftarrow"), i18n("&Previous Sentence"), hbox2);
197 btn->setObjectName("job_prevsentence");
198 wt = i18n(
199 "<p>Rewinds a job to the previous sentence.</p>");
200 btn->setWhatsThis(wt);
201 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_prev_sen()));
202 btn = new QPushButton(KIcon("1rightarrow"), i18n("&Next Sentence"), hbox2);
203 btn->setObjectName("job_nextsentence");
204 wt = i18n(
205 "<p>Advances a job to the next sentence.</p>");
206 btn->setWhatsThis(wt);
207 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_next_sen()));
209 btn = new QPushButton(KIcon("klipper"), i18n("&Speak Clipboard"), hbox3);
210 btn->setObjectName("speak_clipboard");
211 wt = i18n(
212 "<p>Queues the current contents of the clipboard for speaking and sets its state "
213 "to Waiting. If the job is the topmost in the list, it begins speaking. "
214 "The job will be spoken by the topmost Talker in the <b>Talkers</b> tab.</p>");
215 btn->setWhatsThis(wt);
216 connect (btn, SIGNAL(clicked()), this, SLOT(slot_speak_clipboard()));
217 btn = new QPushButton(KIcon("fileopen"), i18n("Spea&k File"), hbox3);
218 btn->setObjectName("speak_file");
219 wt = i18n(
220 "<p>Prompts you for a file name and queues the contents of the file for speaking. "
221 "You must click the <b>Resume</b> button before the job will be speakable. "
222 "The job will be spoken by the topmost Talker in the <b>Talkers</b> tab.</p>");
223 btn->setWhatsThis(wt);
224 connect (btn, SIGNAL(clicked()), this, SLOT(slot_speak_file()));
225 btn = new QPushButton(KIcon("translate"), i18n("Change Talker"), hbox3);
226 btn->setObjectName("job_changetalker");
227 wt = i18n(
228 "<p>Prompts you with a list of your configured Talkers from the <b>Talkers</b> tab. "
229 "The job will be spoken using the selected Talker.</p>");
230 btn->setWhatsThis(wt);
231 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_change_talker()));
232 btn = new QPushButton(KIcon("reload_page"), i18n("&Refresh"), hbox3);
233 btn->setObjectName("refresh");
234 wt = i18n(
235 "<p>Refresh the list of jobs.</p>");
236 btn->setWhatsThis(wt);
237 connect (btn, SIGNAL(clicked()), this, SLOT(slot_refresh()));
239 // Disable job buttons until a job is selected.
240 enableJobActions(false);
242 // Create a VBox for the current sentence and sentence label.
243 KVBox* sentenceVBox = new KVBox(bottomBox);
245 // Create a label for current sentence.
246 QLabel* currentSentenceLabel = new QLabel(sentenceVBox);
247 currentSentenceLabel->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
248 currentSentenceLabel->setText(i18n("Current Sentence"));
250 // Create a box to contain the current sentence.
251 m_currentSentence = new KTextEdit(sentenceVBox);
252 m_currentSentence->setReadOnly(true);
253 m_currentSentence->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
254 m_currentSentence->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
255 m_currentSentence->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
256 wt = i18n(
257 "<p>The text of the sentence currently speaking.</p>");
258 m_currentSentence->setWhatsThis(wt);
260 // Set the main widget for the part.
261 setWidget(vBox);
263 connect(m_jobListView, SIGNAL(clicked(const QModelIndex&)),
264 this, SLOT(slot_jobListView_clicked()));
266 // Fill the Job List.
267 refreshJobList();
269 // Select first item (if any).
270 autoSelectInJobListView();
272 // Connect DBUS Signals emitted by KTTSD to our own slots.
273 connect(m_kspeech, SIGNAL(kttsdStarted()),
274 this, SLOT(kttsdStarted()));
275 connect(m_kspeech, SIGNAL(jobStateChanged(const QString&, int, int)),
276 this, SLOT(jobStateChanged(const QString&, int, int)));
277 connect(m_kspeech, SIGNAL(marker(const QString&, int, int, const QString&)),
278 this, SLOT(marker(const QString&, int, int, const QString&)));
280 m_extension = new KttsJobMgrBrowserExtension(this);
282 // Divide splitter in half. ListView gets half. Buttons and Current Sentence get half.
283 int halfSplitterSize = splitter->height()/2;
284 QList<int> splitterSizes;
285 splitterSizes.append(halfSplitterSize);
286 splitterSizes.append(halfSplitterSize);
287 splitter->setSizes(splitterSizes);
290 KttsJobMgrPart::~KttsJobMgrPart()
292 KGlobal::locale()->removeCatalog("kttsd");
293 closeUrl();
294 delete m_jobListModel;
297 bool KttsJobMgrPart::openFile()
299 return true;
302 bool KttsJobMgrPart::closeUrl()
304 return true;
308 * This slot is connected to the Job List View clicked signal.
310 void KttsJobMgrPart::slot_jobListView_clicked()
312 // Enable job buttons.
313 enableJobActions(true);
317 * Slots connected to buttons.
319 void KttsJobMgrPart::slot_job_hold()
321 m_kspeech->pause();
324 void KttsJobMgrPart::slot_job_resume()
326 m_kspeech->resume();
329 void KttsJobMgrPart::slot_job_restart()
331 int jobNum = getCurrentJobNum();
332 // kDebug() << "KttsJobMgrPart::slot_job_restart: jobNum = " << jobNum << endl;
333 if (jobNum)
335 int seq = m_kspeech->moveRelSentence(jobNum, 0);
336 m_kspeech->moveRelSentence(jobNum, -seq);
337 refreshJob(jobNum);
341 void KttsJobMgrPart::slot_job_prev_sen()
343 int jobNum = getCurrentJobNum();
344 if (jobNum)
346 m_kspeech->moveRelSentence(jobNum, -1);
347 refreshJob(jobNum);
351 void KttsJobMgrPart::slot_job_next_sen()
353 int jobNum = getCurrentJobNum();
354 if (jobNum)
356 m_kspeech->moveRelSentence(jobNum, 1);
357 refreshJob(jobNum);
361 void KttsJobMgrPart::slot_job_remove()
363 int jobNum = getCurrentJobNum();
364 if (jobNum)
366 m_kspeech->removeJob(jobNum);
367 m_currentSentence->clear();
371 void KttsJobMgrPart::slot_job_move()
373 int jobNum = getCurrentJobNum();
374 if (jobNum)
376 m_kspeech->moveJobLater(jobNum);
377 refreshJobList();
378 // Select the job we just moved.
379 QModelIndex index = m_jobListModel->jobNumToIndex(jobNum);
380 if (index.isValid())
382 m_jobListView->setCurrentIndex(index);
383 slot_jobListView_clicked();
388 void KttsJobMgrPart::slot_job_change_talker()
390 QModelIndex index = m_jobListView->currentIndex();
391 if (index.isValid())
393 JobInfo job = m_jobListModel->getRow(index.row());
394 QString talkerID = job.talkerID;
395 QStringList talkerIDs = m_talkerCodesToTalkerIDs.values();
396 int ndx = talkerIDs.indexOf(talkerID);
397 QString talkerCode;
398 if (ndx >= 0) talkerCode = m_talkerCodesToTalkerIDs.keys()[ndx];
399 SelectTalkerDlg dlg(widget(), "selecttalkerdialog", i18n("Select Talker"), talkerCode, true);
400 int dlgResult = dlg.exec();
401 if (dlgResult != KDialog::Accepted) return;
402 talkerCode = dlg.getSelectedTalkerCode();
403 int jobNum = job.jobNum;
404 m_kspeech->changeJobTalker(jobNum, talkerCode);
405 refreshJob(jobNum);
409 void KttsJobMgrPart::slot_speak_clipboard()
411 // kDebug() << "KttsJobMgrPart::slot_speak_clipboard: running" << endl;
413 // Get the clipboard object.
414 QClipboard *cb = kapp->clipboard();
416 // Copy text from the clipboard.
417 QString text;
418 KSpeech::SayOptions sayOptions = KSpeech::soNone;
419 const QMimeData* data = cb->mimeData();
420 if (data)
422 if (data->hasFormat("text/html"))
424 // if (m_kspeech->supportsMarkup(NULL, KSpeech::mtHtml))
425 text = data->html();
426 sayOptions = KSpeech::soHtml;
428 if (data->hasFormat("text/ssml"))
430 // if (m_kspeech->supportsMarkup(NULL, KSpeech::mtSsml))
432 QByteArray d = data->data("text/ssml");
433 text = QString(d);
434 sayOptions = KSpeech::soSsml;
438 if (text.isEmpty()) {
439 text = cb->text();
440 sayOptions = KSpeech::soPlainText;
443 // Speak it.
444 if ( !text.isEmpty() )
446 m_kspeech->say(text, sayOptions);
447 // int jobNum = m_kspeech->say(text, sayOptions);
448 // kDebug() << "KttsJobMgrPart::slot_speak_clipboard: started jobNum " << jobNum << endl;
449 // Set flag so that the job we just created will be selected when textSet signal is received.
450 m_selectOnTextSet = true;
454 void KttsJobMgrPart::slot_speak_file()
456 KEncodingFileDialog dlg;
457 KEncodingFileDialog::Result result = dlg.getOpenFileNameAndEncoding();
458 if (result.fileNames.count() == 1)
460 // kDebug() << "KttsJobMgr::slot_speak_file: calling setFile with filename " <<
461 // result.fileNames[0] << " and encoding " << result.encoding << endl;
462 m_kspeech->sayFile(result.fileNames[0], result.encoding);
466 void KttsJobMgrPart::slot_refresh()
468 // Clear TalkerID cache.
469 m_talkerCodesToTalkerIDs.clear();
470 // Get current job number.
471 int jobNum = getCurrentJobNum();
472 refreshJobList();
473 // Select the previously-selected job.
474 if (jobNum)
476 QModelIndex index = m_jobListModel->jobNumToIndex(jobNum);
477 if (index.isValid())
479 m_jobListView->setCurrentIndex(index);
480 slot_jobListView_clicked();
487 * Get the Job Number of the currently-selected job in the Job List View.
488 * @return Job Number of currently-selected job.
489 * 0 if no currently-selected job.
491 int KttsJobMgrPart::getCurrentJobNum()
493 int jobNum = 0;
494 QModelIndex index = m_jobListView->currentIndex();
495 if (index.isValid())
496 jobNum = m_jobListModel->getRow(index.row()).jobNum;
497 return jobNum;
501 * Retrieves JobInfo from KTTSD, creates and fills JobInfo object.
502 * @param jobNum Job Number.
504 JobInfo* KttsJobMgrPart::retrieveJobInfo(int jobNum)
506 QByteArray jobInfo = m_kspeech->getJobInfo(jobNum);
507 if (jobInfo != QByteArray()) {
508 JobInfo* job = new JobInfo();
509 QDataStream stream(&jobInfo, QIODevice::ReadOnly);
510 qint32 priority;
511 qint32 state;
512 QString talkerCode;
513 qint32 sentenceNum;
514 qint32 sentenceCount;
515 stream >> priority;
516 stream >> state;
517 stream >> job->appId;
518 stream >> talkerCode;
519 stream >> sentenceNum;
520 stream >> sentenceCount;
521 stream >> job->applicationName;
522 job->jobNum = jobNum;
523 job->priority = priority;
524 job->state = state;
525 job->sentenceNum = sentenceNum;
526 job->sentenceCount = sentenceCount;
527 job->talkerID = cachedTalkerCodeToTalkerID(talkerCode);
528 return job;
530 return NULL;
534 * Refresh display of a single job in the JobListView.
535 * @param jobNum Job Number.
537 void KttsJobMgrPart::refreshJob(int jobNum)
539 QModelIndex index = m_jobListModel->jobNumToIndex(jobNum);
540 if (index.isValid()) {
541 JobInfo* job = retrieveJobInfo(jobNum);
542 if (job)
543 m_jobListModel->updateRow(index.row(), *job);
544 else
545 m_jobListModel->removeRow(index.row());
550 * Fill the Job List View.
552 void KttsJobMgrPart::refreshJobList()
554 // kDebug() << "KttsJobMgrPart::refreshJobList: Running" << endl;
555 m_jobListModel->clear();
556 JobInfoList jobInfoList;
557 enableJobActions(false);
558 QStringList jobNums = m_kspeech->getJobNumbers(KSpeech::jpAll);
559 for (int ndx = 0; ndx < jobNums.count(); ++ndx)
561 QString jobNumStr = jobNums[ndx];
562 kDebug() << "jobNumStr = " << jobNumStr << endl;
563 int jobNum = jobNumStr.toInt(0, 10);
564 kDebug() << "jobNum = " << jobNum << endl;
565 JobInfo* job = retrieveJobInfo(jobNum);
566 if (job)
567 jobInfoList.append(*job);
569 m_jobListModel->setDatastore(jobInfoList);
573 * If nothing selected in Job List View and list not empty, select top item.
574 * If nothing selected and list is empty, disable job buttons.
576 void KttsJobMgrPart::autoSelectInJobListView()
578 // If something selected, nothing to do.
579 if (m_jobListView->currentIndex().isValid()) return;
580 // If empty, disable job buttons.
582 if (m_jobListModel->rowCount() == 0)
583 enableJobActions(false);
584 else
586 // Select first item.
587 m_jobListView->setCurrentIndex(m_jobListModel->index(0, 0));
588 slot_jobListView_clicked();
593 * Return the Talker ID corresponding to a Talker Code, retrieving from cached list if present.
594 * @param talkerCode Talker Code.
595 * @return Talker ID.
597 QString KttsJobMgrPart::cachedTalkerCodeToTalkerID(const QString& talkerCode)
599 // If in the cache, return that.
600 if (m_talkerCodesToTalkerIDs.contains(talkerCode))
601 return m_talkerCodesToTalkerIDs[talkerCode];
602 else
604 // Otherwise, retrieve Talker ID from KTTSD and cache it.
605 QString talkerID = m_kspeech->talkerToTalkerId(talkerCode);
606 m_talkerCodesToTalkerIDs[talkerCode] = talkerID;
607 // kdDebug() << "KttsJobMgrPart::cachedTalkerCodeToTalkerID: talkerCode = " << talkerCode << " talkerID = " << talkerID << endl;
608 return talkerID;
613 * Enables or disables all the job-related buttons.
614 * @param enable True to enable the job-related butons. False to disable.
616 void KttsJobMgrPart::enableJobActions(bool enable)
618 if (!m_buttonBox) return;
620 #if defined Q_CC_MSVC && _MSC_VER < 1300
621 QList<QPushButton *> l = qfindChildren<QPushButton *>( m_buttonBox, QRegExp("job_*") );
622 #else
623 QList<QPushButton *> l = m_buttonBox->findChildren<QPushButton *>( QRegExp("job_*") );
624 #endif
625 QListIterator<QPushButton *> i(l);
627 while (i.hasNext())
628 (i.next())->setEnabled( enable );
630 if (enable)
632 // Later button only enables if currently selected list item is not bottom of list.
633 QModelIndex index = m_jobListView->currentIndex();
634 if (index.isValid())
636 bool enableLater = (index.row() < m_jobListModel->rowCount());
638 #if defined Q_CC_MSVC && _MSC_VER < 1300
639 l = qfindChildren<QPushButton *>( m_buttonBox, "job_later" );
640 #else
641 l = m_buttonBox->findChildren<QPushButton *>( "job_later" );
642 #endif
643 QListIterator<QPushButton *> it(l); // iterate over the buttons
644 while (it.hasNext())
645 // for each found object...
646 (it.next())->setEnabled( enableLater );
651 /** Slots connected to DBUS Signals emitted by KTTSD. */
654 * This signal is emitted when KTTSD starts or restarts after a call to reinit.
656 Q_SCRIPTABLE void KttsJobMgrPart::kttsdStarted() { slot_refresh(); }
660 * This signal is emitted each time the state of a job changes.
661 * @param appId The DBUS sender ID of the application that
662 * submitted the job.
663 * @param jobNum Job Number.
664 * @param state Job state. @see KSpeech::JobState.
666 Q_SCRIPTABLE void KttsJobMgrPart::jobStateChanged(const QString &appId, int jobNum, int state)
668 Q_UNUSED(appId);
669 switch (state)
671 case KSpeech::jsQueued:
673 QModelIndex index = m_jobListModel->jobNumToIndex(jobNum);
674 if (index.isValid())
675 refreshJob(jobNum);
676 else
678 JobInfo* job = retrieveJobInfo(jobNum);
679 if (job) {
680 m_jobListModel->appendRow(*job);
681 // Should we select this job?
682 if (m_selectOnTextSet)
684 m_jobListView->setCurrentIndex(m_jobListModel->jobNumToIndex(jobNum));
685 m_selectOnTextSet = false;
686 slot_jobListView_clicked();
690 // If a job not already selected, select this one.
691 autoSelectInJobListView();
692 break;
694 case KSpeech::jsSpeakable:
696 QModelIndex index = m_jobListModel->jobNumToIndex(jobNum);
697 if (index.isValid()) {
698 JobInfo* job = retrieveJobInfo(jobNum);
699 if (job)
700 m_jobListModel->updateRow(index.row(), *job);
701 else
702 m_jobListModel->removeRow(index.row());
704 break;
706 case KSpeech::jsFiltering:
707 case KSpeech::jsSpeaking:
708 case KSpeech::jsPaused:
709 case KSpeech::jsInterrupted:
710 case KSpeech::jsFinished:
712 QModelIndex index = m_jobListModel->jobNumToIndex(jobNum);
713 if (index.isValid())
715 JobInfo job = m_jobListModel->getRow(index.row());
716 job.state = state;
717 m_jobListModel->updateRow(index.row(), job);
719 m_currentSentence->setPlainText(QString());
720 break;
722 case KSpeech::jsDeleted:
724 QModelIndex index = m_jobListModel->jobNumToIndex(jobNum);
725 if (index.isValid())
726 m_jobListModel->removeRow(index.row());
727 autoSelectInJobListView();
728 break;
734 * This signal is emitted when a marker is processed.
735 * Currently only emits mtSentenceBegin and mtSentenceEnd.
736 * @param appId The DBUS sender ID of the application that submitted the job.
737 * @param jobNum Job Number of the job emitting the marker.
738 * @param markerType The type of marker.
739 * Currently either mtSentenceBegin or mtSentenceEnd.
740 * @param markerData Data for the marker.
741 * Currently, this is the sequence number of the sentence
742 * begun or ended. Sequence numbers begin at 1.
744 Q_SCRIPTABLE void KttsJobMgrPart::marker(const QString &appId, int jobNum, int markerType, const QString &markerData)
746 Q_UNUSED(appId);
747 if (KSpeech::mtSentenceBegin == markerType) {
748 QModelIndex index = m_jobListModel->jobNumToIndex(jobNum);
749 if (index.isValid())
751 JobInfo job = m_jobListModel->getRow(index.row());
752 int seq = markerData.toInt();
753 job.sentenceNum = seq;
754 m_jobListModel->updateRow(index.row(), job);
755 m_currentSentence->setPlainText(m_kspeech->getJobSentence(jobNum, seq));
758 if (KSpeech::mtSentenceEnd == markerType) {
759 m_currentSentence->setPlainText(QString());
764 KttsJobMgrBrowserExtension::KttsJobMgrBrowserExtension(KttsJobMgrPart *parent)
765 : KParts::BrowserExtension(parent)
769 KttsJobMgrBrowserExtension::~KttsJobMgrBrowserExtension()