Compile/link
[kdeaccessibility.git] / kttsd / kttsjobmgr / kttsjobmgr.cpp
blobf93bc3573f1110395d3668aca7162e16b3f4986e
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>
8 ******************************************************************************/
10 /***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; version 2 of the License. *
15 * *
16 ***************************************************************************/
18 // QT includes.
21 #include <qlabel.h>
22 #include <qsplitter.h>
23 #include <qclipboard.h>
24 #include <qpushbutton.h>
25 #include <qobject.h>
28 #include <qmime.h>
29 #include <QList>
30 #include <Q3TextEdit>
31 // KDE includes.
32 #include <kinstance.h>
33 #include <klocale.h>
34 #include <kaboutdata.h>
35 #include <klistview.h>
36 #include <kiconloader.h>
37 #include <kdebug.h>
38 #include <kencodingfiledialog.h>
39 #include <kapplication.h>
40 #include <kinputdialog.h>
41 #include <ktextedit.h>
42 #include <kvbox.h>
44 // KTTS includes.
45 #include "kspeech.h"
46 #include "talkercode.h"
47 #include "selecttalkerdlg.h"
48 #include "kttsjobmgr.h"
49 #include "kttsjobmgr.moc"
51 extern "C"
53 /**
54 * This function is the 'main' function of this part. It takes
55 * the form 'void *init_lib<library name>() It always returns a
56 * new factory object
58 KDE_EXPORT void *init_libkttsjobmgrpart()
60 return new KttsJobMgrFactory;
64 /**
65 * We need one static instance of the factory for our C 'main'
66 * function
68 KInstance *KttsJobMgrFactory::s_instance = 0L;
70 KttsJobMgrFactory::~KttsJobMgrFactory()
72 if (s_instance)
74 delete s_instance->aboutData();
75 delete s_instance;
78 s_instance = 0;
81 QObject *KttsJobMgrFactory::createObject(QObject *parent, const char *name, const char*,
82 const QStringList& )
84 QObject *obj = new KttsJobMgrPart((QWidget*)parent, name);
85 emit objectCreated(obj);
86 return obj;
89 KInstance *KttsJobMgrFactory::instance()
91 if ( !s_instance )
92 s_instance = new KInstance( aboutData() );
93 return s_instance;
96 KAboutData *KttsJobMgrFactory::aboutData()
98 KAboutData *about = new KAboutData("kttsjobmgr", I18N_NOOP("KttsJobMgr"), "1.99");
99 return about;
102 KttsJobMgrPart::KttsJobMgrPart(QWidget *parent, const char *name) :
103 DCOPStub("kttsd", "KSpeech"),
104 DCOPObject("kttsjobmgr_kspeechsink"),
105 KParts::ReadOnlyPart(parent)
107 setObjectName(name);
108 // Initialize some variables.
109 m_selectOnTextSet = false;
110 m_buttonBox = 0;
112 setInstance(KttsJobMgrFactory::instance());
114 // All the ktts components use the same catalogue.
115 KGlobal::locale()->insertCatalog("kttsd");
117 // Create a QVBox to host everything.
118 KVBox* vBox = new KVBox(parent);
119 //vBox->setMargin(6);
121 // Create a splitter to contain the Job List View and the current sentence.
122 QSplitter* splitter = new QSplitter(vBox);
123 splitter->setOrientation(Qt::Vertical);
125 // Create Job List View widget.
126 m_jobListView = new KListView( splitter );
127 m_jobListView->setObjectName( "joblistview" );
128 m_jobListView->setSelectionModeExt(KListView::Single);
129 m_jobListView->addColumn(i18n("Job Num"));
130 m_jobListView->addColumn(i18n("Owner"));
131 m_jobListView->addColumn(i18n("Talker ID"));
132 m_jobListView->addColumn(i18n("State"));
133 m_jobListView->addColumn(i18n("Position"));
134 m_jobListView->addColumn(i18n("Sentences"));
135 m_jobListView->addColumn(i18n("Part Num"));
136 m_jobListView->addColumn(i18n("Parts"));
138 // Do not sort the list.
139 m_jobListView->setSorting(-1);
141 QString jobListViewWT = i18n(
142 "<p>These are all the text jobs. The <b>State</b> column "
143 "may be:"
144 "<ul>"
145 "<li><b>Queued</b> - the job is waiting and will not be spoken until its state "
146 "is changed to <b>Waiting</b> by clicking the <b>Resume</b> or <b>Restart</b> buttons.</li>"
147 "<li><b>Waiting</b> - the job is ready to be spoken. It will be spoken when the jobs "
148 "preceding it in the list have finished.</li>"
149 "<li><b>Speaking</b> - the job is speaking. The <b>Position</b> column shows the current "
150 "sentence of the job being spoken. You may pause a speaking job by clicking the "
151 "<b>Hold</b> button.</li>"
152 "<li><b>Paused</b> - the job is currently paused. Paused jobs prevent jobs below them "
153 "from speaking. Use the <b>Resume</b> or <b>Restart</b> buttons to resume speaking the "
154 "job, or click <b>Later</b> to move the job down in the list.</li>"
155 "<li><b>Finished</b> - the job has finished speaking. When a second job finishes, "
156 "this one will be deleted. You may click <b>Restart</b> to repeat the job.</li>"
157 "</ul>"
158 "<em>Note</em>: Messages, Warnings, and Screen Reader Output do not appear in this list. "
159 "See the Handbook for more information."
160 "</p>");
161 m_jobListView->setWhatsThis( jobListViewWT);
163 // splitter->setResizeMode(m_jobListView, QSplitter::Stretch);
165 // Create a VBox to hold buttons and current sentence.
166 KVBox* bottomBox = new KVBox(splitter);
168 // Create a box to hold buttons.
169 m_buttonBox = new KVBox(bottomBox);
170 m_buttonBox->setSpacing(6);
172 // Create 3 HBoxes to host buttons.
173 KHBox* hbox1 = new KHBox(m_buttonBox);
174 hbox1->setSpacing(6);
175 KHBox* hbox2 = new KHBox(m_buttonBox);
176 hbox2->setSpacing(6);
177 KHBox* hbox3 = new KHBox(m_buttonBox);
178 hbox3->setSpacing(6);
180 // Do not let button box stretch vertically.
181 m_buttonBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
183 // All the buttons with "job_" at start of their names will be enabled/disabled when a job is
184 // selected in the Job List View.
185 // All the buttons with "part_" at the start of their names will be enabled/disabled when a
186 // job is selected in the Job List View that has multiple parts.
188 QPushButton* btn;
189 QString wt;
190 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("stop", KIcon::Small, 0, true),
191 i18n("Hold"), hbox1, "job_hold");
192 wt = i18n(
193 "<p>Changes a job to Paused state. If currently speaking, the job stops speaking. "
194 "Paused jobs prevent jobs that follow them from speaking, so either click "
195 "<b>Resume</b> to make the job speakable, or click <b>Later</b> to move it "
196 "down in the list.</p>");
197 btn->setWhatsThis( wt);
198 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_hold()));
199 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("exec", KIcon::Small, 0, true),
200 i18n("Resume"), hbox1, "job_resume");
201 wt = i18n(
202 "<p>Resumes a paused job or changes a Queued job to Waiting. If the job is the "
203 "top speakable job in the list, it begins speaking.</p>");
204 btn->setWhatsThis( wt);
205 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_resume()));
206 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("redo", KIcon::Small, 0, true),
207 i18n("R&estart"), hbox1, "job_restart");
208 wt = i18n(
209 "<p>Rewinds a job to the beginning and changes its state to Waiting. If the job "
210 "is the top speakable job in the list, it begins speaking.</p>");
211 btn->setWhatsThis( wt);
212 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_restart()));
213 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("edittrash", KIcon::Small, 0, true),
214 i18n("Re&move"), hbox1, "job_remove");
215 wt = i18n(
216 "<p>Deletes the job. If it is currently speaking, it stops speaking. The next "
217 "speakable job in the list begins speaking.</p>");
218 btn->setWhatsThis( wt);
219 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_remove()));
220 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("down", KIcon::Small, 0, true),
221 i18n("&Later"), hbox1, "job_later");
222 wt = i18n(
223 "<p>Moves a job downward in the list so that it will be spoken later. If the job "
224 "is currently speaking, its state changes to Paused.</p>");
225 btn->setWhatsThis( wt);
226 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_move()));
228 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("2leftarrow", KIcon::Small, 0, true),
229 i18n("Pre&vious Part"), hbox2, "part_prevpart");
230 wt = i18n(
231 "<p>Rewinds a multi-part job to the previous part.</p>");
232 btn->setWhatsThis( wt);
233 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_prev_par()));
234 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("1leftarrow", KIcon::Small, 0, true),
235 i18n("&Previous Sentence"), hbox2, "job_prevsentence");
236 wt = i18n(
237 "<p>Rewinds a job to the previous sentence.</p>");
238 btn->setWhatsThis( wt);
239 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_prev_sen()));
240 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("1rightarrow", KIcon::Small, 0, true),
241 i18n("&Next Sentence"), hbox2, "job_nextsentence");
242 wt = i18n(
243 "<p>Advances a job to the next sentence.</p>");
244 btn->setWhatsThis( wt);
245 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_next_sen()));
246 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("2rightarrow", KIcon::Small, 0, true),
247 i18n("Ne&xt Part"), hbox2, "part_nextpart");
248 wt = i18n(
249 "<p>Advances a multi-part job to the next part.</p>");
250 btn->setWhatsThis( wt);
251 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_next_par()));
253 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("klipper", KIcon::Small, 0, true),
254 i18n("&Speak Clipboard"), hbox3, "speak_clipboard");
255 wt = i18n(
256 "<p>Queues the current contents of the clipboard for speaking and sets its state "
257 "to Waiting. If the job is the topmost in the list, it begins speaking. "
258 "The job will be spoken by the topmost Talker in the <b>Talkers</b> tab.</p>");
259 btn->setWhatsThis( wt);
260 connect (btn, SIGNAL(clicked()), this, SLOT(slot_speak_clipboard()));
261 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("fileopen", KIcon::Small, 0, true),
262 i18n("Spea&k File"), hbox3, "speak_file");
263 wt = i18n(
264 "<p>Prompts you for a file name and queues the contents of the file for speaking. "
265 "You must click the <b>Resume</b> button before the job will be speakable. "
266 "The job will be spoken by the topmost Talker in the <b>Talkers</b> tab.</p>");
267 btn->setWhatsThis( wt);
268 connect (btn, SIGNAL(clicked()), this, SLOT(slot_speak_file()));
269 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("translate", KIcon::Small, 0, true),
270 i18n("Change Talker"), hbox3, "job_changetalker");
271 wt = i18n(
272 "<p>Prompts you with a list of your configured Talkers from the <b>Talkers</b> tab. "
273 "The job will be spoken using the selected Talker.</p>");
274 btn->setWhatsThis( wt);
275 connect (btn, SIGNAL(clicked()), this, SLOT(slot_job_change_talker()));
276 btn = new QPushButton(KGlobal::iconLoader()->loadIconSet("reload_page", KIcon::Small, 0, true),
277 i18n("&Refresh"), hbox3, "refresh");
278 wt = i18n(
279 "<p>Refresh the list of jobs.</p>");
280 btn->setWhatsThis( wt);
281 connect (btn, SIGNAL(clicked()), this, SLOT(slot_refresh()));
283 // Disable job buttons until a job is selected.
284 enableJobActions(false);
285 enableJobPartActions(false);
287 // Create a VBox for the current sentence and sentence label.
288 KVBox* sentenceVBox = new KVBox(bottomBox);
290 // Create a label for current sentence.
291 QLabel* currentSentenceLabel = new QLabel(sentenceVBox);
292 currentSentenceLabel->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
293 currentSentenceLabel->setText(i18n("Current Sentence"));
295 // Create a box to contain the current sentence.
296 m_currentSentence = new KTextEdit(sentenceVBox);
297 m_currentSentence->setReadOnly(true);
298 #warning "kde4: port them"
299 //m_currentSentence->setWordWrap(Q3TextEdit::WidgetWidth);
300 //m_currentSentence->setWrapPolicy(Q3TextEdit::AtWordOrDocumentBoundary);
301 //m_currentSentence->setHScrollBarMode(Q3ScrollView::AlwaysOff);
302 //m_currentSentence->setVScrollBarMode(Q3ScrollView::Auto);
303 wt = i18n(
304 "<p>The text of the sentence currently speaking.</p>");
305 m_currentSentence->setWhatsThis( wt);
307 // Set the main widget for the part.
308 setWidget(vBox);
310 connect(m_jobListView, SIGNAL(selectionChanged(Q3ListViewItem* )),
311 this, SLOT(slot_selectionChanged(Q3ListViewItem* )));
313 // Fill the Job List View.
314 refreshJobListView();
315 // Select first item (if any).
316 autoSelectInJobListView();
318 // Connect DCOP Signals emitted by KTTSD to our own DCOP methods.
319 connectDCOPSignal("kttsd", "KSpeech",
320 "kttsdStarted()",
321 "kttsdStarted()",
322 false);
323 connectDCOPSignal("kttsd", "KSpeech",
324 "markerSeen(QByteArray,QString)",
325 "markerSeen(QByteArray,QString)",
326 false);
327 if (!connectDCOPSignal("kttsd", "KSpeech",
328 "sentenceStarted(QByteArray,uint,uint)",
329 "sentenceStarted(QByteArray,uint,uint)",
330 false)) kdDebug() << "KttsJobMgrPart::KttsJobMgrPart: failed to connect DCOP signal sentenceStarted" << endl;
331 connectDCOPSignal(0, 0,
332 "sentenceFinished(QByteArray,uint,uint)",
333 "sentenceFinished(QByteArray,uint,uint)",
334 false);
335 connectDCOPSignal("kttsd", "KSpeech",
336 "textSet(QByteArray,uint)",
337 "textSet(QByteArray,uint)",
338 false);
339 connectDCOPSignal("kttsd", "KSpeech",
340 "textStarted(QByteArray,uint)",
341 "textStarted(QByteArray,uint)",
342 false);
343 connectDCOPSignal("kttsd", "KSpeech",
344 "textFinished(QByteArray,uint)",
345 "textFinished(QByteArray,uint)",
346 false);
347 connectDCOPSignal("kttsd", "KSpeech",
348 "textStopped(QByteArray,uint)",
349 "textStopped(QByteArray,uint)",
350 false);
351 connectDCOPSignal("kttsd", "KSpeech",
352 "textPaused(QByteArray,uint)",
353 "textPaused(QByteArray,uint)",
354 false);
355 connectDCOPSignal("kttsd", "KSpeech",
356 "textResumed(QByteArray,uint)",
357 "textResumed(QByteArray,uint)",
358 false);
359 connectDCOPSignal("kttsd", "KSpeech",
360 "textRemoved(QByteArray,uint)",
361 "textRemoved(QByteArray,uint)",
362 false);
364 m_extension = new KttsJobMgrBrowserExtension(this);
366 m_jobListView->show();
368 // Divide splitter in half. ListView gets half. Buttons and Current Sentence get half.
369 int halfSplitterSize = splitter->height()/2;
370 QList<int> splitterSizes;
371 splitterSizes.append(halfSplitterSize);
372 splitterSizes.append(halfSplitterSize);
373 splitter->setSizes(splitterSizes);
376 KttsJobMgrPart::~KttsJobMgrPart()
378 KGlobal::locale()->removeCatalog("kttsd");
379 closeURL();
382 bool KttsJobMgrPart::openFile()
384 return true;
387 bool KttsJobMgrPart::closeURL()
389 return true;
393 * This slot is connected to the Job List View selectionChanged signal.
395 void KttsJobMgrPart::slot_selectionChanged(Q3ListViewItem*)
397 // Enable job buttons.
398 enableJobActions(true);
399 enableJobPartActions((getCurrentJobPartCount() > 1));
403 * Slots connected to buttons.
405 void KttsJobMgrPart::slot_job_hold()
407 uint jobNum = getCurrentJobNum();
408 if (jobNum)
410 pauseText(jobNum);
411 refreshJob(jobNum);
415 void KttsJobMgrPart::slot_job_resume()
417 uint jobNum = getCurrentJobNum();
418 if (jobNum)
420 resumeText(jobNum);
421 refreshJob(jobNum);
425 void KttsJobMgrPart::slot_job_restart()
427 uint jobNum = getCurrentJobNum();
428 // kdDebug() << "KttsJobMgrPart::slot_job_restart: jobNum = " << jobNum << endl;
429 if (jobNum)
431 startText(jobNum);
432 refreshJob(jobNum);
436 void KttsJobMgrPart::slot_job_prev_par()
438 uint jobNum = getCurrentJobNum();
439 if (jobNum)
441 // Get current part number.
442 uint partNum = jumpToTextPart(0, jobNum);
443 if (partNum > 1) jumpToTextPart(--partNum, jobNum);
444 refreshJob(jobNum);
448 void KttsJobMgrPart::slot_job_prev_sen()
450 uint jobNum = getCurrentJobNum();
451 if (jobNum)
453 moveRelTextSentence(-1, jobNum);
454 refreshJob(jobNum);
458 void KttsJobMgrPart::slot_job_next_sen()
460 uint jobNum = getCurrentJobNum();
461 if (jobNum)
463 moveRelTextSentence(1, jobNum);
464 refreshJob(jobNum);
468 void KttsJobMgrPart::slot_job_next_par()
470 uint jobNum = getCurrentJobNum();
471 if (jobNum)
473 // Get current part number.
474 uint partNum = jumpToTextPart(0, jobNum);
475 jumpToTextPart(++partNum, jobNum);
476 refreshJob(jobNum);
480 void KttsJobMgrPart::slot_job_remove()
482 uint jobNum = getCurrentJobNum();
483 if (jobNum)
485 removeText(jobNum);
486 m_currentSentence->clear();
490 void KttsJobMgrPart::slot_job_move()
492 uint jobNum = getCurrentJobNum();
493 if (jobNum)
495 moveTextLater(jobNum);
496 refreshJobListView();
497 // Select the job we just moved.
498 Q3ListViewItem* item = findItemByJobNum(jobNum);
499 if (item) m_jobListView->setSelected(item, true);
503 void KttsJobMgrPart::slot_job_change_talker()
505 Q3ListViewItem* item = m_jobListView->selectedItem();
506 if (item)
508 QString talkerID = item->text(jlvcTalkerID);
509 QStringList talkerIDs = m_talkerCodesToTalkerIDs.values();
510 int ndx = talkerIDs.findIndex(talkerID);
511 QString talkerCode;
512 if (ndx >= 0) talkerCode = m_talkerCodesToTalkerIDs.keys()[ndx];
513 SelectTalkerDlg dlg(widget(), "selecttalkerdialog", i18n("Select Talker"), talkerCode, true);
514 int dlgResult = dlg.exec();
515 if (dlgResult != KDialogBase::Accepted) return;
516 talkerCode = dlg.getSelectedTalkerCode();
517 int jobNum = item->text(jlvcJobNum).toInt();
518 changeTextTalker(talkerCode, jobNum);
519 refreshJob(jobNum);
523 void KttsJobMgrPart::slot_speak_clipboard()
525 // Get the clipboard object.
526 QClipboard *cb = kapp->clipboard();
529 // Copy text from the clipboard.
530 QString text;
531 QMimeSource* data = cb->data();
532 if (data)
534 if (data->provides("text/html"))
536 if (supportsMarkup(NULL, KSpeech::mtHtml))
538 QByteArray d = data->encodedData("text/html");
539 text = QString(d);
542 if (data->provides("text/ssml"))
544 if (supportsMarkup(NULL, KSpeech::mtSsml))
546 QByteArray d = data->encodedData("text/ssml");
547 text = QString(d);
551 if (text.isEmpty())
552 text = cb->text();
554 // Speak it.
555 if ( !text.isEmpty() )
557 uint jobNum = setText(text, NULL);
558 // kdDebug() << "KttsJobMgrPart::slot_speak_clipboard: started jobNum " << jobNum << endl;
559 startText(jobNum);
560 // Set flag so that the job we just created will be selected when textSet signal is received.
561 m_selectOnTextSet = true;
565 void KttsJobMgrPart::slot_speak_file()
567 KEncodingFileDialog dlg;
568 KEncodingFileDialog::Result result = dlg.getOpenFileNameAndEncoding();
569 if (result.fileNames.count() == 1)
571 // kdDebug() << "KttsJobMgr::slot_speak_file: calling setFile with filename " <<
572 // result.fileNames[0] << " and encoding " << result.encoding << endl;
573 setFile(result.fileNames[0], NULL, result.encoding);
577 void KttsJobMgrPart::slot_refresh()
579 // Clear TalkerID cache.
580 m_talkerCodesToTalkerIDs.clear();
581 // Get current job number.
582 uint jobNum = getCurrentJobNum();
583 refreshJobListView();
584 // Select the previously-selected job.
585 if (jobNum)
587 Q3ListViewItem* item = findItemByJobNum(jobNum);
588 if (item) m_jobListView->setSelected(item, true);
594 * Convert a KTTSD job state integer into a display string.
595 * @param state KTTSD job state
596 * @return Display string for the state.
598 QString KttsJobMgrPart::stateToStr(int state)
600 switch( state )
602 case KSpeech::jsQueued: return i18n("Queued");
603 case KSpeech::jsSpeakable: return i18n("Waiting");
604 case KSpeech::jsSpeaking: return i18n("Speaking");
605 case KSpeech::jsPaused: return i18n("Paused");
606 case KSpeech::jsFinished: return i18n("Finished");
607 default: return i18n("Unknown");
612 * Get the Job Number of the currently-selected job in the Job List View.
613 * @return Job Number of currently-selected job.
614 * 0 if no currently-selected job.
616 uint KttsJobMgrPart::getCurrentJobNum()
618 uint jobNum = 0;
619 Q3ListViewItem* item = m_jobListView->selectedItem();
620 if (item)
622 QString jobNumStr = item->text(jlvcJobNum);
623 jobNum = jobNumStr.toUInt(0, 10);
625 return jobNum;
629 * Get the number of parts in the currently-selected job in the Job List View.
630 * @return Number of parts in currently-selected job.
631 * 0 if no currently-selected job.
633 int KttsJobMgrPart::getCurrentJobPartCount()
635 int partCount = 0;
636 Q3ListViewItem* item = m_jobListView->selectedItem();
637 if (item)
639 QString partCountStr = item->text(jlvcPartCount);
640 partCount = partCountStr.toUInt(0, 10);
642 return partCount;
646 * Given a Job Number, returns the Job List View item containing the job.
647 * @param jobNum Job Number.
648 * @return QListViewItem containing the job or 0 if not found.
650 Q3ListViewItem* KttsJobMgrPart::findItemByJobNum(const uint jobNum)
652 return m_jobListView->findItem(QString::number(jobNum), jlvcJobNum);
656 * Refresh display of a single job in the JobListView.
657 * @param jobNum Job Number.
659 void KttsJobMgrPart::refreshJob(uint jobNum)
661 QByteArray jobInfo = getTextJobInfo(jobNum);
662 QDataStream stream(&jobInfo, QIODevice::ReadOnly);
663 int state;
664 DCOPCString appId;
665 QString talker;
666 int seq;
667 int sentenceCount;
668 int partNum;
669 int partCount;
670 stream >> state;
671 stream >> appId;
672 stream >> talker;
673 stream >> seq;
674 stream >> sentenceCount;
675 stream >> partNum;
676 stream >> partCount;
677 QString talkerID = cachedTalkerCodeToTalkerID(talker);
678 Q3ListViewItem* item = findItemByJobNum(jobNum);
679 if (item)
681 item->setText(jlvcTalkerID, talkerID);
682 item->setText(jlvcState, stateToStr(state));
683 item->setText(jlvcPosition, QString::number(seq));
684 item->setText(jlvcSentences, QString::number(sentenceCount));
685 item->setText(jlvcPartNum, QString::number(partNum));
686 item->setText(jlvcPartCount, QString::number(partCount));
691 * Fill the Job List View.
693 void KttsJobMgrPart::refreshJobListView()
695 // kdDebug() << "KttsJobMgrPart::refreshJobListView: Running" << endl;
696 m_jobListView->clear();
697 enableJobActions(false);
698 enableJobPartActions(false);
699 QString jobNumbers = getTextJobNumbers();
700 // kdDebug() << "jobNumbers: " << jobNumbers << endl;
701 QStringList jobNums = QStringList::split(",", jobNumbers);
702 Q3ListViewItem* lastItem = 0;
703 QStringList::ConstIterator endJobNums(jobNums.constEnd());
704 for( QStringList::ConstIterator it = jobNums.constBegin(); it != endJobNums; ++it)
706 QString jobNumStr = *it;
707 // kdDebug() << "jobNumStr: " << jobNumStr << endl;
708 uint jobNum = jobNumStr.toUInt(0, 10);
709 QByteArray jobInfo = getTextJobInfo(jobNum);
710 QDataStream stream(&jobInfo, QIODevice::ReadOnly);
711 int state;
712 DCOPCString appId;
713 QString talkerCode;
714 int seq;
715 int sentenceCount;
716 int partNum;
717 int partCount;
718 stream >> state;
719 stream >> appId;
720 stream >> talkerCode;
721 stream >> seq;
722 stream >> sentenceCount;
723 stream >> partNum;
724 stream >> partCount;
725 QString talkerID = cachedTalkerCodeToTalkerID(talkerCode);
726 // Append to list.
727 if (lastItem)
728 lastItem = new Q3ListViewItem(m_jobListView, lastItem, jobNumStr, appId, talkerID,
729 stateToStr(state), QString::number(seq), QString::number(sentenceCount),
730 QString::number(partNum), QString::number(partCount));
731 else
732 lastItem = new Q3ListViewItem(m_jobListView, jobNumStr, appId, talkerID,
733 stateToStr(state), QString::number(seq), QString::number(sentenceCount),
734 QString::number(partNum), QString::number(partCount));
739 * If nothing selected in Job List View and list not empty, select top item.
740 * If nothing selected and list is empty, disable job buttons.
742 void KttsJobMgrPart::autoSelectInJobListView()
744 // If something selected, nothing to do.
745 if (m_jobListView->selectedItem()) return;
746 // If empty, disable job buttons.
747 Q3ListViewItem* item = m_jobListView->firstChild();
748 if (!item)
750 enableJobActions(false);
751 enableJobPartActions(false);
753 else
754 // Select first item. Should fire itemSelected event which will enable job buttons.
755 m_jobListView->setSelected(item, true);
759 * Return the Talker ID corresponding to a Talker Code, retrieving from cached list if present.
760 * @param talkerCode Talker Code.
761 * @return Talker ID.
763 QString KttsJobMgrPart::cachedTalkerCodeToTalkerID(const QString& talkerCode)
765 // If in the cache, return that.
766 if (m_talkerCodesToTalkerIDs.contains(talkerCode))
767 return m_talkerCodesToTalkerIDs[talkerCode];
768 else
770 // Otherwise, retrieve Talker ID from KTTSD and cache it.
771 QString talkerID = talkerCodeToTalkerId(talkerCode);
772 m_talkerCodesToTalkerIDs[talkerCode] = talkerID;
773 return talkerID;
778 * Enables or disables all the job-related buttons.
779 * @param enable True to enable the job-related butons. False to disable.
781 void KttsJobMgrPart::enableJobActions(bool enable)
783 if (!m_buttonBox) return;
785 QList<QObject *> l = m_buttonBox->queryList( "QPushButton", "job_*", true, true );
786 QListIterator<QObject *> i(l);
788 while (i.hasNext())
789 ((QPushButton*)i.next())->setEnabled( enable );
791 if (enable)
793 // Later button only enables if currently selected list item is not bottom of list.
794 Q3ListViewItem* item = m_jobListView->selectedItem();
795 if (item)
797 bool enableLater = item->nextSibling();
799 l = m_buttonBox->queryList( "QPushButton", "job_later", false, true );
800 QListIterator<QObject *> it(l); // iterate over the buttons
801 while (it.hasNext())
802 // for each found object...
803 ((QPushButton*)it.next())->setEnabled( enableLater );
809 * Enables or disables all the job part-related buttons.
810 * @param enable True to enable the job par-related butons. False to disable.
812 void KttsJobMgrPart::enableJobPartActions(bool enable)
814 if (!m_buttonBox) return;
815 QList<QObject *> l = m_buttonBox->queryList( "QPushButton", "part_*", true, true );
816 QListIterator<QObject *> i(l);
818 while (i.hasNext())
819 ((QPushButton*)i.next())->setEnabled( enable );
823 /** DCOP Methods connected to DCOP Signals emitted by KTTSD. */
826 * This signal is emitted when KTTSD starts or restarts after a call to reinit.
828 ASYNC KttsJobMgrPart::kttsdStarted() { slot_refresh(); };
831 * This signal is emitted when the speech engine/plugin encounters a marker in the text.
832 * @param appId DCOP application ID of the application that queued the text.
833 * @param markerName The name of the marker seen.
834 * @see markers
836 ASYNC KttsJobMgrPart::markerSeen(const QByteArray&, const QString&)
841 * This signal is emitted whenever a sentence begins speaking.
842 * @param appId DCOP application ID of the application that queued the text.
843 * @param jobNum Job number of the text job.
844 * @param seq Sequence number of the text.
845 * @see getTextCount
847 ASYNC KttsJobMgrPart::sentenceStarted(const QByteArray&, const uint jobNum, const uint seq)
849 // kdDebug() << "KttsJobMgrPart::sentencedStarted: jobNum = " << jobNum << " seq = " << seq << endl;
850 Q3ListViewItem* item = findItemByJobNum(jobNum);
851 if (item)
853 item->setText(jlvcState, stateToStr(KSpeech::jsSpeaking));
854 item->setText(jlvcPosition, QString::number(seq));
855 m_currentSentence->setText(getTextJobSentence(jobNum, seq));
860 * This signal is emitted when a sentence has finished speaking.
861 * @param appId DCOP application ID of the application that queued the text.
862 * @param jobNum Job number of the text job.
863 * @param seq Sequence number of the text.
864 * @see getTextCount
866 ASYNC KttsJobMgrPart::sentenceFinished(const QByteArray& /*appId*/, const uint /*jobNum*/, const uint /*seq*/)
868 // kdDebug() << "KttsJobMgrPart::sentencedFinished: jobNum = " << jobNum << endl;
870 QListViewItem* item = findItemByJobNum(jobNum);
871 if (item)
873 item->setText(jlvcState, stateToStr(KSpeech::jsSpeaking));
879 * This signal is emitted whenever a new text job is added to the queue.
880 * @param appId The DCOP senderId of the application that created the job.
881 * @param jobNum Job number of the text job.
883 ASYNC KttsJobMgrPart::textSet(const QByteArray&, const uint jobNum)
885 QByteArray jobInfo = getTextJobInfo(jobNum);
886 QDataStream stream(&jobInfo, QIODevice::ReadOnly);
887 int state;
888 DCOPCString appId;
889 QString talkerCode;
890 int seq;
891 int sentenceCount;
892 int partNum;
893 int partCount;
894 stream >> state;
895 stream >> appId;
896 stream >> talkerCode;
897 stream >> seq;
898 stream >> sentenceCount;
899 stream >> partNum;
900 stream >> partCount;
901 QString talkerID = cachedTalkerCodeToTalkerID(talkerCode);
902 Q3ListViewItem* item = new Q3ListViewItem(m_jobListView, m_jobListView->lastItem(),
903 QString::number(jobNum), appId, talkerID,
904 stateToStr(state), QString::number(seq), QString::number(sentenceCount),
905 QString::number(partNum), QString::number(partCount));
906 // Should we select this job?
907 if (m_selectOnTextSet)
909 m_jobListView->setSelected(item, true);
910 m_selectOnTextSet = false;
912 // If a job not already selected, select this one.
913 autoSelectInJobListView();
917 * This signal is emitted whenever a new part is appended to a text job.
918 * @param appId The DCOP senderId of the application that created the job.
919 * @param jobNum Job number of the text job.
920 * @param partNum Part number of the new part. Parts are numbered starting
921 * at 1.
923 ASYNC KttsJobMgrPart::textAppended(const QByteArray& appId, const uint jobNum, const int /*partNum*/)
925 textSet(appId, jobNum);
929 * This signal is emitted whenever speaking of a text job begins.
930 * @param appId The DCOP senderId of the application that created the job.
931 * @param jobNum Job number of the text job.
933 ASYNC KttsJobMgrPart::textStarted(const QByteArray&, const uint jobNum)
935 Q3ListViewItem* item = findItemByJobNum(jobNum);
936 if (item)
938 item->setText(jlvcState, stateToStr(KSpeech::jsSpeaking));
939 item->setText(jlvcPosition, "1");
944 * This signal is emitted whenever a text job is finished. The job has
945 * been marked for deletion from the queue and will be deleted when another
946 * job reaches the Finished state. (Only one job in the text queue may be
947 * in state Finished at one time.) If @ref startText or @ref resumeText is
948 * called before the job is deleted, it will remain in the queue for speaking.
949 * @param appId The DCOP senderId of the application that created the job.
950 * @param jobNum Job number of the text job.
952 ASYNC KttsJobMgrPart::textFinished(const QByteArray&, const uint jobNum)
954 // kdDebug() << "KttsJobMgrPart::textFinished: jobNum = " << jobNum << endl;
955 Q3ListViewItem* item = findItemByJobNum(jobNum);
956 if (item)
958 item->setText(jlvcState, stateToStr(KSpeech::jsFinished));
959 // Update sentence pointer, since signal may not be emitted for final CR.
960 refreshJob(jobNum);
962 m_currentSentence->setText(QString::null);
966 * This signal is emitted whenever a speaking text job stops speaking.
967 * @param appId The DCOP senderId of the application that created the job.
968 * @param jobNum Job number of the text job.
970 ASYNC KttsJobMgrPart::textStopped(const QByteArray&, const uint jobNum)
972 // kdDebug() << "KttsJobMgrPart::textStopped: jobNum = " << jobNum << endl;
973 Q3ListViewItem* item = findItemByJobNum(jobNum);
974 if (item)
976 item->setText(jlvcState, stateToStr(KSpeech::jsQueued));
977 item->setText(jlvcPosition, "1");
982 * This signal is emitted whenever a speaking text job is paused.
983 * @param appId The DCOP senderId of the application that created the job.
984 * @param jobNum Job number of the text job.
986 ASYNC KttsJobMgrPart::textPaused(const QByteArray&, const uint jobNum)
988 // kdDebug() << "KttsJobMgrPart::textPaused: jobNum = " << jobNum << endl;
989 Q3ListViewItem* item = findItemByJobNum(jobNum);
990 if (item)
992 item->setText(jlvcState, stateToStr(KSpeech::jsPaused));
997 * This signal is emitted when a text job, that was previously paused, resumes speaking.
998 * @param appId The DCOP senderId of the application that created the job.
999 * @param jobNum Job number of the text job.
1001 ASYNC KttsJobMgrPart::textResumed(const QByteArray&, const uint jobNum)
1003 Q3ListViewItem* item = findItemByJobNum(jobNum);
1004 if (item)
1006 item->setText(jlvcState, stateToStr(KSpeech::jsSpeaking));
1011 * This signal is emitted whenever a text job is deleted from the queue.
1012 * The job is no longer in the queue when this signal is emitted.
1013 * @param appId The DCOP senderId of the application that created the job.
1014 * @param jobNum Job number of the text job.
1016 ASYNC KttsJobMgrPart::textRemoved(const QByteArray&, const uint jobNum)
1018 Q3ListViewItem* item = findItemByJobNum(jobNum);
1019 delete item;
1020 autoSelectInJobListView();
1023 KttsJobMgrBrowserExtension::KttsJobMgrBrowserExtension(KttsJobMgrPart *parent)
1024 : KParts::BrowserExtension(parent)
1028 KttsJobMgrBrowserExtension::~KttsJobMgrBrowserExtension()