summaryrefslogtreecommitdiffstats
path: root/kttsd
diff options
context:
space:
mode:
Diffstat (limited to 'kttsd')
-rw-r--r--kttsd/AUTHORS5
-rw-r--r--kttsd/ChangeLog609
-rw-r--r--kttsd/Makefile.am19
-rw-r--r--kttsd/README166
-rw-r--r--kttsd/README.kttsd10
-rw-r--r--kttsd/TODO95
-rw-r--r--kttsd/TODO.french31
-rw-r--r--kttsd/app-plugins/Makefile.am1
-rw-r--r--kttsd/app-plugins/kate/Makefile.am19
-rw-r--r--kttsd/app-plugins/kate/katekttsd.cpp120
-rw-r--r--kttsd/app-plugins/kate/katekttsd.h57
-rw-r--r--kttsd/app-plugins/kate/ktexteditor_kttsd.desktop104
-rw-r--r--kttsd/app-plugins/kate/ktexteditor_kttsdui.rc11
-rwxr-xr-xkttsd/clean_obsolete.sh105
-rw-r--r--kttsd/compat/Makefile.am3
-rw-r--r--kttsd/compat/README_COMPAT6
-rw-r--r--kttsd/compat/icons/Makefile.am1
-rw-r--r--kttsd/compat/icons/cr128-app-kttsd.pngbin0 -> 23932 bytes
-rw-r--r--kttsd/compat/icons/cr16-app-kttsd.pngbin0 -> 965 bytes
-rw-r--r--kttsd/compat/icons/cr22-app-kttsd.pngbin0 -> 1509 bytes
-rw-r--r--kttsd/compat/icons/cr32-app-kttsd.pngbin0 -> 2688 bytes
-rw-r--r--kttsd/compat/icons/cr48-app-kttsd.pngbin0 -> 5039 bytes
-rw-r--r--kttsd/compat/icons/cr64-app-kttsd.pngbin0 -> 7877 bytes
-rw-r--r--kttsd/compat/icons/crsc-app-kttsd.svgzbin0 -> 17596 bytes
-rw-r--r--kttsd/compat/interfaces/Makefile.am1
-rw-r--r--kttsd/compat/interfaces/kspeech/Makefile.am8
-rw-r--r--kttsd/compat/interfaces/kspeech/dcoptexttospeech.desktop52
-rw-r--r--kttsd/compat/interfaces/kspeech/kspeech.h1285
-rw-r--r--kttsd/compat/interfaces/kspeech/kspeechsink.h164
-rw-r--r--kttsd/configure.in.bot65
-rw-r--r--kttsd/configure.in.in304
-rwxr-xr-xkttsd/cvs2dist634
-rw-r--r--kttsd/debian/TODO36
-rw-r--r--kttsd/debian/changelog5
-rw-r--r--kttsd/debian/compat1
-rw-r--r--kttsd/debian/control40
-rw-r--r--kttsd/debian/copyright33
-rw-r--r--kttsd/debian/dirs1
-rw-r--r--kttsd/debian/docs2
-rw-r--r--kttsd/debian/kttsd-gstreamer.install3
-rw-r--r--kttsd/debian/kttsd.install107
-rw-r--r--kttsd/debian/kttsd.manpages2
-rw-r--r--kttsd/debian/kttsmgr.menu6
-rw-r--r--kttsd/debian/man/kttsd.1159
-rw-r--r--kttsd/debian/man/kttsmgr.1157
-rw-r--r--kttsd/debian/man/manpages.in2
-rwxr-xr-xkttsd/debian/rules5
-rw-r--r--kttsd/debian/shlibs.kttsd2
-rw-r--r--kttsd/filters/Makefile.am26
-rw-r--r--kttsd/filters/kttsd_filterplugin.desktop6
-rw-r--r--kttsd/filters/main.cpp140
-rw-r--r--kttsd/filters/sbd/Makefile.am27
-rw-r--r--kttsd/filters/sbd/kttsd_sbdplugin.desktop91
-rw-r--r--kttsd/filters/sbd/polish_festival_sbdrc6
-rw-r--r--kttsd/filters/sbd/sbdconf.cpp341
-rw-r--r--kttsd/filters/sbd/sbdconf.h139
-rw-r--r--kttsd/filters/sbd/sbdconfwidget.ui363
-rw-r--r--kttsd/filters/sbd/sbdplugin.cpp33
-rw-r--r--kttsd/filters/sbd/sbdproc.cpp784
-rw-r--r--kttsd/filters/sbd/sbdproc.h366
-rw-r--r--kttsd/filters/sbd/standard_sbdrc6
-rw-r--r--kttsd/filters/stringreplacer/Makefile.am34
-rw-r--r--kttsd/filters/stringreplacer/abbreviations.xml58
-rw-r--r--kttsd/filters/stringreplacer/chat-de.xml616
-rw-r--r--kttsd/filters/stringreplacer/chat.xml616
-rw-r--r--kttsd/filters/stringreplacer/editreplacementwidget.ui263
-rw-r--r--kttsd/filters/stringreplacer/emoticons.xml304
-rw-r--r--kttsd/filters/stringreplacer/festival_unspeakable_chars.xml94
-rw-r--r--kttsd/filters/stringreplacer/kmail.xml31
-rw-r--r--kttsd/filters/stringreplacer/kttsd_stringreplacerplugin.desktop92
-rw-r--r--kttsd/filters/stringreplacer/polish_festival_fixes.xml12
-rw-r--r--kttsd/filters/stringreplacer/polish_festival_unspeakables.xml78
-rw-r--r--kttsd/filters/stringreplacer/qt2plaintext.xml359
-rw-r--r--kttsd/filters/stringreplacer/stringreplacerconf.cpp725
-rw-r--r--kttsd/filters/stringreplacer/stringreplacerconf.h158
-rw-r--r--kttsd/filters/stringreplacer/stringreplacerconfwidget.ui474
-rw-r--r--kttsd/filters/stringreplacer/stringreplacerplugin.cpp32
-rw-r--r--kttsd/filters/stringreplacer/stringreplacerproc.cpp231
-rw-r--r--kttsd/filters/stringreplacer/stringreplacerproc.h97
-rw-r--r--kttsd/filters/talkerchooser/Makefile.am25
-rw-r--r--kttsd/filters/talkerchooser/female_notifications_rc10
-rw-r--r--kttsd/filters/talkerchooser/kttsd_talkerchooserplugin.desktop89
-rw-r--r--kttsd/filters/talkerchooser/talkerchooserconf.cpp269
-rw-r--r--kttsd/filters/talkerchooser/talkerchooserconf.h134
-rw-r--r--kttsd/filters/talkerchooser/talkerchooserconfwidget.ui319
-rw-r--r--kttsd/filters/talkerchooser/talkerchooserplugin.cpp32
-rw-r--r--kttsd/filters/talkerchooser/talkerchooserproc.cpp148
-rw-r--r--kttsd/filters/talkerchooser/talkerchooserproc.h87
-rw-r--r--kttsd/filters/xhtml2ssml/Doxyfile266
-rw-r--r--kttsd/filters/xhtml2ssml/demonstration.html5
-rw-r--r--kttsd/filters/xhtml2ssml/main.cpp22
-rw-r--r--kttsd/filters/xhtml2ssml/tagmappingrc5
-rw-r--r--kttsd/filters/xhtml2ssml/xhtml2ssml.cpp105
-rw-r--r--kttsd/filters/xhtml2ssml/xhtml2ssml.h61
-rw-r--r--kttsd/filters/xhtml2ssml/xhtml2ssml.kdevelop112
-rw-r--r--kttsd/filters/xhtml2ssml/xhtml2ssml.kdevelop.pcsbin0 -> 14766 bytes
-rw-r--r--kttsd/filters/xhtml2ssml/xhtml2ssml.kdevses38
-rw-r--r--kttsd/filters/xhtml2ssml/xhtml2ssml.pro10
-rw-r--r--kttsd/filters/xhtml2ssml/xmlelement.cpp102
-rw-r--r--kttsd/filters/xhtml2ssml/xmlelement.h91
-rw-r--r--kttsd/filters/xmltransformer/Makefile.am24
-rw-r--r--kttsd/filters/xmltransformer/kttsd_xmltransformerplugin.desktop88
-rw-r--r--kttsd/filters/xmltransformer/xhtml2ssml.xsl252
-rw-r--r--kttsd/filters/xmltransformer/xhtml2ssml_simple.xsl95
-rw-r--r--kttsd/filters/xmltransformer/xmltransformerconf.cpp182
-rw-r--r--kttsd/filters/xmltransformer/xmltransformerconf.h120
-rw-r--r--kttsd/filters/xmltransformer/xmltransformerconfwidget.ui249
-rw-r--r--kttsd/filters/xmltransformer/xmltransformerplugin.cpp31
-rw-r--r--kttsd/filters/xmltransformer/xmltransformerproc.cpp385
-rw-r--r--kttsd/filters/xmltransformer/xmltransformerproc.h167
-rw-r--r--kttsd/icons/Makefile.am1
-rw-r--r--kttsd/icons/hi16-action-female.pngbin0 -> 206 bytes
-rw-r--r--kttsd/icons/hi16-action-male.pngbin0 -> 186 bytes
-rw-r--r--kttsd/icons/hi16-action-nospeak.pngbin0 -> 237 bytes
-rw-r--r--kttsd/icons/hi16-action-speak.pngbin0 -> 219 bytes
-rw-r--r--kttsd/icons/hi22-action-nospeak.pngbin0 -> 296 bytes
-rw-r--r--kttsd/icons/hi22-action-speak.pngbin0 -> 285 bytes
-rw-r--r--kttsd/icons/hi32-action-nospeak.pngbin0 -> 424 bytes
-rw-r--r--kttsd/icons/hi32-action-speak.pngbin0 -> 383 bytes
-rw-r--r--kttsd/icons/hi48-action-nospeak.pngbin0 -> 638 bytes
-rw-r--r--kttsd/icons/hi48-action-speak.pngbin0 -> 563 bytes
-rw-r--r--kttsd/icons/lo16-action-speak.pngbin0 -> 219 bytes
-rw-r--r--kttsd/icons/lo22-action-speak.pngbin0 -> 285 bytes
-rw-r--r--kttsd/icons/lo32-action-speak.pngbin0 -> 383 bytes
-rw-r--r--kttsd/kcmkttsmgr/Makefile.am51
-rw-r--r--kttsd/kcmkttsmgr/addtalker.cpp225
-rw-r--r--kttsd/kcmkttsmgr/addtalker.h89
-rw-r--r--kttsd/kcmkttsmgr/addtalkerwidget.ui260
-rw-r--r--kttsd/kcmkttsmgr/kcmkttsd.desktop142
-rw-r--r--kttsd/kcmkttsmgr/kcmkttsd_testmessage.desktop46
-rw-r--r--kttsd/kcmkttsmgr/kcmkttsmgr.cpp2713
-rw-r--r--kttsd/kcmkttsmgr/kcmkttsmgr.h530
-rw-r--r--kttsd/kcmkttsmgr/kcmkttsmgrwidget.ui1928
-rw-r--r--kttsd/kcmkttsmgr/kcmkttsmgrwidget.ui.h16
-rw-r--r--kttsd/kcmkttsmgr/selectevent.cpp149
-rw-r--r--kttsd/kcmkttsmgr/selectevent.h69
-rw-r--r--kttsd/kcmkttsmgr/selecteventwidget.ui62
-rw-r--r--kttsd/kttsd.lsm27
-rw-r--r--kttsd/kttsd/Makefile.am51
-rw-r--r--kttsd/kttsd/SSMLtoPlainText.xsl9
-rw-r--r--kttsd/kttsd/filtermgr.cpp405
-rw-r--r--kttsd/kttsd/filtermgr.h199
-rw-r--r--kttsd/kttsd/kttsd.cpp1183
-rw-r--r--kttsd/kttsd/kttsd.desktop56
-rw-r--r--kttsd/kttsd/kttsd.h686
-rw-r--r--kttsd/kttsd/main.cpp68
-rw-r--r--kttsd/kttsd/speaker.cpp1701
-rw-r--r--kttsd/kttsd/speaker.h599
-rw-r--r--kttsd/kttsd/speechdata.cpp1275
-rw-r--r--kttsd/kttsd/speechdata.h731
-rw-r--r--kttsd/kttsd/ssmlconvert.cpp295
-rw-r--r--kttsd/kttsd/ssmlconvert.h129
-rw-r--r--kttsd/kttsd/talkermgr.cpp388
-rw-r--r--kttsd/kttsd/talkermgr.h159
-rw-r--r--kttsd/kttsd/threadedplugin.cpp282
-rw-r--r--kttsd/kttsd/threadedplugin.h200
-rw-r--r--kttsd/kttsjobmgr/Makefile.am40
-rw-r--r--kttsd/kttsjobmgr/kttsjobmgr.cpp1023
-rw-r--r--kttsd/kttsjobmgr/kttsjobmgr.desktop49
-rw-r--r--kttsd/kttsjobmgr/kttsjobmgr.h298
-rw-r--r--kttsd/kttsmgr/Makefile.am34
-rw-r--r--kttsd/kttsmgr/kttsmgr.cpp334
-rw-r--r--kttsd/kttsmgr/kttsmgr.desktop98
-rw-r--r--kttsd/kttsmgr/kttsmgr.h86
-rw-r--r--kttsd/libkttsd/Makefile.am45
-rw-r--r--kttsd/libkttsd/filterconf.cpp166
-rw-r--r--kttsd/libkttsd/filterconf.h149
-rw-r--r--kttsd/libkttsd/filterproc.cpp153
-rw-r--r--kttsd/libkttsd/filterproc.h179
-rw-r--r--kttsd/libkttsd/kdeexportfix.h27
-rw-r--r--kttsd/libkttsd/kttsd_synthplugin.desktop8
-rw-r--r--kttsd/libkttsd/notify.cpp177
-rw-r--r--kttsd/libkttsd/notify.h85
-rw-r--r--kttsd/libkttsd/player.h76
-rw-r--r--kttsd/libkttsd/pluginconf.cpp245
-rw-r--r--kttsd/libkttsd/pluginconf.h378
-rw-r--r--kttsd/libkttsd/pluginproc.cpp292
-rw-r--r--kttsd/libkttsd/pluginproc.h466
-rw-r--r--kttsd/libkttsd/selecttalkerdlg.cpp365
-rw-r--r--kttsd/libkttsd/selecttalkerdlg.h110
-rw-r--r--kttsd/libkttsd/selecttalkerwidget.ui572
-rw-r--r--kttsd/libkttsd/stretcher.cpp99
-rw-r--r--kttsd/libkttsd/stretcher.h97
-rw-r--r--kttsd/libkttsd/talkercode.cpp517
-rw-r--r--kttsd/libkttsd/talkercode.h197
-rw-r--r--kttsd/libkttsd/testplayer.cpp209
-rw-r--r--kttsd/libkttsd/testplayer.h121
-rw-r--r--kttsd/libkttsd/utils.cpp132
-rw-r--r--kttsd/libkttsd/utils.h61
-rw-r--r--kttsd/players/Makefile.am27
-rw-r--r--kttsd/players/akodeplayer/Makefile.am28
-rw-r--r--kttsd/players/akodeplayer/README19
-rw-r--r--kttsd/players/akodeplayer/akodeplayer.cpp179
-rw-r--r--kttsd/players/akodeplayer/akodeplayer.h67
-rw-r--r--kttsd/players/akodeplayer/akodeplugin.cpp29
-rw-r--r--kttsd/players/akodeplayer/kttsd_akodeplugin.desktop89
-rw-r--r--kttsd/players/alsaplayer/Makefile.am30
-rw-r--r--kttsd/players/alsaplayer/alsaplayer.cpp1729
-rw-r--r--kttsd/players/alsaplayer/alsaplayer.h187
-rw-r--r--kttsd/players/alsaplayer/alsaplugin.cpp29
-rw-r--r--kttsd/players/alsaplayer/formats.h110
-rw-r--r--kttsd/players/alsaplayer/kttsd_alsaplugin.desktop89
-rw-r--r--kttsd/players/artsplayer/Makefile.am30
-rw-r--r--kttsd/players/artsplayer/artsplayer.cpp296
-rw-r--r--kttsd/players/artsplayer/artsplayer.h95
-rw-r--r--kttsd/players/artsplayer/artsplugin.cpp29
-rw-r--r--kttsd/players/artsplayer/kttsd_artsplugin.desktop91
-rw-r--r--kttsd/players/gstplayer/Makefile.am30
-rw-r--r--kttsd/players/gstplayer/gstplugin.cpp29
-rw-r--r--kttsd/players/gstplayer/gstreamerplayer.cpp258
-rw-r--r--kttsd/players/gstplayer/gstreamerplayer.h76
-rw-r--r--kttsd/players/gstplayer/kttsd_gstplugin.desktop92
-rw-r--r--kttsd/players/kttsd_audioplugin.desktop47
-rw-r--r--kttsd/plugins/Makefile.am37
-rw-r--r--kttsd/plugins/command/Makefile.am18
-rw-r--r--kttsd/plugins/command/README8
-rw-r--r--kttsd/plugins/command/commandconf.cpp217
-rw-r--r--kttsd/plugins/command/commandconf.h121
-rw-r--r--kttsd/plugins/command/commandconfwidget.ui227
-rw-r--r--kttsd/plugins/command/commandplugin.cpp24
-rw-r--r--kttsd/plugins/command/commandproc.cpp446
-rw-r--r--kttsd/plugins/command/commandproc.h201
-rw-r--r--kttsd/plugins/command/configure.in.in17
-rw-r--r--kttsd/plugins/command/kttsd_commandplugin.desktop92
-rw-r--r--kttsd/plugins/epos/Makefile.am20
-rw-r--r--kttsd/plugins/epos/README3
-rw-r--r--kttsd/plugins/epos/configure.in.bot15
-rw-r--r--kttsd/plugins/epos/configure.in.in22
-rw-r--r--kttsd/plugins/epos/eposconf.cpp319
-rw-r--r--kttsd/plugins/epos/eposconf.h141
-rw-r--r--kttsd/plugins/epos/eposconfwidget.ui610
-rw-r--r--kttsd/plugins/epos/eposplugin.cpp31
-rw-r--r--kttsd/plugins/epos/eposproc.cpp389
-rw-r--r--kttsd/plugins/epos/eposproc.h241
-rw-r--r--kttsd/plugins/epos/kttsd_eposplugin.desktop87
-rw-r--r--kttsd/plugins/festivalint/Makefile.am27
-rw-r--r--kttsd/plugins/festivalint/README9
-rw-r--r--kttsd/plugins/festivalint/SSMLtoSable.xsl272
-rw-r--r--kttsd/plugins/festivalint/configure.in.bot16
-rw-r--r--kttsd/plugins/festivalint/configure.in.in22
-rw-r--r--kttsd/plugins/festivalint/festivalintconf.cpp730
-rw-r--r--kttsd/plugins/festivalint/festivalintconf.h187
-rw-r--r--kttsd/plugins/festivalint/festivalintconfwidget.ui598
-rw-r--r--kttsd/plugins/festivalint/festivalintplugin.cpp31
-rw-r--r--kttsd/plugins/festivalint/festivalintproc.cpp662
-rw-r--r--kttsd/plugins/festivalint/festivalintproc.h361
-rw-r--r--kttsd/plugins/festivalint/kttsd_festivalintplugin.desktop72
-rw-r--r--kttsd/plugins/festivalint/sabletowave.scm92
-rw-r--r--kttsd/plugins/festivalint/voices738
-rw-r--r--kttsd/plugins/flite/Makefile.am20
-rw-r--r--kttsd/plugins/flite/README3
-rw-r--r--kttsd/plugins/flite/configure.in.bot15
-rw-r--r--kttsd/plugins/flite/configure.in.in22
-rw-r--r--kttsd/plugins/flite/fliteconf.cpp199
-rw-r--r--kttsd/plugins/flite/fliteconf.h124
-rw-r--r--kttsd/plugins/flite/fliteconfwidget.ui186
-rw-r--r--kttsd/plugins/flite/fliteplugin.cpp31
-rw-r--r--kttsd/plugins/flite/fliteproc.cpp281
-rw-r--r--kttsd/plugins/flite/fliteproc.h187
-rw-r--r--kttsd/plugins/flite/kttsd_fliteplugin.desktop59
-rw-r--r--kttsd/plugins/freetts/Makefile.am18
-rw-r--r--kttsd/plugins/freetts/README6
-rw-r--r--kttsd/plugins/freetts/configure.in.bot15
-rw-r--r--kttsd/plugins/freetts/configure.in.in22
-rw-r--r--kttsd/plugins/freetts/freettsconf.cpp230
-rw-r--r--kttsd/plugins/freetts/freettsconf.h122
-rw-r--r--kttsd/plugins/freetts/freettsconfigwidget.ui200
-rw-r--r--kttsd/plugins/freetts/freettsplugin.cpp26
-rw-r--r--kttsd/plugins/freetts/freettsproc.cpp275
-rw-r--r--kttsd/plugins/freetts/freettsproc.h180
-rw-r--r--kttsd/plugins/freetts/kttsd_freettsplugin.desktop51
-rw-r--r--kttsd/plugins/hadifix/Makefile.am23
-rw-r--r--kttsd/plugins/hadifix/README3
-rw-r--r--kttsd/plugins/hadifix/SSMLtoTxt2pho.xsl164
-rw-r--r--kttsd/plugins/hadifix/configure.in.bot37
-rw-r--r--kttsd/plugins/hadifix/configure.in.in37
-rw-r--r--kttsd/plugins/hadifix/hadifixconf.cpp406
-rw-r--r--kttsd/plugins/hadifix/hadifixconf.h83
-rw-r--r--kttsd/plugins/hadifix/hadifixconfigui.ui692
-rw-r--r--kttsd/plugins/hadifix/hadifixconfigui.ui.h114
-rw-r--r--kttsd/plugins/hadifix/hadifixplugin.cpp23
-rw-r--r--kttsd/plugins/hadifix/hadifixproc.cpp411
-rw-r--r--kttsd/plugins/hadifix/hadifixproc.h203
-rw-r--r--kttsd/plugins/hadifix/initialconfig.h164
-rw-r--r--kttsd/plugins/hadifix/kttsd_hadifixplugin.desktop51
-rw-r--r--kttsd/plugins/hadifix/voicefileui.ui119
-rw-r--r--kttsd/plugins/hadifix/voicefileui.ui.h35
-rw-r--r--kttsd/sample.polish8
-rw-r--r--kttsd/sample.ssml1
289 files changed, 51807 insertions, 0 deletions
diff --git a/kttsd/AUTHORS b/kttsd/AUTHORS
new file mode 100644
index 0000000..33193d5
--- /dev/null
+++ b/kttsd/AUTHORS
@@ -0,0 +1,5 @@
+José Pablo Ezequiel Fernández <pupeno@pupeno.com>
+Gary Cramblitt <garycramblitt@comcast.net>
+Gunnar Schmi Dt <gunnar@schmi-dt.de>
+Olaf Schmidt <ojschmidt@kde.org>
+Paul Giannaros <ceruleanblaze@gmail.com>
diff --git a/kttsd/ChangeLog b/kttsd/ChangeLog
new file mode 100644
index 0000000..549f975
--- /dev/null
+++ b/kttsd/ChangeLog
@@ -0,0 +1,609 @@
+2006-11-02 Gary Cramblitt (PhantomsDad)
+ * Add support for new Vietnamese voices to festivalintvoices file. Get them at http://sourceforge.net/projects/vietnamesevoice.
+
+2006-02-09 Gary Cramblitt (PhantomsDad)
+ * Use KDE_CHECK_{HEADER,LIB} instead of AC_CHECK_{HEADER,LIB} to locate alsalib.
+
+2006-02-07 Stephan Johach
+ * Fix translation of "Speak Text" in kate/ktextedit.
+
+2006-02-06 Gary Cramblitt (PhantomsDad)
+ * Bump version to 0.3.5.2.
+ * Fix BUG:121427 Translations sometimes not working due to incorrect catalog
+ insertion/removal.
+
+2006-01-20 ======== Release v0.3.5.1 with KDE 3.5.1
+
+2006-01-13 Gary Cramblitt (PhantomsDad)
+ * Fix BUG:120083 buffer length problem in Epos and Command plugin.
+ * Fix BUG:115795 Don't try to start the Epos server for every utterance.
+ * Epos server command changed from epos to eposd. Epos client command changed from
+ say to say-epos. These changes appeared around Epos v2.5.35. Enhance to try for these
+ automatically.
+
+2006-01-10 Gary Cramblitt (PhantomsDad)
+ * Bug fix. Pausing when popping up status in systray.
+ * Plug small memory leak.
+ * Allow user to specify custom ALSA device name.
+
+2006-01-09 Gary Cramblitt (PhantomsDad)
+ * Fix BUG:119753 Freezing when removing a speaking text job speaking on AlsaPlayer.
+ AlsaPlayer now uses non-blocking pcm open and polling.
+ * The ALSA device list pickable by user is now restricted to "default" and available
+ "plughw" devices.
+ * The following parameters may be placed in the [ALSAPlayer] section of
+ ~/.kde/share/config/kttsdrc:
+ PcmName=default (Any valid alsa pcm device, but your on your own. Examples:
+ dmix, hw:1,0)
+ DebugLevel=1 (0 = errors only; 1 = messages; 2 = verbose debug)
+ PeriodSize=128 (Number of frames in the ALSA buffer between interrupts.
+ If you have trouble, try adjusting up or down.)
+ Periods=8 (Same)
+ * If the ALSA pcm does not support pausing, simulates by not writing to the
+ pcm anymore, which will cause a slight delay, and underruns,
+ but that's the best we can do, I suppose.
+ * Fix bug. When starting KTTSMgr, it loaded the aRts plugin to determine if aRts is
+ available. But this started the aRts server and if user's machine does not have
+ proper audio sharing enabled, caused "device busy" errors. Now it starts the aRts
+ server only when playback begins the first time.
+ * Bump version from 0.3.5 to 0.3.5.1.
+
+2006-01-06 Gary Cramblitt (PhantomsDad)
+ * Fix BUG:118016 Not loading plugins when desktop language is not ISO-8859-1.
+
+2005-12-03 Jürgen Zdero
+ * Add German chat filter by Jürgen Zdero.
+
+2005-11-13 Gary Cramblitt (PhantomsDad)
+ * BUG:116031 Fix appendText method. Add version method to dcop interface.
+ This change did not make it into the KDE 3.5 release.
+
+2005-11-29 ======== Release v0.3.5 with KDE 3.5
+
+2005-10-16 J. Riddell
+ * Make install error. Install the Hadifix icons.
+
+2005-07-19 Gary Cramblitt (PhantomsDad)
+ * Name kept .wav files in format kttsd-jjjjjjjj-ssssssss.wav where jjjjjjjj is the job
+ number zero-filled to the left and ssssssss is the sentence sequence number zero-filled
+ to the left.
+
+2005-07-01 Gary Cramblitt (PhantomsDad)
+ * Since ALSA plugin seems to work pretty well, enable building --without-arts and build
+ ALSA plugin by default (if headers found).
+
+2005-06-25 Gary Cramblitt (PhantomsDad)
+ * The XML Transformer filter now applies itself when the root element OR doctype and appId match.
+
+2005-06-12 Gary Cramblitt (PhantomsDad)
+ * New aKode audio plugin. Build it with ./configure --enable-kttsd-akode.
+ There are a couple of problems. See README players/akodeplayer/README.
+ * Activate rich speak (XHTML to SSML) in Konqueror plugin. To speak richly,
+ you must configure the xhtml2ssml_simple XML Transformer plugin.
+
+2005-06-03 Gary Cramblitt (PhantomsDad)
+ * New ALSA audio plugin. Build it with ./configure --enable-kttsd-alsa for now.
+ * New Qt Rich Text to Plain Text filter by David Powell.
+
+2005-04-30 Gary Cramblitt (PhantomsDad)
+ * Change Current Sentence widget in Jobs tab to KTextEdit to avoid resizing when text does
+ not fit in box.
+ * HTML to SSML now working pretty well. Note that you must
+ 1. Have Festival 1.95 installed.
+ 2. Have rab_diphone voice installed.
+ 3. Have xsltproc installed.
+ 4. If you have Festival Talker configured, reconfigure it (Edit) so that it will detect
+ if you have rab_diphone voice installed. You must hit the Apply button.
+ 5. Enable XML Transformer filter and point it to xhtml2ssml_simple.xsl stylesheet.
+ 6. Right now, only speaks HTML from Konqi if you paste HTML from clipboard.
+ Speak button in Konqi not yet enabled until I get some confidence it is working well.
+
+2005-04-23 Gary Cramblitt (PhantomsDad)
+ * Break sentences longer than 600 characters into shorter sentences by changing comma to
+ period. This prevents Festival from droning on lower and lower in tone until it is
+ unintelligible or crashes.
+
+2005-04-22 Gary Cramblitt (PhantomsDad)
+ * If resumeText is called on a speaking job, do not restart it.
+
+2005-04-21 Gary Cramblitt (PhantomsDad)
+ * New Hungarian Hadifix (mbrola and txt2pho) voice available at
+ http://tkltrans.sourceforge.net/
+ Since Hungarian requires ISO 8859-2 character encoding, added encoding option to
+ Hadifix plugin. Also, Hadifix plugin auto-selects a voice matching the user's
+ chosen language.
+ * Abbreviate USA and UK country names to save space.
+ * Display male/female icons in Festival Interactive configuration dialog.
+ * Use new Select Talker dialog in Talker Chooser filter.
+
+2005-04-17 Gary Cramblitt (PhantomsDad)
+ * Actions to be taken on notifications may now be specified at three levels
+ Specific event of specific application
+ All other events of specific application
+ All other events
+ * When the last event of an application is deleted, delete the app from
+ Notifications list.
+
+2005-04-12 Gary Cramblitt (PhantomsDad)
+ * Enhanced notification options. Ability to customize each application event.
+ * Enhanced Talker chooser for notifications and Job Manager.
+ * Fix bug in Talker matching algorithm.
+
+2005-03-18 Gary Cramblitt (PhantomsDad)
+ * Added --systray cmdline option to KTTSMgr, which causes it to start minimized in system
+ tray.
+ * Added --autoexit cmdline option to KTTSMgr, which causes it to exit when no longer
+ speaking any text jobs.
+ * Added AutoStartManager and AutoExitManager options to config. These cause kttsd
+ to automatically start KTTSMgr when a text job starts, and automatically exit
+ KTTSMgr when all text jobs have finished speaking.
+
+2005-03-16 Gary Cramblitt (PhantomsDad)
+ * Bug fix. Interruption messages are spoken using the Talker of the interrupting message.
+ So if default Talker is en, and you do sayMessage "Guten Tag" "de", the "Text Interrupted.
+ Message" is spoken using German Talker. Interruption messages should speak using the
+ default Talker.
+
+2005-03-13 Gary Cramblitt (PhantomsDad)
+ * Bug. SBD Filter turned off by default. Not good!
+ * When running kttsd and no Talkers or Filters have been configured, automatically
+ attempt to configure them. Try to configure a Talker in the user's desktop language
+ and if that doesn't work, in English. Automatically configure the Standard
+ Sentence Boundary Detector.
+
+2005-03-12 Gary Cramblitt (PhantomsDad)
+ * Change toolbar buttons on Jobs tab to push buttons so they can be used from keyboard.
+ Clean up screen layout and add WhatsThis help.
+ * Added sayText convenience method to kspeech.h, which combines setText and startText
+ into a single call. Be sure to update kdelibs/interfaces/kspeech before attempting to
+ compile kttsd:
+ cd kdelibs/interfaces/kspeech
+ cvs up
+ make install
+ * When starting or restoring KTTSMgr, defaults to Jobs tab if visible.
+ * When clicking on Jobs tab, warn user if there are config changes not yet saved.
+
+2005-03-09 Gary Cramblitt (PhantomsDad)
+ * Add Hold and Resume items to systray menu.
+
+2005-03-06 Gary Cramblitt (PhantomsDad)
+ * Consolidated all the translation catalogues into single catalog called "kttsd".
+
+2005-03-05 Gary Cramblitt (PhantomsDad)
+ * Add support for Kiswahili, Zulu, and Ibibio Festival languages. Get them at
+ http://www.llsti.org/index.htm. Note that Ibibio does not have an assigned two-letter
+ (iso 639) code, so I gave it Zulu (zu), which is probably as bad as saying that English
+ is French, but it cannot be helped. The Ibibio and Zulu voices will only speak valid
+ Ibibio or Zulu text, so the Test button is non-functional for them until translators
+ provide translations.
+
+2005-03-02 Gary Cramblitt (PhantomsDad)
+ * BUG:100600 Fix for messages and warnings not spoken when text job is paused.
+ * Bug. Talker Chooser claims it can autoconfigure itself, but it cannot really.
+ * Allow to remove any Filter.
+
+2005-02-17 Gary Cramblitt (PhantomsDad)
+ * Remove festival/ and festivalcs/ plugins from source tree. AFAIK, these plugins don't work
+ and nobody is using them. And these are confusing packagers who think we have a build
+ dependency on Festival and Speech Tools libraries. Use festivalint/.
+
+2005-02-15 Gary Cramblitt (PhantomsDad)
+ * Translations now working.
+ * Include a copy of kdelibs/interfaces/kspeech in compat/ dir. This permits distribution
+ and compilation of KTTS for KDE less than 3.4.
+ * Support for Italian voices. Download from
+ http://www.csrf.pd.cnr.it/TTS/It-FESTIVAL-download.htm.
+ or http://mirko.lilik.it/Italian-FESTIVAL.zip
+
+2005-02-05 Gary Cramblitt (PhantomsDad)
+ * Version bumped to 0.3.0.
+ * Russian Festival voice added to voices file. Download voice from
+ http://nshmyrev.narod.ru/festival/festival.html. Must have Festival 1.95 beta or later.
+ Untar to festival/lib/voices/russian/ directory. Encoding must be one of the
+ single-byte cryllics, such as KOI8-R.
+ * Ability to load/save Talker Chooser and XML Transformer configurations.
+ * Some bug fixes related to Filters.
+
+2005-01-24 Gary Cramblitt (PhantomsDad)
+ * Add Talker Chooser Filter.
+ * Add option on Audio tab to preserve generated audio files by copying to user-specified
+ directory.
+
+2005-01-22 Gary Cramblitt (PhantomsDad)
+ * Allow filtering of notifications. (only setText and appendText are currently filtered.)
+ * Fix bug. Synchronous filters not being run.
+
+2005-01-21 Gary Cramblitt (PhantomsDad)
+ * Sentence Boundary Detector plugin now active. This means that SSML is parsed into
+ sentences and therefore can be rewound/advanced by sentence. It also means that
+ KTTS no longer crashes (taking KDE and X11 with it) on large HTML/SSML files.
+ * Filters can be applied based on the DCOP Application ID of app that queued the text
+ job.
+ * Filters can be applied based on language of Talker.
+ * StringReplacer filter can now load and save word lists to/from external file.
+ * Several other bug fixes.
+
+2005-01-13 Gary Cramblitt (PhantomsDad)
+ * FilterMgr class now implemented in kttsd, which means that filters now work. Well
+ almost. See TODO file for some nasty problems. (Hint: avoid large HTML/SSML pages!)
+ * Moved the TalkerCode matching and Talker plugins to TalkerMgr class so both
+ Speaker and SpeechData classes can access them.
+
+2005-01-09 Gary Cramblitt (PhantomsDad)
+ * Epos plugin defaults to ISO 8859-2 encoding. Pass encoded text to Epos client
+ via Stdin rather than command line to avoid encoding problem.
+ * Added encoding parameter to kspeech::setFile method. This allows for speaking a
+ file that is encoded different from global desktop default.
+
+2005-01-07 Gary Cramblitt (PhantomsDad)
+ * Start to Filters capability. StringReplacer Filter implemented in KTTSMgr GUI,
+ but not yet implemented in kttsd.
+
+2004-12-31 Gary Cramblitt (PhantomsDad)
+ * In KTTSD, if user has not yet configured any Talkers, prompt user and if they click
+ Yes, run KTTSMgr. User has option to turn off prompt.
+ * Activate kspeech::showDialog() method.
+ * The khmtlktts plugin automatically senses if KTTSD is installed and if not,
+ hides menu item.
+
+2004-12-30 Gary Cramblitt (PhantomsDad)
+ * Set LANG and LC_CTYPE environment variables before starting subprocess in Epos and
+ and Command plugins. Fix encoding bug in Epos plugin. Move common encoding routines
+ to PluginProc.
+
+2004-12-27 Gary Cramblitt (PhantomsDad)
+ * Add encoding option to Festival Interactive Plugin. When choosing a voice, default the
+ encoding option based on voices file.
+ * Add support for Polish Festival.
+
+2004-12-21 Gary Cramblitt (PhantomsDad)
+ * Require GStreamer 0.8.5 or above in configure.in.in. SuSE 9.2 users have
+ GStreamer 0.8.0, which causes KTTSMgr to immediately crash on startup.
+
+2004-12-20 Gary Cramblitt (PhantomsDad)
+ * kdenonbeta/kttsd moved to kdeaccessibility/kttsd.
+ * kdenonbeta/kttsd/libktts moved to kdelibs/interfaces/kspeech. libktts dropped.
+ * kdenonbeta/app-plugins/khtml-plugin moved to kdebase/konqueror/kttsplugin.
+ * kdenonbeta/app-plugins/kate-plugin moved to kdebase/kate/plugins/ktts.
+ * kdenonbeta/app-plugins/katepart-plugin moved to kdebase/kate/plugin/katepartktts.
+
+2004-12-19 Gary Cramblitt (PhantomsDad)
+ * Change Festival voices from ini to xml format. Permit translators to translate voice names.
+ * Add "--enable-kttsd-gstreamer" option to configure, defaulting to no.
+ Warn packagers not to distribute gstreamer in binary packages of kdeaccessibility as it
+ creates unwanted dependencies.
+
+2004-12-18 Gary Cramblitt (PhantomsDad)
+ * Remove kcmkttsmgr. Use kcmkttsd instead.
+
+2004-12-14 Gary Cramblitt (PhantomsDad)
+ * Under KDE 3.2, FestivalInt plugin automatically finding /usr/share/festival, rather
+ than /usr/bin/festival.
+
+2004-12-12 Release 0.2.0. First public release.
+
+2004-12-09 Gary Cramblitt (PhantomsDad)
+ * Require GStreamer >= 0.8.7.
+ * Bug. Always using default GStreamer sink in KTTSD. Honor user's choice now.
+
+2004-12-07 Gary Cramblitt (PhantomsDad)
+ * Add Festival Czech voice.
+ * Apply some Juk patches to GStreamerPlayer.
+
+2004-12-06 Gary Cramblitt (PhantomsDad)
+ * Initial, but primitive support for SSML with Hadifix.
+
+2004-12-03 Gary Cramblitt (PhantomsDad)
+ * Audio players are now plugins. This permits distribution of binary packages
+ without GStreamer being a mandatory dependency.
+
+2004-12-02 Gary Cramblitt (PhantomsDad)
+ * Bypass stretching (overall Speed setting) when utterance contains SSML. sox
+ mangles SSML pitch settings.
+
+2004-12-01 Gary Cramblitt (PhantomsDad)
+ * Some code reorganization. New TalkerCode object in libkttsd.
+ * Better Talker selection dialog when changing Talker in Jobs tab.
+
+2004-11-29 Gary Cramblitt (PhantomsDad)
+ * When clicking Test button, now honors users output method (arts or gstreamer) and
+ overall Audio Speed setting.
+ * Add option for GStreamer output sink.
+
+2004-11-27 Gary Cramblitt (PhantomsDad)
+ * Extremely rudimentary support for SSML/Sable using FestivalInt plugin. If it works for
+ you, it will be minor miracle.
+ * In FestivalInt configuration dialog, do not enable OK button if EXE Path is invalid.
+ * When Editing existing FestivalInt configuration, do not inadvertently change the selected
+ voice when rescanning.
+ * In FestivalInt configuration dialog, disable voice combo box until scan has been clicked.
+
+2004-11-26 Gary Cramblitt (PhantomsDad)
+ * Slight throughput improvement by eliminating pause at start of each Festival utterance.
+ * Bug fix. Can find synthesizers when HOME env variable is in the path.
+
+2004-11-25 Gary Cramblitt (PhantomsDad)
+ * Add Finnish Male voice (http://www.ling.helsinki.fi/suopuhe/download/)
+ * Improve throughput slightly by emitting Text Started signal after playback has begun.
+
+2004-11-24 Gary Cramblitt (PhantomsDad)
+ * Add overall Speed control to KTTSMgr Audio tab. This permits to speed up speech
+ even if the synth does not support it. Must have sox installed for this to work.
+ * Add Speed and Pitch controls to Epos plugin. Also set language.
+ * Better Speed adjustment for HTS voices.
+
+2004-11-23 Gary Cramblitt (PhantomsDad)
+ * Add support for OGI English and Spanish voices.
+ * Update Handbook.
+ * Better Spanish translations for voice names.
+
+2004-11-22 Gary Cramblitt (PhantomsDad)
+ * Add support for IMS German Festival.
+ * Update Handbook.
+
+2004-11-21 Gary Cramblitt (PhantomsDad)
+ * Add volume control to Festival Interactive.
+ * Accelerators for Festival Interactive configuration dialog.
+ * HTS voices only support Volume (not Speed or Pitch)
+ * Talker Codes reflect volume setting.
+
+2004-11-20 Gary Cramblitt (PhantomsDad)
+ * Add pitch control to Festival Interactive.
+ * GStreamer plugin.
+
+2004-11-17 Gary Cramblitt (PhantomsDad)
+ * Bug fix. Hosed Talker in KTTSMgr after removing a Talker and clicking Cancel.
+ * In KTTSMgr no longer record LastTalkerID in config file; compute at load time instead.
+ * Change Talker tab in KTTSMgr to "standard" layout.
+ * Bug fix. Talker matching. Tended to pick last talker no matter what.
+
+2004-11-13 Gary Cramblitt (PhantomsDad)
+ * Fix. Nothing happens when clicking Configure button for Festival Interactive
+ plugin if your desktop language is not English. Display translated name for
+ Synthesizer in Talkers tab.
+ * Display translated words for "male", "female", "neutral", "fast", "slow", "medium",
+ "loud", "soft" in KTTSMgr Talkers list and from Jobs "Change Talker" button.
+ * getTalkers() not returning country code as part of Talker Code.
+ * The Command plugin configuration dialog should enable OK button if %t or %f
+ appear in command, or "Send data via stdin" is checked. Also uncheck this option
+ by default in order for plugin to sense proper configuration.
+ * Add Jorge Luis Arzola to credits as tester.
+
+2004-11-11 Gary Cramblitt (PhantomsDad)
+ * Support for Festival 2.0. and Festival MultiSyn voices in FestivalInt plugin.
+ * Query Festival for available voices, rather than scanning for directories.
+ * Support for multiple versions of Festival executable. Now asks for EXE path rather
+ than voices path.
+ * Allow preload of Festival voices that take a long time to load.
+ If set, Festival is started when KTTSD starts and the voice is loaded.
+ * When stopText() is called and FestivalInt plugin is synthing (not saying) using
+ a pre-loaded voice, instead of killing Festival, which would cost hugely in
+ re-startup time, Festival is allowed to finish synthing and result is discarded.
+ This improves performance when rewinding/fastforwarding.
+ * Corrected FestivalInt voices file as to voice descriptions and languages.
+ Added MultiSyn voices.
+ * Added accelerators and WhatsThis help to FestivalInt, Command, Epos, Flite, and Hadifix
+ configuration dialogs.
+ * Added modal, cancelable, progress dialog while Testing in FestivalInt, Command, Epos,
+ Flite, FreeTTS, and Hadifix configuration dialogs.
+ This prevents a crash when user clicks OK or Cancel before test has completed.
+ * Command plugin always displays configuration dialog when added, i.e., never
+ autoconfigs.
+ * Speed adjustment disabled when using MultiSyn Festival voices.
+ * Allow KTTSMgr screen to be resized to minimum size. Allow splitter to resize jobs
+ ListView to minimum vertical size.
+ * No longer attempt to build Festival plugin (static linking to Festival/Speech Tools
+ libaries). User must explicitly request via ./configure --enable-kttsd-festival.
+ Code is woefully behind, I cannot get it to work, and probably wouldn't work
+ anymore even if I could get it to link and get past crash on first call to library.
+ FestivalInt seems to work just fine..grc.
+
+2004-11-10 Paul Giannaros (Cerulean)
+ * getTalkerCodes() returning corrupted talker codes.
+
+2004-11-04 Gary Cramblitt (PhantomsDad)
+ * Add English languages to FreeTTS desktop file so they show up in Add Talker dialog.
+ * When starting kttsmgr, if no Talkers are configured, default to Talker page.
+ * In kttsmgr, uncheck and disable Enable TTS checkbox until at least one Talker
+ has been configured. Once at least one Talker is added, enable the checkbox.
+ If all Talkers are removed, uncheck and disable the box and stop KTTSD.
+ * Give kttsmgr window an icon.
+ * Add option to embed KTTSMgr in the system tray.
+
+2004-11-03 Gary Cramblitt (PhantomsDad)
+ * Add ability to configure more than one plugin for a language, but with different
+ voices. Call them "talkers".
+ * Improve language selection and management in the KTTSD's configuration. Languages
+ added shouldn't be shown in the list of languages to add. Default languages should
+ show only the current languages. Languages should be shown as names and not codes.
+ Languages should be erased from the default language combo box. If a plugin does
+ not support a language, it should not be choosable.
+ * Add support for moving a text job to a different talker (language/plugin).
+ * Standarize the .desktop files
+
+2004-10-20 Gary Cramblitt (PhantomsDad)
+ * kcm_kttsmgr and kcm_kttsd are now identical libraries/KCModules.
+ Applications should use kcm_kttsd. When all apps have stopped
+ using kcm_kttsmgr, remove it.
+
+2004-10-19 Gary Cramblitt (PhantomsDad)
+ * The following installed files were renamed
+ on or about 19 Oct 2004:
+ In $KDEDIR/share/services/:
+ festival.desktop -> kttsd_festivalplugin.desktop
+ festivalint.desktop -> kttsd_festivalintplugin.desktop
+ command.desktop -> kttsd_commandplugin.desktop
+ hadifix.desktop -> kttsd_hadifixplugin.desktop
+ flite.desktop -> kttsd_fliteplugin.desktop
+ epos-kttsdplugin.desktop -> kttsd_eposplugin.desktop
+ freetts.desktop -> kttsd_freettsplugin.desktop
+ In $KDEDIR/lib/kde3/:
+ libfestivalplugin -> libkttsd_festivalplugin
+ libfestivalintplugin -> libkttsd_festivalintplugin
+ libcommandplugin -> libkttsd_commandplugin
+ libhadifixplugin -> libkttsd_hadifixplugin
+ libfliteplugin -> libkttsd_fliteplugin
+ libeposkttsdplugin -> libkttsd_eposplugin
+ libfreettsplugin -> libkttsd_freettsplugin
+
+ Rename libkttsjobmgr to libkttsjobmgrpart per kdelibs/NAMING convention.
+
+ There is a new shell script, clean_obsolete.sh that will remove these
+ obsolete files from your system.
+
+2004-10-14 Gary Cramblitt (PhantomsDad)
+ * Fix crash when clicking Cancel to prompt for Other language code, or user
+ enters an invalid language code.
+
+2004-10-13 Gary Cramblitt (PhantomsDad)
+ * libktts is now a versioned shared library. You may need to remove the
+ unversioned library, ie.
+ rm $KDEDIR/lib/libktts.*
+
+2004-10-13 Gary Cramblitt (PhantomsDad)
+ * Revert previous change. Sorry.
+
+2004-10-13 Gary Cramblitt (PhantomsDad)
+ * Remove versioning from libkttsd.
+ NOTE: After rebuilding and installing, you will want to delete
+ the following file:
+ $KDEDIR/lib/libkttsd.so.1.0.0
+
+2004-10-12 Gary Cramblitt (PhantomsDad)
+ * Added Handbook.
+ * Help button and system tray content menu display Handbook.
+
+2004-09-07 Gary Cramblitt (PhantomsDad)
+ * Added 6 new HTS voices for Festival and FestivalInt plugins.
+ Courtesy of "N.Cat" Triskelios.
+ Download the voices from http://hts.ics.nitech.ac.jp/
+
+2004-09-04 Gary Cramblitt (PhantomsDad)
+ * Rename Hadifax to Hadifix.
+ NOTE: After rebuilding and installing, you will want to delete the
+ following files:
+ $KDEDIR/lib/kde3/libhadifaxplugin.la
+ $KDEDIR/lib/kde3/libhadifaxplugin.so
+ $KDEDIR/share/services/hadifax.desktop
+
+2004-09-02 Paul Giannaros
+ * FreeTTS plugin.
+
+2004-08-28 Gary Cramblitt (PhantomsDad)
+ * GStreamer player added. Doesn't work right now because gstreamer 0.6
+ has issues with wav files. Try again when KDE bindings (gst) have been
+ updated to gstreamer 0.8.
+ * If jobNum parameter in dcop calls is 0, default to last job queued by the
+ application, or if no such job, the current job (instead of last job).
+ * After call to stopText, if there more speakable jobs in the queue, they begin
+ speaking.
+ * Emit textPaused and textStopped signals as documented.
+ * Fix bug in festivalint plugin. Hangs sometimes with short utterances caused
+ by writing to Stdin before Stdin buffer is empty.
+ * Better sentence parsing.
+ * Minor fixes to kttsjobmgrpart.
+
+2004-08-09 Gary Cramblitt (PhantomsDad)
+ * Remove requirement to copy pluginconf.h to $KDEDIR/include when running designer
+ against plugin configuration widgets.
+ * Epos plugin not listing codecs.
+ * Some plugins listing codecs multiple times.
+ * Select and ensure default language visible when first displaying kttsmgr.
+ * Auto select and prepare Properties tab when adding a new language in kttsmgr.
+
+2004-08-08 Gary Cramblitt (PhantomsDad)
+ * Add plugin for Epos TTS Synthesis System (czech and slovak).
+
+2004-08-07 Gary Cramblitt (PhantomsDad)
+ * Existing release marked with tag ktts-0-1.
+ * New version of KTTS is 0.2.
+ * Many changes to KTTSD and the KTTSD plugins.
+ * QThreads have been mostly eliminated, which were causing anomalies.
+ * See libkttsd/pluginproc.h for the new plugin API. The new API is backwards
+ compatible to the old API.
+ * Plugins now perform synthesis separate from audibilizing, but they may do
+ both if needed. If a plugin supports separate synthesis, it returns True
+ in supportsSynth() method.
+ * If a plugin supports separate synthesis, KTTSD sends the synthesized audio file
+ to aRts for playback. The playback code has been designed with future
+ alternate playback plugins in mind, example gstreamer. (The code was adapted
+ from Juk with minor changes.)
+ * Plugins may work asynchronously, provide status via state() method and emit
+ signals when an operation has completed. If a plugin supports asynchronous
+ operation, it returns True in supportsAsync() method.
+ * If a plugin does not support asynchronous operation, it is wrapped in a QThread,
+ which is the same as before. See threadedplugin.h/cpp.
+ * Because playback is separate from synthesis and plugins work asynchronously,
+ pauseText or stopText _immediately_ pause or stop playback in mid-sentence.
+ * New plugin, flite, added for direct support of Festival Lite.
+ * The festivalint, command, and hadifax plugins were rewritten to support
+ these new capabilities.
+ * Need someone to rework the freetts plugin. I don't have JVM.
+ * Each plugin (except festival and freetts) now has a "Test" button on the
+ configuration dialog.
+ * The option to play a sound on text interruption now works.
+
+2004-07-10 Gary Cramblitt (PhantomsDad)
+ * Warn user if festival not installed.
+ * Install voices data file for festival interactive plugin even if
+ festival plugin not installed.
+
+2004-06-05 Gary Cramblitt (PhantomsDad)
+ * Draft KDE Text-to-Speech API Draft 3.
+ * Removed concept of paragraphs.
+ * Added concept of text job parts.
+ * Added sayScreenReaderOutput method.
+ * Replaced nextSenText, prevSenText, nextParText, prevParText with moveRelTextSentence.
+ * Added jumpToTextPart.
+ * Removed paragraph settings from configuration dialog.
+
+2004-05-31 Gary Cramblitt (PhantomsDad)
+ * Move speaking of notifications to KTTSD and persist notify settings.
+ * Clean up kcmkttsmgr.desktop and install to correct place.
+
+2004-05-23 Gary Cramblitt (PhantomsDad)
+ * Add option to speak KNotify notifications.
+
+2004-05-22 Gary Cramblitt (PhantomsDad)
+ * Change menu item to "Speak Text" on the Tools menu in app-plugins. Also start KTTSD if it is
+ not running.
+
+2004-05-21 Gary Cramblitt (PhantomsDad)
+ * Bug fix. Upon startup of kttsmgr, Remove button and Properties tab not enabled despite
+ default language selected.
+
+2004-05-19 Gary Cramblitt (PhantomsDad)
+ * Allow kttsmgr screen to be resized as narrow as possible.
+ * Correct some mispellings.
+ * When calling reinit() pauseText only if isSpeakingText().
+
+2004-05-18 Gary Cramblitt (PhantomsDad)
+ * Reinit() without losing existing queued text jobs, messages, or warnings.
+ * When kttsd restarts because of reinit(), job manager part refreshes list.
+
+2004-05-17 Gary Cramblitt (PhantomsDad)
+ * Fix hang when calling reinit() while speaking.
+
+2004-05-15 Gary Cramblitt (PhantomsDad)
+ * Lots of changes:
+ * Defined the KDE Text-to-speech API. See /libktts/kspeech.h.
+ * Moved all the GUI stuff out of KTTSD into kttsmgr. KTTSD is a pure non-GUI deamon now.
+ * Added text job manager as a KPart (kttsjobmgr) for GUI interface.
+ * Replaced existing configuration manager (kcmkttsd) with kcmkttsmgr, which includes kttsjobmgr.
+ * Fixed several typos and minor bugs.
+ * Fixed Kate and KHTML Plugins.
+ * Updated README, TODO and this file.
+ *
+ * IMPORTANT note to developers using KTTSD: The startText, stopText, resumeText DCOP
+ * methods now take a jobNum argument, which you can code as 0 to operate against the last text
+ * job your app queued. See /plugins/kate-plugin/katekttsd.cpp for example, or /libktts/kspeech.h.
+
+2002-11-21 Pupeno <pupeno@pupeno.com>
+ * Full port to the new architecture finished. Some fine tunning still needed.
+
+2002-09-25 Pupeno <pupeno@pupeno.com>
+ * Festival Cliente/Server plug in added. Festival plug in was added initially in the
+ project. FreeTTS never was meant to work yet.
+
+2002-07-28 Pupeno <pupeno@pupeno.com>
+ * ChangeLog created.
diff --git a/kttsd/Makefile.am b/kttsd/Makefile.am
new file mode 100644
index 0000000..5a54368
--- /dev/null
+++ b/kttsd/Makefile.am
@@ -0,0 +1,19 @@
+# The build order must be libktts, then libkttsd, then the rest.
+SUBDIRS = \
+ compat \
+ libkttsd \
+ players \
+ plugins \
+ filters \
+ kttsd \
+ kttsjobmgr \
+ kcmkttsmgr \
+ kttsmgr \
+ app-plugins \
+ icons
+
+messages: rc.cpp
+ $(EXTRACTRC) */*.rc */*/*.rc >> rc.cpp
+ $(EXTRACTRC) */*.ui */*/*.ui >> rc.cpp
+ $(EXTRACTRC) --tag=name --context=FestivalVoiceName plugins/festivalint/voices >> rc.cpp
+ $(XGETTEXT) rc.cpp */*.cpp */*.h */*/*.cpp */*/*.h -o $(podir)/kttsd.pot
diff --git a/kttsd/README b/kttsd/README
new file mode 100644
index 0000000..7906f4f
--- /dev/null
+++ b/kttsd/README
@@ -0,0 +1,166 @@
+KTTS -- KDE Text-to-Speech -- is a subsystem within the KDE desktop
+for conversion of text to audible speech. KTTS is currently under
+development and aims to become the standard subsystem for all KDE
+applications to provide speech output. Currently, KTTS consists of
+the following components:
+
+KTTSD
+ The KDE Text-to-Speech Deamon, a non-gui application that runs in
+the background, providing TTS support to KDE applications. Applications
+initiate TTS by making DCOP calls to kttsd.
+
+KTTSMGR
+ An application for configuring the KTTS System and for managing in-progress
+speech jobs. kttsmgr provides an icon in the system tray for performing
+these functions as needed.
+
+kttsjobmgr
+ A KPart for managing in-progress speech jobs.
+
+kcmkttsd
+ A KControl module for configuring the KTTS System. kcmkttsd runs in the
+KDE Control Center or start it with the command "kcmshell kcmkttsd".
+
+ktexteditor_kttsd
+ A plugin for the KDE Advanced Text Editor that permits you to speak an entire
+text file or any portion of a file.
+
+khmtl-plugin
+ A plugin for Konqueror that permits you to speak all or any portion of an
+HTML web page. (Note: this component is in kdebase/konqueror/kttsplugin)
+
+Original Author: Jos Pablo Ezequiel "Pupeno" Fernndez <pupeno@kde.org>
+Current Maintainer: Gary Cramblitt <garycramblitt@comcast.net>
+Contributors:
+ Olaf Schmidt <ojschmidt@kde.org>
+ Gunnar Schmi Dt <gunnar@schmi-dt.de>
+ Paul Giannaros <ceruleanblaze@gmail.com>
+ Jorge Luis Arzola <arzolacub@hotmail.com>
+ David Powell <achiestdragon@gmail.com>
+
+User features:
+ * Speak contents of a text file.
+ * Speak KDE notification events (KNotify).
+ * Speak all or part of the text of a web page in Konqueror.
+ * Speak all or part of the text in Kate text editor, including
+ instances where Kate is embedded in another KDE application.
+ * Long text is parsed into sentences. User may backup by sentence
+ or paragraph, replay, pause, and stop playing.
+ * Filter plugins for converting chat emoticons to speakable words,
+ fix mispronunciations, and convert xhtml to SSML.
+ * Audio output via aRts, ALSA, GStreamer (version 0.8.7 or later),
+ or aKode.
+
+Programmer features:
+ * Priority system for screen reader outputs, warnings and messages,
+ while still playing regular texts.
+ * Plugin-based architecture for support of a wide variety of speech
+ synthesis engines and drivers.
+ * Permit generation of speech from the command line (or via shell scripts)
+ using the KDE DCOP utilities.
+ * Provide a lightweight and easily usable interface for applications
+ to generate speech output.
+ * Applications need not be concerned about contention over the speech device.
+ * FUTURE: Provide support for speech markup languages, such as VoiceXML, Sable,
+ Java Speech Markup Language (JSML), and Speech Markup Meta-language (SMML).
+ * FUTURE: Provide limited support for embedded speech markers.
+ * Asynchronous to prevent system blocking.
+
+Requirements
+------------
+KDE 3.2 or greater and a speech synthesis engine, such as Festival. Festival
+can be obtained from http://www.cstr.ed.ac.uk/projects/festival/. Festival
+is distributed with most Linux distros. Check your distro CDs. Also works
+with Hadifix, Epos, Festival Lite (flite), FreeTTS, or any command that can
+speak text.
+
+Optional Components
+-------------------
+ * The sox utility is needed for adjusting overall speech rate.
+ * The xsltproc utility is needed for SSML support.
+ * GStreamer 0.8.7 or greater.
+
+See the KTTS Handbook
+
+ (http://accessibility.kde.org/developer/kttsd/handbook/index.html)
+
+for complete instructions on installing, compiling, configuring, and using
+KTTS.
+
+Audio Plugins
+-------------
+KTTS can be built with the following audio plugins. The "Default Configure
+"Option" column shows the default option for the configure command.
+The "Alternate" column gives the opposite configure option:
+
+ System Plugin Default Configure Option Alternate
+ ------ ------------ ------------------------- ------------------------
+ aRts artsplayer --with-arts --without-arts
+ ALSA alsaplayer --with-alsa=check --with-alsa=no
+ GStreamer gstplayer --with-gstreamer=no --with-gstreamer=check
+ aKode akodeplayer --with-akode=no --with-akode=check
+
+You *must* have at least one of these plugins for KTTS to work.
+
+The aKode and GStreamer players are not built by default because they have issues
+with instant stopping and starting.
+
+Packager Notes
+--------------
+The following speech synthesizer plugins are all built by default.
+Some of them are runtime only dependent upon non-free software.
+(Non-free according to Debian Policy). The "Configure Option to
+not build" column shows the configure command to not build the plugin:
+
+ Synth License Configure Option to not build
+ ------------- -------- -----------------------------
+ Festival free --disable-kttsd-festivalint
+ Festival Lite free --disable-kttsd-flite
+ Epos free --disable-kttsd-epos
+ Command free --disable-kttsd-command
+ Hadifix non-free --disable-kttsd-hadifix
+ FreeTTS non-free --disable-kttsd-freetts
+
+IMPORTANT NOTE TO BINARY PACKAGERS:
+Please do not distribute binary packages of kdeaccessibility with the
+gstreamer plugin, as this creates unwanted dependencies. Instead,
+distribute the gstreamer plugin in a separate package, e.g.
+kde-accessibility-extras. The separate package should require
+gstreamer >= 0.8.7. Thank you.
+
+Support
+-------
+The KTTS website is
+
+ http://accessibility.kde.org/developer/kttsd
+
+In addition to the KDE Bugzilla database (bugs.kde.org), discussions for KTTSD
+currently take place in the kde-accessibility mailing list. Subscribe at
+https://mail.kde.org/mailman/listinfo/kde-accessibility. Developers
+also hang out in IRC (irc.kde.org channel #kde-accessibility).
+
+Directories
+-----------
+libktts Library for applications desiring to speak text. This must be built first.
+libkttsd Library for KTTSD. Defines the interface for plugins for KTTSD. Must be built second.
+players Audio plugins for KTTSD.
+ artsplayer aRts audio plugin for KTTSD.
+ gstplayer GStreamer audio plugin for KTTSD.
+ alsaplayer ALSA audio plugin for KTTSD.
+ akodeplayer aKode audio plugin for KTTSD.
+plugins Plugins for KTTSD. You must have at least one plugin to use KTTSD.
+ festivalint Plugin for Festival using Festival Interactive mode (festival --interactive).
+ flite Plugin for Festival Lite.
+ hadifix Plugin for Hadifix.
+ freetts Plugin for FreeTTS.
+ epos Plugin for Epos.
+ command Generic command plugin.
+kttsd KTTSD itself. Non-interactive deamon.
+icons Icon for kttsmgr and KTTSD.
+kttsjobmgr A KPart used by kcmkttsmgr for managing text jobs in KTTSD.
+kcmkttsmgr A KControl module for managing KTTSD. Run using "kcmshell kcmkttsd".
+kttsmgr Application for managing KTTSD. Wrapper for kcmkttsmgr plus a system tray icon.
+app-plugins Plugins for other applications to speak text.
+ kate Embedded Kate plugin.
+compat Copy of kdelibs/interfaces/kspeech. Used when compiling for KDE less than 3.4.
+debian Debian packaging files. (possibly way out of date)
diff --git a/kttsd/README.kttsd b/kttsd/README.kttsd
new file mode 100644
index 0000000..2fe8d51
--- /dev/null
+++ b/kttsd/README.kttsd
@@ -0,0 +1,10 @@
+Where is KTTSD?
+
+KTTSD was moved on 20 Dec 2004.
+Most of it has moved to kdeaccessibility/kttsd.
+The following pieces were also moved.
+
+kttsd/libktts -> kdelibs/interfaces/kspeech
+kttsd/app-plugins/khtml-plugin -> kdebase/konqueror/kttsplugin
+kttsd/app-plugins/kate-plugin -> kdebase/kate/plugins/ktts
+kttsd/app-plugins/katepart-plugin -> kdebase/kate/plugin/katepartktts
diff --git a/kttsd/TODO b/kttsd/TODO
new file mode 100644
index 0000000..27ef1a3
--- /dev/null
+++ b/kttsd/TODO
@@ -0,0 +1,95 @@
+_ Filters:
+ _ XHTMLtoSSML stylesheet needs work to provide better mappings for most web pages.
+ _ Add KNewStuff capability for folks to upload/download filter configs.
+ _ There should be a default set of filters configured when user first runs KTTSMgr.
+ If user presses Default button, it should ask user whether to replace all existing
+ filters with the standard set. The standard set should probably include
+ the Qt to Plain Text and Fix Festival Unspeakable Characters filters, but I'm not
+ sure about the latter when desktop is not ISO 8859-1.
+ _ The SBD Filter configuration dialog can be shrunk smaller than the widgets on it.
+ This apparently due to a bug in the QLabel widget when it contains RichText. If
+ forced to plain text, the problem won't happen (I am told). However, the WARNING
+ in the dialog needs to be bolded. What to do?
+_ Handbook:
+ _ Mention that "Root element is" and "DOCTYPE" are case sensitive. "html" is not
+ the same as "HTML". It should stay this way, BTW. Proper xhtml requires lowercase
+ tags.
+_ Audio Plugins:
+ _ Audio Plugins are loaded for each sentence. Instead, reuse the plugins from a pool
+ of loaded plugins.
+ _ BUG:116542. Apply patch and resolve compile issue.
+ _ At least one user experiences a freeze-up using ALSA plugin. Speak a web page,
+ pause the page, cause a knotify to speak, kttsd freezes. This appears to be an
+ ALSA device contention problem? In this situation, there are two alsaplayer objects;
+ one in pause state, and one attempting to speak notify.
+ _ akodelib does not stop instantly when pause() or stop() is called. See bug:107135.
+ _ Why must Player constructor take a 3rd "args" argument, while PluginProc constructor
+ does not. They are essentially the same. ??
+ _ Add option to automatically turn down music player volume while speaking (via dcop).
+_ Festival Interactive plugin:
+ _ Need someone who can read czech to try integrating this into KTTS:
+ http://www.freebsoft.org/festival-czech
+ _ New Italian voice for Festival. http://www.pd.istc.cnr.it/FESTIVAL/home/default.htm
+_ EPOS plugin:
+_ Command plugin:
+ _ Command plugin encodes text on command line using %t in user's chosen encoding, but
+ if this differs from user's desktop default encoding, doesn't work. KProcess always
+ encodes command line stuff using user's default encoding. There is no point, therefore,
+ in attempting to encode it differently, just mangles the text even more. Short of modifying
+ KProcess, I see no way around this. But perhaps a warning to user advising to use %f instead?
+ _ Command plugin crashes when using command 'flite -t "%t"' and flite can't get write access to /dev/dsp*.
+_ Hadifix plugin:
+ _ BUG:116151 Add options for using the new prepoc capability in Hadifix.
+ _ When stopText() is called, and Hadifix process is killed, the temporary wav file is not deleted,
+ despite QFile::remove call. Possibly still locked by exiting mbrola process? This only seems
+ to happen in the configuration dialog when canceling Tests.
+_ KTTSMgr:
+ _ Give Talkers a Talker Name entered by user. Show this name in Jobs tab, Change Talker screen,
+ and in systray menu.
+ _ Change the Current Sentence panel to show the current sentence of the selected job? If selected
+ job is not the currently speaking job, won't show currently-speaking text anymore. However, would
+ be helpful when using advance/rewind buttons. Perhaps to be effective, if the currently-selected
+ job IS the currently speaking job, and that job finishes, would automatically select the next
+ speaking job? But that could become confusing for users with selection jumping around.
+ _ Add ability to quickly pick default Talker in systray menu.
+ _ KCMultiDialog has a bug that won't allow sizing the screen narrower than 640.
+ _ Overall Audio Speed should be a realtime setting, i.e., not necessary to click Apply.
+ _ Disable Audio Speed control if sox not installed (configure.in.in but runtime check would be better).
+ _ Add drag N drop for the Talkers so it is easier to change the ordering.
+ _ It is possible to configure multiple instances of Talkers with the exact same configuration.
+ _ In kcmkttsmgr, use setHelp() to set help anchor based on current tab.
+ _ Add playback controls to kttsmgr. Volume, pause. Maybe rewind?
+_ KTTSD:
+ _ I am told that when kttsd crashes, it can take knotify down with it. See about
+ "disconnecting" knotify from kttsd (using post to Qt event queue).
+ _ Strange msg being produced by KIO::move, but it works fine. ??
+ kio (KIOJob): stat file:///home/kde-devel/.kde/share/apps/kttsd/audio/kttsd-5-1.wav
+ kio (KIOJob): error 11 /home/kde-devel/.kde/share/apps/kttsd/audio/kttsd-5-1.wav
+ kio (KIOJob): This seems to be a suitable case for trying to rename before stat+[list+]copy+del
+ _ While kttsd currently configures a Talker automatically, would be nice if it could
+ autoconfigure talkers for each requested language, if one has not already been configured.
+ _ Add support for speech markers.
+ _ Implement error signal handling in KTTSD.
+ _ Add support for JSML and other Speech Markup languages.
+ _ Add method for apps to play a sound file, including in the middle of a job.
+ Could be done with SSML or with special Talker Code = "sound".
+_ Other/General:
+ _ As pointed out by NOKUBI Takatsugu on Planet Debian, there exists an
+ open-source synthesis + recognition engine for Japanese.
+ http://aniki.daionet.gr.jp/~knok/blog/blosxom.cgi/2005/11/24
+ http://hil.t.u-tokyo.ac.jp/~galatea/index.html
+ _ Save buttons should confirm if user chooses an existing file. KFileDialog doesn't seem to
+ offer this option, but shouldn't it?
+ _ .desktop files must have a Type keyword, but what to use for kcmkttsd_testmessage.desktop?
+ _ Add option to kill plugin process when no longer needed so that memory can be recovered.
+ Or maybe some sort of "nice" setting so that process will be swapped out when no longer needed.
+ _ Convert to KConfig XT.
+ _ Add a plugin for TuxTalk, http://tuxtalk.sourceforge.net/. Since it only supports
+ English (at the moment) and is alpha, don't think it is worth it now.
+ _ Add a plugin for dhvani, an Indian and Hindi TTS engine, http://dhvani.sourceforge.net/
+ Currently written in c, but it looks like future versions will require Java VM.
+ Main problem at the moment is that dhvani sends audio directly to /dev/dsp with no option
+ to send to a wav file.
+ _ IBM ViaVoice plugin? IBM TTS is a proprietary runtime product with opensource API.
+ http://ibmtts-sdk.sourceforge.net/
+ _ Add KTTS plugin to aKregator.
diff --git a/kttsd/TODO.french b/kttsd/TODO.french
new file mode 100644
index 0000000..32372c3
--- /dev/null
+++ b/kttsd/TODO.french
@@ -0,0 +1,31 @@
+The <a href="http://accessibility.kde.org/developer/kttsd/index.php">KDE Text-to-Speech System</a> currently supports the following languages via non-commercial TTS systems and voices on the Linux platform:
+
+American English
+British
+Spanish
+German
+Finnish
+Czech
+Polish
+Russian
+Italian
+Kiswahili
+Zulu
+Ibibio
+
+Notably absent from this list is French (French Canadian voices can be purchased from <a href="http://www.cepstral.com">Cepstral LLC</a>). This is a damn shame.
+
+If you are French speaking, your mission, should you choose to accept it, is to develop a free and easy-to-install French language package for KTTS on the Linux platform. There are several possible ways this could be done:
+
+1. MBROLA and txt2pho. This solution uses MBROLA to synthesize voice from phonemes. What's needed is a means to convert text into phonemes. There are French voices available for MBROLA at <a href="http://tcts.fpms.ac.be/synthesis/mbrola/mbrcopybin.html">http://tcts.fpms.ac.be/synthesis/mbrola/mbrcopybin.html</a>. There are txt2pho utilities and other TTS systems available at <a href="http://tcts.fpms.ac.be/synthesis/mbrola/mbrtts.html">http://tcts.fpms.ac.be/synthesis/mbrola/mbrtts.html</a>. I tried these without success. In some cases, the txt2pho programs fussed about "little endian", so this might require some perl programming. If you get a solution working this way, it would employ the Hadifix plugin in KTTS.
+
+2. MBROLA and Festival. Like #1, this solution uses MBROLA to synthesize voice from phonemes, but uses Festival to do the text to phoneme conversion. More info at <a href="http://www.cstr.ed.ac.uk/projects/festival/mbrola.html">http://www.cstr.ed.ac.uk/projects/festival/mbrola.html</a>. A solution using this technique was developed for Festival 1.4.3 called FranFest. Google for "FranFest". Also, here's an article that explains how to install it: <a href="http://www.pollock-nageoire.net/festival/festival-english004.html">http://www.pollock-nageoire.net/festival/festival-english004.html</a>. The problem with this is 1) it requires patching and rebuilding Festival, and 2) it needs to be adapted to Festival 2.0 (1.95 beta). I would recommend approaching the Festival programmers about incorporating this patch into Festival permanently.
+
+3. Native Festival. Develop a "native" voice for Festival so that Festival can do the full TTS conversion. This is much harder than #1 or #2, but would be much easier for KTTS users to install. From time to time, I have seen people mention on the festival-talk mailing list that they are working on this, so it may already be done or near done. More info at <a href="http://festvox.org/maillists.html">http://festvox.org/maillists.html</a>. Unfortunately, the festival-talk mailing list archive is not available. I can send you an mbox of what I have if you are interested.
+
+Whatever solution you come up with, you'll need to document how French KTTS users install and configure it. If your solution uses Festival, it must list the voice code for the French voice in response to the following Scheme statement:
+
+ (print (mapcar (lambda (pair) (car pair)) voice-locations))
+
+Contact me in irc.kde.org channel #kde-accessibility for more information.
+
diff --git a/kttsd/app-plugins/Makefile.am b/kttsd/app-plugins/Makefile.am
new file mode 100644
index 0000000..22a2493
--- /dev/null
+++ b/kttsd/app-plugins/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = kate
diff --git a/kttsd/app-plugins/kate/Makefile.am b/kttsd/app-plugins/kate/Makefile.am
new file mode 100644
index 0000000..3508e52
--- /dev/null
+++ b/kttsd/app-plugins/kate/Makefile.am
@@ -0,0 +1,19 @@
+# Allow build from within kdebase or kdeaccessibility.
+INCLUDES = \
+ -I$(top_srcdir)/kate/interfaces \
+ -I$(kde_includes)/kate \
+ $(all_includes)
+
+METASOURCES = AUTO
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = ktexteditor_kttsd.la
+
+ktexteditor_kttsd_la_SOURCES = katekttsd.cpp
+ktexteditor_kttsd_la_LIBADD = -lktexteditor
+ktexteditor_kttsd_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+kttsddatadir = $(kde_datadir)/ktexteditor_kttsd
+kttsddata_DATA = ktexteditor_kttsdui.rc
+
+kde_services_DATA = ktexteditor_kttsd.desktop
diff --git a/kttsd/app-plugins/kate/katekttsd.cpp b/kttsd/app-plugins/kate/katekttsd.cpp
new file mode 100644
index 0000000..a2e64e6
--- /dev/null
+++ b/kttsd/app-plugins/kate/katekttsd.cpp
@@ -0,0 +1,120 @@
+/***************************************************************************
+ A KTextEditor (Kate Part) plugin for speaking text.
+
+ Copyright:
+ (C) 2003-2004 by Olaf Schmidt <ojschmidt@kde.org>
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+
+ Original Author: Olaf Schmidt <ojschmidt@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// Qt includes.
+#include <qmessagebox.h>
+#include <dcopclient.h>
+#include <qtimer.h>
+
+// KDE includes.
+#include <ktexteditor/editinterface.h>
+#include <ktexteditor/selectioninterface.h>
+
+#include <kaction.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kgenericfactory.h>
+
+// KateKttsdPlugin includes.
+#include "katekttsd.h"
+#include "katekttsd.moc"
+
+K_EXPORT_COMPONENT_FACTORY( ktexteditor_kttsd, KGenericFactory<KateKttsdPlugin>( "ktexteditor_kttsd" ) )
+
+KateKttsdPlugin::KateKttsdPlugin( QObject *parent, const char* name, const QStringList& )
+ : KTextEditor::Plugin ( (KTextEditor::Document*) parent, name )
+{
+}
+
+KateKttsdPlugin::~KateKttsdPlugin()
+{
+}
+
+
+void KateKttsdPlugin::addView(KTextEditor::View *view)
+{
+ KateKttsdPluginView *nview = new KateKttsdPluginView (view, "KTTSD Plugin");
+ m_views.append (nview);
+}
+
+void KateKttsdPlugin::removeView(KTextEditor::View *view)
+{
+ for (uint z=0; z < m_views.count(); ++z)
+ if (m_views.at(z)->parentClient() == view)
+ {
+ KateKttsdPluginView *nview = m_views.at(z);
+ m_views.remove (nview);
+ delete nview;
+ }
+ KGlobal::locale()->removeCatalogue("kttsd");
+}
+
+
+KateKttsdPluginView::KateKttsdPluginView( KTextEditor::View *view, const char *name )
+ : QObject( view, name ),
+ KXMLGUIClient( view )
+{
+ view->insertChildClient( this );
+ setInstance( KGenericFactory<KateKttsdPlugin>::instance() );
+ KGlobal::locale()->insertCatalogue("kttsd");
+ (void) new KAction( i18n("Speak Text"), "kttsd", 0, this, SLOT(slotReadOut()), actionCollection(), "tools_kttsd" );
+ setXMLFile( "ktexteditor_kttsdui.rc" );
+}
+
+void KateKttsdPluginView::slotReadOut()
+{
+ KTextEditor::View *v = (KTextEditor::View*)parent();
+ KTextEditor::SelectionInterface *si = KTextEditor::selectionInterface( v->document() );
+ QString text;
+
+ if ( si->hasSelection() )
+ text = si->selection();
+ else {
+ KTextEditor::EditInterface *ei = KTextEditor::editInterface( v->document() );
+ text = ei->text();
+ }
+
+ DCOPClient *client = kapp->dcopClient();
+ // If KTTSD not running, start it.
+ if (!client->isApplicationRegistered("kttsd"))
+ {
+ QString error;
+ if (kapp->startServiceByDesktopName("kttsd", QStringList(), &error))
+ QMessageBox::warning(0, i18n( "Starting KTTSD Failed"), error );
+ }
+ QByteArray data;
+ QByteArray data2;
+ QCString replyType;
+ QByteArray replyData;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << text << "";
+ if ( !client->call("kttsd", "KSpeech", "setText(QString,QString)",
+ data, replyType, replyData, true) )
+ QMessageBox::warning( 0, i18n( "DCOP Call Failed" ),
+ i18n( "The DCOP call setText failed." ));
+ QDataStream arg2(data2, IO_WriteOnly);
+
+ arg2 << 0;
+ if ( !client->call("kttsd", "KSpeech", "startText(uint)",
+ data2, replyType, replyData, true) )
+ QMessageBox::warning( 0, i18n( "DCOP Call Failed" ),
+ i18n( "The DCOP call startText failed." ));
+}
+
diff --git a/kttsd/app-plugins/kate/katekttsd.h b/kttsd/app-plugins/kate/katekttsd.h
new file mode 100644
index 0000000..cbab720
--- /dev/null
+++ b/kttsd/app-plugins/kate/katekttsd.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ A KTextEditor (Kate Part) plugin for speaking text.
+
+ Copyright:
+ (C) 2003-2004 by Olaf Schmidt <ojschmidt@kde.org>
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+
+ Original Author: Olaf Schmidt <ojschmidt@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _KATEKTTSD_H_
+#define _KATEKTTSD_H_
+
+#include <ktexteditor/plugin.h>
+#include <ktexteditor/view.h>
+#include <kxmlguiclient.h>
+#include <qobject.h>
+
+class KateKttsdPlugin : public KTextEditor::Plugin, public KTextEditor::PluginViewInterface
+{
+ Q_OBJECT
+
+ public:
+ KateKttsdPlugin( QObject *parent = 0,
+ const char* name = 0,
+ const QStringList &args = QStringList() );
+ virtual ~KateKttsdPlugin();
+
+ void addView (KTextEditor::View *view);
+ void removeView (KTextEditor::View *view);
+
+ private:
+ QPtrList<class KateKttsdPluginView> m_views;
+};
+
+class KateKttsdPluginView : public QObject, public KXMLGUIClient
+{
+ Q_OBJECT
+
+ public:
+ KateKttsdPluginView( KTextEditor::View *view, const char *name=0 );
+ ~KateKttsdPluginView() {};
+
+ public slots:
+ void slotReadOut();
+};
+
+#endif // _KATEKTTSD_H_
diff --git a/kttsd/app-plugins/kate/ktexteditor_kttsd.desktop b/kttsd/app-plugins/kate/ktexteditor_kttsd.desktop
new file mode 100644
index 0000000..aac7e0c
--- /dev/null
+++ b/kttsd/app-plugins/kate/ktexteditor_kttsd.desktop
@@ -0,0 +1,104 @@
+[Desktop Entry]
+Name=KTextEditor KTTSD Plugin
+Name[bg]=Приставка KTextEditor KTTSD
+Name[br]=Lugent KTTSD KTextEditor
+Name[bs]=KTextEditor KTTSD dodatak
+Name[ca]=Connector pel KTTSD del KTextEditor
+Name[cs]=KTextEditor KTTSD modul
+Name[de]=KTextEditor-Modul für KTTSD
+Name[el]=Πρόσθετο KTextEditor KTTSD
+Name[es]=Complemento KTextEditor KTTSD
+Name[et]=KTextEditor KTTSD plugin
+Name[eu]=KTextEditor-en KTTSD plugina
+Name[fa]=وصلۀ KTextEditor KTTSD
+Name[fi]=KTextEditor KTTSD -liitännäinen
+Name[fr]=Module KTTSD pour KTextEditor
+Name[ga]=Breiseán KTTSD KTextEditor
+Name[gl]=Plugin de KTTSD para KTextEditor
+Name[he]=תוסף KTextEditor עבור KTTSD
+Name[hu]=KTextEditor KTTSD-modul
+Name[is]=KTextEditor KTTSD íforrit
+Name[it]=Plugin di KTTSD per KTextEditor
+Name[ja]=KTextEditor KTTSD プラグイン
+Name[ka]=KTextEditor KTTSD მოდული
+Name[km]= កម្មវិធី​ជំនួយ​ KTextEditor KTTSD
+Name[lt]=KTextEditor KTTSD priedas
+Name[mk]=KTTSD-приклучок за KTextEditor
+Name[ms]=Plugin KTextEditor KTTSD
+Name[nb]=KTextEditor programtillegg for KTTSD
+Name[nds]=KTTSD-Moduul KTextEditor
+Name[ne]=केडीई पाठ सम्पादक KTTSD प्लगइन
+Name[nl]=KTextEditor KTTSD-plugin
+Name[pa]=KTextEditor KTTSD ਪਲੱਗਿੰਨ
+Name[pl]=Wtyczka KTTSD dla edytora tekstu
+Name[pt]='Plugin' KTextEditor do KTTSD
+Name[pt_BR]=Plug-in do KTTSD para o KTextEditor
+Name[ru]=Модуль KTextEditor для KTTSD
+Name[sk]=KTextEditor KTTSD modul
+Name[sl]=Vstavek KTTSD za KTextEditor
+Name[sr]=KTTSD као прикључак за KTextEditor
+Name[sr@Latn]=KTTSD kao priključak za KTextEditor
+Name[sv]=KTTSD-insticksprogram för Ktexteditor
+Name[ta]=KTextEditor KTTSD சொருகுப்பொருள்
+Name[tg]=Модли KTextEditor барои KTTSD
+Name[th]=ปลั๊กอิน KTTSD สำหรับ KTextEditor
+Name[tr]=Ktexteditor KTTSD Eklentisi
+Name[uk]=Втулок KTextEditor KTTSD
+Name[vi]=Trình bổ sung KTTSD cho Trình soạn thảo K
+Name[zh_CN]=KTextEditor KTTSD 插件
+Name[zh_TW]=K-文字編輯器的 kttsd 外掛程式
+Comment=Adds a menu entry for speaking the text
+Comment[bg]=Добавяне на операция в менюто за изговаряне на текст
+Comment[bs]=Dodaje stavku u meniju za čitanje teksta
+Comment[ca]=Afegeix una entrada de menú per pronunciar el text
+Comment[cs]=Vložení nabídky pro předčítání textu
+Comment[da]=Tilføjer et menupunkt for at læse teksten op
+Comment[de]=Fügt einen Menüeintrag zum Vorlesen des Textes hinzu
+Comment[el]=Προσθέτει μία καταχώρηση στο μενού για τη μετατροπή σε φωνή του κειμένου
+Comment[es]=Añadir una entrada al menú para leer el texto
+Comment[et]=Lisab menüükirje teksti kõnelemiseks
+Comment[eu]=Testuak ahoskatzeko menuko sarrera bat gehitzen du
+Comment[fa]=مدخل گزینگان را برای گفتن متن اضافه می‌کند
+Comment[fi]=Lisää valikkovalinnan tekstin puhumiseksi
+Comment[fr]=Ajoute une entrée dans le menu pour prononcer le texte
+Comment[ga]=Cuir iontráil sa roghchlár chun an téacs a rá
+Comment[gl]=Engade unha entrada no menu para falar o texto
+Comment[he]=מוסיף כניסה בתפריט להקראת הטקסט
+Comment[hu]=Menüpont létrehozása szövegfelolvasáshoz
+Comment[is]=Bætir við valmyndarfærslu fyrir tal af textanum
+Comment[it]=Aggiunge una voce del menu per pronunciare il testo
+Comment[ja]=テキスト読み上げをメニューエントリに追加する
+Comment[ka]=ტექსტის წაკითხვას ამატებს მენიუს ჩანაწერს
+Comment[km]=បន្ថែម​ធាតុ​ម៉ឺនុយ​សម្រាប់​ការ​និយាយ​អត្ថបទ
+Comment[lt]=Prideda meniu įrašą teksto įkalbėjimui
+Comment[mk]=Додава елемент во менито за зборување на текстот
+Comment[ms]=Tambah entri menu untuk menjadikan teks bercakap
+Comment[nb]=Legger til en menyoppføring for å si teksten høyt
+Comment[nds]=Föögt en Menüindrag för dat Textvörlesen to
+Comment[ne]=पाठ बोल्नका लागि मेनु प्रविष्टि थप्छ
+Comment[nl]=Voegt een menuoptie toe voor het uitspreken van de tekst
+Comment[pa]=ਪਾਠ ਬੋਲਣ ਲਈ ਇੱਕ ਮੇਨੂ ਇੰਦਰਾਜ਼ ਜੋੜਦਾ ਹੈ
+Comment[pl]=Dodaje wpis w menu do mówienia tekstu
+Comment[pt]=Adiciona uma entrada de menu para ler o texto
+Comment[pt_BR]=Adiciona uma entrada no menu para falar o texto
+Comment[ru]=Добавляет меню синтеза речи
+Comment[sk]=Pridá položku menu pre hovorenie textu
+Comment[sl]=Dodaj menijski vnos za govorjenje besedila
+Comment[sr]=Додаје ставку менија за изговарање текста
+Comment[sr@Latn]=Dodaje stavku menija za izgovaranje teksta
+Comment[sv]=Lägger till ett menyalternativ för att läsa upp texten
+Comment[ta]=உரையை பேசுவதற்கு ஒரு பட்டியல் உள்ளிட்டை சேர்க்கிறது
+Comment[tg]=Илова кардани менюи таҳлили овоз
+Comment[th]=เพิ่มรายการเมนูสำหรับอ่านข้อความเป็นเสียง
+Comment[tr]=Metni okumak için bir menü girdisi oluşturur
+Comment[uk]=Додає елемент меню для декламування тексту
+Comment[vi]=Thêm danh mục thực đơn cho việc đọc văn bản
+Comment[zh_CN]=添加可读出文本的菜单项
+Comment[zh_TW]=新增朗讀文字的目錄
+Type=Service
+ServiceTypes=KTextEditor/Plugin
+X-KDE-Library=ktexteditor_kttsd
+X-Kate-Version=2.2
+MimeType=text/plain
+Icon=kttsd
+author=Olaf Jan Schmidt, ojschmidt@kde.org
diff --git a/kttsd/app-plugins/kate/ktexteditor_kttsdui.rc b/kttsd/app-plugins/kate/ktexteditor_kttsdui.rc
new file mode 100644
index 0000000..9dea629
--- /dev/null
+++ b/kttsd/app-plugins/kate/ktexteditor_kttsdui.rc
@@ -0,0 +1,11 @@
+<!DOCTYPE kpartgui>
+<kpartplugin name="ktexteditor_kttsd" library="ktexteditor_kttsd" version="2">
+ <MenuBar>
+ <Menu name="tools"><Text>&amp;Tools</Text>
+ <Action name="tools_kttsd" />
+ </Menu>
+ </MenuBar>
+ <ToolBar name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="tools_kttsd" />
+ </ToolBar>
+</kpartplugin>
diff --git a/kttsd/clean_obsolete.sh b/kttsd/clean_obsolete.sh
new file mode 100755
index 0000000..17e8c26
--- /dev/null
+++ b/kttsd/clean_obsolete.sh
@@ -0,0 +1,105 @@
+#! /bin/sh
+
+# This script cleans obsolete KTTS files from your system.
+# You should run this if you have been downloading KTTS and installing
+# prior to the indicated dates.
+
+# You would normally run this after running configure and before
+# make install, i.e.,
+# cd kdenonbeta
+# echo kttsd>inst-apps
+# make -f Makefile.cvs
+# ./configure
+# cd kttsd
+# ./clean_obsolete.sh
+# make install
+
+PREFIX=$(kde-config --prefix)
+LIBTOOL="../libtool"
+
+if [ -z "$PREFIX" ]; then
+ echo "KDE prefix not found. Do you have kde-config installed?"
+ exit
+fi
+
+if [ ! -x $LIBTOOL ]; then
+ echo "libtool was not found. Did you run configure?"
+ exit
+fi
+
+set -x
+
+# libktts removed. See kdeaccessibility/kttsd/kcmkttsmgr/Makefile.am
+# for example how to build without it.
+# on or about 20 Dec 2004.
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/libktts
+$LIBTOOL --mode=uninstall $PREFIX/lib/libktts
+
+# ServiceType kttsd.desktop renamed to kttsd_synthplugin.desktop,
+# which distinquishes it from kttsd.desktop in the services dir
+# and more accurately reflects its purpose
+# on or about 8 Dec 2004.
+rm -f $PREFIX/share/servicetypes/kttsd.desktop
+
+# kcm_kttsmgr removed. Use kcm_kttsd instead.
+# Change made on or about 18 Dec 2004.
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/kcm_kttsmgr
+rm -f $PREFIX/share/applnk/Settings/Accessibility/kcmkttsmgr.desktop
+rm -f $PREFIX/share/applications/kde/kcmkttsmgr.desktop
+
+# Renamed libkttsjobmgr to libkttsjobmgrpart per kdelibs/NAMING convention
+# on or about 19 Oct 2004:
+
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/libkttsjobmgr
+
+# The following installed files were renamed
+# on or about 19 Oct 2004:
+# In $KDEDIR/share/services/:
+# festival.desktop -> kttsd_festivalplugin.desktop
+# festivalint.desktop -> kttsd_festivalintplugin.desktop
+# command.desktop -> kttsd_commandplugin.desktop
+# hadifix.desktop -> kttsd_hadifixplugin.desktop
+# flite.desktop -> kttsd_fliteplugin.desktop
+# epos-kttsdplugin.desktop -> kttsd_eposplugin.desktop
+# freetts.desktop -> kttsd_freettsplugin.desktop
+# In $KDEDIR/lib/kde3/:
+# libfestivalplugin -> libkttsd_festivalplugin
+# libfestivalintplugin -> libkttsd_festivalintplugin
+# libcommandplugin -> libkttsd_commandplugin
+# libhadifixplugin -> libkttsd_hadifixplugin
+# libfliteplugin -> libkttsd_fliteplugin
+# libeposkttsdplugin -> libkttsd_eposplugin
+# libfreettsplugin -> libkttsd_freettsplugin
+
+rm -f $PREFIX/share/services/festival.desktop
+rm -f $PREFIX/share/services/festivalint.desktop
+rm -f $PREFIX/share/services/command.desktop
+rm -f $PREFIX/share/services/hadifix.desktop
+rm -f $PREFIX/share/services/flite.desktop
+rm -f $PREFIX/share/services/epos-kttsdplugin.desktop
+rm -f $PREFIX/share/services/freetts.desktop
+
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/libfestivalplugin
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/libfestivalintplugin
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/libcommandplugin
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/libhadifixplugin
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/libfliteplugin
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/libeposkttsdplugin
+$LIBTOOL --mode=uninstall $PREFIX/lib/kde3/libfreettsplugin
+
+# The following library was changed from unversioned to versioned
+# on or about 13 Oct 2004,
+
+$LIBTOOL --mode=uninstall $PREFIX/lib/libktts
+
+# The hadifax plugin was renamed to hadifix
+# on or about 4 Sep 2004.
+
+rm -f $PREFIX/share/services/hadifax.desktop
+$LIBTOOL --mode=uninstall /lib/kde3/libhadifaxplugin
+
+# Clean up the library cache.
+
+$LIBTOOL --mode=finish -n $PREFIX/lib
+$LIBTOOL --mode=finish -n $PREFIX/lib/kde3/
+
diff --git a/kttsd/compat/Makefile.am b/kttsd/compat/Makefile.am
new file mode 100644
index 0000000..f1e3edd
--- /dev/null
+++ b/kttsd/compat/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = \
+ $(KTTS_ICONS_DIR) \
+ $(KTTS_INTERFACES_DIR)
diff --git a/kttsd/compat/README_COMPAT b/kttsd/compat/README_COMPAT
new file mode 100644
index 0000000..40729d0
--- /dev/null
+++ b/kttsd/compat/README_COMPAT
@@ -0,0 +1,6 @@
+This is a directory to keep compatibility in KTTSD.
+This directory permits distribution and compilation of the following kttsd components:
+ If KDE < 3.4, copy of kdelibs/interfaces/kspeech.
+ If KDE < 3.5, copy of kdelibs/pics (kttsd icons only)
+
+Last Sync: Sat Mar 26 18:00:00 EST 2004 by Gary Cramblitt (PhantomsDad) <garycramblitt@comcast.net>
diff --git a/kttsd/compat/icons/Makefile.am b/kttsd/compat/icons/Makefile.am
new file mode 100644
index 0000000..e5515a8
--- /dev/null
+++ b/kttsd/compat/icons/Makefile.am
@@ -0,0 +1 @@
+KDE_ICON = AUTO
diff --git a/kttsd/compat/icons/cr128-app-kttsd.png b/kttsd/compat/icons/cr128-app-kttsd.png
new file mode 100644
index 0000000..0efd8c9
--- /dev/null
+++ b/kttsd/compat/icons/cr128-app-kttsd.png
Binary files differ
diff --git a/kttsd/compat/icons/cr16-app-kttsd.png b/kttsd/compat/icons/cr16-app-kttsd.png
new file mode 100644
index 0000000..3be5160
--- /dev/null
+++ b/kttsd/compat/icons/cr16-app-kttsd.png
Binary files differ
diff --git a/kttsd/compat/icons/cr22-app-kttsd.png b/kttsd/compat/icons/cr22-app-kttsd.png
new file mode 100644
index 0000000..8372208
--- /dev/null
+++ b/kttsd/compat/icons/cr22-app-kttsd.png
Binary files differ
diff --git a/kttsd/compat/icons/cr32-app-kttsd.png b/kttsd/compat/icons/cr32-app-kttsd.png
new file mode 100644
index 0000000..dde2333
--- /dev/null
+++ b/kttsd/compat/icons/cr32-app-kttsd.png
Binary files differ
diff --git a/kttsd/compat/icons/cr48-app-kttsd.png b/kttsd/compat/icons/cr48-app-kttsd.png
new file mode 100644
index 0000000..9b14757
--- /dev/null
+++ b/kttsd/compat/icons/cr48-app-kttsd.png
Binary files differ
diff --git a/kttsd/compat/icons/cr64-app-kttsd.png b/kttsd/compat/icons/cr64-app-kttsd.png
new file mode 100644
index 0000000..9cbc325
--- /dev/null
+++ b/kttsd/compat/icons/cr64-app-kttsd.png
Binary files differ
diff --git a/kttsd/compat/icons/crsc-app-kttsd.svgz b/kttsd/compat/icons/crsc-app-kttsd.svgz
new file mode 100644
index 0000000..199484f
--- /dev/null
+++ b/kttsd/compat/icons/crsc-app-kttsd.svgz
Binary files differ
diff --git a/kttsd/compat/interfaces/Makefile.am b/kttsd/compat/interfaces/Makefile.am
new file mode 100644
index 0000000..54cb7de
--- /dev/null
+++ b/kttsd/compat/interfaces/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = $(AUTODIRS)
diff --git a/kttsd/compat/interfaces/kspeech/Makefile.am b/kttsd/compat/interfaces/kspeech/Makefile.am
new file mode 100644
index 0000000..d7b5aaa
--- /dev/null
+++ b/kttsd/compat/interfaces/kspeech/Makefile.am
@@ -0,0 +1,8 @@
+# This is necessary for "make bcheck" to work.
+INCLUDES = $(all_includes)
+
+# Header files to be installed.
+include_HEADERS = kspeech.h kspeechsink.h
+
+# Define DCOP/Text-to-Speech Service Type.
+kde_servicetypes_DATA = dcoptexttospeech.desktop
diff --git a/kttsd/compat/interfaces/kspeech/dcoptexttospeech.desktop b/kttsd/compat/interfaces/kspeech/dcoptexttospeech.desktop
new file mode 100644
index 0000000..637cb7e
--- /dev/null
+++ b/kttsd/compat/interfaces/kspeech/dcoptexttospeech.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=DCOP/Text-to-Speech
+Comment=Text-to-Speech Service with a DCOP interface
+Comment[bg]=Модул за синтез на глас с интерфейс DCOP
+Comment[bs]=Servis za čitanje teksta za DCOP interfejsom
+Comment[ca]=Servei de text a veu amb una interfície DCOP
+Comment[cs]=Služba hlasové syntézy s DCOP rozhraním
+Comment[cy]=Gwasanaeth Testun-i-Lafar efo rhyngwyneb DCOP
+Comment[da]=Tekst-til-tale tjeneste med en DCOP grænseflade
+Comment[de]=Sprachausgabedienst mit DCOP-Schnittstelle
+Comment[el]=Υπηρεσία κειμένου-σε-ομιλία με διασύνδεση DCOP
+Comment[es]=Servicio de texto a voz con interfaz DCOP
+Comment[et]=Teksti kõneks muutmise teenus DCOP-liidesega
+Comment[eu]=DCOP interfazedun testutik hizketarako zerbitzua
+Comment[fa]=خدمت متن به گفتار با یک واسط DCOP
+Comment[fi]=Teksti puheeksi -palvelu DCOP -liittymällä
+Comment[fr]=Service de synthèse vocale avec une interface DCOP
+Comment[ga]=Seirbhís Téacs-go-Caint le comhéadan DCOP
+Comment[gl]= Servizo de Texto-para-Fala con interface DCOP
+Comment[he]=שירות טקסט לדיבור עם ממשק DCOP
+Comment[hu]=Szövegfelolvasó szolgáltatás DCOP-felülettel
+Comment[is]=Texti-í-tal þjónusta með DCOP viðmóti
+Comment[it]=Servizio di pronuncia con interfaccia DCOP
+Comment[ja]=DCOP インターフェースによるテキスト読み上げサービス
+Comment[ka]=ტექსტი-სიტყვა სერვისი DCOP ინტერფეისით
+Comment[km]=សេវា​អត្ថបទ​ដែល​ត្រូវ​និយាយ​ជាមួយ​នឹង​ចំណុច​ប្រទាក់ DCOP
+Comment[lt]=Teksto vertimo kalba tarnyba su DCOP sąsaja
+Comment[mk]=Сервис за текст-во-говор со DCOP-интерфејс
+Comment[ms]=Servis Teks-ke-Tutur dengan antara muka DCOP
+Comment[nb]=Tjeneste for tekst-til-tale med DCOP-grensesnitt
+Comment[nds]=Vörleesdeenst mit DCOP-Koppelsteed
+Comment[ne]=DCOP इन्टरफेससँग पाठ वाचक सेवा
+Comment[nl]=Tekst-tot-spraak-dienst met een DCOP-interface
+Comment[pl]=Usługa odczytywania tekstu z interfejsem DCOP
+Comment[pt]=Servidor Texto-para-Voz com interface DCOP
+Comment[pt_BR]=Serviço de Fala de Textos com uma interface DCOP
+Comment[ru]=Сервис синтеза речи через интерфейс DCOP
+Comment[rw]=Serivise Umwandiko-ku-Kuvuga ifite imigaragarire DCOP
+Comment[sk]=Text-na-reč služba pre DCOP
+Comment[sl]=Storitev besedila v govor z vmesnikom DCOP
+Comment[sr]=Услуга изговарања текста са DCOP интерфејсом
+Comment[sr@Latn]=Usluga izgovaranja teksta sa DCOP interfejsom
+Comment[sv]=Text-till-tal tjänst med DCOP-gränssnitt
+Comment[ta]=ஒரு DCOP இடைமுகத்தில் உரையில் இருந்து பேச்சு சேவை
+Comment[tg]=Бартарафсозии таҳлили овоз ба воситаи интерфейси DCOP
+Comment[th]=บริการแปลงข้อความเป็นคำพูดผ่านทาง DCOP
+Comment[tr]=DCOP arayüzü ile Metinden Konuşmaya Servisi
+Comment[uk]=Служба синтезу мовлення з тексту із інтерфейсом DCOP
+Comment[vi]=Dịch vụ chuyển Văn bản thành Tiếng nói cho giao diện DCOP
+Comment[zh_CN]=带 DCOP 接口的文本到语音服务
+Comment[zh_TW]=有 DCOP 介面的文字轉語音服務
diff --git a/kttsd/compat/interfaces/kspeech/kspeech.h b/kttsd/compat/interfaces/kspeech/kspeech.h
new file mode 100644
index 0000000..e4a831c
--- /dev/null
+++ b/kttsd/compat/interfaces/kspeech/kspeech.h
@@ -0,0 +1,1285 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ kspeech.h
+ KTTSD DCOP Interface
+ --------------------
+ Copyright:
+ (C) 2002-2003 by José Pablo Ezequiel "Pupeno" Fernández <pupeno@kde.org>
+ (C) 2003-2004 by Olaf Schmidt <ojschmidt@kde.org>
+ (C) 2004-2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: José Pablo Ezequiel "Pupeno" Fernández
+ ******************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#ifndef _KSPEECH_H_
+#define _KSPEECH_H_
+
+#include <dcopobject.h>
+#include <qstringlist.h>
+
+/**
+ * @interface KSpeech
+ *
+ * kspeech - the KDE Text-to-Speech API.
+ *
+ * @version 1.0 Draft 10
+ *
+ * @since KDE 3.4
+ *
+ * This class defines the DCOP interface for applications desiring to speak text.
+ * Applications may speak text by sending DCOP messages to application "kttsd" object "KSpeech".
+ *
+ * %KTTSD -- the KDE Text-to-Speech Deamon -- is the program that supplies the services
+ * in the KDE Text-to-Speech API.
+ *
+ * @warning The KSpeech interface is still being developed and is likely to change in the future.
+ *
+ * @section Features
+ *
+ * - Priority system for Screen Readers, warnings and messages, while still playing
+ * regular texts.
+ * - Long text is parsed into sentences. User may backup by sentence or part,
+ * replay, pause, and stop playing.
+ * - Handles multiple speaking applications. Text messages are treated like print jobs.
+ * Jobs may be created, started, stopped, paused, resumed, and deleted.
+ * - Speak contents of clipboard.
+ * - Speak KDE notifications.
+ * - Plugin-based text job filtering permits substitution for misspoken words,
+ * abbreviations, etc., transformation of XML or XHTML to SSML, and automatic
+ * choice of appropriate synthesis engine.
+ *
+ * @section Requirements
+ *
+ * You may build any KDE application to use KSpeech, since the interface is in kdelibs, but
+ * the kdeaccessibility package must be installed for KTTS to function.
+ *
+ * You will need a speech synthesis engine, such as Festival. See the KTTS Handbook
+ * for the latest information on installing and configuring speech engines and voices
+ * with KTTS.
+ *
+ * @section goals Design Goals
+ *
+ * The KDE Text-to-Speech API is designed with the following goals:
+ *
+ * - Support the features enumerated above.
+ * - Plugin-based architecture for support of a wide variety of speech synthesis
+ * engines and drivers.
+ * - Permit generation of speech from the command line (or via shell scripts)
+ * using the KDE DCOP utilities.
+ * - Provide a lightweight and easily usable interface for applications to
+ * generate speech output.
+ * - Applications need not be concerned about contention over the speech device.
+ * - Provide limited support for speech markup languages, such as Sable,
+ * Java %Speech Markup Language (JSML), and %Speech Markup Meta-language (SMML).
+ * - Provide limited support for embedded speech markers.
+ * - Asynchronous to prevent system blocking.
+ * - Plugin-based audio architecture. Currently supports aRts but will support
+ * additional audio engines in the future, such as gstreamer.
+ * - Compatible with original %KTTSD API as developed by José Pablo Ezequiel
+ * "Pupeno" Fernández (avoid breaking existing applications).
+ *
+ * Architecturally, applications interface with %KTTSD, which performs queueing,
+ * speech job managment, plugin management and sentence parsing. %KTTSD interfaces with a
+ * %KTTSD speech plugin(s), which then interfaces with the speech engine(s) or driver(s).
+ *
+ @verbatim
+ application
+ ^
+ | via DCOP (the KDE Text-to-Speech API)
+ v
+ kttsd
+ ^
+ | KTTSD plugin API
+ v
+ kttsd plugin
+ ^
+ |
+ v
+ speech engine
+ @endverbatim
+ *
+ * The %KTTSD Plugin API is documented in PluginConf in the kdeaccessibility module.
+ *
+ * There is a separate GUI application, called kttsmgr, for providing %KTTSD
+ * configuration and job management.
+ *
+ * kttsd maintains 4 types of speech output:
+ * - Screen Reader Output
+ * - Warnings
+ * - Messages
+ * - Text Jobs
+ *
+ * Method sayScreenReaderOutput speaks Screen Reader output.
+ * It pre-empts any other speech in progress,
+ * including other Screen Reader outputs, i.e., it is not a queue.
+ * This method is reserved for use by Screen Readers.
+ *
+ * Methods sayWarning and sayMessage place messages into the Warnings and
+ * Messages queues respectively. Warnings take priority over messages, which take priority
+ * over text jobs. Warnings and messages are spoken when the currently-speaking
+ * sentence of a text job is finished.
+ *
+ * setText places text into the text job queue. startText begins speaking jobs.
+ * When one job finishes, the next job begins. Method appendText adds
+ * additional parts to a text job. Within a text job, the application (and user
+ * via the kttsmgr GUI), may back up or advance by sentence or part, or rewind
+ * to the beginning.
+ * See jumpToTextPart and moveRelTextSentence.
+ * Text jobs may be paused, stopped, and resumed or deleted from the queue.
+ * See pauseText, stopText, resumeText, and removeText.
+ *
+ * @section cmdline DCOP Command-line Interface
+ *
+ * To create a text job to be spoken
+ *
+ @verbatim
+ dcop kttsd KSpeech setText <text> <talker>
+ @endverbatim
+ *
+ * where \<text\> is the text to be spoken, and \<talker\> is usually a language code
+ * such as "en", "cy", etc.
+ *
+ * Example.
+ *
+ @verbatim
+ dcop kttsd KSpeech setText "This is a test." "en"
+ @endverbatim
+ *
+ * To start speaking the text.
+ *
+ @verbatim
+ dcop kttsd KSpeech startText 0
+ @endverbatim
+ *
+ * You can combine the setText and startText commands into a single command.
+ *
+ @verbatim
+ dcop kttsd KSpeech sayText <text> <talker>
+ @endverbatim
+ *
+ * @since KDE 3.5
+ *
+ * To stop speaking and rewind to the beginning of the text.
+ *
+ @verbatim
+ dcop kttsd KSpeech stopText 0
+ @endverbatim
+ *
+ * Depending upon the speech plugin used, speaking may not immediately stop.
+ *
+ * To stop and remove a text job.
+ *
+ @verbatim
+ dcop kttsd KSpeech removeText 0
+ @endverbatim
+ *
+ * Note: For more information about talker codes, see talkers below.
+ *
+ * @section programming Calling KTTSD from a Program
+ *
+ * There are two methods of making DCOP calls from your application to %KTTSD.
+ *
+ * - Manually code them using dcopClient object. See kdebase/konqueror/kttsplugin/khtmlkttsd.cpp
+ * for an example. This method is recommended if you want to make a few simple calls to KTTSD.
+ * - Use kspeech_stub as described below. This method generates the marshalling code for you
+ * and is recommended for a more complex speech-enabled applications. kcmkttsmgr in the
+ * kdeaccessibility module is an example that uses this method.
+ *
+ * To make DCOP calls from your program using kspeech_stub, follow these steps:
+ *
+ * 1. Include kspeech_stub.h in your code. Derive an object from the KSpeech_stub interface.
+ * For example, suppose you are developing a KPart and want to call %KTTSD.
+ * Your class declaration might look like this:
+ *
+ @verbatim
+ #include <kspeech_stub.h>
+ class MyPart: public KParts::ReadOnlyPart, public KSpeech_stub {
+ @endverbatim
+ *
+ * 2. In your class constructor, initialize DCOPStub, giving it the sender
+ * "kttsd", object "KSpeech".
+ *
+ @verbatim
+ MyPart::MyPart(QWidget *parent, const char *name) :
+ KParts::ReadOnlyPart(parent, name),
+ DCOPStub("kttsd", "KSpeech") {
+ @endverbatim
+ *
+ * 3. See if KTTSD is running, and if not, start it.
+ *
+ @verbatim
+ DCOPClient *client = dcopClient();
+ client->attach();
+ if (!client->isApplicationRegistered("kttsd")) {
+ QString error;
+ if (KApplication::startServiceByDesktopName("kttsd", QStringList(), &error))
+ cout << "Starting KTTSD failed with message " << error << endl;
+ }
+ @endverbatim
+ *
+ * If you want to detect if KTTSD is installed without starting it, use this code.
+ *
+ @verbatim
+ KTrader::OfferList offers = KTrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'");
+ if (offers.count() > 0)
+ {
+ // KTTSD is installed.
+ }
+ @endverbatim
+ *
+ * Typically, you would do this to hide a menu item or button if KTTSD is not installed.
+ *
+ * 4. Make calls to KTTSD in your code.
+ *
+ @verbatim
+ uint jobNum = setText("Hello World", "en");
+ startText(jobNum);
+ @endverbatim
+ *
+ * 4. Add kspeech_DIR and kspeech.stub to your Makefile.am. Example:
+ *
+ @verbatim
+ kspeech_DIR = $(kde_includes)
+ libmypart_la_SOURCES = kspeech.stub
+ @endverbatim
+ *
+ * @section signals Signals Emitted by KTTSD
+ *
+ * %KTTSD emits a number of DCOP signals, which provide information about sentences spoken,
+ * text jobs started, stopped, paused, resumed, finished, or deleted and markers seen.
+ * In general, these signals are broadcast to any application that connects to them.
+ * Applications should check the appId argument to determine whether the signal belongs to
+ * them or not.
+ *
+ * To receive %KTTSD DCOP signals, follow these steps:
+ *
+ * 1. Include kspeechsink.h in your code. Derive an object from the KSpeechSink interface
+ * and declare a method for each signal you'd like to receive. For example,
+ * if you were coding a KPart and wanted to receive the KTTSD signal sentenceStarted:
+ *
+ @verbatim
+ #include <kspeechsink.h>
+ class MyPart:
+ public KParts::ReadOnlyPart,
+ virtual public KSpeechSink
+ {
+ protected:
+ ASYNC sentenceStarted(const QCString& appId, const uint jobNum, const uint seq);
+ @endverbatim
+ *
+ * You can combine sending and receiving in one object.
+ *
+ @verbatim
+ #include <kspeechsink.h>
+ class MyPart:
+ public KParts::ReadOnlyPart,
+ public KSpeech_stub,
+ virtual public KSpeechSink
+ {
+ protected:
+ ASYNC sentenceStarted(const QCString& appId, const uint jobNum, const uint seq);
+ @endverbatim
+ *
+ * See below for the signals you can declare.
+ *
+ * 2. In your class constructor, initialize DCOPObject with the name of your DCOP
+ * receiving object.
+ *
+ @verbatim
+ MyPart::MyPart(QWidget *parent, const char *name) :
+ KParts::ReadOnlyPart(parent, name),
+ DCOPObject("mypart_kspeechsink") {
+ @endverbatim
+ *
+ * Use any name you like.
+ *
+ * 3. Where appropriate (usually in your constructor), make sure your DCOPClient
+ * is registered and connect the %KTTSD DCOP signals to your declared receiving
+ * methods.
+ *
+ @verbatim
+ // Register DCOP client.
+ DCOPClient *client = kapp->dcopClient();
+ if (!client->isRegistered())
+ {
+ client->attach();
+ client->registerAs(kapp->name());
+ }
+ // Connect KTTSD DCOP signals to our slots.
+ connectDCOPSignal("kttsd", "KSpeech",
+ "sentenceStarted(QCString,uint,uint)",
+ "sentenceStarted(QCString,uint,uint)",
+ false);
+ @endverbatim
+ *
+ * Notice that the argument signatures differ slightly from the actual declarations. For
+ * example
+ *
+ @verbatim
+ ASYNC sentenceStarted(const QCString& appId, const uint jobNum, const uint seq);
+ @endverbatim
+ *
+ * becomes
+ *
+ @verbatim
+ "sentenceStarted(QCString,uint,uint)",
+ @endverbatim
+ *
+ * in the connectDCOPSignal call.
+ *
+ * 4. Write the definition for the received signal. Be sure to check whether the signal
+ * is intended for your application.
+ *
+ @verbatim
+ ASYNC MyPart::sentenceStarted(const QCString& appId, const uint jobNum, const uint seq)
+ {
+ // Check appId to determine if this is our signal.
+ if (appId != dcopClient()->appId()) return;
+ // Do something here.
+ }
+ @endverbatim
+ *
+ * 5. Add kspeechsink_DIR and kspeechsink.skel to your Makefile.am. Example for an app
+ * both sending and receiving.
+ *
+ @verbatim
+ kspeech_DIR = $(kde_includes)
+ kspeechsink_DIR = $(kde_includes)
+ libmypart_la_SOURCES = kspeech.stub kspeechsink.skel
+ @endverbatim
+ *
+ * @section talkers Talkers, Talker Codes, and Plugins
+ *
+ * Many of the methods permit you to specify a desired "talker". This
+ * may be a simple language code, such as "en" for English, "es" for Spanish, etc.
+ * Code as NULL to use the default configured talker.
+ *
+ * Within KTTSMGR, the user has the ability to configure more than one talker for each language,
+ * with different voices, genders, volumes, and talking speeds.
+ *
+ * Talker codes serve two functions:
+ * - They identify configured plugins, and
+ * - They provide a way for applications to specify the desired speaking attributes
+ * that influence the choice of plugin to speak text.
+ *
+ * A Talker Code consists of a series of XML tags and attributes.
+ * An example of a full Talker Code with all attributes specified is
+ *
+ * <voice lang="en" name="kal" gender="male"/>
+ * <prosody volume="soft" rate="fast"/>
+ * <kttsd synthesizer="Festival" />
+ *
+ * (The @e voice and @e prosody tags are adapted from the W3C Speech Synthesis
+ * Markup Language (SSML) and Java Speech Markup Language (JSML).
+ * The @e kttsd tag is an extension to the SMML and JSML languages to support
+ * named synthesizers and text encodings.)
+ * %KTTS doesn't really care about the @e voice, @e prosody, and @e kttsd tags. In fact,
+ * they may be omitted and just the attributes specified. The example above then
+ * becomes
+ *
+ * lang="en" name="kal" gender="male" volume="soft" rate="fast"
+ * synthesizer="Festival"
+ *
+ * The attributes may be specified in any order.
+ *
+ * For clarity, the rest of the discussion
+ * will omit the @e voice, @e prosody, and @e kttsd tags.
+ *
+ * The attributes that make up a talker code are:
+ *
+ * - @e lang. Language code and optional country code.
+ * Examples: en, es, en_US, en_GB. Codes
+ * are case in-sensitive and hyphen (-) or underscore (_) may be
+ * used to separate the country code from the language code.
+ * - @e synthesizer. The name of the synthesizer (plugin) used to produce the speech.
+ * - @e gender. May be either "male", "female", or "neutral".
+ * - @e name. The name of the voice code.
+ * The choice of voice codes is synthesizer-specific.
+ * - @e volume. May be "loud", "medium", or "quiet". A synonym for "quiet" is
+ * "soft".
+ * - @e rate. May be "fast", "medium", or "slow".
+ *
+ * Each plugin, once it has been configured by a user in kttsmgr, returns a
+ * fully-specified talker code to identify itself. If the plugin supports it,
+ * the user may configure another instance of the plugin with a different set
+ * of attributes. This is the difference between a "plugin" and a "talker".
+ * A talker is a configured instance of a plugin. Each plugin (if it supports it)
+ * may be configured as multiple talkers.
+ *
+ * When the user configures %KTTSD, she configures one or more talkers and then
+ * places them in preferred order, top to bottom in kttsmgr. In effect,
+ * she specifies her preferences for each of the talkers.
+ *
+ * When applications specify a talker code, they need not (and typically do not)
+ * give a full specification. An example of a talker code with only some of the
+ * attributes specified might be
+ *
+ * lang="en" gender="female"
+ *
+ * If the talker code is not in XML attribute format, it assumed to be a @e lang
+ * attribute. So the talker code
+ *
+ * en
+ *
+ * is interpreted as
+ *
+ * lang="en"
+ *
+ * When a program requests a talker code in calls to setText, appendText,
+ * sayMessage, sayWarning, and sayScreenReaderOutput,
+ * %KTTSD tries to match the requested talker code to the closest matching
+ * configured talker.
+ *
+ * The @e lang attribute has highest priority (attempting to speak English with
+ * a Spanish synthesizer would likely be unintelligible). So the language
+ * attribute is said to have "priority".
+ * If an application does not specify a language attribute, a default one will be assumed.
+ * The rest of the attributes are said to be "preferred". If %KTTSD cannot find
+ * a talker with the exact preferred attributes requested, the closest matching
+ * talker will likely still be understandable.
+ *
+ * An application may specify that one or more of the attributes it gives in a talker
+ * code have priority by preceeding each priority attribute with an asterisk.
+ * For example, the following talker code
+ *
+ * lang="en" gender="*female" volume="soft"
+ *
+ * means that the application wants to use a talker that supports American English language
+ * and Female gender. If there is more than one such talker, one that supports
+ * Soft volume would be preferred. Notice that a talker configured as English, Male,
+ * and Soft volume would not be picked as long as an English Female talker is
+ * available.
+ *
+ * The algorithm used by %KTTSD to find a matching talker is as follows:
+ *
+ * - If language code is not specified by the application, assume default configured
+ * by user. The primary language code automatically has priority.
+ * - (Note: This is not yet implemented.)
+ * If there are no talkers configured in the language, %KTTSD will attempt
+ * to automatically configure one (see automatic configuraton discussion below)
+ * - The talker that matches on the most priority attributes wins.
+ * - If a tie, the one that matches on the most preferred attributes wins.
+ * - If there is still a tie, the one nearest the top of the kttsmgr display
+ * (first configured) will be chosen.
+ *
+ * Language codes actually consist of two parts, a language code and an optional
+ * country code. For example, en_GB is English (United Kingdom). The language code is
+ * treated as a priority attribute, but the country code (if specified) is treated
+ * as preferred. So for example, if an application requests the following
+ * talker code
+ *
+ * lang="en_GB" gender="male" volume="medium"
+ *
+ * then a talker configured as lang="en" gender="male" volume="medium" would be
+ * picked over one configured as lang="en_GB" gender="female" volume="soft",
+ * since the former matches on two preferred attributes and the latter only on the
+ * preferred attribute GB. An application can override this and make the country
+ * code priority with an asterisk. For example,
+ *
+ * lang="*en_GB" gender="male" volume="medium"
+ *
+ * To specify that American English is priority, put an asterisk in front of
+ * en_US, like this.
+ *
+ * lang="*en_US" gender="male" volume="medium"
+ *
+ * Here the application is indicating that a talker that speaks American English
+ * has priorty over one that speaks a different form of English.
+ *
+ * (Note: Not yet implemented).
+ * If a language code is specified, and no plugin is currently configured
+ * with a matching language code, %KTTSD will attempt to automatically
+ * load and configure a plugin to support the requested language. If
+ * there is no such plugin, or there is a plugin but it cannot automatically
+ * configure itself, %KTTSD will pick one of the configured plugins using the
+ * algorithm given above.
+ *
+ * Notice that %KTTSD will always pick a talker, even if it is a terrible match.
+ * (The principle is that something heard is better than nothing at all. If
+ * it sounds terrible, user will change his configuration.)
+ * If an attribute is absolutely mandatory -- in other words the application
+ * must speak with the attribute or not at all -- the application can determine if
+ * there are any talkers configured with the attribute by calling getTalkers,
+ * and if there are none, display an error message to the user.
+ *
+ * Applications can implement their own talker-matching algorithm by
+ * calling getTalkers, then finding the desired talker from the returned
+ * list. When the full talker code is passed in, %KKTSD will find an exact
+ * match and use the specified talker.
+ *
+ * If an application requires a configuration that user has not created,
+ * it should display a message to user instructing them to run kttsmgr and
+ * configure the desired talker. (This must be done interactively because
+ * plugins often need user assistance locating voice files, etc.)
+ *
+ * The above scheme is designed to balance the needs
+ * of applications against user preferences. Applications are given the control
+ * they @e might need, without unnecessarily burdening the application author.
+ * If you are an application author, the above discussion might seem overly
+ * complicated. It isn't really all that complicated. Here are rules of thumb:
+ *
+ * - It is legitimate to give a NULL (0) talker code, in which case, the user's default
+ * talker will be used.
+ * - If you know the language code, give that in the talker code, otherwise
+ * leave it out.
+ * - If there is an attribute your application @e requires for proper functioning,
+ * specify that with an asterisk in front of it. For example, your app might
+ * speak in two different voices, Male and Female. (Since your
+ * app requires both genders, call getTalkers to determine if both genders
+ * are available, and if not, advise user to configure them. Better yet,
+ * give the user a choice of available distinquishing attributes
+ * (loud/soft, fast/slow, etc.)
+ * - If there are other attributes you would prefer, specify those without an
+ * asterisk, but leave them out if it doesn't really make any difference
+ * to proper functioning of your application. Let the user decide them
+ * when they configure %KTTS.
+ *
+ * One final note about talkers. %KTTSD does talker matching for each sentence
+ * spoken, just before the sentence is sent to a plugin for synthesis. Therefore,
+ * the user can change the effective talker in mid processing of a text job by
+ * changing his preferences, or even deleting or adding new talkers to the configuration.
+ *
+ * @section markup Speech Markup
+ *
+ * Note: %Speech Markup is not yet fully implemented in %KTTSD.
+ *
+ * Each of the five methods for queueing text to be spoken -- sayScreenReaderOutput,
+ * setText, appendText, sayMessage, and sayWarning -- may contain speech markup,
+ * provided that the plugin the user has configured supports that markup. The markup
+ * languages and plugins currently supported are:
+ *
+ * - %Speech Synthesis Markup language (SSML): Festival and Hadifix.
+ *
+ * This may change in the future as synthesizers improve.
+ *
+ * Before including markup in the text sent to kttsd, the application should
+ * query whether the currently-configured plugin
+ * supports the markup language by calling supportsMarkup.
+ *
+ * It it does not support the markup, it will be stripped out of the text.
+ *
+ * @section markers Support for Markers
+ *
+ * Note: Markers are not yet implemented in %KTTSD.
+ *
+ * When using a speech markup language, such as Sable, JSML, or SSML, the application may embed
+ * named markers into the text. If the user's chosen speech plugin supports markers, %KTTSD
+ * will emit DCOP signal markerSeen when the speech engine encounters the marker.
+ * Depending upon the speech engine and plugin, this may occur either when the speech engine
+ * encounters the marker during synthesis from text to speech, or when the speech is actually
+ * spoken on the audio device. The calling application can call the supportsMarkers
+ * method to determine if the currently configured plugin supports markers or not.
+ *
+ * @section sentenceparsing Sentence Parsing
+ *
+ * Not all speech engines provide robust capabilities for stopping synthesis that is in progress.
+ * To compensate for this, %KTTSD parses text jobs given to it by the setText and
+ * appendText methods into sentences and sends the sentences to the speech
+ * plugin one at a time. In this way, should the user wish to stop the speech
+ * output, they can do so, and the worst that will happen is that the last sentence
+ * will be completed. This is called Sentence Boundary Detection (SBD).
+ *
+ * Sentence Boundary Detection also permits the user to rewind by sentences.
+ *
+ * The default sentence delimiter used for plain text is as follows:
+ *
+ * - A period (.), question mark (?), exclamation mark (!), colon (:), or
+ * semi-colon (;) followed by whitespace (including newline), or
+ * - Two newlines in a row separated by optional whitespace, or
+ * - The end of the text.
+ *
+ * When given text containing speech markup, %KTTSD automatically determines the markup type
+ * and parses based on the sentence semantics of the markup language.
+ *
+ * An application may change the sentence delimiter by calling setSentenceDelimiter
+ * prior to calling setText. Changing the delimiter does not affect other
+ * applications.
+ *
+ * Text given to %KTTSD via the sayWarning, sayMessage, and sayScreenReaderOutput
+ * methods is @e not parsed into sentences. For this reason, applications
+ * should @e not send long messages with these methods.
+ *
+ * Sentence Boundary Detection is implemented as a plugin SBD filter. See
+ * filters for more information.
+ *
+ * @section filters Filters
+ *
+ * Users may specify filters in the kttsmgr GUI. Filters are plugins that modify the text
+ * to be spoken or change other characteristics of jobs. Currently, the following filter plugins
+ * are available:
+ *
+ * - String Replacer. Permits users to substitute for mispoken words, or vocalize chat
+ * emoticons.
+ * - XML Transformer. Given a particular XML or XHTML format, permits conversion of the
+ * XML to SSML (Speech Synthesis Markup Language) using XSLT (XML Style Language - Transforms)
+ * stylesheets.
+ * - Talker Chooser. Permits users to redirect jobs from one configured Talker to another
+ * based on the contents of the job or application that sent it.
+ *
+ * Additional plugins may be available in the future.
+ *
+ * In additional to these regular filters, KTTS also implements Sentence Boundary Detection (SBD)
+ * as a plugin filter. See sentenceparsing for more information.
+ *
+ * Regular filters are applied to Warnings, Messages, and Text jobs. SBD filters are
+ * only applied to regular Text jobs; they are not applied to Warnings and Messages. Screen
+ * Reader Outputs are never filtered.
+ *
+ * @section authors Authors
+ *
+ * @author José Pablo Ezequiel "Pupeno" Fernández <pupeno@kde.org>
+ * @author Gary Cramblitt <garycramblitt@comcast.net>
+ * @author Olaf Schmidt <ojschmidt@kde.org>
+ * @author Gunnar Schmi Dt <gunnar@schmi-dt.de>
+ */
+
+// NOTE: kspeech class is now obsolete. Please use KSpeech instead.
+
+class KSpeech : virtual public DCOPObject {
+ K_DCOP
+
+ public:
+ /**
+ * @enum kttsdJobState
+ * Job states returned by method getTextJobState.
+ */
+ enum kttsdJobState
+ {
+ jsQueued = 0, /**< Job has been queued but is not yet speakable. */
+ jsSpeakable = 1, /**< Job is speakable, but is not speaking. */
+ jsSpeaking = 2, /**< Job is currently speaking. */
+ jsPaused = 3, /**< Job has been paused. */
+ jsFinished = 4 /**< Job is finished and is deleteable. */
+ };
+
+ /**
+ * @enum kttsdMarkupType
+ * %Speech markup language types.
+ */
+ enum kttsdMarkupType
+ {
+ mtPlain = 0, /**< Plain text */
+ mtJsml = 1, /**< Java %Speech Markup Language */
+ mtSsml = 2, /**< %Speech Synthesis Markup Language */
+ mtSable = 3, /**< Sable 2.0 */
+ mtHtml = 4 /**< HTML @since 3.5 */
+ };
+
+ k_dcop:
+ /** @name DCOP Methods */
+ //@{
+
+ /**
+ * Determine whether the currently-configured speech plugin supports a speech markup language.
+ * @param talker Code for the talker to do the speaking. Example "en".
+ * If NULL, defaults to the user's default talker.
+ * @param markupType The kttsd code for the desired speech markup language.
+ * @return True if the plugin currently configured for the indicated
+ * talker supports the indicated speech markup language.
+ * @see kttsdMarkupType
+ */
+ virtual bool supportsMarkup(const QString &talker, uint markupType = 0) const = 0;
+
+ /**
+ * Determine whether the currently-configured speech plugin supports markers in speech markup.
+ * @param talker Code for the talker to do the speaking. Example "en".
+ * If NULL, defaults to the user's default talker.
+ * @return True if the plugin currently configured for the indicated
+ * talker supports markers.
+ */
+ virtual bool supportsMarkers(const QString &talker) const = 0;
+
+ /**
+ * Say a message as soon as possible, interrupting any other speech in progress.
+ * IMPORTANT: This method is reserved for use by Screen Readers and should not be used
+ * by any other applications.
+ * @param msg The message to be spoken.
+ * @param talker Code for the talker to do the speaking. Example "en".
+ * If NULL, defaults to the user's default talker.
+ * If no plugin has been configured for the specified Talker code,
+ * defaults to the closest matching talker.
+ *
+ * If an existing Screen Reader output is in progress, it is stopped and discarded and
+ * replaced with this new message.
+ */
+ virtual ASYNC sayScreenReaderOutput(const QString &msg, const QString &talker) = 0;
+
+ /**
+ * Say a warning. The warning will be spoken when the current sentence
+ * stops speaking and takes precedence over Messages and regular text. Warnings should only
+ * be used for high-priority messages requiring immediate user attention, such as
+ * "WARNING. CPU is overheating."
+ * @param warning The warning to be spoken.
+ * @param talker Code for the talker to do the speaking. Example "en".
+ * If NULL, defaults to the user's default talker.
+ * If no plugin has been configured for the specified Talker code,
+ * defaults to the closest matching talker.
+ */
+ virtual ASYNC sayWarning(const QString &warning, const QString &talker) = 0;
+
+ /**
+ * Say a message. The message will be spoken when the current sentence stops speaking
+ * but after any warnings have been spoken.
+ * Messages should be used for one-shot messages that can't wait for
+ * normal text messages to stop speaking, such as "You have mail.".
+ * @param message The message to be spoken.
+ * @param talker Code for the talker to do the speaking. Example "en".
+ * If NULL, defaults to the user's default talker.
+ * If no talker has been configured for the specified talker code,
+ * defaults to the closest matching talker.
+ */
+ virtual ASYNC sayMessage(const QString &message, const QString &talker) = 0;
+
+ /**
+ * Sets the GREP pattern that will be used as the sentence delimiter.
+ * @param delimiter A valid GREP pattern.
+ *
+ * The default sentence delimiter is
+ @verbatim
+ ([\\.\\?\\!\\:\\;])(\\s|$|(\\n *\\n))
+ @endverbatim
+ *
+ * Note that backward slashes must be escaped.
+ * When %KTTSD parses the text, it replaces all tabs, spaces, and formfeeds
+ * with a single space, and then replaces the sentence delimiters using
+ * the following statement:
+ @verbatim
+ QString::replace(sentenceDelimiter, "\\1\t");
+ @endverbatim
+ *
+ * which replaces all sentence delimiters with a tab, but
+ * preserving the first capture text (first parenthesis). In other
+ * words, the sentence punctuation is preserved.
+ * The tab is later used to separate the text into sentences.
+ *
+ * Changing the sentence delimiter does not affect other applications.
+ *
+ * @see sentenceparsing
+ */
+ virtual ASYNC setSentenceDelimiter(const QString &delimiter) = 0;
+
+ /**
+ * Queue a text job. Does not start speaking the text.
+ * @param text The message to be spoken.
+ * @param talker Code for the talker to do the speaking. Example "en".
+ * If NULL, defaults to the user's default plugin.
+ * If no plugin has been configured for the specified Talker code,
+ * defaults to the closest matching talker.
+ * @return Job number.
+ *
+ * Plain text is parsed into individual sentences using the current sentence delimiter.
+ * Call setSentenceDelimiter to change the sentence delimiter prior to
+ * calling setText.
+ * Call getTextCount to retrieve the sentence count after calling setText.
+ *
+ * The text may contain speech mark language, such as Sable, JSML, or SSML,
+ * provided that the speech plugin/engine support it. In this case,
+ * sentence parsing follows the semantics of the markup language.
+ *
+ * Call startText to mark the job as speakable and if the
+ * job is the first speakable job in the queue, speaking will begin.
+ *
+ * @see getTextCount
+ * @see startText
+ */
+ virtual uint setText(const QString &text, const QString &talker) = 0;
+
+ /**
+ * Say a plain text job. This is a convenience method that
+ * combines setText and startText into a single call.
+ * @param text The message to be spoken.
+ * @param talker Code for the talker to do the speaking. Example "en".
+ * If NULL, defaults to the user's default plugin.
+ * If no plugin has been configured for the specified Talker code,
+ * defaults to the closest matching talker.
+ * @return Job number.
+ *
+ * Plain text is parsed into individual sentences using the current sentence delimiter.
+ * Call setSentenceDelimiter to change the sentence delimiter prior to
+ * calling setText.
+ * Call getTextCount to retrieve the sentence count after calling setText.
+ *
+ * The text may contain speech mark language, such as Sable, JSML, or SSML,
+ * provided that the speech plugin/engine support it. In this case,
+ * sentence parsing follows the semantics of the markup language.
+ *
+ * The job is marked speakable.
+ * If there are other speakable jobs preceeding this one in the queue,
+ * those jobs continue speaking and when finished, this job will begin speaking.
+ * If there are no other speakable jobs preceeding this one, it begins speaking.
+ *
+ * @see getTextCount
+ *
+ * @since KDE 3.5
+ */
+ virtual uint sayText(const QString &text, const QString &talker) = 0;
+
+ /**
+ * Adds another part to a text job. Does not start speaking the text.
+ * @param text The message to be spoken.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ * @return Part number for the added part. Parts are numbered starting at 1.
+ *
+ * The text is parsed into individual sentences. Call getTextCount to retrieve
+ * the sentence count. Call startText to mark the job as speakable and if the
+ * job is the first speakable job in the queue, speaking will begin.
+ *
+ * @see setText.
+ * @see startText.
+ */
+ virtual int appendText(const QString &text, uint jobNum=0) = 0;
+
+ /**
+ * Queue a text job from the contents of a file. Does not start speaking the text.
+ * @param filename Full path to the file to be spoken. May be a URL.
+ * @param talker Code for the talker to do the speaking. Example "en".
+ * If NULL, defaults to the user's default talker.
+ * If no plugin has been configured for the specified Talker code,
+ * defaults to the closest matching talker.
+ * @param encoding Name of the encoding to use when reading the file. If
+ * NULL or Empty, uses default stream encoding.
+ * @return Job number. 0 if an error occurs.
+ *
+ * Plain text is parsed into individual sentences using the current sentence delimiter.
+ * Call setSentenceDelimiter to change the sentence delimiter prior to calling setText.
+ * Call getTextCount to retrieve the sentence count after calling setText.
+ *
+ * The text may contain speech mark language, such as Sable, JSML, or SSML,
+ * provided that the speech plugin/engine support it. In this case,
+ * sentence parsing follows the semantics of the markup language.
+ *
+ * Call startText to mark the job as speakable and if the
+ * job is the first speakable job in the queue, speaking will begin.
+ *
+ * @see getTextCount
+ * @see startText
+ */
+ virtual uint setFile(const QString &filename, const QString &talker,
+ const QString& encoding) = 0;
+
+ /**
+ * Get the number of sentences in a text job.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ * @return The number of sentences in the job. -1 if no such job.
+ *
+ * The sentences of a job are given sequence numbers from 1 to the number returned by this
+ * method. The sequence numbers are emitted in the sentenceStarted and
+ * sentenceFinished signals.
+ */
+ virtual int getTextCount(uint jobNum=0) = 0;
+
+ /**
+ * Get the job number of the current text job.
+ * @return Job number of the current text job. 0 if no jobs.
+ *
+ * Note that the current job may not be speaking. See isSpeakingText.
+ *
+ * @see getTextJobState.
+ * @see isSpeakingText
+ */
+ virtual uint getCurrentTextJob() = 0;
+
+ /**
+ * Get the number of jobs in the text job queue.
+ * @return Number of text jobs in the queue. 0 if none.
+ */
+ virtual uint getTextJobCount() = 0;
+
+ /**
+ * Get a comma-separated list of text job numbers in the queue.
+ * @return Comma-separated list of text job numbers in the queue.
+ */
+ virtual QString getTextJobNumbers() = 0;
+
+ /**
+ * Get the state of a text job.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ * @return State of the job. -1 if invalid job number.
+ *
+ * @see kttsdJobState
+ */
+ virtual int getTextJobState(uint jobNum=0) = 0;
+
+ /**
+ * Get information about a text job.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ * @return A QDataStream containing information about the job.
+ * Blank if no such job.
+ *
+ * The stream contains the following elements:
+ * - int state - Job state.
+ * - QCString appId - DCOP senderId of the application that requested the speech job.
+ * - QString talker - Talker Code requested by application.
+ * - int seq - Current sentence being spoken. Sentences are numbered starting at 1.
+ * - int sentenceCount - Total number of sentences in the job.
+ * - int partNum - Current part of the job begin spoken. Parts are numbered starting at 1.
+ * - int partCount - Total number of parts in the job.
+ *
+ * Note that sequence numbers apply to the entire job. They do not start from 1 at the beginning of
+ * each part.
+ *
+ * The following sample code will decode the stream:
+ @code
+ QByteArray jobInfo = getTextJobInfo(jobNum);
+ QDataStream stream(jobInfo, IO_ReadOnly);
+ int state;
+ QCString appId;
+ QString talker;
+ int seq;
+ int sentenceCount;
+ int partNum;
+ int partCount;
+ stream >> state;
+ stream >> appId;
+ stream >> talker;
+ stream >> seq;
+ stream >> sentenceCount;
+ stream >> partNum;
+ stream >> partCount;
+ @endcode
+ */
+ virtual QByteArray getTextJobInfo(uint jobNum=0) = 0;
+
+ /**
+ * Given a Talker Code, returns the Talker ID of the talker that would speak
+ * a text job with that Talker Code.
+ * @param talkerCode Talker Code.
+ * @return Talker ID of the talker that would speak the text job.
+ */
+ virtual QString talkerCodeToTalkerId(const QString& talkerCode) = 0;
+
+ /**
+ * Return a sentence of a job.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ * @param seq Sequence number of the sentence.
+ * @return The specified sentence in the specified job. If no such
+ * job or sentence, returns "".
+ */
+ virtual QString getTextJobSentence(uint jobNum=0, uint seq=0) = 0;
+
+ /**
+ * Determine if kttsd is currently speaking any text jobs.
+ * @return True if currently speaking any text jobs.
+ */
+ virtual bool isSpeakingText() const = 0;
+
+ /**
+ * Remove a text job from the queue.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ *
+ * The job is deleted from the queue and the textRemoved signal is emitted.
+ *
+ * If there is another job in the text queue, and it is marked speakable,
+ * that job begins speaking.
+ */
+ virtual ASYNC removeText(uint jobNum=0) = 0;
+
+ /**
+ * Start a text job at the beginning.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ *
+ * Rewinds the job to the beginning.
+ *
+ * The job is marked speakable.
+ * If there are other speakable jobs preceeding this one in the queue,
+ * those jobs continue speaking and when finished, this job will begin speaking.
+ * If there are no other speakable jobs preceeding this one, it begins speaking.
+ *
+ * The textStarted signal is emitted when the text job begins speaking.
+ * When all the sentences of the job have been spoken, the job is marked for deletion from
+ * the text queue and the textFinished signal is emitted.
+ */
+ virtual ASYNC startText(uint jobNum=0) = 0;
+
+ /**
+ * Stop a text job and rewind to the beginning.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ *
+ * The job is marked not speakable and will not be speakable until startText
+ * or resumeText is called.
+ *
+ * If there are speaking jobs preceeding this one in the queue, they continue speaking.
+ *
+ * If the job is currently speaking, the textStopped signal is emitted,
+ * the job stops speaking, and if the next job in the queue is speakable, it
+ * begins speaking.
+ *
+ * Depending upon the speech engine and plugin used, speech may not stop immediately
+ * (it might finish the current sentence).
+ */
+ virtual ASYNC stopText(uint jobNum=0) = 0;
+
+ /**
+ * Pause a text job.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ *
+ * The job is marked as paused and will not be speakable until resumeText or
+ * startText is called.
+ *
+ * If there are speaking jobs preceeding this one in the queue, they continue speaking.
+ *
+ * If the job is currently speaking, the textPaused signal is emitted and the job
+ * stops speaking. Note that if the next job in the queue is speakable, it does
+ * not start speaking as long as this job is paused.
+ *
+ * Depending upon the speech engine and plugin used, speech may not stop immediately
+ * (it might finish the current sentence).
+ *
+ * @see resumeText
+ */
+ virtual ASYNC pauseText(uint jobNum=0) = 0;
+
+ /**
+ * Start or resume a text job where it was paused.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ *
+ * The job is marked speakable.
+ *
+ * If the job is currently speaking, or is waiting to be spoken (speakable
+ * state), the resumeText() call is ignored.
+ *
+ * If the job is currently queued, or is finished, it is the same as calling
+ * @see startText .
+ *
+ * If there are speaking jobs preceeding this one in the queue,
+ * those jobs continue speaking and when finished this job will begin
+ * speaking where it left off.
+ *
+ * The textResumed signal is emitted when the job resumes.
+ *
+ * @see pauseText
+ */
+ virtual ASYNC resumeText(uint jobNum=0) = 0;
+
+ /**
+ * Get a list of the talkers configured in KTTS.
+ * @return A QStringList of fully-specified talker codes, one
+ * for each talker user has configured.
+ *
+ * @see talkers
+ */
+ virtual QStringList getTalkers() = 0;
+
+ /**
+ * Change the talker for a text job.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ * @param talker New code for the talker to do the speaking. Example "en".
+ * If NULL, defaults to the user's default talker.
+ * If no plugin has been configured for the specified Talker code,
+ * defaults to the closest matching talker.
+ */
+ virtual ASYNC changeTextTalker(const QString &talker, uint jobNum=0 ) = 0;
+
+ /**
+ * Get the user's default talker.
+ * @return A fully-specified talker code.
+ *
+ * @see talkers
+ * @see getTalkers
+ */
+ virtual QString userDefaultTalker() = 0;
+
+ /**
+ * Move a text job down in the queue so that it is spoken later.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ *
+ * If the job is currently speaking, it is paused.
+ * If the next job in the queue is speakable, it begins speaking.
+ */
+ virtual ASYNC moveTextLater(uint jobNum=0) = 0;
+
+ /**
+ * Jump to the first sentence of a specified part of a text job.
+ * @param partNum Part number of the part to jump to. Parts are numbered starting at 1.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ * @return Part number of the part actually jumped to.
+ *
+ * If partNum is greater than the number of parts in the job, jumps to last part.
+ * If partNum is 0, does nothing and returns the current part number.
+ * If no such job, does nothing and returns 0.
+ * Does not affect the current speaking/not-speaking state of the job.
+ */
+ virtual int jumpToTextPart(int partNum, uint jobNum=0) = 0;
+
+ /**
+ * Advance or rewind N sentences in a text job.
+ * @param n Number of sentences to advance (positive) or rewind (negative) in the job.
+ * @param jobNum Job number of the text job.
+ * If zero, applies to the last job queued by the application,
+ * but if no such job, applies to the current job (if any).
+ * @return Sequence number of the sentence actually moved to. Sequence numbers
+ * are numbered starting at 1.
+ *
+ * If no such job, does nothing and returns 0.
+ * If n is zero, returns the current sequence number of the job.
+ * Does not affect the current speaking/not-speaking state of the job.
+ */
+ virtual uint moveRelTextSentence(int n, uint jobNum=0) = 0;
+
+ /**
+ * Add the clipboard contents to the text queue and begin speaking it.
+ */
+ virtual ASYNC speakClipboard() = 0;
+
+ /**
+ * Displays the %KTTS Manager dialog. In this dialog, the user may backup or skip forward in
+ * any text job by sentence or part, rewind jobs, pause or resume jobs, or
+ * delete jobs.
+ */
+ virtual void showDialog() = 0;
+
+ /**
+ * Stop the service.
+ */
+ virtual void kttsdExit() = 0;
+
+ /**
+ * Re-start %KTTSD.
+ */
+ virtual void reinit() = 0;
+
+ /**
+ * Return the KTTSD deamon version number.
+ * @since KDE 3.5
+ */
+ virtual QString version() = 0;
+ //@}
+
+ k_dcop_signals:
+ void ignoreThis();
+
+ /** @name DCOP Signals */
+ //@{
+
+ /**
+ * This signal is emitted when KTTSD starts or restarts after a call to reinit.
+ */
+ void kttsdStarted();
+ /**
+ * This signal is emitted just before KTTSD exits.
+ */
+ void kttsdExiting();
+ /**
+ * This signal is emitted when the speech engine/plugin encounters a marker in the text.
+ * @param appId DCOP application ID of the application that queued the text.
+ * @param markerName The name of the marker seen.
+ *
+ * @see markers
+ */
+ void markerSeen(const QCString& appId, const QString& markerName);
+ /**
+ * This signal is emitted whenever a sentence begins speaking.
+ * @param appId DCOP application ID of the application that queued the text.
+ * @param jobNum Job number of the text job.
+ * @param seq Sequence number of the text.
+ *
+ * @see getTextCount
+ */
+ void sentenceStarted(const QCString& appId, uint jobNum, uint seq);
+ /**
+ * This signal is emitted when a sentence has finished speaking.
+ * @param appId DCOP application ID of the application that queued the text.
+ * @param jobNum Job number of the text job.
+ * @param seq Sequence number of the text.
+ *
+ * @see getTextCount
+ */
+ void sentenceFinished(const QCString& appId, uint jobNum, uint seq);
+
+ /**
+ * This signal is emitted whenever a new text job is added to the queue.
+ * @param appId The DCOP senderId of the application that created the job.
+ * @param jobNum Job number of the text job.
+ */
+ void textSet(const QCString& appId, uint jobNum);
+
+ /**
+ * This signal is emitted whenever a new part is appended to a text job.
+ * @param appId The DCOP senderId of the application that created the job.
+ * @param jobNum Job number of the text job.
+ * @param partNum Part number of the new part. Parts are numbered starting
+ * at 1.
+ */
+ void textAppended(const QCString& appId, uint jobNum, int partNum);
+
+ /**
+ * This signal is emitted whenever speaking of a text job begins.
+ * @param appId The DCOP senderId of the application that created the job.
+ * @param jobNum Job number of the text job.
+ */
+ void textStarted(const QCString& appId, uint jobNum);
+ /**
+ * This signal is emitted whenever a text job is finished. The job has
+ * been marked for deletion from the queue and will be deleted when another
+ * job reaches the Finished state. (Only one job in the text queue may be
+ * in state Finished at one time.) If startText or resumeText is
+ * called before the job is deleted, it will remain in the queue for speaking.
+ * @param appId The DCOP senderId of the application that created the job.
+ * @param jobNum Job number of the text job.
+ */
+ void textFinished(const QCString& appId, uint jobNum);
+ /**
+ * This signal is emitted whenever a speaking text job stops speaking.
+ * @param appId The DCOP senderId of the application that created the job.
+ * @param jobNum Job number of the text job.
+ *
+ * The signal is only emitted if stopText() is called and the job is currently
+ * speaking.
+ */
+ void textStopped(const QCString& appId, uint jobNum);
+ /**
+ * This signal is emitted whenever a speaking text job is paused.
+ * @param appId The DCOP senderId of the application that created the job.
+ * @param jobNum Job number of the text job.
+ */
+ void textPaused(const QCString& appId, uint jobNum);
+ /**
+ * This signal is emitted when a text job, that was previously paused, resumes speaking.
+ * @param appId The DCOP senderId of the application that created the job.
+ * @param jobNum Job number of the text job.
+ */
+ void textResumed(const QCString& appId, uint jobNum);
+ /**
+ * This signal is emitted whenever a text job is deleted from the queue.
+ * The job is no longer in the queue when this signal is emitted.
+ * @param appId The DCOP senderId of the application that created the job.
+ * @param jobNum Job number of the text job.
+ */
+ void textRemoved(const QCString& appId, uint jobNum);
+ //@}
+};
+
+#endif // _KSPEECH_H_
diff --git a/kttsd/compat/interfaces/kspeech/kspeechsink.h b/kttsd/compat/interfaces/kspeech/kspeechsink.h
new file mode 100644
index 0000000..e90a005
--- /dev/null
+++ b/kttsd/compat/interfaces/kspeech/kspeechsink.h
@@ -0,0 +1,164 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ kspeechsink.h
+ KTTSD DCOP Signal Sink Interface
+ --------------------------------
+ Copyright:
+ (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+ ******************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+/**
+ * @interface KSpeechSink
+ *
+ * KTTSD DCOP Signal Sink
+ *
+ * @since KDE 3.4
+ *
+ * This defines the interface to sink signals emitted by KTTSD, the KDE Text-to-speech Deamon.
+ * The DCOP IDL Compiler generates a skeleton file from this interface definition that will
+ * marshal the arguments for you.
+ *
+ * @section Usage
+ *
+ * See the Signals section of kspeech.h for instructions.
+ *
+ * @warning The KSpeechSink interface is still being developed and is likely to change in the future.
+*/
+
+#ifndef _KSPEECHSINK_H_
+#define _KSPEECHSINK_H_
+
+#include <dcopobject.h>
+
+class KSpeechSink : virtual public DCOPObject {
+ K_DCOP
+
+ public:
+ /**
+ * @enum kttsdJobState
+ * Job states returned by method getTextJobState.
+ */
+ enum kttsdJobState
+ {
+ jsQueued = 0, /**< Job has been queued but is not yet speakable. */
+ jsSpeakable = 1, /**< Job is speakable, but is not speaking. */
+ jsSpeaking = 2, /**< Job is currently speaking. */
+ jsPaused = 3, /**< Job has been paused. */
+ jsFinished = 4 /**< Job is finished and is deleteable. */
+ };
+
+ /**
+ * @enum kttsdMarkupType
+ * %Speech markup language types.
+ */
+ enum kttsdMarkupType
+ {
+ mtPlain = 0, /**< Plain text */
+ mtJsml = 1, /**< Java %Speech Markup Language */
+ mtSmml = 2, /**< %Speech Markup Meta-language */
+ mtSable = 3 /**< Sable 2.0 */
+ };
+
+ k_dcop:
+ /**
+ * This signal is emitted when KTTSD starts or restarts after a call to reinit.
+ */
+ virtual ASYNC kttsdStarted() { };
+ /**
+ * This signal is emitted just before KTTSD exits.
+ */
+ virtual ASYNC kttsdExiting() { };
+
+ /**
+ * This signal is emitted when the speech engine/plugin encounters a marker in the text.
+ * @param appId DCOP application ID of the application that queued the text.
+ * @param markerName The name of the marker seen.
+ * @see markers
+ */
+ virtual ASYNC markerSeen(const QCString& appId, const QString& markerName) { Q_UNUSED(appId); Q_UNUSED(markerName); };
+ /**
+ * This signal is emitted whenever a sentence begins speaking.
+ * @param appId DCOP application ID of the application that queued the text.
+ * @param jobNum Job number of the text job.
+ * @param seq Sequence number of the text.
+ * @see getTextCount
+ */
+ virtual ASYNC sentenceStarted(const QCString& appId, uint jobNum, uint seq) { Q_UNUSED(appId); Q_UNUSED(jobNum); Q_UNUSED(seq); };
+ /**
+ * This signal is emitted when a sentence has finished speaking.
+ * @param appId DCOP application ID of the application that queued the text.
+ * @param jobNum Job number of the text job.
+ * @param seq Sequence number of the text.
+ * @see getTextCount
+ */
+ virtual ASYNC sentenceFinished(const QCString& appId, uint jobNum, uint seq) { Q_UNUSED(appId); Q_UNUSED(jobNum); Q_UNUSED(seq); };
+
+ /**
+ * This signal is emitted whenever a new text job is added to the queue.
+ * @param appId The DCOP senderId of the application that created the job. NULL if kttsd.
+ * @param jobNum Job number of the text job.
+ */
+ virtual ASYNC textSet(const QCString& appId, uint jobNum) { Q_UNUSED(appId); Q_UNUSED(jobNum); };
+
+ /**
+ * This signal is emitted whenever a new part is appended to a text job.
+ * @param appId The DCOP senderId of the application that created the job.
+ * @param jobNum Job number of the text job.
+ * @param partNum Part number of the new part. Parts are numbered starting
+ * at 1.
+ */
+ virtual ASYNC textAppended(const QCString& appId, uint jobNum, int partNum) { Q_UNUSED(appId); Q_UNUSED(jobNum); Q_UNUSED(partNum); };
+
+ /**
+ * This signal is emitted whenever speaking of a text job begins.
+ * @param appId The DCOP senderId of the application that created the job. NULL if kttsd.
+ * @param jobNum Job number of the text job.
+ */
+ virtual ASYNC textStarted(const QCString& appId, uint jobNum) { Q_UNUSED(appId); Q_UNUSED(jobNum); };
+ /**
+ * This signal is emitted whenever a text job is finished. The job has
+ * been marked for deletion from the queue and will be deleted when another
+ * job reaches the Finished state. (Only one job in the text queue may be
+ * in state Finished at one time.) If startText or resumeText is
+ * called before the job is deleted, it will remain in the queue for speaking.
+ * @param appId The DCOP senderId of the application that created the job. NULL if kttsd.
+ * @param jobNum Job number of the text job.
+ */
+ virtual ASYNC textFinished(const QCString& appId, uint jobNum) { Q_UNUSED(appId); Q_UNUSED(jobNum); };
+ /**
+ * This signal is emitted whenever a speaking text job stops speaking.
+ * @param appId The DCOP senderId of the application that created the job. NULL if kttsd.
+ * @param jobNum Job number of the text job.
+ */
+ virtual ASYNC textStopped(const QCString& appId, uint jobNum) { Q_UNUSED(appId); Q_UNUSED(jobNum); };
+ /**
+ * This signal is emitted whenever a speaking text job is paused.
+ * @param appId The DCOP senderId of the application that created the job. NULL if kttsd.
+ * @param jobNum Job number of the text job.
+ */
+ virtual ASYNC textPaused(const QCString& appId, uint jobNum) { Q_UNUSED(appId); Q_UNUSED(jobNum); };
+ /**
+ * This signal is emitted when a text job, that was previously paused, resumes speaking.
+ * @param appId The DCOP senderId of the application that created the job. NULL if kttsd.
+ * @param jobNum Job number of the text job.
+ */
+ virtual ASYNC textResumed(const QCString& appId, uint jobNum) { Q_UNUSED(appId); Q_UNUSED(jobNum); };
+ /**
+ * This signal is emitted whenever a text job is deleted from the queue.
+ * The job is no longer in the queue when this signal is emitted.
+ * @param appId The DCOP senderId of the application that created the job. NULL if kttsd.
+ * @param jobNum Job number of the text job.
+ */
+ virtual ASYNC textRemoved(const QCString& appId, uint jobNum) { Q_UNUSED(appId); Q_UNUSED(jobNum); };
+};
+
+#endif // _KSPEECHSINK_H_
diff --git a/kttsd/configure.in.bot b/kttsd/configure.in.bot
new file mode 100644
index 0000000..b24a085
--- /dev/null
+++ b/kttsd/configure.in.bot
@@ -0,0 +1,65 @@
+if test "x$have_gst" = xno && test "x$with_gstreamer" != xno; then
+ echo "********************************************************"
+ echo "*"
+ echo "* You do not seem to have GStreamer >= 0.8.7 installed."
+ echo "*"
+ echo "* KTTSD supports GStreamer output but will also"
+ echo "* work with aRts, ALSA, and aKode"
+ echo "*"
+ echo "* PACKAGERS: Please do not include the gstreamer plugin"
+ echo "* in binary distributions of kdeaccessibility as it"
+ echo "* creates unwanted dependencies. Instead, include in a"
+ echo "* separate package, e.g., kdeaccessibility-extras."
+ echo "* The separate package should require gstreamer >= 0.8.7"
+ echo "*"
+ echo "********************************************************"
+fi
+if test "x$have_gst" = xyes && test "x$with_gstreamer" = xno; then
+ echo "********************************************************"
+ echo "*"
+ echo "* You seem to have GStreamer >= 0.8.7 installed."
+ echo "* but you did not choose to build the gstreamer plugin."
+ echo "* To enable GStreamer plugin, configure with"
+ echo "*"
+ echo "* --with-gstreamer"
+ echo "*"
+ echo "* KTTSD supports GStreamer output but will also"
+ echo "* work with aRts, ALSA, and aKode"
+ echo "*"
+ echo "* PACKAGERS: Please do not include the gstreamer plugin"
+ echo "* in binary distributions of kdeaccessibility as it"
+ echo "* creates unwanted dependencies. Instead, include in a"
+ echo "* separate package, e.g., kdeaccessibility-extras."
+ echo "* The separate package should require gstreamer >= 0.8.7"
+ echo "*"
+ echo "********************************************************"
+fi
+if test "x$have_gst" = xyes && test "x$with_gstreamer" != xno; then
+ echo "********************************************************"
+ echo "* The build of the GStreamer audio plugin has been enabled."
+ echo "*"
+ echo "* PACKAGERS: Please do not include the gstreamer plugin"
+ echo "* in binary distributions of kdeaccessibility as it"
+ echo "* creates unwanted dependencies. Instead, include in a"
+ echo "* separate package, e.g., kdeaccessibility-extras."
+ echo "* The separate package should require gstreamer >= 0.8.7"
+ echo "*"
+ echo "********************************************************"
+fi
+if test "x$have_alsa" = xno && test "x$with_alsa" = xcheck; then
+ echo "********************************************************"
+ echo "* The build of the KTTS ALSA audio plugin has been"
+ echo "* disabled because the ALSA sound library headers"
+ echo "* (alsa/asoundlib.h) were not found."
+ echo "*"
+ echo "********************************************************"
+fi
+if test "x$have_akode" = xno && test "x$with_akode" = xcheck; then
+ echo "********************************************************"
+ echo "* The build of the KTTS aKode audio plugin has been"
+ echo "* disabled because the aKode library configuration"
+ echo "* script (akode-config) was not found. The aKode libary"
+ echo "* is part of the kdesupport module."
+ echo "*"
+ echo "********************************************************"
+fi
diff --git a/kttsd/configure.in.in b/kttsd/configure.in.in
new file mode 100644
index 0000000..4adcfb1
--- /dev/null
+++ b/kttsd/configure.in.in
@@ -0,0 +1,304 @@
+#MIN_CONFIG(3.2)
+
+### AM_INIT_AUTOMAKE(kttsd,0.2.0)
+
+dnl ================================================================================
+
+dnl Check for GStreamer >= 0.8.7
+
+AC_ARG_WITH(gstreamer,
+ [AC_HELP_STRING(--with-gstreamer,
+ [enable support for GStreamer @<:@default=no@:>@])],
+ [], with_gstreamer=no)
+
+have_gst=no
+if test "x$with_gstreamer" != xno; then
+ # pkg-config seems to have a bug where it masks needed -L entries when it
+ # shouldn't, so disable that.
+
+ PKG_CONFIG_ALLOW_SYSTEM_LIBS=1
+ export PKG_CONFIG_ALLOW_SYSTEM_LIBS
+
+ dnl start with 0.8
+ GST_MAJORMINOR=0.8
+ dnl Actually need 0.8.7, but plugins were version 0.8.5. argh!
+ GST_REQ=0.8.5
+
+ PKG_CHECK_MODULES(GST, \
+ gstreamer-$GST_MAJORMINOR >= $GST_REQ \
+ gstreamer-control-$GST_MAJORMINOR >= $GST_REQ \
+ gstreamer-libs-$GST_MAJORMINOR >= $GST_REQ,
+ have_gst=yes, have_gst=no)
+
+ if test "x$with_gstreamer" != xcheck && test "x$have_gst" != xyes; then
+ AC_MSG_ERROR([--with-gstreamer was given, but test for GStreamer >= 0.8.5 failed])
+ fi
+fi
+
+if test "x$have_gst" = "xno"; then
+ GST_CFLAGS=""
+ LDADD_GST=""
+ LDFLAGS_GST=""
+ AC_DEFINE(HAVE_GSTREAMER, 0, [have GStreamer])
+else
+ LDADD_GST=`$PKG_CONFIG --libs-only-l gstreamer-$GST_MAJORMINOR`
+ LDFLAGS_GST=`$PKG_CONFIG --libs-only-other gstreamer-$GST_MAJORMINOR`
+
+ # Append -L entries, since they are masked by --libs-only-l and
+ # --libs-only-other
+ LIBDIRS_GST=`$PKG_CONFIG --libs-only-L gstreamer-$GST_MAJORMINOR`
+ LDADD_GST="$LDADD_GST $LIBDIRS_GST"
+
+ AC_MSG_NOTICE([GStreamer version >= $GST_REQ found.])
+ AC_DEFINE(HAVE_GSTREAMER, 1, [have GStreamer])
+
+ if test "x$with_gstreamer" != xcheck && test "x$have_gst" != xyes; then
+ AC_MSG_ERROR([--with-gstreamer was given, but test for GStreamer >= 0.8.7 failed])
+ fi
+fi
+
+AC_SUBST(GST_CFLAGS)
+AC_SUBST(LDADD_GST)
+AC_SUBST(LDFLAGS_GST)
+
+AM_CONDITIONAL(include_kttsd_gstplayer, [test "x$have_gst" = "xyes"])
+
+dnl ================================================================================
+
+dnl Do not compile artsplayer plugin if user specifies --without-arts
+
+AM_CONDITIONAL(include_kttsd_artsplayer, [test "x$build_arts" = "xyes"])
+
+dnl ================================================================================
+
+dnl Check for ALSA.
+dnl TODO: Don't know if 0.5 works or not.
+
+AC_DEFUN([KDE_CHECK_ALSA],
+[
+ have_alsa=no
+
+ KDE_CHECK_HEADERS([sys/asoundlib.h alsa/asoundlib.h],
+ [have_alsa=yes])
+
+ KDE_CHECK_LIB(asound, snd_seq_create_simple_port,
+ [:], [have_alsa=no])
+
+ AC_LANG_SAVE
+ AC_LANG_C
+ if test "x$have_alsa" = xyes; then
+ AC_TRY_COMPILE([
+ #include "confdefs.h"
+ #ifdef HAVE_SYS_ASOUNDLIB_H
+ #include <sys/asoundlib.h>
+ #endif
+ #ifdef HAVE_ALSA_ASOUNDLIB_H
+ #include <alsa/asoundlib.h>
+ #endif
+ ],[
+ #if (SND_LIB_MAJOR == 0) && (SND_LIB_MINOR == 5)
+ /* we have ALSA 0.5.x */
+ #else
+ #error not ALSA 0.5.x
+ #endif
+ ],
+ have_alsa_0_5=yes)
+
+ AC_TRY_COMPILE([
+ #include "confdefs.h"
+ #ifdef HAVE_SYS_ASOUNDLIB_H
+ #include <sys/asoundlib.h>
+ #endif
+ #ifdef HAVE_ALSA_ASOUNDLIB_H
+ #include <alsa/asoundlib.h>
+ #endif
+ ],[
+ #if (SND_LIB_MAJOR == 0) && (SND_LIB_MINOR == 9)
+ /* we have ALSA 0.9.x */
+ #else
+ #error not ALSA 0.9.x
+ #endif
+ ],
+ have_alsa_0_9=yes)
+
+ AC_TRY_COMPILE([
+ #include "confdefs.h"
+ #ifdef HAVE_SYS_ASOUNDLIB_H
+ #include <sys/asoundlib.h>
+ #endif
+ #ifdef HAVE_ALSA_ASOUNDLIB_H
+ #include <alsa/asoundlib.h>
+ #endif
+ ],[
+ #if (SND_LIB_MAJOR == 1)
+ /* we have ALSA 1.x */
+ #else
+ #error not ALSA 1.x
+ #endif
+ ],
+ have_alsa_1=yes)
+ fi
+ AC_LANG_RESTORE
+
+ if test "x$have_alsa_0_9" = xyes || test "x$have_alsa_1" = xyes; then
+ # for kmix/ and akode/
+ LIBASOUND="-lasound"
+ AC_DEFINE(HAVE_LIBASOUND2, 1, [Define if you have libasound.so.2 (required for ALSA 0.9.x/1.x support)])
+
+ # for arts/
+ ARTS_LIBASOUND="-lasound"
+ AC_DEFINE(HAVE_ARTS_LIBASOUND2, 1, [Define if you have libasound.so.2 (required for ALSA 0.9.x/1.x support)])
+ fi
+
+ if test "x$have_alsa_0_5" = xyes; then
+ # for arts/
+ ARTS_LIBASOUND="-lasound"
+ AC_DEFINE(HAVE_ARTS_LIBASOUND, 1, [Define if you have libasound.so.1 (required for ALSA 0.5.x support)])
+ fi
+
+ AC_SUBST(LIBASOUND)
+ AC_SUBST(ARTS_LIBASOUND)
+])
+
+AC_ARG_WITH(alsa,
+ [AC_HELP_STRING(--with-alsa,
+ [enable support for ALSA @<:@default=check@:>@])],
+ [], with_alsa=check)
+
+have_alsa=no
+if test "x$with_alsa" != xno; then
+ KDE_CHECK_ALSA
+
+ if test "x$with_alsa" != xcheck && test "x$have_alsa" != xyes; then
+ AC_MSG_ERROR([--with-alsa was given, but test for ALSA failed])
+ fi
+fi
+
+AM_CONDITIONAL(include_kttsd_alsaplayer, [test "x$have_alsa" = "xyes"])
+
+dnl ================================================================================
+
+dnl Check for aKode library. Note: As of about 16 Jul 2005, it got moved
+dnl from kdemultimedia to kdesupport.
+
+AC_DEFUN([KDE_CHECK_AKODE],
+[
+ AC_PATH_PROG(AKODE_CONFIG, akode-config, [no], [$PATH:$prefix/bin])
+
+ if test "x$AKODE_CONFIG" != xno; then
+ AC_DEFINE(HAVE_AKODE, 1, [define if you have aKodelib installed])
+ akode_includes=`$AKODE_CONFIG --cflags`
+ akode_libs=`$AKODE_CONFIG --libs`
+ have_akode=yes
+ else
+ akode_includes=""
+ akode_libs=""
+ have_akode=no
+ fi
+
+ AC_SUBST(akode_includes)
+ AC_SUBST(akode_libs)
+])
+
+AC_ARG_WITH(akode,
+ [AC_HELP_STRING([--with-akode],
+ [enable the aKode decoder @<:@default=no@:>@])],
+ [], with_akode=no)
+
+have_akode=no
+if test "x$with_akode" != xno; then
+ KDE_CHECK_AKODE
+
+ if test "x$with_akode" != xcheck && test "x$have_akode" != xyes; then
+ AC_MSG_ERROR([--with-akode was given, but test for aKode failed])
+ fi
+fi
+
+AM_CONDITIONAL(include_kttsd_akodeplayer, [test "x$have_akode" = "xyes"])
+
+dnl ================================================================================
+
+dnl Check whether to include sys/time.h and time.h, or just sys/time.h.
+dnl Defines TIME_WITH_SYS_TIME and HAVE_SYS_TIME_H, which are used in
+dnl alsaplayer.cpp.
+
+AC_HEADER_TIME
+AC_CHECK_HEADERS(sys/time.h)
+
+dnl ================================================================================
+
+dnl See if the latest kspeech.h is installed and if not, compile against
+dnl kttsd/compat directory.
+
+if test "$KTTS_KSPEECH_DIR" = ""; then
+ KDE_CHECK_HEADER(kspeech.h, ktts_have_kspeech_h=yes, ktts_have_kspeech_h=no)
+ have_latest_kspeech=no
+ if test "x$ktts_have_kspeech_h" = xyes; then
+ AC_MSG_CHECKING([whether installed kspeech.h is latest version])
+ ktts_save_cppflags=$CPPFLAGS
+ AC_LANG_SAVE
+ CPPFLAGS="$all_includes $CPPFLAGS"
+ AC_LANG_CPLUSPLUS
+ AC_TRY_COMPILE(
+ [#include <kspeech.h>],
+ [
+ if (4 == KSpeech::mtHtml);
+ ],
+ have_latest_kspeech=yes,
+ have_latest_kspeech=no)
+ AC_MSG_RESULT($have_latest_kspeech)
+ CPPFLAGS=$ktts_save_cppflags
+ AC_LANG_RESTORE
+ fi
+ if test "x$have_latest_kspeech" = xyes; then
+ KTTS_KSPEECH_DIR='$(kde_includes)'
+ KTTS_KSPEECH_INCLUDE=""
+ KTTS_INTERFACES_DIR=""
+ else
+ KTTS_KSPEECH_DIR='$(top_srcdir)/kttsd/compat/interfaces/kspeech'
+ KTTS_KSPEECH_INCLUDE='-I$(top_srcdir)/kttsd/compat/interfaces/kspeech'
+ KTTS_INTERFACES_DIR="interfaces"
+ AC_MSG_WARN([Latest kspeech.h not installed. Compiling using kttsd/compat directory.])
+ fi
+
+ AC_SUBST(KTTS_KSPEECH_DIR)
+ AC_SUBST(KTTS_KSPEECH_INCLUDE)
+ AC_SUBST(KTTS_INTERFACES_DIR)
+fi
+
+dnl ================================================================================
+
+# --- Check for KDE < 3.5 ---
+# If so, install icons.
+
+AC_MSG_CHECKING([for KDE version])
+
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+kdeversion_save_CXXFLAGS="$CXXFLAGS"
+kdeversion_save_LIBS="$LIBS"
+LIBS="$LIBS $X_EXTRA_LIBS"
+CXXFLAGS="$CXXFLAGS $all_includes"
+
+AC_COMPILE_IFELSE([
+#include <kdeversion.h>
+#if ! ( KDE_IS_VERSION( 3, 4, 90 ) )
+#error KDE 3.4
+#endif
+],
+ KTTS_ICONS_DIR=""
+,
+ KTTS_ICONS_DIR="icons"
+)
+
+CXXFLAGS="$kdeversion_save_CXXFLAGS"
+LIBS="$kdeversion_save_LIBS"
+AC_LANG_RESTORE
+
+if test "$KTTS_ICONS_DIR" = ""; then
+ AC_MSG_RESULT([KDE 3.4.x or less])
+else
+ AC_MSG_RESULT([KDE 3.5 or later])
+fi
+
+AC_SUBST(KTTS_ICONS_DIR)
diff --git a/kttsd/cvs2dist b/kttsd/cvs2dist
new file mode 100755
index 0000000..da2c08d
--- /dev/null
+++ b/kttsd/cvs2dist
@@ -0,0 +1,634 @@
+#! /bin/bash
+
+# This is cvs2dist
+# Webpage: http://www.katzbrown.com/shiritsu/programming/cvs2dist/
+# Newest version is always available there!
+# Please report bugs to <jason@katzbrown.com>.
+
+# Original author (of cvs2pack.sh) was Sebastian Stein <seb.stein@hpfsc.de>
+# Heavy, heavy modifications by Jason Katz-Brown <jason@katzbrown.com>
+# Some modifications for i18n inclusion by Dominique Devriese <devriese@kde.org>
+# Added --no-i18n-lang and --replace-files by Michael Buesch <mbuesch@freenet.de>
+# License: GPL (http://www.gnu.org/)
+# Last modification: 2004/10/13
+
+cmdline="$@"
+
+returndir=`pwd`
+override="README ChangeLog INSTALL AUTHORS AUTHOR COPYING COPYING.LIB TODO"
+remove="config.cache config.log config.status Makefile configure inst-apps CVS acinclude.m4 aclocal.m4 config.h config.h.bot config.h.in configure.files libtool stamp-h stamp-h.in stamp-h1 subdirs *.moc *.la .libs .deps .cvsignore autom4te.cache {arch} .arch-ids"
+toplevelremove="configure.in.bot"
+# whitespace seperated list of languages to never include.
+always_skip_languages="xx"
+
+pofilenames="kttsd kttsd_commandplugin kttsd_eposplugin kttsd_festivalintplugin
+kttsd_fliteplugin kttsd_freettsplugin kttsd_hadifixplugin kttsd_sbdplugin
+kttsd_stringreplacerplugin kttsd_talkerchooserplugin kttsd_xmltransformerplugin
+kttsjobmgr kttsmgr kcmkttsd khtmlkttsd ktexteditor_kttsd"
+
+exit_cleanup()
+{
+ echo -n "Cleaning up... "
+ if [ -d $temp_dir ]; then
+ test -z "$debug" && rm -Rf $temp_dir
+ fi
+ echo "done."
+}
+
+trap "exit_cleanup; exit 1" SIGINT SIGTERM
+
+test -e ~/.cvs2distrc && extraoptions=`cat ~/.cvs2distrc`
+
+# getopt usage from the getopt bash example
+# --log has optional argument
+TEMP=`getopt \
+-o v:n:r:e:a:B:dhmbgol \
+--long log::,version:,name:,required-header:,required-header-error-message:,make-unpackaged,help,no-bz2,no-bzip2,no-gzip,only-directory,remove-hidden,admin-dir:,branch:,no-i18n,no-i18n-lang:,cvs-root:,debug,replace-files: \
+-n cvs2dist -- $extraoptions "$@"`
+
+if [ $? != 0 ]; then
+ echo "Aborted." >&2
+ exit 1
+fi
+
+eval set -- "$TEMP"
+
+log="/dev/null"
+calclog=0
+doi18n="yes"
+noi18nlang=""
+replace_files=""
+cvsroot=""
+debug=""
+
+while true; do
+ case "$1" in
+ -v|--version) version=$2; shift 2 ;;
+ -n|--name) name=$2; shift 2 ;;
+ -a|--admin-dir) admindir=$2;
+ if [ `echo $admindir | sed -e 's#^/##'` = $admindir ]; then
+ admindir="`pwd`/$admindir"
+ fi
+ shift 2 ;;
+ -B|--branch) branch="-r$2"; shift 2;;
+ --debug) debug="non-empty"; shift 1 ;;
+ --cvs-root) cvsroot="$2"; shift 2 ;;
+ -r|--required-header) requiredheader=$2; shift 2 ;;
+ --no-i18n) doi18n="no"; shift 1 ;;
+ --no-i18n-lang) noi18nlang="$2"; shift 2 ;;
+ -e|--required-header-error-message) requiredmsg=$2; shift 2 ;;
+ -m|--make-unpackaged) leavedir="non-empty"; shift 1 ;;
+ -h|--help) showhelp="non-empty"; shift 1 ;;
+ -b|--no-bz2|--no-bzip2) nobzip2="non-empty"; shift 1 ;;
+ -o|--only-directory)
+ nogzip="non-empty"
+ nobzip2="non-empty"
+ leavedir="non-empty"
+ shift 1 ;;
+ -g|--no-gzip) nogzip="non-empty"; shift 1 ;;
+ -d|--remove-hidden) removehidden="non-empty"; shift 1 ;;
+ -l) calclog=1; shift 1 ;;
+ --log)
+ case "$2" in
+ # no-argument case
+ "") calclog=1; shift 2 ;;
+ # something, should be a file
+ *) log=$2
+ origlog=$log
+ if [ `echo $log | sed -e 's#^/##'` = $log ]; then
+ log="`pwd`/$log"
+ fi
+
+ shift 2 ;;
+ esac ;;
+ --replace-files) replace_files="$2"; shift 2 ;;
+ --) shift
+ break ;;
+ *) echo "Aborted."
+ exit 1 ;;
+ esac
+done
+
+count=0
+for arg do
+ test $count = 0 && module=$arg
+ test $count = 1 && directory=$arg
+
+ if [ $count -ge 2 ]; then
+ modarg=$arg
+ if [ `echo $modarg | sed -e 's#^/##'` = $modarg ]; then
+ modarg="`pwd`/$modarg"
+ fi
+ addfiles="$addfiles $modarg"
+ fi
+
+ let count count++
+done
+
+# test if a module and directory name was given
+if [ ! -z $showhelp ] || [ -z $module ] || [ -z $directory ]; then
+ echo "Usage: cvs2dist module directory [options] [addfile1] [addfile2] ..."
+ echo ""
+ echo " -n --name <name>"
+ echo " -v --version <version>"
+ echo " --cvs-root <root> the value to use as cvs root"
+ echo " variable. It is not necessary if you use --no-i18n."
+ echo " if this is not given, it is taken from the CVSROOT "
+ echo " environment variable."
+ echo " --admin-dir <dir> admin/ location (default is module/admin)"
+ echo " (symbolic links are OK.)"
+ echo " -B --branch <branch> use branch for i18n checkouts."
+ echo " --no-i18n don't try to automatically checkout the translations from cvs."
+ echo " --no-i18n-lang <languages> exclude all languages in the given comma"
+ echo " seperated list. example:"
+ echo " --no-i18n-lang uk,de,en_GB"
+ echo " --log=<logfile> If logfile unspecified, default file is used."
+ echo " (The '=' is essential and may not be ommited"
+ echo " when specifying the logfile.)"
+ echo " -l Log to default logfile."
+ echo " -m --make-unpackaged Also makes an unpacked distribution"
+ echo " in the current directory."
+ echo " -g --no-gzip Do not create gzip package."
+ echo " -b --no-bz2 Do not create bzip2 package."
+ echo " --no-bzip2 Alias for the above."
+ echo " -o --only-directory Alias for -mbg (no packages, only a directory.)"
+ echo " -r --required-header <header> Errors if header is not installed."
+ echo " -e --required-header-error-message <message>"
+ echo " Error message for above."
+ echo " -d --remove-hidden Remove hidden files/directories from packages"
+ echo " --replace-files <file-pair-list>"
+ echo " <file-pair-list> is a comma separated list of file pairs"
+ echo " which should be replaced in the final distribution package."
+ echo " Each element of a pair is separated by an @"
+ echo -n " Example: --replace-files take_this_file@and_move_it_here,"
+ echo "configure.in.bot.dist@configure.in.bot"
+ echo " The filenames are all relative to your package root."
+ echo " Please be careful! Try to avoid the usage of .. in the path. It"
+ echo " may break stuff! There can not be blank characters in the paths."
+ echo " -h --help Show this help"
+ echo ""
+ echo " Name defaults to the last part of the directory."
+ echo "By default, creates name[-version].tar.gz if gzip is installed"
+ echo "and/or name[-version].tar.bz2 if bzip2 is installed in the current"
+ echo "directory. Removes all temporary files it creates. Produces"
+ echo "tarballs that are standard distribution tarballs with a"
+ echo "configure script."
+ echo " Unless --no-i18n is given, it automatically tries to check out "
+ echo "strings and documentation translation from cvs."
+ echo " Arguments after the second are added to the toplevel directory"
+ echo "in the package. Short options can be combined, eg -dm to create"
+ echo "a directory and remove hidden files. ~/.cvs2distrc is added to"
+ echo "the beginning of command line arguments if it exists."
+ echo " '--' signifies the end of options."
+ echo ""
+ echo "Example: cvs2dist /sources/kdegames kolf/objects/picture \\"
+ echo " -n kolf-picture -v 0.9 -r \"kolf/game.h\" \\"
+ echo " --log ~/tmp/extra-file"
+ echo ""
+ echo " Creates packages of the kolf picture plugin, naming the"
+ echo " packages kolf-picture-0.9 and logging the process. For configure"
+ echo " to succeed, kolf/game.h must be installed or an error will occur."
+ echo " ~/tmp/extra-file is added to the packages."
+ echo ""
+ echo "Webpage: http://www.katzbrown.com/shiritsu/programming/cvs2dist/"
+ echo "Authors: Jason Katz-Brown <jason@katzbrown.com>,"
+ echo " Sebastian Stein <seb.stein@hpfsc.de>,"
+ echo " Dominique Devriese <devriese@kde.org>"
+ exit 1
+fi
+
+# expand module
+module=`echo $module | sed -e 's#/$##'`
+if [ `echo $module | sed -e 's#^/##'` = $module ]; then
+ module="`pwd`/$module"
+fi
+
+# test if the given module is a directory
+test -d $module
+if [ $? -ne 0 ]; then
+ echo "$module is not a directory."
+ echo "Aborted."
+ exit 1
+fi
+
+# go to our module
+cd $module
+
+directory=`echo $directory | sed -e 's#^/##'`
+
+if [ -z $name ]; then
+ name=$directory
+ # get rid of trailing slash
+ name=`echo $name | sed -e 's#/$##'`
+ # leading slash
+ name=`echo $name | sed -e 's#^/##'`
+
+ if [ `echo $name | sed -e 's#/##'` != $name ]; then
+ name=`echo $name | sed -e 's#^.*/##'`
+ fi
+fi
+
+test $calclog = 1 && log="$returndir/cvs2dist-$name.log" && origlog="cvs2dist-$name.log"
+
+# test if the given name is a sub-directory
+if [ ! -d "$directory" ]; then
+ echo "$directory is not a sub-directory of $module."
+ echo "Aborted."
+ exit 1
+fi
+
+test $log != "/dev/null" && echo "Logging to $log."
+
+echo "cvs2dist log on "`date` > $log
+echo "http://katzbrown.com/shiritsu/programming/cvs2dist/" >> $log
+echo -n "Module: $module; Directory: $directory; Name: $name; " >> $log
+if [ -z $version ]; then
+ echo "Version unspecified." >> $log
+else
+ echo "Version $version." >> $log
+fi
+echo $cmdline >> $log
+echo "--------" >> $log
+
+if [ -z $version ]; then
+ filename=$name
+else
+ filename="$name-$version"
+fi
+
+if [ -z $cvsroot ]; then
+ cvsroot="$CVSROOT";
+fi
+if [ $doi18n = "yes" ]; then
+ # a little warning...
+ echo "Will try to fetch i18n files from KDE's CVS."
+ echo "If this doesn't work, use --no-i18n."
+
+ if [ -z "$cvsroot" ]; then
+ echo "No cvs root specified, CVSROOT env var is empty, " >> $log
+ echo "and --no-i18n option is not given.." >> $log
+ echo "Using anonymous cvs.." >> $log
+ cvsroot=":pserver:anonymous@anoncvs.kde.org:/home/kde"
+ # append an entry to ~/.cvspass so the user will not be asked
+ # for a pwd. Thanks to coolo for the idea..
+ if ! grep "anoncvs.kde.org" ~/.cvspass >/dev/null 2>&1; then
+ echo "/1 :pserver:anonymous@anoncvs.kde.org:2401/home/kde A" >> ~/.cvspass
+ fi
+ fi
+fi
+
+# the temporary directory
+temp_dir="$module/cvs2dist-tmp"
+temp_dist="$temp_dir/$filename"
+
+echo "Temporary directory is $temp_dir." >> $log
+
+# make a temporary directory
+test -d $temp_dir && rm -Rf $temp_dir
+
+mkdir -p $temp_dist
+
+# check if we were able to create temp_dir
+test -d $temp_dist
+if [ $? -ne 0 ]; then
+ echo "Could not create temporary directory $temp_dist."
+ echo "$temp_dist could not be created." >> $log
+ echo "Aborted."
+ exit 1
+fi
+
+test -z "$requiredmsg" && requiredmsg="Install development package needed first! $requiredheader, for one, is missing."
+
+### configure.in.in
+if [ ! -z $requiredheader ]; then
+ naiyou="KDE_CHECK_HEADER(
+$requiredheader,
+[],
+[AC_MSG_ERROR(\"$requiredmsg\")]
+)"
+ echo $naiyou > $temp_dir/configure.in.in
+ echo "configure.in.in contents: " >> $log
+ echo "--------" >> $log
+ echo $naiyou >> $log
+ appaddfiles="$appaddfiles $temp_dir/configure.in.in"
+fi
+
+# copy all files of the module to temp_dir/name
+cp -RL $module/$directory $temp_dist/$name
+
+echo "cp -R $module/$directory $temp_dist/$name" >> $log
+
+modulename="$module"
+# get rid of trailing slash
+modulename=`echo $modulename | sed -e 's#/$##'`
+# get the last part
+modulename=`echo $modulename | sed -e 's#^.*/##'`
+
+remove="$remove $modulename.lsm"
+
+# we check out kde-i18n/subdirs in temp_dir/kde-i18n..
+if [ $doi18n = "yes" ]; then
+ pushd $temp_dir
+ echo "cvs co kde-i18n/subdirs" >> $log
+ cvs -z4 -q -d "$cvsroot" co $branch -P kde-i18n/subdirs > /dev/null 2>&1
+ i18nlangs_tmp="$(cat kde-i18n/subdirs)"
+ skiplist="`echo $noi18nlang | sed -e 's/,/ /g'`"
+ skiplist="$skiplist $always_skip_languages"
+ for lang in $i18nlangs_tmp; do
+ must_skip="no"
+ for skip in $skiplist; do
+ if [ "$lang" = "$skip" ]; then
+ must_skip="yes"
+ fi
+ done
+ if [ "$must_skip" = "no" ]; then
+ i18nlangs="$i18nlangs $lang"
+ fi
+ done
+ echo "available languages: $i18nlangs" >> $log
+ popd
+fi
+
+# if a handbook exists, we also copy it to the directory
+if [ -d $module/doc/$name ]; then
+ mkdir -p $temp_dist/doc/$name
+ cp -Rf $module/doc/$name $temp_dist/doc
+ find $module/doc/ ! -xtype d -maxdepth 1 | xargs --replace={} cp {} $temp_dist/doc
+
+ if [ $doi18n = "yes" ]; then
+ pushd $temp_dir
+ for lang in $i18nlangs; do
+ test -d $temp_dist/doc/$lang && rm -Rf $temp_dist/doc/$lang
+ docdirname="kde-i18n/$lang/docs/$modulename/$name"
+ echo "cvs co $docdirname" >> $log
+ cvs -z4 -q -d "$cvsroot" co $branch -P "$docdirname" > /dev/null 2>&1
+ if [ ! -d "$docdirname" ]; then
+ echo "$lang's $name documentation does not exist." >> $log
+ continue
+ fi
+ echo -n "Copying $lang's $name documentation over... "
+ cp -R $docdirname $temp_dist/doc/$lang
+ # we don't want KDE_DOCS = AUTO, cause that makes the
+ # build system assume that the name of the app is the
+ # same as the name of the dir the Makefile.am is in.
+ # Instead, we explicitly pass the name..
+ cat $temp_dist/doc/$lang/Makefile.am | sed -e "s/AUTO/$name/" > $temp_dist/doc/$lang/Makefile.am.nw
+ mv $temp_dist/doc/$lang/Makefile.am.nw $temp_dist/doc/$lang/Makefile.am
+ echo "done."
+ echo "$lang documentation included." >> $log
+ done
+ popd
+ fi
+fi
+
+# clean up doc directory
+if [ -d $temp_dist/doc/$name ]; then
+ pushd $temp_dist/doc/$name
+ echo -n "make clean in $temp_dist/doc/$name/... "
+ echo >> $log
+ echo "make clean in $temp_dist/doc/$name/" >> $log
+ make clean >> $log
+ echo "--------" >> $log
+ echo "done."
+ popd
+fi
+
+if [ $doi18n = "yes" ]; then
+ test -d $temp_dist/po && rm -Rf $temp_dist/po
+ mkdir $temp_dist/po
+
+ pushd $temp_dir/
+ for lang in $i18nlangs; do
+ dest=$temp_dist/po/$lang
+ for poname in $pofilenames; do
+ pofilename="kde-i18n/$lang/messages/$modulename/$poname.po";
+ echo "cvs co $pofilename" >> $log
+ cvs -z4 -q -d "$cvsroot" co $branch -P "$pofilename" > /dev/null 2>&1
+ if [ ! -f "$pofilename" ]; then
+ echo "$lang's $poname.po does not exist." >> $log
+ continue
+ fi
+
+ if [ ! -d $dest ]; then
+ mkdir $dest
+ fi
+ echo -n "Copying $lang's $poname.po over... "
+ echo "$lang's $poname.po file included." >> $log
+ cp $pofilename $dest
+ done
+ echo "done."
+
+ echo "KDE_LANG = $lang
+SUBDIRS = \$(AUTODIRS)
+POFILES = AUTO" > $dest/Makefile.am
+
+ subdirs="non_empty"
+ done
+
+ if [ -z "$subdirs" ]; then
+ rm -Rf $temp_dist/po
+ else
+ echo "SUBDIRS = \$(AUTODIRS)" > $temp_dist/po/Makefile.am
+ fi
+fi
+
+# copy the admin directory
+if [ -z $admindir ]; then
+ cp -pRL $module/admin $temp_dist
+ echo "cp -pRL $module/admin $temp_dist" >> $log
+else
+ cp -pRL $admindir $temp_dist
+ echo "cp -pRL $admindir $temp_dist" >> $log
+fi
+
+# and all files from the base dir, except directories
+echo "Copying over files from the module directory:" >> $log
+find $module ! -xtype d -maxdepth 1 | xargs --verbose --replace={} cp {} $temp_dist 2>> $log
+echo "--------" >> $log
+
+# we now enter the temp_dist and delete all unwanted files
+# and add wanted files
+cd $temp_dist
+
+# override top-level files
+echo "Override files: " >> $log
+for file in $override; do
+ test -e $temp_dist/$name/$file && mv $temp_dist/$name/$file . && echo "mv $temp_dist/$name/$file ." >> $log
+done
+
+test ! -z "$addfiles" && echo "Addfiles: " >> $log
+for file in $addfiles; do
+ test -e $file && cp -R $file $temp_dist && echo "cp -R $file $temp_dist" >> $log
+done
+
+test ! -z "$appaddfiles" && echo "Application addfiles: " >> $log
+for file in $appaddfiles; do
+ test -e $file && cp -R $file $temp_dist/$name/ && echo "cp -R $file $temp_dist/$name/" >> $log
+done
+
+echo "--------" >> $log
+
+# replace all user requested files
+if [ -n "$replace_files" ]; then
+ echo "Replace user requested files" >> $log
+ pair_list="`echo $replace_files | sed -e 's/,/ /g'`"
+ for pair in $pair_list; do
+ pair_tmp="`echo $pair | sed -e 's/@/ /g'`"
+ from="`echo $pair_tmp | awk '//{print $1}'`"
+ to="`echo $pair_tmp | awk '//{print $2}'`"
+ if [ -z "$from" ] || [ -z "$to" ]; then
+ echo "bogus pair \"$from@$to\"" >> $log
+ continue
+ fi
+ echo "Replacing \"$to\" by \"$from\"" >> $log
+ from_path="$temp_dist/$name/$from"
+ to_path="$temp_dist/$name/$to"
+ if [ ! -f "$from_path" ]; then
+ echo "$from_path does not exist!" >> $log
+ echo ""
+ echo "Warning: \"$from\" does not exist!"
+ echo -n "Please enter the path in --replace-files relative "
+ echo "to the package root of your project."
+ echo "Your package root is: \"$module/$directory\""
+ echo ""
+ continue
+ fi
+ rm -f "$to_path" && \
+ mv "$from_path" "$to_path"
+ if [ $? -ne 0 ]; then
+ echo -n "Moving \"$from_path\" failed! " >> $log
+ echo -n "This should not happen." >> $log
+ if [ -f "$to_path" ]; then
+ echo ""
+ else
+ echo " No \"$to\" will exist in the archive!" >> $log
+ fi
+ fi
+ done
+ echo "--------" >> $log
+fi
+
+# version file, if it doesn't exist
+test ! -z $version && test ! -e VERSION && echo "$name version $version" > VERSION
+
+cd $temp_dist/$name
+echo "make clean in $temp_dist/$name/:" >> $log
+echo "" >> $log
+echo -n "make clean in $temp_dist/$name/... "
+make clean >> $log
+echo "--------" >> $log
+echo "done."
+
+cd $temp_dist
+
+# remove files
+echo "Remove files: " >> $log
+for file in $remove; do
+ find . -name $file | xargs rm -Rf
+ echo "find . -name $file | xargs rm -Rf" >> $log
+done
+
+# remove more files
+echo "Remove toplevel files: " >> $log
+for file in $toplevelremove; do
+ test -e $file && rm -Rf $file && echo "rm -Rf $file" >> $log
+done
+unset file
+
+# remove hidden files
+test ! -z $removehidden && echo "Remove hidden files: " >> $log && find $temp_dist -name ".*" -and ! -name "." | xargs --verbose rm -Rf 2>> $log
+
+echo "--------" >> $log
+
+cd $temp_dist
+
+# create the configure script
+# working directory is $temp_dist
+echo "make -f Makefile.cvs in $temp_dist/:" >> $log
+echo "" >> $log
+echo -n "make -f Makefile.cvs in $temp_dist/... "
+make -f Makefile.cvs >> $log 2>> $log
+echo "rm Makefile.cvs" >> $log
+rm -f Makefile.cvs
+echo "rm autom4te.cache" >> $log
+rm -Rf autom4te.cache
+echo "--------" >> $log
+echo "done."
+
+echo "Directory will be $filename."
+
+# play around with our tar file in temp_dir
+cd $temp_dir
+
+if [ ! -z $leavedir ]; then
+ test -e $returndir/$filename && rm -Rf $returndir/$filename
+ cp -R $filename $returndir
+fi
+
+# make a tar of temp_dist
+if [ -z $nogzip ] || [ -z $nobzip2 ]; then
+ echo -n "Tarring... "
+ echo "tar cf $filename.tar $filename" >> $log
+ tar cf $filename.tar $filename >> $log
+ echo "done."
+fi
+
+if [ -z $nogzip ] && [ ! -z `which gzip 2> /dev/null` ]; then
+ cp $filename.tar $filename.tar.tmp
+ echo -n "running gzip... "
+ echo "gzip $filename.tar" >> $log
+ gzip $filename.tar
+ echo "done."
+ mv $filename.tar.tmp $filename.tar
+ mv $filename.tar.gz $returndir
+ echo "mv $filename.tar.gz $returndir" >> $log
+fi
+if [ -z $nobzip2 ] && [ ! -z `which bzip2 2> /dev/null` ]; then
+ echo -n "running bzip2... "
+ echo "bzip2 $filename.tar" >> $log
+ bzip2 $filename.tar
+ echo "done."
+ mv $filename.tar.bz2 $returndir
+ echo "mv $filename.tar.bz2 $returndir" >> $log
+fi
+
+test -e $filename.tar && rm -f $filename.tar
+
+# cleanup all tempoaries
+exit_cleanup
+
+cd $returndir
+
+test -z $leavedir && test ! -z $nobzip2 && test ! -z $nogzip && echo "Finished - no created files." && exit 1
+
+# cool, everything went ok!
+if [ -z $leavedir ]; then
+ echo "Finished. Created packages:"
+else
+ if [ -z $nogzip ] || [ -z $nobzip2 ]; then
+ echo "Finished. Created packages/directories:"
+ else
+ echo "Finished. Created directory:"
+ fi
+fi
+
+echo "--------" >> $log
+echo "Done: " >> $log
+echo "Files are in `pwd`." >> $log
+
+if [ ! -z $leavedir ] && [ -d $filename ]; then
+ ls -ld $filename
+ ls -ld $filename >> $log
+fi
+if [ -z $nogzip ] && [ -e $filename.tar.gz ]; then
+ ls -l $filename.tar.gz
+ ls -l $filename.tar.gz >> $log
+fi
+if [ -z $nobzip2 ] && [ -e $filename.tar.bz2 ]; then
+ ls -l $filename.tar.bz2
+ ls -l $filename.tar.bz2 >> $log
+fi
+if [ $log != "/dev/null" ]; then
+ echo "Created log:"
+ ls -l $origlog
+fi
diff --git a/kttsd/debian/TODO b/kttsd/debian/TODO
new file mode 100644
index 0000000..12b05e3
--- /dev/null
+++ b/kttsd/debian/TODO
@@ -0,0 +1,36 @@
+* FWIW, I have the following packages installed (among many others, of course):
+ libqt3-headers 3.3.3-4.1 Qt3 header files
+ libqt3-mt-dev 3.3.3-4.1 Qt development files (Threaded)
+ libqt3c102-mt 3.3.3-4.1 Qt GUI Library (Threaded runtime version), V
+ libqthreads-12 1.6.4-4 QuickThreads library for Guile
+ qt3-designer 3.3.3-4.1 Qt3 Designer
+ qt3-dev-tools 3.3.3-4.1 Qt3 development tools
+ qt3-doc 3.3.3-4.1 Qt3 API documentation
+ kde 3.1.2 The K Desktop Environment
+ kdelibs4 3.2.3-2 KDE core libraries
+ kdelibs4-dev 3.2.3-2 KDE core libraries (development files)
+ kdelibs4-doc 3.2.3-2 KDE core library documentation
+ kde-devel 3.1.2 The K Desktop Environment (development files
+ kde-devel-extr 3.1.2-0.2 The K Desktop Environment (extra development
+ exuberant-ctag 5.5.4-1 build tag file indexes of source code defini
+ cdbs 0.4.26-1.1 common build system for Debian packages
+
+* Here's my build procedure (note that I'm using CDBS):
+ - cd kdeaccessibility/doc/kttsd && make distclean && cd kdeaccessibility/kttsd && make distclean
+ - cvs2dist kdeaccessibility kttsd --version 0.3.0
+ - Copy resulting kttsd-0.3.0.tar.gz to a work folder and rename to kttsd_0.3.0.orig.tar.gz
+ (Note underscore)
+ - Unpack tarball
+ - cd kttsd-0.3.0
+ - rm -fR autom4te.cache
+ - cp -R kttsd/debian debian
+ - debuild -uc -us
+
+* dpkg-shlibdeps is reporting:
+ dpkg-shlibdeps: warning: could not find path for libkttsd.so.1
+ Should I have libkttsd.so in the .install file?
+
+* Should rc files be installed to etc/ tree?
+
+* For unknown reason, several of the doc translations aren't being built (da, pt for example),
+ but en and de are being built. ??
diff --git a/kttsd/debian/changelog b/kttsd/debian/changelog
new file mode 100644
index 0000000..81f503a
--- /dev/null
+++ b/kttsd/debian/changelog
@@ -0,0 +1,5 @@
+kttsd (0.3.0-1) unstable; urgency=low
+
+ * Second Release
+
+ -- Gary Cramblitt (PhantomsDad) <garycramblitt@comcast.net> Wed, 9 Feb 2005 23:05:18 -0500
diff --git a/kttsd/debian/compat b/kttsd/debian/compat
new file mode 100644
index 0000000..b8626c4
--- /dev/null
+++ b/kttsd/debian/compat
@@ -0,0 +1 @@
+4
diff --git a/kttsd/debian/control b/kttsd/debian/control
new file mode 100644
index 0000000..61c10b7
--- /dev/null
+++ b/kttsd/debian/control
@@ -0,0 +1,40 @@
+Source: kttsd
+Section: kde
+Priority: extra
+Maintainer: Gary Cramblitt (PhantomsDad) <garycramblitt@comcast.net>
+Build-Depends: debhelper (>= 4.0.0), kdelibs4-dev (>= 4:3.2), qt3-doc (>=3.3.3)
+Standards-Version: 3.6.1.1
+
+Package: kttsd
+Architecture: any
+Depends: ${shlibs:Depends}
+Suggests: festival, festival-doc, festvox-kallpc, flite, epos,
+ xsltproc, sox, kttsd-gstreamer
+Description: KDE Text-to-Speech system
+ KTTS, the KDE Text-to-Speech (TTS) system, is a plug-in based dcop service
+ that allows any KDE (or non-KDE) application to speak using the DCOP
+ interface.
+ .
+ KTTS intends to be the implementation for the KDE Text-to-Speech API.
+ .
+ Features
+ --------
+ * Priority system for warnings and messages, while still playing
+ regular text.
+ * Long text is parsed into sentences. User may backup by sentence or
+ paragraph, replay, pause, and stop playing.
+ * Speak contents of clipboard.
+ * Speak KDE notification events (KNotify).
+ .
+ You must also install a speech synthesis engine, such as festival, flite,
+ epos, freetts, or hadifix (MBROLA and txt2pho). khelpcenter help:/kttsd/
+ for links and suggestions for obtaining and installing synthesizers.
+
+Package: kttsd-gstreamer
+Architecture: any
+Depends: kttsd, libgstreamer0.8-0 (>= 0.8.7)
+Description: KTTSD GStreamer plugin
+ A plugin for the KDE Text-to-Speech system for producing
+ audio output via GStreamer. You will also need the
+ GStreamer wav file plugin and at least one GStreamer
+ output plugin (aRts, oss, or nas).
diff --git a/kttsd/debian/copyright b/kttsd/debian/copyright
new file mode 100644
index 0000000..c4848dc
--- /dev/null
+++ b/kttsd/debian/copyright
@@ -0,0 +1,33 @@
+This package was debianized by Gary Cramblitt (PhantomsDad)
+<garycramblitt@comcast.net> on
+Wed, 9 FEb 2005 17:06:00 +0500.
+
+It was downloaded from the KDE CVS repository.
+
+Upstream Authors:
+ José Pablo Ezequiel Fernández <pupeno@pupeno.com>
+ Gary Cramblitt <garycramblitt@comcast.net>
+ Gunnar Schmi Dt <gunnar@schmi-dt.de>
+ Olaf Schmidt <ojschmidt@kde.org>
+ Paul Giannaros <ceruleanblaze@gmail.com>
+
+Copyright:
+(c) 2002, José Pablo Ezequiel Fernández
+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 dated June, 1991.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in /usr/share/common-licenses/GPL file.
diff --git a/kttsd/debian/dirs b/kttsd/debian/dirs
new file mode 100644
index 0000000..e772481
--- /dev/null
+++ b/kttsd/debian/dirs
@@ -0,0 +1 @@
+usr/bin
diff --git a/kttsd/debian/docs b/kttsd/debian/docs
new file mode 100644
index 0000000..724e084
--- /dev/null
+++ b/kttsd/debian/docs
@@ -0,0 +1,2 @@
+README
+TODO
diff --git a/kttsd/debian/kttsd-gstreamer.install b/kttsd/debian/kttsd-gstreamer.install
new file mode 100644
index 0000000..dbe0185
--- /dev/null
+++ b/kttsd/debian/kttsd-gstreamer.install
@@ -0,0 +1,3 @@
+debian/tmp/usr/lib/kde3/libkttsd_gstplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_gstplugin.la
+debian/tmp/usr/share/services/kttsd_gstplugin.desktop
diff --git a/kttsd/debian/kttsd.install b/kttsd/debian/kttsd.install
new file mode 100644
index 0000000..1ed977e
--- /dev/null
+++ b/kttsd/debian/kttsd.install
@@ -0,0 +1,107 @@
+debian/tmp/usr/bin/kttsd
+debian/tmp/usr/bin/kttsmgr
+debian/tmp/usr/lib/libkttsd.so.1.0.0
+debian/tmp/usr/lib/libkttsd.so.1
+debian/tmp/usr/lib/libkttsd.la
+debian/tmp/usr/lib/kde3/libkttsd_festivalintplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_festivalintplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_commandplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_commandplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_hadifixplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_hadifixplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_fliteplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_fliteplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_eposplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_eposplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_freettsplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_freettsplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_artsplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_artsplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_stringreplacerplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_stringreplacerplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_sbdplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_sbdplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_talkerchooserplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_talkerchooserplugin.la
+debian/tmp/usr/lib/kde3/libkttsd_xmltransformerplugin.so
+debian/tmp/usr/lib/kde3/libkttsd_xmltransformerplugin.la
+debian/tmp/usr/lib/kde3/libkttsjobmgrpart.so
+debian/tmp/usr/lib/kde3/libkttsjobmgrpart.la
+debian/tmp/usr/lib/kde3/kcm_kttsd.so
+debian/tmp/usr/lib/kde3/kcm_kttsd.la
+debian/tmp/usr/lib/kde3/ktexteditor_kttsd.la
+debian/tmp/usr/lib/kde3/ktexteditor_kttsd.so
+
+debian/tmp/usr/lib/kde3/libkhtmlkttsdplugin.la
+debian/tmp/usr/lib/kde3/libkhtmlkttsdplugin.so
+
+debian/tmp/usr/share/servicetypes/kttsd_synthplugin.desktop
+debian/tmp/usr/share/servicetypes/kttsd_audioplugin.desktop
+debian/tmp/usr/share/servicetypes/kttsd_filterplugin.desktop
+debian/tmp/usr/share/servicetypes/dcoptexttospeech.desktop
+
+debian/tmp/usr/share/apps/kttsd/xslt/SSMLtoPlainText.xsl
+debian/tmp/usr/share/apps/kttsd/festivalint/voices
+debian/tmp/usr/share/apps/kttsd/festivalint/sabletowave.scm
+debian/tmp/usr/share/apps/kttsd/festivalint/xslt/SSMLtoSable.xsl
+debian/tmp/usr/share/apps/kttsd/hadifix/xslt/SSMLtoTxt2pho.xsl
+debian/tmp/usr/share/apps/kttsd/talkerchooser/female_notifications_rc
+debian/tmp/usr/share/apps/kttsd/sbd/polish_festival_sbdrc
+debian/tmp/usr/share/apps/kttsd/sbd/standard_sbdrc
+debian/tmp/usr/share/apps/kttsd/stringreplacer/abbreviations.xml
+debian/tmp/usr/share/apps/kttsd/stringreplacer/emoticons.xml
+debian/tmp/usr/share/apps/kttsd/stringreplacer/polish_festival_fixes.xml
+debian/tmp/usr/share/apps/kttsd/stringreplacer/chat.xml
+debian/tmp/usr/share/apps/kttsd/stringreplacer/kmail.xml
+debian/tmp/usr/share/apps/kttsd/stringreplacer/polish_festival_unspeakables.xml
+debian/tmp/usr/share/apps/kttsd/xmltransformer/xhtml2ssml.xsl
+debian/tmp/usr/share/apps/ktexteditor_kttsd/ktexteditor_kttsdui.rc
+
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/common
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/general.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/index.cache.bz2
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/index.docbook
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/addtalker.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/audio.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/festivalintconf.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/general.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/interruption.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/jobs.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/talkers.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/filters.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/stringreplacer.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/xmltransformer.png
+debian/tmp/usr/share/doc/kde/HTML/*/kttsd/talkerchooser.png
+
+debian/tmp/usr/share/services/kttsd_festivalintplugin.desktop
+debian/tmp/usr/share/services/kttsd_commandplugin.desktop
+debian/tmp/usr/share/services/kttsd_hadifixplugin.desktop
+debian/tmp/usr/share/services/kttsd_fliteplugin.desktop
+debian/tmp/usr/share/services/kttsd_eposplugin.desktop
+debian/tmp/usr/share/services/kttsd_freettsplugin.desktop
+debian/tmp/usr/share/services/kttsd_stringreplacerplugin.desktop
+debian/tmp/usr/share/services/kttsd_sbdplugin.desktop
+debian/tmp/usr/share/services/kttsd_xmltransformerplugin.desktop
+debian/tmp/usr/share/services/kttsd_talkerchooserplugin.desktop
+debian/tmp/usr/share/services/kttsd.desktop
+debian/tmp/usr/share/services/kttsjobmgr.desktop
+debian/tmp/usr/share/services/kttsd_artsplugin.desktop
+debian/tmp/usr/share/services/ktexteditor_kttsd.desktop
+
+debian/tmp/usr/share/apps/khtml/kpartplugins/khtmlkttsd.desktop
+debian/tmp/usr/share/apps/khtml/kpartplugins/khtmlkttsd.rc
+
+debian/tmp/usr/share/icons/hicolor/16x16/actions/male.png
+debian/tmp/usr/share/icons/hicolor/16x16/actions/female.png
+debian/tmp/usr/share/icons/crystalsvg/16x16/apps/kttsd.png
+debian/tmp/usr/share/icons/crystalsvg/22x22/apps/kttsd.png
+debian/tmp/usr/share/icons/crystalsvg/32x32/apps/kttsd.png
+debian/tmp/usr/share/icons/crystalsvg/48x48/apps/kttsd.png
+debian/tmp/usr/share/icons/crystalsvg/64x64/apps/kttsd.png
+debian/tmp/usr/share/icons/crystalsvg/128x128/apps/kttsd.png
+debian/tmp/usr/share/icons/crystalsvg/scalable/apps/kttsd.svgz
+
+debian/tmp/usr/share/applications/kde/kcmkttsd.desktop
+debian/tmp/usr/share/applications/kde/kttsmgr.desktop
+
+debian/tmp/usr/share/locale/*/LC_MESSAGES/
diff --git a/kttsd/debian/kttsd.manpages b/kttsd/debian/kttsd.manpages
new file mode 100644
index 0000000..8051bd1
--- /dev/null
+++ b/kttsd/debian/kttsd.manpages
@@ -0,0 +1,2 @@
+debian/man/kttsmgr.1
+debian/man/kttsd.1
diff --git a/kttsd/debian/kttsmgr.menu b/kttsd/debian/kttsmgr.menu
new file mode 100644
index 0000000..f39b56b
--- /dev/null
+++ b/kttsd/debian/kttsmgr.menu
@@ -0,0 +1,6 @@
+?package(kttsd):\
+ needs="x11"\
+ section="Apps/Tools"\
+ hints="KDE"\
+ title="KTTSMgr"\
+ command="/usr/bin/kttsmgr"
diff --git a/kttsd/debian/man/kttsd.1 b/kttsd/debian/man/kttsd.1
new file mode 100644
index 0000000..379d7f0
--- /dev/null
+++ b/kttsd/debian/man/kttsd.1
@@ -0,0 +1,159 @@
+.\" This file was generated by kdemangen.pl and hand edited
+.TH KTTSD 1 "Oct 2004" "K Desktop Environment" "Text-to-speech synthesis deamon"
+.SH NAME
+kttsd
+- Text-to-speech synthesis deamon
+.SH SYNOPSIS
+kttsd [Qt-options] [KDE-options]
+.SH DESCRIPTION
+kttsd is part of the KDE Text-to-Speech system. kttsd is the
+non-GUI deamon that provides TTS services to applications
+via the DCOP interface. kttsd is configured via kttsmgr.
+.SH OPTIONS
+.SS Generic options:
+.TP
+.B --help
+Show help about options
+.TP
+.B --help-qt
+Show Qt specific options
+.TP
+.B --help-kde
+Show KDE specific options
+.TP
+.B --help-all
+Show all options
+.TP
+.B --author
+Show author information
+.TP
+.B -v, --version
+Show version information
+.TP
+.B --license
+Show license information
+.TP
+.B --
+End of options
+.SS
+.SS KDE options:
+.TP
+.B --caption <caption>
+Use 'caption' as name in the titlebar
+.TP
+.B --icon <icon>
+Use 'icon' as the application icon
+.TP
+.B --miniicon <icon>
+Use 'icon' as the icon in the titlebar
+.TP
+.B --config <filename>
+Use alternative configuration file
+.TP
+.B --dcopserver <server>
+Use the DCOP Server specified by 'server'
+.TP
+.B --nocrashhandler
+Disable crash handler, to get core dumps
+.TP
+.B --waitforwm
+Waits for a WM_NET compatible windowmanager
+.TP
+.B --style <style>
+sets the application GUI style
+.TP
+.B --geometry <geometry>
+sets the client geometry of the main widget
+.TP
+.B --nofork
+Don't run in the background.
+.SS Qt options:
+.TP
+.B --display <displayname>
+Use the X-server display 'displayname'
+.TP
+.B --session <sessionId>
+Restore the application for the given 'sessionId'
+.TP
+.B --cmap
+Causes the application to install a private color
+map on an 8-bit display
+.TP
+.B --ncols <count>
+Limits the number of colors allocated in the color
+cube on an 8-bit display, if the application is
+using the QApplication::ManyColor color
+specification
+.TP
+.B --nograb
+tells Qt to never grab the mouse or the keyboard
+.TP
+.B --dograb
+running under a debugger can cause an implicit
+-nograb, use -dograb to override
+.TP
+.B --sync
+switches to synchronous mode for debugging
+.TP
+.B --fn, --font <fontname>
+defines the application font
+.TP
+.B --bg, --background <color>
+sets the default background color and an
+application palette (light and dark shades are
+calculated)
+.TP
+.B --fg, --foreground <color>
+sets the default foreground color
+.TP
+.B --btn, --button <color>
+sets the default button color
+.TP
+.B --name <name>
+sets the application name
+.TP
+.B --title <title>
+sets the application title (caption)
+.TP
+.B --visual TrueColor
+forces the application to use a TrueColor visual on
+an 8-bit display
+.TP
+.B --inputstyle <inputstyle>
+sets XIM (X Input Method) input style. Possible
+values are onthespot, overthespot, offthespot and
+root
+.TP
+.B --im <XIM server>
+set XIM server
+.TP
+.B --noxim
+disable XIM
+.TP
+.B --reverse
+mirrors the whole layout of widgets
+.SS
+
+.SH SEE ALSO
+Full user documentation is available through the KDE Help Center. You can also enter the URL
+.BR help:/kttsd/
+directly into konqueror or you can run
+.BR "`khelpcenter help:/kttsd/'"
+from the command-line.
+.br
+
+kttsmgr(1)
+.br
+.SH AUTHORS
+.nf
+Jos Pablo Ezequiel Fernndez <pupeno@pupeno.com>
+.br
+Gary Cramblitt <garycramblitt@comcast.net>
+.br
+Gunnar Schmi Dt <gunnar@schmi-dt.de>
+.br
+Olaf Schmidt <ojschmidt@kde.org>
+.br
+Paul Giannaros <ceruleanblaze@gmail.com>
+.br
+
diff --git a/kttsd/debian/man/kttsmgr.1 b/kttsd/debian/man/kttsmgr.1
new file mode 100644
index 0000000..547ff14
--- /dev/null
+++ b/kttsd/debian/man/kttsmgr.1
@@ -0,0 +1,157 @@
+.\" This file was generated by kdemangen.pl and hand edited.
+.TH KTTSMGR 1 "Oct 2004" "K Desktop Environment" "Text-to-Speech Manager"
+.SH NAME
+kttsmgr
+- Text-to-Speech Manager
+.SH SYNOPSIS
+kttsmgr [Qt-options] [KDE-options]
+.SH DESCRIPTION
+kttsmgr is an application for starting and configuring the
+KDE Text-to-Speech system.
+.SH OPTIONS
+.SS Generic options:
+.TP
+.B --help
+Show help about options
+.TP
+.B --help-qt
+Show Qt specific options
+.TP
+.B --help-kde
+Show KDE specific options
+.TP
+.B --help-all
+Show all options
+.TP
+.B --author
+Show author information
+.TP
+.B -v, --version
+Show version information
+.TP
+.B --license
+Show license information
+.TP
+.B --
+End of options
+.SS
+.SS KDE options:
+.TP
+.B --caption <caption>
+Use 'caption' as name in the titlebar
+.TP
+.B --icon <icon>
+Use 'icon' as the application icon
+.TP
+.B --miniicon <icon>
+Use 'icon' as the icon in the titlebar
+.TP
+.B --config <filename>
+Use alternative configuration file
+.TP
+.B --dcopserver <server>
+Use the DCOP Server specified by 'server'
+.TP
+.B --nocrashhandler
+Disable crash handler, to get core dumps
+.TP
+.B --waitforwm
+Waits for a WM_NET compatible windowmanager
+.TP
+.B --style <style>
+sets the application GUI style
+.TP
+.B --geometry <geometry>
+sets the client geometry of the main widget
+.TP
+.B --nofork
+Don't run in the background.
+.SS Qt options:
+.TP
+.B --display <displayname>
+Use the X-server display 'displayname'
+.TP
+.B --session <sessionId>
+Restore the application for the given 'sessionId'
+.TP
+.B --cmap
+Causes the application to install a private color
+map on an 8-bit display
+.TP
+.B --ncols <count>
+Limits the number of colors allocated in the color
+cube on an 8-bit display, if the application is
+using the QApplication::ManyColor color
+specification
+.TP
+.B --nograb
+tells Qt to never grab the mouse or the keyboard
+.TP
+.B --dograb
+running under a debugger can cause an implicit
+-nograb, use -dograb to override
+.TP
+.B --sync
+switches to synchronous mode for debugging
+.TP
+.B --fn, --font <fontname>
+defines the application font
+.TP
+.B --bg, --background <color>
+sets the default background color and an
+application palette (light and dark shades are
+calculated)
+.TP
+.B --fg, --foreground <color>
+sets the default foreground color
+.TP
+.B --btn, --button <color>
+sets the default button color
+.TP
+.B --name <name>
+sets the application name
+.TP
+.B --title <title>
+sets the application title (caption)
+.TP
+.B --visual TrueColor
+forces the application to use a TrueColor visual on
+an 8-bit display
+.TP
+.B --inputstyle <inputstyle>
+sets XIM (X Input Method) input style. Possible
+values are onthespot, overthespot, offthespot and
+root
+.TP
+.B --im <XIM server>
+set XIM server
+.TP
+.B --noxim
+disable XIM
+.TP
+.B --reverse
+mirrors the whole layout of widgets
+.SS
+
+.SH SEE ALSO
+Full user documentation is available through the KDE Help Center. You can also enter the URL
+.BR help:/kttsd/
+directly into konqueror or you can run
+.BR "`khelpcenter help:/kttsd/'"
+from the command-line.
+.br
+
+kttsd(1)
+.SH AUTHORS
+.nf
+Jos Pablo Ezequiel Fernndez <pupeno@pupeno.com>
+.br
+Gary Cramblitt <garycramblitt@comcast.net>
+.br
+Gunnar Schmi Dt <gunnar@schmi-dt.de>
+.br
+Olaf Schmidt <ojschmidt@kde.org>
+.br
+Paul Giannaros <ceruleanblaze@gmail.com>
+.br
+
diff --git a/kttsd/debian/man/manpages.in b/kttsd/debian/man/manpages.in
new file mode 100644
index 0000000..f0a5d64
--- /dev/null
+++ b/kttsd/debian/man/manpages.in
@@ -0,0 +1,2 @@
+kttsd kttsd
+kttsd kttsmgr
diff --git a/kttsd/debian/rules b/kttsd/debian/rules
new file mode 100755
index 0000000..eaed76d
--- /dev/null
+++ b/kttsd/debian/rules
@@ -0,0 +1,5 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/kde.mk
+DEB_CONFIGURE_EXTRA_FLAGS := --enable-kttsd-gstreamer
diff --git a/kttsd/debian/shlibs.kttsd b/kttsd/debian/shlibs.kttsd
new file mode 100644
index 0000000..6746322
--- /dev/null
+++ b/kttsd/debian/shlibs.kttsd
@@ -0,0 +1,2 @@
+libkttsd 1 (>= 1:1.0.0)
+
diff --git a/kttsd/filters/Makefile.am b/kttsd/filters/Makefile.am
new file mode 100644
index 0000000..8c068f0
--- /dev/null
+++ b/kttsd/filters/Makefile.am
@@ -0,0 +1,26 @@
+# Include paths. INCLUDES is maintained by KDevelop, AM_CPPFLAGS is the preferred variable,
+# so keep them synchronized.
+INCLUDES = \
+ -I$(top_srcdir)/kttsd/libkttsd \
+ -I$(kde_includes)/arts \
+ $(CFLAGS_GST) \
+ $(all_includes)
+
+SUBDIRS = stringreplacer xmltransformer sbd talkerchooser
+
+#########################################################################
+# APPLICATION SECTION
+#########################################################################
+# This is the program that gets installed. It's name is used for all
+# of the other Makefile.am variables.
+check_PROGRAMS = testfilter
+
+testfilter_SOURCES = main.cpp
+
+testfilter_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+testfilter_LDADD = \
+ $(top_builddir)/kttsd/libkttsd/libkttsd.la \
+ $(LIB_KDECORE)
+
+kde_servicetypes_DATA = kttsd_filterplugin.desktop
+
diff --git a/kttsd/filters/kttsd_filterplugin.desktop b/kttsd/filters/kttsd_filterplugin.desktop
new file mode 100644
index 0000000..afede99
--- /dev/null
+++ b/kttsd/filters/kttsd_filterplugin.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KTTSD/FilterPlugin
+
+[PropertyDef::X-KDE-Languages]
+Type=QStringList
diff --git a/kttsd/filters/main.cpp b/kttsd/filters/main.cpp
new file mode 100644
index 0000000..d358da8
--- /dev/null
+++ b/kttsd/filters/main.cpp
@@ -0,0 +1,140 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ KTTSD Filter Test Program
+ -------------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+#include <qstring.h>
+#include <iostream>
+using namespace std;
+
+#include <qtextstream.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kconfig.h>
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+
+#include "filterproc.h"
+#include "talkercode.h"
+
+static const KCmdLineOptions options[] =
+{
+ { "+pluginName", I18N_NOOP("Name of a KTTSD filter plugin (required)"), 0 },
+ { "t", 0, 0 },
+ { "talker <talker>", I18N_NOOP("Talker code passed to filter"), "en" },
+ { "a", 0, 0 },
+ { "appid <appID>", I18N_NOOP("DCOP application ID passed to filter"), "testfilter" },
+ { "g", 0, 0 },
+ { "group <filterID>",
+ I18N_NOOP2("A string that appears in a single config file, not a group of config files",
+ "Config file group name passed to filter"), "testfilter" },
+ { "list", I18N_NOOP("Display list of available Filter PlugIns and exit"), 0 },
+ { "b", 0, 0 },
+ { "break", I18N_NOOP("Display tabs as \\t, otherwise they are removed"), 0 },
+ { "list", I18N_NOOP("Display list of available filter plugins and exit"), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char *argv[])
+{
+ KAboutData aboutdata(
+ "testfilter", I18N_NOOP("testfilter"),
+ "0.1.0", I18N_NOOP("A utility for testing KTTSD filter plugins."),
+ KAboutData::License_GPL, "(C) 2005, Gary Cramblitt <garycramblitt@comcast.net>");
+ aboutdata.addAuthor("Gary Cramblitt", I18N_NOOP("Maintainer"),"garycramblitt@comcast.net");
+
+ KCmdLineArgs::init( argc, argv, &aboutdata );
+ // Tell which options are supported
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app( false, false );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ KTrader::OfferList offers = KTrader::self()->query("KTTSD/FilterPlugin");
+
+ if (args->isSet("list"))
+ {
+ // Iterate thru the offers to list the plugins.
+ const int offersCount = offers.count();
+ for(int ndx=0; ndx < offersCount ; ++ndx)
+ {
+ QString name = offers[ndx]->name();
+ cout << name.latin1() << endl;
+ }
+ return 0;
+ }
+
+ QString filterName;
+ if (args->count() > 0) filterName = args->arg(0);
+ QString talker = args->getOption("talker");
+ QCString appId = args->getOption("appid");
+ QString groupName = args->getOption("group");
+
+ if (filterName.isEmpty()) kdError(1) << "No filter name given." << endl;
+
+ const int offersCount = offers.count();
+ for(int ndx=0; ndx < offersCount ; ++ndx)
+ {
+ if(offers[ndx]->name() == filterName)
+ {
+ // When the entry is found, load the plug in
+ // First create a factory for the library
+ KLibFactory *factory = KLibLoader::self()->factory(offers[ndx]->library().latin1());
+ if(factory)
+ {
+ // If the factory is created successfully, instantiate the KttsFilterConf class for the
+ // specific plug in to get the plug in configuration object.
+ int errorNo;
+ KttsFilterProc *plugIn =
+ KParts::ComponentFactory::createInstanceFromLibrary<KttsFilterProc>(
+ offers[ndx]->library().latin1(), NULL, offers[ndx]->library().latin1(),
+ QStringList(), &errorNo);
+ if(plugIn)
+ {
+ KConfig* config = new KConfig("kttsdrc");
+ config->setGroup( "General" );
+ plugIn->init( config, groupName );
+ QTextStream inp ( stdin, IO_ReadOnly );
+ QString text;
+ text = inp.read();
+ TalkerCode* talkerCode = new TalkerCode( talker );
+ text = plugIn->convert( text, talkerCode, appId );
+ if ( args->isSet("break") )
+ text.replace( "\t", "\\t" );
+ else
+ text.replace( "\t", "" );
+ cout << text.latin1() << endl;
+ delete config;
+ delete plugIn;
+ return 0;
+ } else
+ kdError(2) << "Unable to create instance from library." << endl;
+ } else
+ kdError(3) << "Unable to create factory." << endl;
+ }
+ }
+ kdError(4) << "Unable to find a plugin named " << filterName << endl;
+}
diff --git a/kttsd/filters/sbd/Makefile.am b/kttsd/filters/sbd/Makefile.am
new file mode 100644
index 0000000..4faa8a9
--- /dev/null
+++ b/kttsd/filters/sbd/Makefile.am
@@ -0,0 +1,27 @@
+INCLUDES = \
+ -I$(top_srcdir)/kttsd/libkttsd -I$(top_builddir)/kttsd/libkttsd \
+ $(all_includes)
+
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = libkttsd_sbdplugin.la
+
+libkttsd_sbdplugin_la_SOURCES = \
+ sbdproc.cpp \
+ sbdconf.cpp \
+ sbdconfwidget.ui \
+ sbdplugin.cpp
+
+libkttsd_sbdplugin_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries)
+libkttsd_sbdplugin_la_LIBADD = $(top_builddir)/kttsd/libkttsd/libkttsd.la
+
+services_DATA = kttsd_sbdplugin.desktop
+servicesdir = $(kde_servicesdir)
+
+# Install data files.
+sbddatadir = $(kde_datadir)/kttsd/sbd/
+sbddata_DATA = \
+ standard_sbdrc \
+ polish_festival_sbdrc
+
+noinst_HEADERS = sbdproc.h
diff --git a/kttsd/filters/sbd/kttsd_sbdplugin.desktop b/kttsd/filters/sbd/kttsd_sbdplugin.desktop
new file mode 100644
index 0000000..0e8a483
--- /dev/null
+++ b/kttsd/filters/sbd/kttsd_sbdplugin.desktop
@@ -0,0 +1,91 @@
+[Desktop Entry]
+Name=Sentence Boundary Detector
+Name[bg]=Детектор на изречения
+Name[ca]=Detector de límit de frase
+Name[cs]=Zjištění vět
+Name[da]=Grænsedetektor for sætninger
+Name[de]=Satzgrenzenerkennung
+Name[el]=Ανιχνευτής ορίων πρότασης
+Name[es]=Detector de final de frase
+Name[et]=Lausepiiri tuvastaja
+Name[eu]=Esaldien mugen detektorea
+Name[fa]=آشکارساز کرانۀ جمله
+Name[fi]=Lauserajojen tunnistin
+Name[fr]=Détecteur de fins de phrases
+Name[ga]=Brathadóir Teorainneacha Abairtí
+Name[gl]=Detector de Límite de Frases
+Name[hu]=Mondathatár-detektáló
+Name[is]=Setningamarka greinir
+Name[it]=Rilevatore del limite delle frasi
+Name[ja]=センテンスの境界検出
+Name[ka]=წინადადების საზღვრის დამდგენი
+Name[km]= ឧបករណ៍​ចាប់​ព្រំដែន​ប្រយោគ
+Name[lt]=Sakinio ribų aptikiklis
+Name[mk]=Детектор на граница на реченица
+Name[ms]=Pengesan Sempadan Ayat
+Name[nb]=Finner setningsgrenser
+Name[nds]=Satzgrenz-Faststellen
+Name[ne]=वाक्य सीमा संसूचक
+Name[nl]=Zingrensdetectie
+Name[pl]=Wykrywanie granicy zdania
+Name[pt]=Detector de Limite de Frase
+Name[pt_BR]=Detector de Fim de Sentenças
+Name[ru]=Определитель границ предложения
+Name[sk]=Detekcia okraja vety
+Name[sl]=Detektor meje stavkov
+Name[sr]=Детектор граница реченице
+Name[sr@Latn]=Detektor granica rečenice
+Name[sv]=Meningsgränsdetektering
+Name[ta]=வாக்கிய பவுண்டரி கண்டுபிடிப்பான்
+Name[tg]=Муайянсозии ҳудуди ҷумлаҳо
+Name[tr]=Cümle Sınırlama Algılayıcı
+Name[uk]=Виявлення меж речень
+Name[vi]=Trình nhận dạng Ranh giới Câu văn
+Name[zh_CN]=语句分界检测器
+Name[zh_TW]=句子界限偵測器
+Comment=Sentence Boundary Detection Filter Plugin for KTTS
+Comment[bg]=Приставка филтър за определяне границите на изречението
+Comment[ca]=Connector del filtre detector de límit de frase pel KTTS
+Comment[cs]=Modul filtru zjišťování vět KTTS
+Comment[da]=Grænsedetektor for sætninger, filter-plugin for KTTS
+Comment[de]=Generisches KTTS-Modul zur Erkennung von Satzgrenzen
+Comment[el]=Φίλτρο πρόσθετο ανίχνευσης ορίων πρότασης για το KTTS
+Comment[es]=Complemento de filtrado que detecta el final de las frases para KTTS
+Comment[et]=KTTS-i lausepiiri tuvastamise filtri plugin
+Comment[eu]=KTTS-ren esaldien mugen detektorearen iragazkien plugina
+Comment[fa]=وصلۀ پالایۀ آشکارسازی کرانۀ جمله برای KTTS
+Comment[fi]=Lauserajojen tunnistussuodatin liitännäinen KTTS-ohjelmalle
+Comment[fr]=Module de filtrage de fins de phrases pour KTTS
+Comment[gl]=Plugin de Filtro Detector de Límite de Frases para KTTS
+Comment[hu]=Mondatvég-detektáló szűrőmodul a KTTS-hez
+Comment[is]=Setningamarka greinasía fyrir KTTS
+Comment[it]=Plugin per il filtro di rilevazione del limite delle frasi per KTTS
+Comment[ja]=KTTS 用センテンスの境界検出フィルタプラグイン
+Comment[ka]=წინადადების საზღვრის დამდგენის ფილტრის მოდული KTTS-სთვის
+Comment[km]=កម្មវិធី​ជំនួយ​តម្រង​ឧបករណ៍​ចាប់​ព្រំដែន​ប្រយោគ​សម្រាប់ KTTS
+Comment[lt]=Sakinio ribų aptikiklio filtro priedas, skirtas KTTS
+Comment[mk]=Филтер за KTTS за детекција на границата на реченица
+Comment[ms]=Plugin Penapis Pengesan Sempadan Ayat bagi KTTS
+Comment[nb]=Programtillegg for KTTS som finner setningsgrenser
+Comment[nds]=KTTS-Filtermoduul för dat Faststellen vun Satzgrenzen
+Comment[ne]=KTTS का लागि वाक्य सीमा पत्ता लगाउने फिल्टर
+Comment[nl]=Zingrensdetectieplugin voor KTTS
+Comment[pl]=Wtyczka filtra wykrywania granicy zdania dla KTTS
+Comment[pt]='Plugin' de Filtro de Detecção de Limite de Frase para o KTTS
+Comment[pt_BR]=Plug-in de Detector de Fim de Sentenças para o KTTSD
+Comment[ru]=Фильтр границ предложения для KTTS
+Comment[sk]=Modul filtra na detekciu okraja vety v KTTS
+Comment[sl]=Filtrni vstavek KTTS za zanavanje mej stavka
+Comment[sr]=Филтерски прикључак KTTS-а за откривање граница реченице
+Comment[sr@Latn]=Filterski priključak KTTS-a za otkrivanje granica rečenice
+Comment[sv]=Insticksprogram för KTTS med filter för meningsgränsdetektering
+Comment[ta]=KTTSக்கான வாக்கிய கண்டறி அலங்கார சொருகுப்பொருள்
+Comment[tg]=Филтри ҳудуди ҷумлаҳо барои KTTS
+Comment[tr]=KTTS için Cümle Sınırlama Algılayıcı Süzgeci Eklentisi
+Comment[uk]=Втулок фільтра виявлення меж для KTTS
+Comment[vi]=Trình bổ sung Lọc Nhận dạng Ranh giới Câu văn cho KTTS
+Comment[zh_TW]=KTTS 使用的偵測句子是否已結束的外掛程式
+Type=Service
+ServiceTypes=KTTSD/FilterPlugin
+X-KDE-Library=libkttsd_sbdplugin
+X-KDE-Languages=en,en_US,en_GB,en_CA,es,es_mx,cy,de,fi,cs,pl
diff --git a/kttsd/filters/sbd/polish_festival_sbdrc b/kttsd/filters/sbd/polish_festival_sbdrc
new file mode 100644
index 0000000..ad64153
--- /dev/null
+++ b/kttsd/filters/sbd/polish_festival_sbdrc
@@ -0,0 +1,6 @@
+[Filter]
+AppID=
+LanguageCodes=pl
+SentenceBoundary=\\t
+SentenceDelimiterRegExp=([\\.\\?\\!\\:\\;])(\\s|$|(\\n *\\n))
+UserFilterName=Polish Sentence Boundary Detector
diff --git a/kttsd/filters/sbd/sbdconf.cpp b/kttsd/filters/sbd/sbdconf.cpp
new file mode 100644
index 0000000..2d4cf5d
--- /dev/null
+++ b/kttsd/filters/sbd/sbdconf.cpp
@@ -0,0 +1,341 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Sentence Boundary Detection Filter Configuration class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+// Qt includes.
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qstring.h>
+#include <qhbox.h>
+#include <qlayout.h>
+#include <qdom.h>
+#include <qfile.h>
+#include <qradiobutton.h>
+
+// KDE includes.
+#include <kglobal.h>
+#include <klocale.h>
+#include <klistview.h>
+#include <klineedit.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+#include <kpushbutton.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kregexpeditorinterface.h>
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+#include <kfiledialog.h>
+
+// KTTS includes.
+#include "filterconf.h"
+
+// SBD includes.
+#include "sbdconf.h"
+#include "sbdconf.moc"
+
+/**
+* Constructor
+*/
+SbdConf::SbdConf( QWidget *parent, const char *name, const QStringList& /*args*/) :
+ KttsFilterConf(parent, name)
+{
+ // kdDebug() << "SbdConf::SbdConf: Running" << endl;
+
+ // Create configuration widget.
+ QVBoxLayout *layout = new QVBoxLayout(this, KDialog::marginHint(),
+ KDialog::spacingHint(), "SbdConfigWidgetLayout");
+ layout->setAlignment (Qt::AlignTop);
+ m_widget = new SbdConfWidget(this, "SbdConfigWidget");
+ layout->addWidget(m_widget);
+
+ // Determine if kdeutils Regular Expression Editor is installed.
+ m_reEditorInstalled = !KTrader::self()->query("KRegExpEditor/KRegExpEditor").isEmpty();
+
+ m_widget->reButton->setEnabled( m_reEditorInstalled );
+ if ( m_reEditorInstalled )
+ connect( m_widget->reButton, SIGNAL(clicked()), this, SLOT(slotReButton_clicked()) );
+
+ connect( m_widget->reLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()) );
+ connect( m_widget->sbLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()) );
+ connect( m_widget->nameLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()) );
+ connect( m_widget->appIdLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()) );
+ connect(m_widget->languageBrowseButton, SIGNAL(clicked()),
+ this, SLOT(slotLanguageBrowseButton_clicked()));
+ connect(m_widget->loadButton, SIGNAL(clicked()),
+ this, SLOT(slotLoadButton_clicked()));
+ connect(m_widget->saveButton, SIGNAL(clicked()),
+ this, SLOT(slotSaveButton_clicked()));
+ connect(m_widget->clearButton, SIGNAL(clicked()),
+ this, SLOT(slotClearButton_clicked()));
+
+ // Set up defaults.
+ defaults();
+}
+
+/**
+* Destructor.
+*/
+SbdConf::~SbdConf(){
+ // kdDebug() << "SbdConf::~SbdConf: Running" << endl;
+}
+
+/**
+* This method is invoked whenever the module should read its
+* configuration (most of the times from a config file) and update the
+* user interface. This happens when the user clicks the "Reset" button in
+* the control center, to undo all of his changes and restore the currently
+* valid settings. Note that kttsmgr calls this when the plugin is
+* loaded, so it not necessary to call it in your constructor.
+* The plugin should read its configuration from the specified group
+* in the specified config file.
+* @param config Pointer to a KConfig object.
+* @param configGroup Call config->setGroup with this argument before
+* loading your configuration.
+*/
+void SbdConf::load(KConfig* config, const QString& configGroup){
+ // kdDebug() << "SbdConf::load: Running" << endl;
+ config->setGroup( configGroup );
+ m_widget->nameLineEdit->setText(
+ config->readEntry("UserFilterName", m_widget->nameLineEdit->text()) );
+ m_widget->reLineEdit->setText(
+ config->readEntry("SentenceDelimiterRegExp", m_widget->reLineEdit->text()) );
+ m_widget->sbLineEdit->setText(
+ config->readEntry("SentenceBoundary", m_widget->sbLineEdit->text()) );
+ QStringList langCodeList = config->readListEntry("LanguageCodes");
+ if (!langCodeList.isEmpty())
+ m_languageCodeList = langCodeList;
+ QString language = "";
+ for ( uint ndx=0; ndx < m_languageCodeList.count(); ++ndx)
+ {
+ if (!language.isEmpty()) language += ",";
+ language += KGlobal::locale()->twoAlphaToLanguageName(m_languageCodeList[ndx]);
+ }
+ m_widget->languageLineEdit->setText(language);
+ m_widget->appIdLineEdit->setText(
+ config->readEntry("AppID", m_widget->appIdLineEdit->text()) );
+}
+
+/**
+* This function gets called when the user wants to save the settings in
+* the user interface, updating the config files or wherever the
+* configuration is stored. The method is called when the user clicks "Apply"
+* or "Ok". The plugin should save its configuration in the specified
+* group of the specified config file.
+* @param config Pointer to a KConfig object.
+* @param configGroup Call config->setGroup with this argument before
+* saving your configuration.
+*/
+void SbdConf::save(KConfig* config, const QString& configGroup){
+ // kdDebug() << "SbdConf::save: Running" << endl;
+ config->setGroup( configGroup );
+ config->writeEntry("UserFilterName", m_widget->nameLineEdit->text() );
+ config->writeEntry("SentenceDelimiterRegExp", m_widget->reLineEdit->text() );
+ config->writeEntry("SentenceBoundary", m_widget->sbLineEdit->text() );
+ config->writeEntry("LanguageCodes", m_languageCodeList );
+ config->writeEntry("AppID", m_widget->appIdLineEdit->text().replace(" ", "") );
+}
+
+/**
+* This function is called to set the settings in the module to sensible
+* default values. It gets called when hitting the "Default" button. The
+* default values should probably be the same as the ones the application
+* uses when started without a config file. Note that defaults should
+* be applied to the on-screen widgets; not to the config file.
+*/
+void SbdConf::defaults(){
+ // kdDebug() << "SbdConf::defaults: Running" << endl;
+ m_widget->nameLineEdit->setText( i18n("Standard Sentence Boundary Detector") );
+ m_widget->reLineEdit->setText( "([\\.\\?\\!\\:\\;])(\\s|$|(\\n *\\n))" );
+ m_widget->sbLineEdit->setText( "\\1\\t" );
+ m_languageCodeList.clear();
+ m_widget->languageLineEdit->setText( "" );
+ m_widget->appIdLineEdit->setText( "" );
+ // kdDebug() << "SbdConf::defaults: Exiting" << endl;
+}
+
+/**
+ * Indicates whether the plugin supports multiple instances. Return
+ * False if only one instance of the plugin can be configured.
+ * @return True if multiple instances are possible.
+ */
+bool SbdConf::supportsMultiInstance() { return true; }
+
+/**
+ * Returns the name of the plugin. Displayed in Filters tab of KTTSMgr.
+ * If there can be more than one instance of a filter, it should return
+ * a unique name for each instance. The name should be translated for
+ * the user if possible. If the plugin is not correctly configured,
+ * return an empty string.
+ * @return Filter instance name.
+ */
+QString SbdConf::userPlugInName()
+{
+ if ( m_widget->reLineEdit->text().isEmpty() )
+ return QString::null;
+ else
+ return m_widget->nameLineEdit->text();
+}
+
+/**
+ * Returns True if this filter is a Sentence Boundary Detector.
+ * @return True if this filter is a SBD.
+ */
+bool SbdConf::isSBD() { return true; }
+
+void SbdConf::slotReButton_clicked()
+{
+ // Show Regular Expression Editor dialog if it is installed.
+ if ( !m_reEditorInstalled ) return;
+ QDialog *editorDialog =
+ KParts::ComponentFactory::createInstanceFromQuery<QDialog>( "KRegExpEditor/KRegExpEditor" );
+ if ( editorDialog )
+ {
+ // kdeutils was installed, so the dialog was found. Fetch the editor interface.
+ KRegExpEditorInterface *reEditor =
+ static_cast<KRegExpEditorInterface *>(editorDialog->qt_cast( "KRegExpEditorInterface" ) );
+ Q_ASSERT( reEditor ); // This should not fail!// now use the editor.
+ reEditor->setRegExp( m_widget->reLineEdit->text() );
+ int dlgResult = editorDialog->exec();
+ if ( dlgResult == QDialog::Accepted )
+ {
+ QString re = reEditor->regExp();
+ m_widget->reLineEdit->setText( re );
+ configChanged();
+ }
+ delete editorDialog;
+ } else return;
+}
+
+void SbdConf::slotLanguageBrowseButton_clicked()
+{
+ // Create a QHBox to host KListView.
+ QHBox* hBox = new QHBox(m_widget, "SelectLanguage_hbox");
+ // Create a KListView and fill with all known languages.
+ KListView* langLView = new KListView(hBox, "SelectLanguage_lview");
+ langLView->addColumn(i18n("Language"));
+ langLView->addColumn(i18n("Code"));
+ langLView->setSelectionMode(QListView::Extended);
+ QStringList allLocales = KGlobal::locale()->allLanguagesTwoAlpha();
+ QString locale;
+ QString languageCode;
+ QString countryCode;
+ QString charSet;
+ QString language;
+ // Blank line so user can select no language.
+ QListViewItem* item = new KListViewItem(langLView, "", "");
+ if (m_languageCodeList.isEmpty()) item->setSelected(true);
+ const int allLocalesCount = allLocales.count();
+ for (int ndx=0; ndx < allLocalesCount; ++ndx)
+ {
+ locale = allLocales[ndx];
+ KGlobal::locale()->splitLocale(locale, languageCode, countryCode, charSet);
+ language = KGlobal::locale()->twoAlphaToLanguageName(languageCode);
+ if (!countryCode.isEmpty()) language +=
+ " (" + KGlobal::locale()->twoAlphaToCountryName(countryCode)+")";
+ QListViewItem* item = new KListViewItem(langLView, language, locale);
+ if (m_languageCodeList.contains(locale)) item->setSelected(true);
+ }
+ // Sort by language.
+ langLView->setSorting(0);
+ langLView->sort();
+ // Display the box in a dialog.
+ KDialogBase* dlg = new KDialogBase(
+ KDialogBase::Swallow,
+ i18n("Select Languages"),
+ KDialogBase::Help|KDialogBase::Ok|KDialogBase::Cancel,
+ KDialogBase::Cancel,
+ m_widget,
+ "SelectLanguage_dlg",
+ true,
+ true);
+ dlg->setMainWidget(hBox);
+ dlg->setHelp("", "kttsd");
+ dlg->setInitialSize(QSize(300, 500), false);
+ int dlgResult = dlg->exec();
+ languageCode = QString::null;
+ if (dlgResult == QDialog::Accepted)
+ {
+ m_languageCodeList.clear();
+ QListViewItem* item = langLView->firstChild();
+ while (item)
+ {
+ if (item->isSelected()) m_languageCodeList += item->text(1);
+ item = item->nextSibling();
+ }
+ }
+ delete dlg;
+ // TODO: Also delete KListView and QHBox?
+ if (dlgResult != QDialog::Accepted) return;
+ language = "";
+ for ( uint ndx=0; ndx < m_languageCodeList.count(); ++ndx)
+ {
+ if (!language.isEmpty()) language += ",";
+ language += KGlobal::locale()->twoAlphaToLanguageName(m_languageCodeList[ndx]);
+ }
+ m_widget->languageLineEdit->setText(language);
+ configChanged();
+}
+
+void SbdConf::slotLoadButton_clicked()
+{
+ // QString dataDir = KGlobal::dirs()->resourceDirs("data").last() + "/kttsd/stringreplacer/";
+ QString dataDir = KGlobal::dirs()->findAllResources("data", "kttsd/sbd/").last();
+ QString filename = KFileDialog::getOpenFileName(
+ dataDir,
+ "*rc|SBD Config (*rc)",
+ m_widget,
+ "sbd_loadfile");
+ if ( filename.isEmpty() ) return;
+ KConfig* cfg = new KConfig( filename, true, false, 0 );
+ load( cfg, "Filter" );
+ delete cfg;
+ configChanged();
+}
+
+void SbdConf::slotSaveButton_clicked()
+{
+ QString filename = KFileDialog::getSaveFileName(
+ KGlobal::dirs()->saveLocation( "data" ,"kttsd/sbd/", false ),
+ "*rc|SBD Config (*rc)",
+ m_widget,
+ "sbd_savefile");
+ if ( filename.isEmpty() ) return;
+ KConfig* cfg = new KConfig( filename, false, false, 0 );
+ save( cfg, "Filter" );
+ delete cfg;
+}
+
+void SbdConf::slotClearButton_clicked()
+{
+ m_widget->nameLineEdit->setText( QString::null );
+ m_widget->reLineEdit->setText( QString::null );
+ m_widget->sbLineEdit->setText( QString::null );
+ m_languageCodeList.clear();
+ m_widget->languageLineEdit->setText( QString::null );
+ m_widget->appIdLineEdit->setText( QString::null );
+ configChanged();
+}
diff --git a/kttsd/filters/sbd/sbdconf.h b/kttsd/filters/sbd/sbdconf.h
new file mode 100644
index 0000000..131a759
--- /dev/null
+++ b/kttsd/filters/sbd/sbdconf.h
@@ -0,0 +1,139 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Standard Sentence Boundary Detection Filter Configuration class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+#ifndef _SBDCONF_H_
+#define _SBDCONF_H_
+
+// Qt includes.
+#include <qwidget.h>
+
+// KDE includes.
+#include <kconfig.h>
+#include <kdebug.h>
+
+// KTTS includes.
+#include "filterconf.h"
+
+// SBD includes.
+#include "sbdconfwidget.h"
+
+class KDialogBase;
+class EditReplacementWidget;
+
+class SbdConf : public KttsFilterConf
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor
+ */
+ SbdConf( QWidget *parent, const char *name, const QStringList &args = QStringList() );
+
+ /**
+ * Destructor
+ */
+ virtual ~SbdConf();
+
+ /**
+ * This method is invoked whenever the module should read its
+ * configuration (most of the times from a config file) and update the
+ * user interface. This happens when the user clicks the "Reset" button in
+ * the control center, to undo all of his changes and restore the currently
+ * valid settings. Note that KTTSMGR calls this when the plugin is
+ * loaded, so it not necessary to call it in your constructor.
+ * The plugin should read its configuration from the specified group
+ * in the specified config file.
+ * @param config Pointer to a KConfig object.
+ * @param configGroup Call config->setGroup with this argument before
+ * loading your configuration.
+ *
+ * When a plugin is first added to KTTSMGR, @e load will be called with
+ * a Null @e configGroup. In this case, the plugin will not have
+ * any instance-specific parameters to load, but it may still wish
+ * to load parameters that apply to all instances of the plugin.
+ */
+ virtual void load(KConfig *config, const QString &configGroup);
+
+ /**
+ * This function gets called when the user wants to save the settings in
+ * the user interface, updating the config files or wherever the
+ * configuration is stored. The method is called when the user clicks "Apply"
+ * or "Ok". The plugin should save its configuration in the specified
+ * group of the specified config file.
+ * @param config Pointer to a KConfig object.
+ * @param configGroup Call config->setGroup with this argument before
+ * saving your configuration.
+ */
+ virtual void save(KConfig *config, const QString &configGroup);
+
+ /**
+ * This function is called to set the settings in the module to sensible
+ * default values. It gets called when hitting the "Default" button. The
+ * default values should probably be the same as the ones the application
+ * uses when started without a config file. Note that defaults should
+ * be applied to the on-screen widgets; not to the config file.
+ */
+ virtual void defaults();
+
+ /**
+ * Indicates whether the plugin supports multiple instances. Return
+ * False if only one instance of the plugin can be configured.
+ * @return True if multiple instances are possible.
+ */
+ virtual bool supportsMultiInstance();
+
+ /**
+ * Returns the name of the plugin. Displayed in Filters tab of KTTSMgr.
+ * If there can be more than one instance of a filter, it should return
+ * a unique name for each instance. The name should be translated for
+ * the user if possible. If the plugin is not correctly configured,
+ * return an empty string.
+ * @return Filter instance name.
+ */
+ virtual QString userPlugInName();
+
+ /**
+ * Returns True if this filter is a Sentence Boundary Detector.
+ * @return True if this filter is a SBD.
+ */
+ virtual bool isSBD();
+
+ private slots:
+ void slotReButton_clicked();
+ void slotLanguageBrowseButton_clicked();
+ void slotLoadButton_clicked();
+ void slotSaveButton_clicked();
+ void slotClearButton_clicked();
+
+ private:
+
+ // Configuration Widget.
+ SbdConfWidget* m_widget;
+ // True if kdeutils Regular Expression Editor is installed.
+ bool m_reEditorInstalled;
+ // Language Code.
+ QStringList m_languageCodeList;
+};
+
+#endif //_SBDCONF_H_
diff --git a/kttsd/filters/sbd/sbdconfwidget.ui b/kttsd/filters/sbd/sbdconfwidget.ui
new file mode 100644
index 0000000..17cd525
--- /dev/null
+++ b/kttsd/filters/sbd/sbdconfwidget.ui
@@ -0,0 +1,363 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>SbdConfWidget</class>
+<author>Gary Cramblitt &lt;garycramblitt@comcast.net&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>SbdConfWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>544</width>
+ <height>315</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;WARNING: This filter is a key component of the KTTS system. Please read the KTTS Handbook before modifying these settings.&lt;/b&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>nameLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Name:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nameLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The name of this filter. Enter any descriptive name you like.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>nameLineEdit</cstring>
+ </property>
+ <property name="text">
+ <string>Standard Sentence Boundary Detector</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The name of this filter. Enter any descriptive name you like.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>reLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Sentence boundary regular expression:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nameLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The regular expression that detects boundaries between sentences in text jobs.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>reLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The regular expression that detects boundaries between sentences in text jobs.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>reButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="0">
+ <property name="name">
+ <cstring>layout17_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>sbLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Replacement sentence boundary:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nameLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This string replaces the matched regular expression. &lt;b&gt;Important&lt;/b&gt;: must end with tab (\t).</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>sbLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This string replaces the matched regular expression. &lt;b&gt;Important&lt;/b&gt;: must end with tab (\t).</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox" row="4" column="0">
+ <property name="name">
+ <cstring>applyGroupBox</cstring>
+ </property>
+ <property name="title">
+ <string>Apply This &amp;Filter When</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>These settings determines when the filter is applied to text.</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>languageLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Language is:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>languageLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter is applied to text jobs of the specified language. You may select more than one language by clicking the browse button and Ctrl-clicking on more than one in the list. If blank the filter applies to all text jobs of any language.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>appIdLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Application &amp;ID contains:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>appIdLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter a DCOP Application ID. This filter will only apply to text jobs queued by that application. You may enter more than one ID separated by commas. If blank, this filter applies to text jobs queued by all applications. Tip: Use kdcop from the command line to get the Application IDs of running applications. Example: "konversation, kvirc,ksirc,kopete"</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>languageLineEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter is applied to text jobs of the specified language. You may select more than one language by clicking the browse button and Ctrl-clicking on more than one in the list. If blank the filter applies to all text jobs of any language.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>languageBrowseButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to select one or more languages. This filter will be applied to text jobs of those languages.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>appIdLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter a DCOP Application ID. This filter will only apply to text jobs queued by that application. You may enter more than one ID separated by commas. Use &lt;b&gt;knotify&lt;/b&gt; to match all messages sent as KDE notifications. If blank, this filter applies to text jobs queued by all applications. Tip: Use kdcop from the command line to get the Application IDs of running applications. Example: "konversation, kvirc,ksirc,kopete"&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="5" column="0">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>loadButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Load...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to load a Sentence Boundary Detection configuration from a file.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>saveButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Sa&amp;ve...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to save this Sentence Boundary Detection configuration to a file.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>clearButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Clea&amp;r</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to clear everything.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>nameLineEdit</tabstop>
+ <tabstop>reLineEdit</tabstop>
+ <tabstop>reButton</tabstop>
+ <tabstop>sbLineEdit</tabstop>
+ <tabstop>languageLineEdit</tabstop>
+ <tabstop>languageBrowseButton</tabstop>
+ <tabstop>appIdLineEdit</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kttsd/filters/sbd/sbdplugin.cpp b/kttsd/filters/sbd/sbdplugin.cpp
new file mode 100644
index 0000000..ab14080
--- /dev/null
+++ b/kttsd/filters/sbd/sbdplugin.cpp
@@ -0,0 +1,33 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generating the factories so Sentence Boundary Detection Filter can be used
+ as plug in.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+#include <kgenericfactory.h>
+
+#include "sbdconf.h"
+#include "sbdproc.h"
+
+typedef K_TYPELIST_2( SbdProc, SbdConf ) SbdPlugin;
+K_EXPORT_COMPONENT_FACTORY( libkttsd_sbdplugin,
+ KGenericFactory<SbdPlugin>("kttsd_sbd") )
+
diff --git a/kttsd/filters/sbd/sbdproc.cpp b/kttsd/filters/sbd/sbdproc.cpp
new file mode 100644
index 0000000..cdc80d9
--- /dev/null
+++ b/kttsd/filters/sbd/sbdproc.cpp
@@ -0,0 +1,784 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Sentence Boundary Detection Filter class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+// Qt includes.
+#include <qregexp.h>
+#include <qdom.h>
+#include <qapplication.h>
+
+// KDE includes.
+#include <kdebug.h>
+#include <klocale.h>
+#include <kconfig.h>
+
+// KTTS includes.
+#include "utils.h"
+#include "talkercode.h"
+
+// SdbProc includes.
+#include "sbdproc.h"
+
+/**
+ * Constructor.
+ */
+SbdThread::SbdThread( QObject *parent, const char *name ) :
+ QObject( parent, name ),
+ QThread()
+{
+}
+
+/**
+ * Destructor.
+ */
+/*virtual*/ SbdThread::~SbdThread()
+{
+}
+
+/**
+ * Get/Set text being processed.
+ */
+void SbdThread::setText( const QString& text ) { m_text = text; }
+QString SbdThread::text() { return m_text; }
+
+/**
+ * Set/Get TalkerCode.
+ */
+void SbdThread::setTalkerCode( TalkerCode* talkerCode ) { m_talkerCode = talkerCode; }
+TalkerCode* SbdThread::talkerCode() { return m_talkerCode; }
+
+/**
+ * Set Sentence Boundary Regular Expression.
+ * This method will only be called if the application overrode the default.
+ *
+ * @param re The sentence delimiter regular expression.
+ */
+void SbdThread::setSbRegExp( const QString& re ) { m_re = re; }
+
+/**
+ * The configured Sentence Boundary Regular Expression.
+ *
+ * @param re The sentence delimiter regular expression.
+ */
+void SbdThread::setConfiguredSbRegExp( const QString& re ) { m_configuredRe = re; }
+
+/**
+ * The configured Sentence Boundary that replaces SB regular expression.
+ *
+ * @param sb The sentence boundary replacement.
+ *
+ */
+void SbdThread::setConfiguredSentenceBoundary( const QString& sb ) { m_configuredSentenceBoundary = sb; }
+
+/**
+ * Did this filter do anything? If the filter returns the input as output
+ * unmolested, it should return False when this method is called.
+ */
+void SbdThread::setWasModified(bool wasModified) { m_wasModified = wasModified; }
+bool SbdThread::wasModified() { return m_wasModified; }
+
+// Given a tag name, returns SsmlElemType.
+SbdThread::SsmlElemType SbdThread::tagToSsmlElemType( const QString tagName )
+{
+ if ( tagName == "speak" ) return etSpeak;
+ if ( tagName == "voice" ) return etVoice;
+ if ( tagName == "prosody" ) return etProsody;
+ if ( tagName == "emphasis" ) return etEmphasis;
+ if ( tagName == "break" ) return etBreak;
+ if ( tagName == "s" ) return etPS;
+ if ( tagName == "p" ) return etPS;
+ return etNotSsml;
+}
+
+// Parses an SSML element, pushing current settings onto the context stack.
+void SbdThread::pushSsmlElem( SsmlElemType et, const QDomElement& elem )
+{
+ // TODO: Need to convert relative values into absolute values and also convert
+ // only to values recognized by SSML2SABLE stylesheet. Either that or enhance all
+ // the synth stylesheets.
+ QDomNamedNodeMap attrList = elem.attributes();
+ int attrCount = attrList.count();
+ switch ( et )
+ {
+ case etSpeak: {
+ SpeakElem e = m_speakStack.top();
+ for ( int ndx=0; ndx < attrCount; ++ndx )
+ {
+ QDomAttr a = attrList.item( ndx ).toAttr();
+ if ( a.name() == "lang" ) e.lang = a.value();
+ }
+ m_speakStack.push( e );
+ break; }
+ case etVoice: {
+ VoiceElem e = m_voiceStack.top();
+ // TODO: Since Festival chokes on <voice> tags, don't output them at all.
+ // This means we can't support voice changes, and probably more irritatingly,
+ // gender changes either.
+ m_voiceStack.push( e );
+ break; }
+ case etProsody: {
+ ProsodyElem e = m_prosodyStack.top();
+ for ( int ndx=0; ndx < attrCount; ++ndx )
+ {
+ QDomAttr a = attrList.item( ndx ).toAttr();
+ if ( a.name() == "pitch" ) e.pitch = a.value();
+ if ( a.name() == "contour" ) e.contour = a.value();
+ if ( a.name() == "range" ) e.range = a.value();
+ if ( a.name() == "rate" ) e.rate = a.value();
+ if ( a.name() == "duration" ) e.duration = a.value();
+ if ( a.name() == "volume" ) e.volume = a.value();
+ }
+ m_prosodyStack.push( e );
+ break; }
+ case etEmphasis: {
+ EmphasisElem e = m_emphasisStack.top();
+ for ( int ndx=0; ndx < attrCount; ++ndx )
+ {
+ QDomAttr a = attrList.item( ndx ).toAttr();
+ if ( a.name() == "level" ) e.level = a.value();
+ }
+ m_emphasisStack.push( e );
+ break; }
+ case etPS: {
+ PSElem e = m_psStack.top();
+ for ( int ndx=0; ndx < attrCount; ++ndx )
+ {
+ QDomAttr a = attrList.item( ndx ).toAttr();
+ if ( a.name() == "lang" ) e.lang = a.value();
+ }
+ m_psStack.push( e );
+ break; }
+ default: break;
+ }
+}
+
+// Given an attribute name and value, constructs an XML representation of the attribute,
+// i.e., name="value".
+QString SbdThread::makeAttr( const QString& name, const QString& value )
+{
+ if ( value.isEmpty() ) return QString::null;
+ return " " + name + "=\"" + value + "\"";
+}
+
+// Returns an XML representation of an SSML tag from the top of the context stack.
+QString SbdThread::makeSsmlElem( SsmlElemType et )
+{
+ QString s;
+ QString a;
+ switch ( et )
+ {
+ // Must always output speak tag, otherwise kttsd won't think each sentence is SSML.
+ // For all other tags, only output the tag if it contains at least one attribute.
+ case etSpeak: {
+ SpeakElem e = m_speakStack.top();
+ s = "<speak";
+ if ( !e.lang.isEmpty() ) s += makeAttr( "lang", e.lang );
+ s += ">";
+ break; }
+ case etVoice: {
+ VoiceElem e = m_voiceStack.top();
+ a += makeAttr( "lang", e.lang );
+ a += makeAttr( "gender", e.gender );
+ a += makeAttr( "age", QString::number(e.age) );
+ a += makeAttr( "name", e.name );
+ a += makeAttr( "variant", e.variant );
+ if ( !a.isEmpty() ) s = "<voice" + a + ">";
+ break; }
+ case etProsody: {
+ ProsodyElem e = m_prosodyStack.top();
+ a += makeAttr( "pitch", e.pitch );
+ a += makeAttr( "contour", e.contour );
+ a += makeAttr( "range", e.range );
+ a += makeAttr( "rate", e.rate );
+ a += makeAttr( "duration", e.duration );
+ a += makeAttr( "volume", e.volume );
+ if ( !a.isEmpty() ) s = "<prosody" + a + ">";
+ break; }
+ case etEmphasis: {
+ EmphasisElem e = m_emphasisStack.top();
+ a += makeAttr( "level", e.level );
+ if ( !a.isEmpty() ) s = "<emphasis" + a + ">";
+ break; }
+ case etPS: {
+ break; }
+ default: break;
+ }
+ return s;
+}
+
+// Pops element from the indicated context stack.
+void SbdThread::popSsmlElem( SsmlElemType et )
+{
+ switch ( et )
+ {
+ case etSpeak: m_speakStack.pop(); break;
+ case etVoice: m_voiceStack.pop(); break;
+ case etProsody: m_prosodyStack.pop(); break;
+ case etEmphasis: m_emphasisStack.pop(); break;
+ case etPS: m_psStack.pop(); break;
+ default: break;
+ }
+}
+
+// Returns an XML representation of a break element.
+QString SbdThread::makeBreakElem( const QDomElement& e )
+{
+ QString s = "<break";
+ QDomNamedNodeMap attrList = e.attributes();
+ int attrCount = attrList.count();
+ for ( int ndx=0; ndx < attrCount; ++ndx )
+ {
+ QDomAttr a = attrList.item( ndx ).toAttr();
+ s += makeAttr( a.name(), a.value() );
+ }
+ s += ">";
+ return s;
+}
+
+// Converts a text fragment into a CDATA section.
+QString SbdThread::makeCDATA( const QString& text )
+{
+ QString s = "<![CDATA[";
+ s += text;
+ s += "]]>";
+ return s;
+}
+
+// Returns an XML representation of an utterance node consisting of voice,
+// prosody, and emphasis elements.
+QString SbdThread::makeSentence( const QString& text )
+{
+ QString s;
+ QString v = makeSsmlElem( etVoice );
+ QString p = makeSsmlElem( etProsody );
+ QString e = makeSsmlElem( etEmphasis );
+ // TODO: Lang settings from psStack.
+ if ( !v.isEmpty() ) s += v;
+ if ( !p.isEmpty() ) s += p;
+ if ( !e.isEmpty() ) s += e;
+ // Escape ampersands and less thans.
+ QString newText = text;
+ newText.replace(QRegExp("&(?!amp;)"), "&amp;");
+ newText.replace(QRegExp("<(?!lt;)"), "&lt;");
+ s += newText;
+ if ( !e.isEmpty() ) s += "</emphasis>";
+ if ( !p.isEmpty() ) s += "</prosody>";
+ if ( !v.isEmpty() ) s += "</voice>";
+ return s;
+}
+
+// Starts a sentence by returning a speak tag.
+QString SbdThread::startSentence()
+{
+ if ( m_sentenceStarted ) return QString::null;
+ QString s;
+ s += makeSsmlElem( etSpeak );
+ m_sentenceStarted = true;
+ return s;
+}
+
+// Ends a sentence and appends a Tab.
+QString SbdThread::endSentence()
+{
+ if ( !m_sentenceStarted ) return QString::null;
+ QString s = "</speak>";
+ s += "\t";
+ m_sentenceStarted = false;
+ return s;
+}
+
+// Parses a node of the SSML tree and recursively parses its children.
+// Returns the filtered text with each sentence a complete ssml tree.
+QString SbdThread::parseSsmlNode( QDomNode& n, const QString& re )
+{
+ QString result;
+ switch ( n.nodeType() )
+ {
+ case QDomNode::ElementNode: { // = 1
+ QDomElement e = n.toElement();
+ QString tagName = e.tagName();
+ SsmlElemType et = tagToSsmlElemType( tagName );
+ switch ( et )
+ {
+ case etSpeak:
+ case etVoice:
+ case etProsody:
+ case etEmphasis:
+ case etPS:
+ {
+ pushSsmlElem( et, e );
+ QDomNode t = n.firstChild();
+ while ( !t.isNull() )
+ {
+ result += parseSsmlNode( t, re );
+ t = t.nextSibling();
+ }
+ popSsmlElem( et );
+ if ( et == etPS )
+ result += endSentence();
+ break;
+ }
+ case etBreak:
+ {
+ // Break elements are empty.
+ result += makeBreakElem( e );
+ }
+ // Ignore any elements we don't recognize.
+ default: break;
+ }
+ break; }
+ case QDomNode::AttributeNode: { // = 2
+ break; }
+ case QDomNode::TextNode: { // = 3
+ QString s = parsePlainText( n.toText().data(), re );
+ // QString d = s;
+ // d.replace("\t", "\\t");
+ // kdDebug() << "SbdThread::parseSsmlNode: parsedPlainText = [" << d << "]" << endl;
+ QStringList sentenceList = QStringList::split( '\t', s, false );
+ int lastNdx = sentenceList.count() - 1;
+ for ( int ndx=0; ndx < lastNdx; ++ndx )
+ {
+ result += startSentence();
+ result += makeSentence( sentenceList[ndx] );
+ result += endSentence();
+ }
+ // Only output sentence boundary if last text fragment ended a sentence.
+ if ( lastNdx >= 0 )
+ {
+ result += startSentence();
+ result += makeSentence( sentenceList[lastNdx] );
+ if ( s.endsWith( "\t" ) ) result += endSentence();
+ }
+ break; }
+ case QDomNode::CDATASectionNode: { // = 4
+ QString s = parsePlainText( n.toCDATASection().data(), re );
+ QStringList sentenceList = QStringList::split( '\t', s, false );
+ int lastNdx = sentenceList.count() - 1;
+ for ( int ndx=0; ndx < lastNdx; ++ndx )
+ {
+ result += startSentence();
+ result += makeSentence( makeCDATA( sentenceList[ndx] ) );
+ result += endSentence();
+ }
+ // Only output sentence boundary if last text fragment ended a sentence.
+ if ( lastNdx >= 0 )
+ {
+ result += startSentence();
+ result += makeSentence( makeCDATA( sentenceList[lastNdx] ) );
+ if ( s.endsWith( "\t" ) ) result += endSentence();
+ }
+ break; }
+ case QDomNode::EntityReferenceNode: { // = 5
+ break; }
+ case QDomNode::EntityNode: { // = 6
+ break; }
+ case QDomNode::ProcessingInstructionNode: { // = 7
+ break; }
+ case QDomNode::CommentNode: { // = 8
+ break; }
+ case QDomNode::DocumentNode: { // = 9
+ break; }
+ case QDomNode::DocumentTypeNode: { // = 10
+ break; }
+ case QDomNode::DocumentFragmentNode: { // = 11
+ break; }
+ case QDomNode::NotationNode: { // = 12
+ break; }
+ case QDomNode::BaseNode: { // = 21
+ break; }
+ case QDomNode::CharacterDataNode: { // = 22
+ break; }
+ }
+ return result;
+}
+
+// Parses Ssml.
+QString SbdThread::parseSsml( const QString& inputText, const QString& re )
+{
+ QRegExp sentenceDelimiter = QRegExp( re );
+
+ // Read the text into xml dom tree.
+ QDomDocument doc( "" );
+ // If an error occurs parsing the SSML, return "invalid S S M L".
+ if ( !doc.setContent( inputText ) ) return i18n("Invalid S S M L.");
+
+ // Set up context stacks and set defaults for all element attributes.
+ m_speakStack.clear();
+ m_voiceStack.clear();
+ m_prosodyStack.clear();
+ m_emphasisStack.clear();
+ m_psStack.clear();
+ SpeakElem se = { "" };
+ m_speakStack.push ( se );
+ VoiceElem ve = {"", "neutral", 40, "", ""};
+ m_voiceStack.push( ve );
+ ProsodyElem pe = { "medium", "", "medium", "medium", "", "medium" };
+ m_prosodyStack.push( pe );
+ EmphasisElem em = { "" };
+ m_emphasisStack.push( em );
+ PSElem pse = { "" };
+ m_psStack.push ( pse );
+
+ // This flag is used to close out a previous sentence.
+ m_sentenceStarted = false;
+
+ // Get the root element (speak) and recursively process its children.
+ QDomElement docElem = doc.documentElement();
+ QDomNode n = docElem.firstChild();
+ QString ssml = parseSsmlNode( docElem, re );
+
+ // Close out last sentence.
+ if ( m_sentenceStarted ) ssml += "</speak>";
+
+ return ssml;
+}
+
+// Parses code. Each newline is converted into a tab character (\t).
+QString SbdThread::parseCode( const QString& inputText )
+{
+ QString temp = inputText;
+ // Replace newlines with tabs.
+ temp.replace("\n","\t");
+ // Remove leading spaces.
+ temp.replace(QRegExp("\\t +"), "\t");
+ // Remove trailing spaces.
+ temp.replace(QRegExp(" +\\t"), "\t");
+ // Remove blank lines.
+ temp.replace(QRegExp("\t\t+"),"\t");
+ return temp;
+}
+
+// Parses plain text.
+QString SbdThread::parsePlainText( const QString& inputText, const QString& re )
+{
+ // kdDebug() << "SbdThread::parsePlainText: parsing " << inputText << " with re " << re << endl;
+ QRegExp sentenceDelimiter = QRegExp( re );
+ QString temp = inputText;
+ // Replace sentence delimiters with tab.
+ temp.replace(sentenceDelimiter, m_configuredSentenceBoundary);
+ // Replace remaining newlines with spaces.
+ temp.replace("\n"," ");
+ temp.replace("\r"," ");
+ // Remove leading spaces.
+ temp.replace(QRegExp("\\t +"), "\t");
+ // Remove trailing spaces.
+ temp.replace(QRegExp(" +\\t"), "\t");
+ // Remove blank lines.
+ temp.replace(QRegExp("\t\t+"),"\t");
+ return temp;
+}
+
+// This is where the real work takes place.
+/*virtual*/ void SbdThread::run()
+{
+ // kdDebug() << "SbdThread::run: processing text = " << m_text << endl;
+
+ // TODO: Determine if we should do anything or not.
+ m_wasModified = true;
+
+ // Determine what kind of input text we are dealing with.
+ int textType;
+ if ( KttsUtils::hasRootElement( m_text, "speak" ) )
+ textType = ttSsml;
+ else
+ {
+ // Examine just the first 500 chars to see if it is code.
+ QString p = m_text.left( 500 );
+ if ( p.contains( QRegExp( "(/\\*)|(if\\b\\()|(^#include\\b)" ) ) )
+ textType = ttCode;
+ else
+ textType = ttPlain;
+ }
+
+ // If application specified a sentence delimiter regular expression, use that,
+ // otherwise use configured default.
+ QString re = m_re;
+ if ( re.isEmpty() ) re = m_configuredRe;
+
+ // Replace spaces, tabs, and formfeeds with a single space.
+ m_text.replace(QRegExp("[ \\t\\f]+"), " ");
+
+ // Perform the filtering based on type of text.
+ switch ( textType )
+ {
+ case ttSsml:
+ m_text = parseSsml( m_text, re );
+ break;
+
+ case ttCode:
+ m_text = parseCode( m_text );
+ break;
+
+ case ttPlain:
+ m_text = parsePlainText( m_text, re);
+ break;
+ }
+
+ // Clear app-specified sentence delimiter. App must call setSbRegExp for each conversion.
+ m_re = QString::null;
+
+ // kdDebug() << "SbdThread::run: filtered text = " << m_text << endl;
+
+ // Result is in m_text;
+
+ // Post an event. We need to emit filterFinished signal, but not from the
+ // separate thread.
+ QCustomEvent* ev = new QCustomEvent(QEvent::User + 301);
+ QApplication::postEvent(this, ev);
+}
+
+bool SbdThread::event ( QEvent * e )
+{
+ if ( e->type() == (QEvent::User + 301) )
+ {
+ // kdDebug() << "SbdThread::event: emitting filteringFinished signal." << endl;
+ emit filteringFinished();
+ return true;
+ }
+ else return false;
+}
+
+// ----------------------------------------------------------------------------
+
+/**
+ * Constructor.
+ */
+SbdProc::SbdProc( QObject *parent, const char *name, const QStringList& /*args*/) :
+ KttsFilterProc(parent, name)
+{
+ // kdDebug() << "SbdProc::SbdProc: Running" << endl;
+ m_sbdThread = new SbdThread( parent, *name + "_thread" );
+ connect( m_sbdThread, SIGNAL(filteringFinished()), this, SLOT(slotSbdThreadFilteringFinished()) );
+}
+
+/**
+ * Destructor.
+ */
+SbdProc::~SbdProc()
+{
+ // kdDebug() << "SbdProc::~SbdProc: Running" << endl;
+ if ( m_sbdThread )
+ {
+ if ( m_sbdThread->running() )
+ {
+ m_sbdThread->terminate();
+ m_sbdThread->wait();
+ }
+ delete m_sbdThread;
+ }
+}
+
+/**
+ * Initialize the filter.
+ * @param config Settings object.
+ * @param configGroup Settings Group.
+ * @return False if filter is not ready to filter.
+ *
+ * Note: The parameters are for reading from kttsdrc file. Plugins may wish to maintain
+ * separate configuration files of their own.
+ */
+bool SbdProc::init(KConfig* config, const QString& configGroup){
+ // kdDebug() << "PlugInProc::init: Running" << endl;
+ config->setGroup( configGroup );
+// m_configuredRe = config->readEntry( "SentenceDelimiterRegExp", "([\\.\\?\\!\\:\\;])\\s|(\\n *\\n)" );
+ m_configuredRe = config->readEntry( "SentenceDelimiterRegExp", "([\\.\\?\\!\\:\\;])(\\s|$|(\\n *\\n))" );
+ m_sbdThread->setConfiguredSbRegExp( m_configuredRe );
+ QString sb = config->readEntry( "SentenceBoundary", "\\1\t" );
+ sb.replace( "\\t", "\t" );
+ m_sbdThread->setConfiguredSentenceBoundary( sb );
+ m_appIdList = config->readListEntry( "AppID" );
+ m_languageCodeList = config->readListEntry( "LanguageCodes" );
+ return true;
+}
+
+/**
+ * Returns True if this filter is a Sentence Boundary Detector.
+ * If so, the filter should implement @ref setSbRegExp() .
+ * @return True if this filter is a SBD.
+ */
+/*virtual*/ bool SbdProc::isSBD() { return true; }
+
+/**
+ * Returns True if the plugin supports asynchronous processing,
+ * i.e., supports asyncConvert method.
+ * @return True if this plugin supports asynchronous processing.
+ *
+ * If the plugin returns True, it must also implement @ref getState .
+ * It must also emit @ref filteringFinished when filtering is completed.
+ * If the plugin returns True, it must also implement @ref stopFiltering .
+ * It must also emit @ref filteringStopped when filtering has been stopped.
+ */
+/*virtual*/ bool SbdProc::supportsAsync() { return true; }
+
+/**
+ * Convert input, returning output. Runs synchronously.
+ * @param inputText Input text.
+ * @param talkerCode TalkerCode structure for the talker that KTTSD intends to
+ * use for synthing the text. Useful for extracting hints about
+ * how to filter the text. For example, languageCode.
+ * @param appId The DCOP appId of the application that queued the text.
+ * Also useful for hints about how to do the filtering.
+ */
+/*virtual*/ QString SbdProc::convert(const QString& inputText, TalkerCode* talkerCode, const QCString& appId)
+{
+ if ( asyncConvert( inputText, talkerCode, appId) )
+ {
+ waitForFinished();
+ // kdDebug() << "SbdProc::convert: returning " << getOutput() << endl;
+ return getOutput();
+ } else return inputText;
+}
+
+/**
+ * Convert input. Runs asynchronously.
+ * @param inputText Input text.
+ * @param talkerCode TalkerCode structure for the talker that KTTSD intends to
+ * use for synthing the text. Useful for extracting hints about
+ * how to filter the text. For example, languageCode.
+ * @param appId The DCOP appId of the application that queued the text.
+ * Also useful for hints about how to do the filtering.
+ * @return False if the filter cannot perform the conversion.
+ *
+ * When conversion is completed, emits signal @ref filteringFinished. Calling
+ * program may then call @ref getOutput to retrieve converted text. Calling
+ * program must call @ref ackFinished to acknowledge the conversion.
+ */
+/*virtual*/ bool SbdProc::asyncConvert(const QString& inputText, TalkerCode* talkerCode,
+ const QCString& appId)
+{
+ m_sbdThread->setWasModified( false );
+ // If language doesn't match, return input unmolested.
+ if ( !m_languageCodeList.isEmpty() )
+ {
+ QString languageCode = talkerCode->languageCode();
+ // kdDebug() << "StringReplacerProc::convert: converting " << inputText <<
+ // " if language code " << languageCode << " matches " << m_languageCodeList << endl;
+ if ( !m_languageCodeList.contains( languageCode ) )
+ {
+ if ( !talkerCode->countryCode().isEmpty() )
+ {
+ languageCode += '_' + talkerCode->countryCode();
+ // kdDebug() << "StringReplacerProc::convert: converting " << inputText <<
+ // " if language code " << languageCode << " matches " << m_languageCodeList << endl;
+ if ( !m_languageCodeList.contains( languageCode ) ) return false;
+ } else return false;
+ }
+ }
+ // If appId doesn't match, return input unmolested.
+ if ( !m_appIdList.isEmpty() )
+ {
+ // kdDebug() << "SbdProc::convert: converting " << inputText << " if appId "
+ // << appId << " matches " << m_appIdList << endl;
+ bool found = false;
+ QString appIdStr = appId;
+ for ( uint ndx=0; ndx < m_appIdList.count(); ++ndx )
+ {
+ if ( appIdStr.contains(m_appIdList[ndx]) )
+ {
+ found = true;
+ break;
+ }
+ }
+ if ( !found ) return false;
+ }
+ m_sbdThread->setText( inputText );
+ m_sbdThread->setTalkerCode( talkerCode );
+ m_state = fsFiltering;
+ m_sbdThread->start();
+ return true;
+}
+
+/**
+ * Waits for a previous call to asyncConvert to finish.
+ */
+/*virtual*/ void SbdProc::waitForFinished()
+{
+ if ( m_sbdThread->running() )
+ {
+ // kdDebug() << "SbdProc::waitForFinished: waiting" << endl;
+ m_sbdThread->wait();
+ // kdDebug() << "SbdProc::waitForFinished: finished waiting" << endl;
+ m_state = fsFinished;
+ }
+}
+
+/**
+ * Returns the state of the Filter.
+ */
+/*virtual*/ int SbdProc::getState() { return m_state; }
+
+/**
+ * Returns the filtered output.
+ */
+/*virtual*/ QString SbdProc::getOutput() { return m_sbdThread->text(); }
+
+/**
+ * Acknowledges the finished filtering.
+ */
+/*virtual*/ void SbdProc::ackFinished()
+{
+ m_state = fsIdle;
+ m_sbdThread->setText( QString::null );
+}
+
+/**
+ * Stops filtering. The filteringStopped signal will emit when filtering
+ * has in fact stopped and state returns to fsIdle;
+ */
+/*virtual*/ void SbdProc::stopFiltering()
+{
+ if ( m_sbdThread->running() )
+ {
+ m_sbdThread->terminate();
+ m_sbdThread->wait();
+ delete m_sbdThread;
+ m_sbdThread = new SbdThread();
+ m_sbdThread->setConfiguredSbRegExp( m_configuredRe );
+ connect( m_sbdThread, SIGNAL(filteringFinished()), this, SLOT(slotSbdThreadFilteringFinished()) );
+ m_state = fsIdle;
+ emit filteringStopped();
+ }
+}
+
+/**
+ * Did this filter do anything? If the filter returns the input as output
+ * unmolested, it should return False when this method is called.
+ */
+/*virtual*/ bool SbdProc::wasModified() { return m_sbdThread->wasModified(); }
+
+/**
+ * Set Sentence Boundary Regular Expression.
+ * This method will only be called if the application overrode the default.
+ *
+ * @param re The sentence delimiter regular expression.
+ */
+/*virtual*/ void SbdProc::setSbRegExp(const QString& re) { m_sbdThread->setSbRegExp( re ); }
+
+// Received when SBD Thread finishes.
+void SbdProc::slotSbdThreadFilteringFinished()
+{
+ m_state = fsFinished;
+ // kdDebug() << "SbdProc::slotSbdThreadFilteringFinished: emitting filterFinished signal." << endl;
+ emit filteringFinished();
+}
+
+#include "sbdproc.moc"
diff --git a/kttsd/filters/sbd/sbdproc.h b/kttsd/filters/sbd/sbdproc.h
new file mode 100644
index 0000000..6c181d5
--- /dev/null
+++ b/kttsd/filters/sbd/sbdproc.h
@@ -0,0 +1,366 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Sentence Boundary Detection (SBD) Filter class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+/******************************************************************************
+
+ This class performs three kinds of SBD:
+ 1. If the text is SSML, generates new SSML where the prosody and voice
+ tags are fully specified for each sentence. This allows user to
+ advance or rewind by sentence without losing SSML context.
+ Input is considered to be SSML if the top-level element is a
+ <speak> tag.
+ 2. If the text is code, each line is considered to be a sentence.
+ Input is considered to be code if any of the following strings are
+ detected:
+ slash asterisk
+ if left-paren
+ pound include
+ 3. If the text is plain text, performs SBD using specified Regular
+ Expression.
+
+ Text is output with tab characters (\t) separating sentences.
+
+ ******************************************************************************/
+
+#ifndef _SBDPROC_H_
+#define _SBDPROC_H_
+
+// Qt includes.
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qthread.h>
+#include <qvaluestack.h>
+#include <qevent.h>
+
+// KTTS includes.
+#include "filterproc.h"
+
+class TalkerCode;
+class KConfig;
+class QDomElement;
+class QDomNode;
+
+class SbdThread: public QObject, public QThread
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor.
+ */
+ SbdThread( QObject *parent = 0, const char *name = 0);
+
+ /**
+ * Destructor.
+ */
+ virtual ~SbdThread();
+
+ /**
+ * Get/Set text being processed.
+ */
+ void setText( const QString& text );
+ QString text();
+
+ /**
+ * Set/Get TalkerCode.
+ */
+ void setTalkerCode( TalkerCode* talkerCode );
+ TalkerCode* talkerCode();
+
+ /**
+ * Set Sentence Boundary Regular Expression.
+ * This method will only be called if the application overrode the default.
+ *
+ * @param re The sentence delimiter regular expression.
+ */
+ void setSbRegExp( const QString& re );
+
+ /**
+ * The configured Sentence Boundary Regular Expression.
+ *
+ * @param re The sentence delimiter regular expression.
+ */
+ void setConfiguredSbRegExp( const QString& re );
+
+ /**
+ * The configured Sentence Boundary that replaces SB regular expression.
+ *
+ * @param sb The sentence boundary replacement.
+ *
+ */
+ void setConfiguredSentenceBoundary( const QString& sb );
+
+ /**
+ * Did this filter do anything? If the filter returns the input as output
+ * unmolested, it should return False when this method is called.
+ */
+ void setWasModified(bool wasModified);
+ bool wasModified();
+
+ signals:
+ void filteringFinished();
+
+ protected:
+ virtual void run();
+ virtual bool event ( QEvent * e );
+
+ private:
+ enum TextType {
+ ttSsml, // SSML
+ ttCode, // Code
+ ttPlain // Plain text
+ };
+
+ enum SsmlElemType {
+ etSpeak,
+ etVoice,
+ etProsody,
+ etEmphasis,
+ etPS, // Paragraph or sentence (we don't care).
+ etBreak,
+ etNotSsml
+ };
+
+ // Speak Element.
+ struct SpeakElem {
+ QString lang; // xml:lang="en".
+ };
+
+ // Voice Element.
+ struct VoiceElem {
+ QString lang; // xml:lang="en".
+ QString gender; // "male", "female", or "neutral".
+ uint age; // Age in years.
+ QString name; // Synth-specific voice name.
+ QString variant; // Ignored.
+ };
+
+ // Prosody Element.
+ struct ProsodyElem {
+ QString pitch; // "x-low", "low", "medium", "high", "x-high", "default".
+ QString contour; // Pitch contour (ignored).
+ QString range; // "x-low", "low", "medium", "high", "x-high", "default".
+ QString rate; // "x-slow", "slow", "medium", "fast", "x-fast", "default".
+ QString duration; // Ignored.
+ QString volume; // "silent", "x-soft", "soft", "medium", "load", "x-load", "default".
+ };
+
+ // Emphasis Element.
+ struct EmphasisElem {
+ QString level; // "strong", "moderate", "none" and "reduced"
+ };
+
+ // Break Element.
+ struct BreakElem {
+ QString strength; // "x-weak", "weak", "medium" (default value), "strong",
+ // or "x-strong", "none"
+ QString time; // Ignored.
+ };
+
+ // Paragraph and Sentence Elements.
+ struct PSElem {
+ QString lang; // xml:lang="en".
+ };
+
+ // Given a tag name, returns SsmlElemType.
+ SsmlElemType tagToSsmlElemType(const QString tagName);
+ // Parses an SSML element, pushing current settings onto the context stack.
+ void pushSsmlElem( SsmlElemType et, const QDomElement& elem );
+ // Given an attribute name and value, constructs an XML representation of the attribute,
+ // i.e., name="value".
+ QString makeAttr( const QString& name, const QString& value );
+ // Returns an XML representation of an SSML tag from the top of the context stack.
+ QString makeSsmlElem( SsmlElemType et );
+ // Pops element from the indicated context stack.
+ void popSsmlElem( SsmlElemType et );
+ QString makeBreakElem( const QDomElement& e );
+ // Converts a text fragment into a CDATA section.
+ QString makeCDATA( const QString& text );
+ // Returns an XML representation of an utterance node consisting of voice,
+ // prosody, and emphasis elements.
+ QString makeSentence( const QString& text );
+ // Starts a sentence by returning a speak tag.
+ QString startSentence();
+ // Ends a sentence and appends a Tab.
+ QString endSentence();
+ // Parses a node of the SSML tree and recursively parses its children.
+ // Returns the filtered text with each sentence a complete ssml tree.
+ QString parseSsmlNode( QDomNode& n, const QString& re );
+
+ // Parses Ssml.
+ QString parseSsml( const QString& inputText, const QString& re );
+ // Parses code. Each newline is converted into a tab character (\t).
+ QString parseCode( const QString& inputText );
+ // Parses plain text.
+ QString parsePlainText( const QString& inputText, const QString& re );
+
+ // Context stacks.
+ QValueStack<SpeakElem> m_speakStack;
+ QValueStack<VoiceElem> m_voiceStack;
+ QValueStack<ProsodyElem> m_prosodyStack;
+ QValueStack<EmphasisElem> m_emphasisStack;
+ QValueStack<PSElem> m_psStack;
+
+ // The text being processed.
+ QString m_text;
+ // Talker Code.
+ TalkerCode* m_talkerCode;
+ // Configured default Sentence Delimiter regular expression.
+ QString m_configuredRe;
+ // Configured Sentence Boundary replacement expression.
+ QString m_configuredSentenceBoundary;
+ // Application-specified Sentence Delimiter regular expression (if any).
+ QString m_re;
+ // False if input was not modified.
+ bool m_wasModified;
+ // True when a sentence has been started.
+ bool m_sentenceStarted;
+};
+
+class SbdProc : virtual public KttsFilterProc
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor.
+ */
+ SbdProc( QObject *parent, const char *name, const QStringList &args = QStringList() );
+
+ /**
+ * Destructor.
+ */
+ virtual ~SbdProc();
+
+ /**
+ * Initialize the filter.
+ * @param config Settings object.
+ * @param configGroup Settings Group.
+ * @return False if filter is not ready to filter.
+ *
+ * Note: The parameters are for reading from kttsdrc file. Plugins may wish to maintain
+ * separate configuration files of their own.
+ */
+ virtual bool init( KConfig *config, const QString &configGroup );
+
+ /**
+ * Returns True if this filter is a Sentence Boundary Detector.
+ * If so, the filter should implement @ref setSbRegExp() .
+ * @return True if this filter is a SBD.
+ */
+ virtual bool isSBD();
+
+ /**
+ * Returns True if the plugin supports asynchronous processing,
+ * i.e., supports asyncConvert method.
+ * @return True if this plugin supports asynchronous processing.
+ *
+ * If the plugin returns True, it must also implement @ref getState .
+ * It must also emit @ref filteringFinished when filtering is completed.
+ * If the plugin returns True, it must also implement @ref stopFiltering .
+ * It must also emit @ref filteringStopped when filtering has been stopped.
+ */
+ virtual bool supportsAsync();
+
+ /**
+ * Convert input, returning output. Runs synchronously.
+ * @param inputText Input text.
+ * @param talkerCode TalkerCode structure for the talker that KTTSD intends to
+ * use for synthing the text. Useful for extracting hints about
+ * how to filter the text. For example, languageCode.
+ * @param appId The DCOP appId of the application that queued the text.
+ * Also useful for hints about how to do the filtering.
+ */
+ virtual QString convert( const QString& inputText, TalkerCode* talkerCode, const QCString& appId );
+
+ /**
+ * Convert input. Runs asynchronously.
+ * @param inputText Input text.
+ * @param talkerCode TalkerCode structure for the talker that KTTSD intends to
+ * use for synthing the text. Useful for extracting hints about
+ * how to filter the text. For example, languageCode.
+ * @param appId The DCOP appId of the application that queued the text.
+ * Also useful for hints about how to do the filtering.
+ * @return False if the filter cannot perform the conversion.
+ *
+ * When conversion is completed, emits signal @ref filteringFinished. Calling
+ * program may then call @ref getOutput to retrieve converted text. Calling
+ * program must call @ref ackFinished to acknowledge the conversion.
+ */
+ virtual bool asyncConvert( const QString& inputText, TalkerCode* talkerCode, const QCString& appId );
+
+ /**
+ * Waits for a previous call to asyncConvert to finish.
+ */
+ virtual void waitForFinished();
+
+ /**
+ * Returns the state of the Filter.
+ */
+ virtual int getState();
+
+ /**
+ * Returns the filtered output.
+ */
+ virtual QString getOutput();
+
+ /**
+ * Acknowledges the finished filtering.
+ */
+ virtual void ackFinished();
+
+ /**
+ * Stops filtering. The filteringStopped signal will emit when filtering
+ * has in fact stopped and state returns to fsIdle;
+ */
+ virtual void stopFiltering();
+
+ /**
+ * Did this filter do anything? If the filter returns the input as output
+ * unmolested, it should return False when this method is called.
+ */
+ virtual bool wasModified();
+
+ /**
+ * Set Sentence Boundary Regular Expression.
+ */
+ virtual void setSbRegExp( const QString& re );
+
+ private slots:
+ // Received when SBD Thread finishes.
+ void slotSbdThreadFilteringFinished();
+
+ private:
+ // If not empty, apply filters only to apps using talkers speaking these language codes.
+ QStringList m_languageCodeList;
+ // If not empty, apply filter only to apps containing this string.
+ QStringList m_appIdList;
+ // SBD Thread Object.
+ SbdThread* m_sbdThread;
+ // State.
+ int m_state;
+ // Configured default Sentence Delimiter regular expression.
+ QString m_configuredRe;
+};
+
+#endif // _SBDPROC_H_
diff --git a/kttsd/filters/sbd/standard_sbdrc b/kttsd/filters/sbd/standard_sbdrc
new file mode 100644
index 0000000..76037a5
--- /dev/null
+++ b/kttsd/filters/sbd/standard_sbdrc
@@ -0,0 +1,6 @@
+[Filter]
+AppID=
+LanguageCodes=
+SentenceBoundary=\\1\\t
+SentenceDelimiterRegExp=([\\.\\?\\!\\:\\;])(\\s|$|(\\n *\\n))
+UserFilterName=Standard Sentence Boundary Detector
diff --git a/kttsd/filters/stringreplacer/Makefile.am b/kttsd/filters/stringreplacer/Makefile.am
new file mode 100644
index 0000000..b52085c
--- /dev/null
+++ b/kttsd/filters/stringreplacer/Makefile.am
@@ -0,0 +1,34 @@
+INCLUDES = \
+ -I$(top_srcdir)/kttsd/libkttsd -I$(top_builddir)/kttsd/libkttsd \
+ $(all_includes)
+
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = libkttsd_stringreplacerplugin.la
+
+libkttsd_stringreplacerplugin_la_SOURCES = \
+ stringreplacerconfwidget.ui \
+ editreplacementwidget.ui \
+ stringreplacerconf.cpp \
+ stringreplacerproc.cpp \
+ stringreplacerplugin.cpp
+libkttsd_stringreplacerplugin_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries)
+libkttsd_stringreplacerplugin_la_LIBADD = $(top_builddir)/kttsd/libkttsd/libkttsd.la
+
+services_DATA = kttsd_stringreplacerplugin.desktop
+servicesdir = $(kde_servicesdir)
+
+# Install data files.
+stringreplacerdatadir = $(kde_datadir)/kttsd/stringreplacer/
+stringreplacerdata_DATA = \
+ abbreviations.xml \
+ chat.xml \
+ chat-de.xml \
+ emoticons.xml \
+ polish_festival_fixes.xml \
+ polish_festival_unspeakables.xml \
+ kmail.xml \
+ festival_unspeakable_chars.xml \
+ qt2plaintext.xml
+
+noinst_HEADERS = stringreplacerconfwidget.h editreplacementwidget.h
diff --git a/kttsd/filters/stringreplacer/abbreviations.xml b/kttsd/filters/stringreplacer/abbreviations.xml
new file mode 100644
index 0000000..d04b7aa
--- /dev/null
+++ b/kttsd/filters/stringreplacer/abbreviations.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wordlist>
+ <name>Abbreviations</name>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[TODO]]></match>
+ <subst><![CDATA[To Do]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[CPU]]></match>
+ <subst><![CDATA[C P U]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[DCOP]]></match>
+ <subst><![CDATA[D Cop]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[IP]]></match>
+ <subst><![CDATA[I P]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[KDE]]></match>
+ <subst><![CDATA[K D E]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[KTTS]]></match>
+ <subst><![CDATA[K T T S]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[kttsd]]></match>
+ <subst><![CDATA[K T T S D]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[KTTSD]]></match>
+ <subst><![CDATA[K T T S D]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[TTS]]></match>
+ <subst><![CDATA[T T S]]></subst>
+ </word>
+</wordlist>
diff --git a/kttsd/filters/stringreplacer/chat-de.xml b/kttsd/filters/stringreplacer/chat-de.xml
new file mode 100644
index 0000000..801c144
--- /dev/null
+++ b/kttsd/filters/stringreplacer/chat-de.xml
@@ -0,0 +1,616 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wordlist>
+ <name>Internet Relay Chat and IM (Deutsch)</name>
+ <language-code>de</language-code>
+ <appid>knotify</appid>
+ <appid>kopete</appid>
+ <appid>kvirc</appid>
+ <appid>ksirc</appid>
+ <appid>konversation</appid>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<qt>]]></match>
+ <subst><![CDATA[ ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[&lt([^>]+)&gt]]></match>
+ <subst><![CDATA[ \1 meint ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<br>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</qt>]]></match>
+ <subst><![CDATA[ ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\;\)]]></match>
+ <subst><![CDATA[ winkt]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\<]]></match>
+ <subst><![CDATA[ traurig]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\/]]></match>
+ <subst><![CDATA[stirnrunzeln]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\>]]></match>
+ <subst><![CDATA[ grinst]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\|]]></match>
+ <subst><![CDATA[ernsthaft]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\-\|]]></match>
+ <subst><![CDATA[ernsthaft]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\-\)]]></match>
+ <subst><![CDATA[ laechelt]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\'\(]]></match>
+ <subst><![CDATA[weint]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\(]]></match>
+ <subst><![CDATA[ traurig]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\)]]></match>
+ <subst><![CDATA[ laechelt]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\@]]></match>
+ <subst><![CDATA[ boese]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\$]]></match>
+ <subst><![CDATA[ schaemt sich]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\@\)]]></match>
+ <subst><![CDATA[ katzengesicht]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(6\)]]></match>
+ <subst><![CDATA[ teufelsfratze]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(a\)]]></match>
+ <subst><![CDATA[ engelsgesicht]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:D]]></match>
+ <subst><![CDATA[ grins]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(h\)]]></match>
+ <subst><![CDATA[ kuhl]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\so\_O]]></match>
+ <subst><![CDATA[ winkt]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:p]]></match>
+ <subst><![CDATA[ baeh]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(s\)]]></match>
+ <subst><![CDATA[ gaehn]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ad]]></match>
+ <subst><![CDATA[fuege hinzu]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[afaik]]></match>
+ <subst><![CDATA[soviel ich weiss]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[afk]]></match>
+ <subst><![CDATA[nicht an tastatur]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[asap]]></match>
+ <subst><![CDATA[so schnell wie moeglich]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[atm]]></match>
+ <subst><![CDATA[momentan]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ayt]]></match>
+ <subst><![CDATA[bist du da]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[b4]]></match>
+ <subst><![CDATA[vorher]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[b4n]]></match>
+ <subst><![CDATA[tschuess]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[bak]]></match>
+ <subst><![CDATA[zurueck]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[bbl]]></match>
+ <subst><![CDATA[komme spaeter wieder]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[bf]]></match>
+ <subst><![CDATA[freund]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[b/f]]></match>
+ <subst><![CDATA[freund]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[brb]]></match>
+ <subst><![CDATA[bin gleich wieder da]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[btw]]></match>
+ <subst><![CDATA[nebenbei bemerkt]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[cu]]></match>
+ <subst><![CDATA[bis dann]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[cul]]></match>
+ <subst><![CDATA[bis spaeter]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[cul8r]]></match>
+ <subst><![CDATA[bis spaeter]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[cya]]></match>
+ <subst><![CDATA[bis spaeter]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[d/l]]></match>
+ <subst><![CDATA[daunlohd]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[dvd]]></match>
+ <subst><![CDATA[die wie die]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[f2f]]></match>
+ <subst><![CDATA[von angesicht zu angesicht]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[fubar]]></match>
+ <subst><![CDATA[leuft trotz reparatur nicht]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[fyi]]></match>
+ <subst><![CDATA[zu deiner information]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[gf]]></match>
+ <subst><![CDATA[freundin]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[g/f]]></match>
+ <subst><![CDATA[freundin]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[gtg]]></match>
+ <subst><![CDATA[ich muss weck]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[hmm]]></match>
+ <subst><![CDATA[aehm]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[hth]]></match>
+ <subst><![CDATA[hoffe es hilft]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ic]]></match>
+ <subst><![CDATA[verstehe]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[iirc]]></match>
+ <subst><![CDATA[wenn ich recht erinnere]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imao]]></match>
+ <subst><![CDATA[meiner arroganten meinung nach]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imco]]></match>
+ <subst><![CDATA[meiner wohlueberlegten meinung nach]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ime]]></match>
+ <subst><![CDATA[meiner erfahrung nach]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imho]]></match>
+ <subst><![CDATA[meiner bescheidenen meinung nach]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imnsho]]></match>
+ <subst><![CDATA[meiner unbescheidenen meinung nach]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imo]]></match>
+ <subst><![CDATA[meiner meinung nach]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ip]]></match>
+ <subst><![CDATA[ei pie]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[isdn]]></match>
+ <subst><![CDATA[i es de en]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[k]]></match>
+ <subst><![CDATA[ho key]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[kde]]></match>
+ <subst><![CDATA[ka de eh]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[kbd]]></match>
+ <subst><![CDATA[tastatur]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[lshmba]]></match>
+ <subst><![CDATA[halte mir den bauch vor lachen]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[lthtt]]></match>
+ <subst><![CDATA[unbeschreibliches gelaechter]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ltns]]></match>
+ <subst><![CDATA[lange nicht gesehen]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[lol]]></match>
+ <subst><![CDATA[h h h]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[m8]]></match>
+ <subst><![CDATA[kumpel]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[msg]]></match>
+ <subst><![CDATA[nachricht]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[np]]></match>
+ <subst><![CDATA[kein problem]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[oic]]></match>
+ <subst><![CDATA[oh verstehe]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ok]]></match>
+ <subst><![CDATA[ho key]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ott]]></match>
+ <subst><![CDATA[übertreiben]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[pc]]></match>
+ <subst><![CDATA[pie cie]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ppc]]></match>
+ <subst><![CDATA[power pie cie]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ppl]]></match>
+ <subst><![CDATA[leute]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[rotfl]]></match>
+ <subst><![CDATA[kugelt sich vor lachen]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[rotflol]]></match>
+ <subst><![CDATA[bruellt vor lachen]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[rsvp]]></match>
+ <subst><![CDATA[antworte bitte]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[scsi]]></match>
+ <subst><![CDATA[skasi]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[suse]]></match>
+ <subst><![CDATA[suse]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[sec]]></match>
+ <subst><![CDATA[sekunde]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[secs]]></match>
+ <subst><![CDATA[sekunden]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[thx]]></match>
+ <subst><![CDATA[danke]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[tnx]]></match>
+ <subst><![CDATA[danke]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wo]]></match>
+ <subst><![CDATA[ohne]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wb]]></match>
+ <subst><![CDATA[willkommen urueck]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wtf]]></match>
+ <subst><![CDATA[was zum teufel]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wth]]></match>
+ <subst><![CDATA[was zum teufel]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wtg]]></match>
+ <subst><![CDATA[gut gemacht]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wtgp]]></match>
+ <subst><![CDATA[bitte um privatchett]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wth]]></match>
+ <subst><![CDATA[was zum teufel]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wygiswypf]]></match>
+ <subst><![CDATA[was du kriegst ist was du bezahlst]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[yw]]></match>
+ <subst><![CDATA[gruess diche]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\_]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\|]]></match>
+ <subst><![CDATA[ ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\\o\/]]></match>
+ <subst><![CDATA[tschuess]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\/o\\]]></match>
+ <subst><![CDATA[haelt sich die ohren zu]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\:\-\/]]></match>
+ <subst><![CDATA[stirnrunzeln]]></subst>
+ </word>
+</wordlist>
diff --git a/kttsd/filters/stringreplacer/chat.xml b/kttsd/filters/stringreplacer/chat.xml
new file mode 100644
index 0000000..2518824
--- /dev/null
+++ b/kttsd/filters/stringreplacer/chat.xml
@@ -0,0 +1,616 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wordlist>
+ <name>Internet Relay Chat and IM</name>
+ <language-code>en</language-code>
+ <appid>knotify</appid>
+ <appid>kopete</appid>
+ <appid>kvirc</appid>
+ <appid>ksirc</appid>
+ <appid>konversation</appid>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<qt>]]></match>
+ <subst><![CDATA[ ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[&lt([^>]+)&gt]]></match>
+ <subst><![CDATA[ \1 says ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<br>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</qt>]]></match>
+ <subst><![CDATA[ ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\;\)]]></match>
+ <subst><![CDATA[ winks]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\<]]></match>
+ <subst><![CDATA[ sad face]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\/]]></match>
+ <subst><![CDATA[ frowns ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\>]]></match>
+ <subst><![CDATA[ grins]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\|]]></match>
+ <subst><![CDATA[ straight faced]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\-\|]]></match>
+ <subst><![CDATA[ straight faced]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\-\)]]></match>
+ <subst><![CDATA[ smiles]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\'\(]]></match>
+ <subst><![CDATA[ cries]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\(]]></match>
+ <subst><![CDATA[ sad face]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\)]]></match>
+ <subst><![CDATA[ smiles]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\@]]></match>
+ <subst><![CDATA[ angry look]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\$]]></match>
+ <subst><![CDATA[ blushes]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\@\)]]></match>
+ <subst><![CDATA[ cat face]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(6\)]]></match>
+ <subst><![CDATA[ devil]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(a\)]]></match>
+ <subst><![CDATA[ angel]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:D]]></match>
+ <subst><![CDATA[ grins]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(h\)]]></match>
+ <subst><![CDATA[ cool shades]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\so\_O]]></match>
+ <subst><![CDATA[ winks]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:p]]></match>
+ <subst><![CDATA[ sticks out tung]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(s\)]]></match>
+ <subst><![CDATA[ sleepy]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ad]]></match>
+ <subst><![CDATA[add]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[afaik]]></match>
+ <subst><![CDATA[as far as I know]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[afk]]></match>
+ <subst><![CDATA[away from keyboard]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[asap]]></match>
+ <subst><![CDATA[as soon as possable]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[atm]]></match>
+ <subst><![CDATA[at the moment]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ayt]]></match>
+ <subst><![CDATA[are you there]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[b4]]></match>
+ <subst><![CDATA[before]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[b4n]]></match>
+ <subst><![CDATA[bye for now]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[bak]]></match>
+ <subst><![CDATA[back]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[bbl]]></match>
+ <subst><![CDATA[be back later]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[bf]]></match>
+ <subst><![CDATA[boy friend]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[b/f]]></match>
+ <subst><![CDATA[boy friend]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[brb]]></match>
+ <subst><![CDATA[be right back]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[btw]]></match>
+ <subst><![CDATA[by the way]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[cu]]></match>
+ <subst><![CDATA[see you]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[cul]]></match>
+ <subst><![CDATA[see you later]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[cul8r]]></match>
+ <subst><![CDATA[see you later]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[cya]]></match>
+ <subst><![CDATA[see you later]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[d/l]]></match>
+ <subst><![CDATA[down load]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[dvd]]></match>
+ <subst><![CDATA[de vee de]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[f2f]]></match>
+ <subst><![CDATA[face to face]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[fubar]]></match>
+ <subst><![CDATA[fecked up beyond all repair]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[fyi]]></match>
+ <subst><![CDATA[for your information]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[gf]]></match>
+ <subst><![CDATA[girl friend]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[g/f]]></match>
+ <subst><![CDATA[girl friend]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[gtg]]></match>
+ <subst><![CDATA[got to go]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[hmm]]></match>
+ <subst><![CDATA[hurrmmm]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[hth]]></match>
+ <subst><![CDATA[hope that helps]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ic]]></match>
+ <subst><![CDATA[i see]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[iirc]]></match>
+ <subst><![CDATA[if I recall correctly]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imao]]></match>
+ <subst><![CDATA[in my arrogant opinion]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imco]]></match>
+ <subst><![CDATA[in my considered opinion]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ime]]></match>
+ <subst><![CDATA[in my experience]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imho]]></match>
+ <subst><![CDATA[in my humble opinion]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imnsho]]></match>
+ <subst><![CDATA[in my not so humble opinion]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[imo]]></match>
+ <subst><![CDATA[in my opinion]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ip]]></match>
+ <subst><![CDATA[i p]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[isdn]]></match>
+ <subst><![CDATA[i s d n]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[k]]></match>
+ <subst><![CDATA[ho kay]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[kde]]></match>
+ <subst><![CDATA[k d e]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[kbd]]></match>
+ <subst><![CDATA[keyboard]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[lshmba]]></match>
+ <subst><![CDATA[laughing so hard my belly aches]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[lthtt]]></match>
+ <subst><![CDATA[laughing too hard to type]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ltns]]></match>
+ <subst><![CDATA[long time no see]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[lol]]></match>
+ <subst><![CDATA[lafes out loud]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[m8]]></match>
+ <subst><![CDATA[mate]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[msg]]></match>
+ <subst><![CDATA[message]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[np]]></match>
+ <subst><![CDATA[no problem]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[oic]]></match>
+ <subst><![CDATA[oh i see]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ok]]></match>
+ <subst><![CDATA[ho kay]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ott]]></match>
+ <subst><![CDATA[over the top]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[pc]]></match>
+ <subst><![CDATA[p c]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ppc]]></match>
+ <subst><![CDATA[power p c]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[ppl]]></match>
+ <subst><![CDATA[people]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[rotfl]]></match>
+ <subst><![CDATA[rolling on the floor laughing]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[rotflol]]></match>
+ <subst><![CDATA[rolling on the floor laughing out loud]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[rsvp]]></match>
+ <subst><![CDATA[please reply]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[scsi]]></match>
+ <subst><![CDATA[scuzy]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[suse]]></match>
+ <subst><![CDATA[sue see]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[sec]]></match>
+ <subst><![CDATA[second]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[secs]]></match>
+ <subst><![CDATA[seconds]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[thx]]></match>
+ <subst><![CDATA[thanks]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[tnx]]></match>
+ <subst><![CDATA[thanks]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wo]]></match>
+ <subst><![CDATA[without]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wb]]></match>
+ <subst><![CDATA[welcome back]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wtf]]></match>
+ <subst><![CDATA[what the heck]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wth]]></match>
+ <subst><![CDATA[what the heck]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wtg]]></match>
+ <subst><![CDATA[way to go]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wtgp]]></match>
+ <subst><![CDATA[want to go private]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wth]]></match>
+ <subst><![CDATA[what the heck]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[wygiswypf]]></match>
+ <subst><![CDATA[what you get is what you pay for]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[yw]]></match>
+ <subst><![CDATA[your welcome]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\_]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\|]]></match>
+ <subst><![CDATA[ ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\\o\/]]></match>
+ <subst><![CDATA[ cheers ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\/o\\]]></match>
+ <subst><![CDATA[ covers ears ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\:\-\/]]></match>
+ <subst><![CDATA[ frowns ]]></subst>
+ </word>
+</wordlist>
diff --git a/kttsd/filters/stringreplacer/editreplacementwidget.ui b/kttsd/filters/stringreplacer/editreplacementwidget.ui
new file mode 100644
index 0000000..917cdf8
--- /dev/null
+++ b/kttsd/filters/stringreplacer/editreplacementwidget.ui
@@ -0,0 +1,263 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>EditReplacementWidget</class>
+<author>Gary Cramblitt &lt;garycramblitt@comcast.net&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>EditReplacementWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>393</width>
+ <height>148</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>255</horstretch>
+ <verstretch>255</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>typeButtonGroup</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>&amp;Type</string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>wordRadioButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Word</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>regexpRadioButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Regular &amp;expression</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>caseCheckBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Match &amp;case</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>substLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Replace with:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>matchLineEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>matchLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Match:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>matchLineEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>substLineEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="0" column="1">
+ <property name="name">
+ <cstring>matchButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="0">
+ <property name="name">
+ <cstring>matchLineEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>wordRadioButton</tabstop>
+ <tabstop>regexpRadioButton</tabstop>
+ <tabstop>caseCheckBox</tabstop>
+ <tabstop>matchLineEdit</tabstop>
+ <tabstop>matchButton</tabstop>
+ <tabstop>substLineEdit</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/kttsd/filters/stringreplacer/emoticons.xml b/kttsd/filters/stringreplacer/emoticons.xml
new file mode 100644
index 0000000..f522358
--- /dev/null
+++ b/kttsd/filters/stringreplacer/emoticons.xml
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wordlist>
+ <name>Emoticons (English)</name>
+ <language-code>en</language-code>
+ <appid>knotify</appid>
+ <appid>kopete</appid>
+ <appid>ksirc</appid>
+ <appid>kvirc</appid>
+ <appid>konversation</appid>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\)]]></match>
+ <subst><![CDATA[. smiles]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\-\)]]></match>
+ <subst><![CDATA[. smiles]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\p]]></match>
+ <subst><![CDATA[. sticks out tung]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:D]]></match>
+ <subst><![CDATA[. grins]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\>]]></match>
+ <subst><![CDATA[.grins]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\;\)]]></match>
+ <subst><![CDATA[. winks]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\o\_\0]]></match>
+ <subst><![CDATA[. winks]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\(]]></match>
+ <subst><![CDATA[. sad face]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\<]]></match>
+ <subst><![CDATA[. sad face]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\\:\|]]></match>
+ <subst><![CDATA[. straight faced]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\-\|]]></match>
+ <subst><![CDATA[. straight faced]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\$]]></match>
+ <subst><![CDATA[. blushes]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\\(h\)]]></match>
+ <subst><![CDATA[. cool shades]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\@]]></match>
+ <subst><![CDATA[. angry look]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\'\(]]></match>
+ <subst><![CDATA[. cries]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(a\)]]></match>
+ <subst><![CDATA[. angel]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(6\)]]></match>
+ <subst><![CDATA[. devil]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\%\)]]></match>
+ <subst><![CDATA[. hand cuffs]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\:\[\]]></match>
+ <subst><![CDATA[. bat]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\@\)]]></match>
+ <subst><![CDATA[. cat face]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\&\)]]></match>
+ <subst><![CDATA[. dog face]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\*\)]]></match>
+ <subst><![CDATA[. star]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(s\)]]></match>
+ <subst><![CDATA[. sleepy]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(Y\)]]></match>
+ <subst><![CDATA[. thumbs up]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(n\)]]></match>
+ <subst><![CDATA[. thumbs down]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\}\)]]></match>
+ <subst><![CDATA[. girl huggs]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\{\)]]></match>
+ <subst><![CDATA[. boy huggs]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(l\)]]></match>
+ <subst><![CDATA[. love]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(U\)]]></match>
+ <subst><![CDATA[. is hart brooken]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(k\)]]></match>
+ <subst><![CDATA[. kisses]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\^\)]]></match>
+ <subst><![CDATA[. birthday cake]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(g\)]]></match>
+ <subst><![CDATA[. a gift]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(f\)]]></match>
+ <subst><![CDATA[. flower]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(w\)]]></match>
+ <subst><![CDATA[. willted flower]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(t\)]]></match>
+ <subst><![CDATA[. telephone]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(e\)]]></match>
+ <subst><![CDATA[. e mail]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(m\)]]></match>
+ <subst><![CDATA[. messenger]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(o\)]]></match>
+ <subst><![CDATA[. time]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(x\)]]></match>
+ <subst><![CDATA[. girl]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(z\)]]></match>
+ <subst><![CDATA[. boy]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(p\)]]></match>
+ <subst><![CDATA[. picture]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\~\)]]></match>
+ <subst><![CDATA[. film]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(b\)]]></match>
+ <subst><![CDATA[. glass of beer]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(d\)]]></match>
+ <subst><![CDATA[. glass of wine]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(\#\)]]></match>
+ <subst><![CDATA[. sunny]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(r\)]]></match>
+ <subst><![CDATA[. rainbow]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(8\)]]></match>
+ <subst><![CDATA[. note]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(i\)]]></match>
+ <subst><![CDATA[. idea]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\s\(c\)]]></match>
+ <subst><![CDATA[. coffee cup]]></subst>
+ </word>
+</wordlist>
diff --git a/kttsd/filters/stringreplacer/festival_unspeakable_chars.xml b/kttsd/filters/stringreplacer/festival_unspeakable_chars.xml
new file mode 100644
index 0000000..5086d01
--- /dev/null
+++ b/kttsd/filters/stringreplacer/festival_unspeakable_chars.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wordlist>
+ <name>Fix Festival Unspeakable Characters</name>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\x80]]></match>
+ <subst><![CDATA[ Euro ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\x82]]></match>
+ <subst><![CDATA[']]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\x84]]></match>
+ <subst><![CDATA["]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\x85]]></match>
+ <subst><![CDATA[...]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\x89]]></match>
+ <subst><![CDATA[ per Mille ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\x8B]]></match>
+ <subst><![CDATA[<]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[[\x91-\x92]]]></match>
+ <subst><![CDATA[']]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[[\x93-\x94]]]></match>
+ <subst><![CDATA["]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[[\x96-\x97]]]></match>
+ <subst><![CDATA[-]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\x98]]></match>
+ <subst><![CDATA[~]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\x99]]></match>
+ <subst><![CDATA[ trademark ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\x9B]]></match>
+ <subst><![CDATA[>]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[[\x80-\x9F]]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\{]]></match>
+ <subst><![CDATA[ left curly brace ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\}]]></match>
+ <subst><![CDATA[ right curly brace ]]></subst>
+ </word>
+</wordlist>
diff --git a/kttsd/filters/stringreplacer/kmail.xml b/kttsd/filters/stringreplacer/kmail.xml
new file mode 100644
index 0000000..b0f33d6
--- /dev/null
+++ b/kttsd/filters/stringreplacer/kmail.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Filter by David Power achiestdragon@gmail.com -->
+<wordlist>
+ <name>kmail notify</name>
+ <appid>knotify</appid>
+ <appid>kmail</appid>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<br>]]></match>
+ <subst><![CDATA[,]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</b>]]></match>
+ <subst><![CDATA[,]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[in /local/inbox]]></match>
+ <subst><![CDATA[,]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<b>]]></match>
+ <subst><![CDATA[,]]></subst>
+ </word>
+</wordlist>
diff --git a/kttsd/filters/stringreplacer/kttsd_stringreplacerplugin.desktop b/kttsd/filters/stringreplacer/kttsd_stringreplacerplugin.desktop
new file mode 100644
index 0000000..df8214c
--- /dev/null
+++ b/kttsd/filters/stringreplacer/kttsd_stringreplacerplugin.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+Name=String Replacer
+Name[bg]=Замяна на низове
+Name[ca]=Reemplaçador de cadenes
+Name[cs]=Nahrazení řetězce
+Name[da]=Streng-erstatter
+Name[de]=Zeichenkettenersetzer
+Name[el]=Αντικαταστάτης συμβολοσειρών
+Name[es]=Reemplazador de cadenas
+Name[et]=Stringiasendaja
+Name[eu]=Kate-ordezkatzailea
+Name[fa]=جایگزین‌کنندۀ رشته
+Name[fi]=Tekstien korvaaja
+Name[fr]=Remplacement de chaînes
+Name[ga]=Ionadóir Teaghrán
+Name[gl]=Reemprazamento de Cadeas
+Name[he]=מחליף מחרוזות
+Name[hu]=Sztringcserélő
+Name[is]=Strengja útskiptir
+Name[it]=Sostitutore di stringhe
+Name[ja]=文字列置換
+Name[ka]=სტრიქონის ჩამნაცვლებელი
+Name[km]= ឧបករណ៍​ជំនួស​ខ្សែ​អក្សរ
+Name[lt]=Eilučių pakeitiklis
+Name[mk]=Менувач на низи знаци
+Name[ms]=Pengganti Rentetan
+Name[nb]=Strengerstatter
+Name[nds]=Tekenkeed-Tuscher
+Name[ne]=स्ट्रिङ प्रतिस्थापक
+Name[nl]=Tekstvervanger
+Name[pa]=ਸਤਰ ਤਬਦੀਲ
+Name[pl]=Zastępowanie tekstu
+Name[pt]=Substituição de Textos
+Name[pt_BR]=Substituidor de Strings
+Name[ru]=Автозамена
+Name[sk]=Náhrada reťazca
+Name[sl]=Zamenjevalnik nizov
+Name[sr]=Замењивач знаковних низова
+Name[sr@Latn]=Zamenjivač znakovnih nizova
+Name[sv]=Strängersättning
+Name[ta]=சர இடமாற்றி
+Name[tg]=Ҷойивазкунии автоматӣ
+Name[tr]=Metin Değiştirici
+Name[uk]=Заміна рядків
+Name[vi]=Trình thay Chuỗi
+Name[zh_TW]=字串置換器
+Comment=Generic String Replacement Filter Plugin for KTTS
+Comment[bg]=Приставка филтър за замяна на низове за KTTS
+Comment[ca]=Connector del filtre reemplaçador genèric de cadenes pel KTTS
+Comment[cs]=Modul filtru náhrady řetězce KTTS
+Comment[da]=Generisk strengerstatnings-filter-plugin for KTTS
+Comment[de]=Ein generisches Modul zur Zeichenkettenersetzung für KTTS
+Comment[el]=Γενικό φίλτρο πρόσθετο αντικατάστασης συμβολοσειρών για το KTTS
+Comment[es]=Complemento de filtro genérico de sustituición de cadenas para KTTS
+Comment[et]=KTTS-i üldine stringiasendusfiltri plugin
+Comment[eu]=KTTS-ren kateak ordezkatzeko iragazki-plugin generikoa
+Comment[fa]=وصلۀ پالایۀ جایگزینی رشتۀ عمومی برای KTTS
+Comment[fi]=Yleinen tekstien korvaussuodatinliitännäinen KTTS-ohjelmaan
+Comment[fr]=Module de filtrage de remplacement de chaînes générique pour KTTS
+Comment[gl]=Plugin de Filtro Xenérico de Substituición de Cadeas para KTTS
+Comment[hu]=Általános sztringcserélő modul a KTTS-hez
+Comment[is]=Almennt strengja útskiptinga íforrit fyrir KTTS
+Comment[it]=Plugin generico per il filtro di sostituzione di stringhe per KTTS
+Comment[ja]=KTTS 用汎用文字列置換フィルタプラグイン
+Comment[ka]=ზოგადი სტრიქონის ჩანაცვლების ფილტრის მოდული KTTS-სთვის
+Comment[km]=កម្មវិធី​ជំនួយ​តម្រង​ការ​ជំនួស​ខ្សែអក្សរ​ទូទៅ​សម្រាប់ KTTS
+Comment[lt]=Bendro pobūdžio eilučių pakeitimo filtro priedas, skirtas KTTS
+Comment[mk]=Филтер за KTTS за општа замена на низи знаци
+Comment[ms]=Plugin Penapis Penggantian Rentetan Generik bagi KTTS
+Comment[nb]=Filter-programtillegg til KTTS for streng-erstatning
+Comment[nds]=KTTS-Filtermoduul för dat Utwesseln vun Tekenkeden
+Comment[ne]=KTTS का लागि जेनेरीक स्ट्रिङ प्रतिस्थापन फिल्टर प्लगइन
+Comment[nl]=Generieke tekst-vervang-filter-plugin voor KTTS
+Comment[pl]=Wtyczka zastępowania tekstu dla KTTS
+Comment[pt]='Plugin' Genérico de Substituição de Textos para o KTTS
+Comment[pt_BR]=Plug-in de Filtro genérico de Substituição de Strings Para o KTTS
+Comment[ru]=Фильтр автозамены для KTTS
+Comment[sk]=Všeobecný modul filtra náhrady reťazca v KTTS
+Comment[sl]=Filtrni vstavek KTTS za generični zamenjevalnik nizov
+Comment[sr]=Генерички филтерски прикључак KTTS-а за замену знаковних низова
+Comment[sr@Latn]=Generički filterski priključak KTTS-a za zamenu znakovnih nizova
+Comment[sv]=Insticksprogram för KTTS med generellt strängersättningsfilter
+Comment[ta]=KTTSக்கான அலங்கார சொருகுபொருள் சர இடமாற்றி
+Comment[tg]=Филтри худивазкунӣ барои KTTS
+Comment[tr]=KTTS için Genel Metin Değiştirme Süzgeci Eklentisi
+Comment[uk]=Втулок загального фільтра заміни рядків для KTTS
+Comment[vi]=Trình bổ sung Lọc Thay Chuỗi Chung cho KTTS
+Comment[zh_TW]=KTTS 使用的字串置換外掛程式
+Type=Service
+ServiceTypes=KTTSD/FilterPlugin
+X-KDE-Library=libkttsd_stringreplacerplugin
+X-KDE-Languages=en,en_US,en_GB,en_CA,es,es_mx,cy,de,fi,cs,pl
diff --git a/kttsd/filters/stringreplacer/polish_festival_fixes.xml b/kttsd/filters/stringreplacer/polish_festival_fixes.xml
new file mode 100644
index 0000000..a6f2533
--- /dev/null
+++ b/kttsd/filters/stringreplacer/polish_festival_fixes.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Author of filter: Mikolaj Machowski ( mikmach AT wp DOT pl ) -->
+<wordlist>
+ <name>Filtr polski / Filter for Polish Festival voice</name>
+ <language-code>pl</language-code>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[[^a-zA-Z0-9ęóąśłżźćńĘÓĄŚŁŻŹĆŃ\,\"\'\\@#$%^*+=`~]]]></match>
+ <subst><![CDATA[ ]]></subst>
+ </word>
+</wordlist>
diff --git a/kttsd/filters/stringreplacer/polish_festival_unspeakables.xml b/kttsd/filters/stringreplacer/polish_festival_unspeakables.xml
new file mode 100644
index 0000000..8fbc18a
--- /dev/null
+++ b/kttsd/filters/stringreplacer/polish_festival_unspeakables.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Author of filter: Mikolaj Machowski ( mikmach AT wp DOT pl ) -->
+<wordlist>
+ <name>Polskie niewymawialne / Polish Festival unspeakables</name>
+ <language-code>pl</language-code>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\(]]></match>
+ <subst><![CDATA[ otwieram nawias ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\)]]></match>
+ <subst><![CDATA[ zamykam nawias ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\{]]></match>
+ <subst><![CDATA[ otwieram nawias klamrowy ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\}]]></match>
+ <subst><![CDATA[ zamykam nawias klamrowy ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\[]]></match>
+ <subst><![CDATA[ otwieram nawias kwadratowy ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\]]]></match>
+ <subst><![CDATA[ zamykam nawias kwadratowy ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\<]]></match>
+ <subst><![CDATA[ otwieram nawias trójkątny ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\>]]></match>
+ <subst><![CDATA[ zamykam nawias trójkątny ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\_]]></match>
+ <subst><![CDATA[ znak podkreślenia ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\&]]></match>
+ <subst><![CDATA[ i ]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[\/]]></match>
+ <subst><![CDATA[ slesz ]]></subst>
+ </word>
+ <word>
+ <type>Word</type>
+ <case>No</case>
+ <match><![CDATA[\\]]></match>
+ <subst><![CDATA[ bekslesz ]]></subst>
+ </word>
+</wordlist>
diff --git a/kttsd/filters/stringreplacer/qt2plaintext.xml b/kttsd/filters/stringreplacer/qt2plaintext.xml
new file mode 100644
index 0000000..8a194ec
--- /dev/null
+++ b/kttsd/filters/stringreplacer/qt2plaintext.xml
@@ -0,0 +1,359 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wordlist>
+ <name>Qt Rich Text to Plain Text</name>
+ <appid>knotify</appid>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<qt>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</qt>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<h1>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<h2>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<h3>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</h1>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</h2>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</h3>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<p>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</p>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<center>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</center>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<blockquote>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</blockquote>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<ul>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</ul>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<ol>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</ol>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<li>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</li>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<a>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</a>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<em>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</em>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<strong>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</strong>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<bold>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</bold>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<b>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</b>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<u>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</u>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<big>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</big>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<small>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</small>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<hr/>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<br/>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<nobr>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</nobr>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<table>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</table>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<tr>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</tr>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<td>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</td>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<th>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</th>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<img src\=]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<a href\=]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[/>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<img>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[">]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<pre>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</pre>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<tt>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</tt>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[<code>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+ <word>
+ <type>RegExp</type>
+ <case>No</case>
+ <match><![CDATA[</code>]]></match>
+ <subst><![CDATA[]]></subst>
+ </word>
+</wordlist>
diff --git a/kttsd/filters/stringreplacer/stringreplacerconf.cpp b/kttsd/filters/stringreplacer/stringreplacerconf.cpp
new file mode 100644
index 0000000..9afa2d5
--- /dev/null
+++ b/kttsd/filters/stringreplacer/stringreplacerconf.cpp
@@ -0,0 +1,725 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic String Replacement Filter Configuration class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+// Qt includes.
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qstring.h>
+#include <qhbox.h>
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qdom.h>
+#include <qfile.h>
+#include <qradiobutton.h>
+
+// KDE includes.
+#include <kglobal.h>
+#include <klocale.h>
+#include <klistview.h>
+#include <klineedit.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+#include <kpushbutton.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kregexpeditorinterface.h>
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+
+// KTTS includes.
+#include "filterconf.h"
+
+// StringReplacer includes.
+#include "stringreplacerconf.h"
+#include "stringreplacerconf.moc"
+#include "editreplacementwidget.h"
+
+/**
+* Constructor
+*/
+StringReplacerConf::StringReplacerConf( QWidget *parent, const char *name, const QStringList& /*args*/) :
+ KttsFilterConf(parent, name),
+ m_editDlg(0),
+ m_editWidget(0)
+{
+ // kdDebug() << "StringReplacerConf::StringReplacerConf: Running" << endl;
+
+ // Create configuration widget.
+ QVBoxLayout *layout = new QVBoxLayout(this, KDialog::marginHint(),
+ KDialog::spacingHint(), "StringReplacerConfigWidgetLayout");
+ layout->setAlignment (Qt::AlignTop);
+ m_widget = new StringReplacerConfWidget(this, "StringReplacerConfigWidget");
+ layout->addWidget(m_widget);
+ m_widget->substLView->setSortColumn(-1);
+
+ connect(m_widget->nameLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()));
+ connect(m_widget->languageBrowseButton, SIGNAL(clicked()),
+ this, SLOT(slotLanguageBrowseButton_clicked()));
+ connect(m_widget->addButton, SIGNAL(clicked()),
+ this, SLOT(slotAddButton_clicked()));
+ connect(m_widget->upButton, SIGNAL(clicked()),
+ this, SLOT(slotUpButton_clicked()));
+ connect(m_widget->downButton, SIGNAL(clicked()),
+ this, SLOT(slotDownButton_clicked()));
+ connect(m_widget->editButton, SIGNAL(clicked()),
+ this, SLOT(slotEditButton_clicked()));
+ connect(m_widget->removeButton, SIGNAL(clicked()),
+ this, SLOT(slotRemoveButton_clicked()));
+ connect(m_widget->loadButton, SIGNAL(clicked()),
+ this, SLOT(slotLoadButton_clicked()));
+ connect(m_widget->saveButton, SIGNAL(clicked()),
+ this, SLOT(slotSaveButton_clicked()));
+ connect(m_widget->clearButton, SIGNAL(clicked()),
+ this, SLOT(slotClearButton_clicked()));
+ connect(m_widget->substLView, SIGNAL(selectionChanged()),
+ this, SLOT(enableDisableButtons()));
+ connect(m_widget->appIdLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()));
+
+ // Determine if kdeutils Regular Expression Editor is installed.
+ m_reEditorInstalled = !KTrader::self()->query("KRegExpEditor/KRegExpEditor").isEmpty();
+
+ // Set up defaults.
+ defaults();
+}
+
+/**
+* Destructor.
+*/
+StringReplacerConf::~StringReplacerConf(){
+ // kdDebug() << "StringReplacerConf::~StringReplacerConf: Running" << endl;
+}
+
+/**
+* This method is invoked whenever the module should read its
+* configuration (most of the times from a config file) and update the
+* user interface. This happens when the user clicks the "Reset" button in
+* the control center, to undo all of his changes and restore the currently
+* valid settings. Note that kttsmgr calls this when the plugin is
+* loaded, so it not necessary to call it in your constructor.
+* The plugin should read its configuration from the specified group
+* in the specified config file.
+* @param config Pointer to a KConfig object.
+* @param configGroup Call config->setGroup with this argument before
+* loading your configuration.
+*/
+void StringReplacerConf::load(KConfig* config, const QString& configGroup){
+ // kdDebug() << "StringReplacerConf::load: Running" << endl;
+ // See if this filter previously save its word list.
+ config->setGroup( configGroup );
+ QString wordsFilename = config->readEntry( "WordListFile" );
+ if ( !wordsFilename.isEmpty() )
+ {
+ QString errMsg = loadFromFile( wordsFilename, true );
+ if ( !errMsg.isEmpty() )
+ kdDebug() << "StringReplacerConf::load: " << errMsg << endl;
+ enableDisableButtons();
+ }
+}
+
+// Loads word list and settings from a file. Clearing configuration if clear is True.
+QString StringReplacerConf::loadFromFile( const QString& filename, bool clear)
+{
+ // Open existing word list.
+ QFile file( filename );
+ if ( !file.open( IO_ReadOnly ) )
+ {
+ return i18n("Unable to open file.") + filename;
+ }
+ // QDomDocument doc( "http://www.kde.org/share/apps/kttsd/stringreplacer/wordlist.dtd []" );
+ QDomDocument doc( "" );
+ if ( !doc.setContent( &file ) ) {
+ file.close();
+ return i18n("File not in proper XML format.");
+ }
+ // kdDebug() << "StringReplacerConf::load: document successfully parsed." << endl;
+ file.close();
+
+ // Clear list view.
+ if ( clear ) m_widget->substLView->clear();
+
+ // Name setting.
+ QDomNodeList nameList = doc.elementsByTagName( "name" );
+ QDomNode nameNode = nameList.item( 0 );
+ m_widget->nameLineEdit->setText( nameNode.toElement().text() );
+ // kdDebug() << "StringReplacerConf::load: name = " << nameNode.toElement().text() << endl;
+
+ // Language Codes setting. List may be single element of comma-separated values,
+ // or multiple elements.
+ QString languageCodes;
+ QDomNodeList languageList = doc.elementsByTagName( "language-code" );
+ for ( uint ndx=0; ndx < languageList.count(); ++ndx )
+ {
+ QDomNode languageNode = languageList.item( ndx );
+ if (!languageCodes.isEmpty()) languageCodes += ",";
+ languageCodes += languageNode.toElement().text();
+ }
+ if ( clear )
+ m_languageCodeList = QStringList::split(',', languageCodes, false);
+ else
+ m_languageCodeList += QStringList::split(',', languageCodes, false);
+ QString language;
+ m_languageCodeList.sort();
+ // Eliminate dups.
+ for ( int ndx = m_languageCodeList.count() - 2; ndx >= 0; --ndx )
+ {
+ if ( m_languageCodeList[ndx] == m_languageCodeList[ndx+1] )
+ m_languageCodeList.remove(m_languageCodeList.at(ndx+1));
+ }
+ for ( uint ndx=0; ndx < m_languageCodeList.count(); ++ndx )
+ {
+ if (!language.isEmpty()) language += ",";
+ language += KGlobal::locale()->twoAlphaToLanguageName(m_languageCodeList[ndx]);
+ }
+ m_widget->languageLineEdit->setText(language);
+
+ // AppId. Apply this filter only if DCOP appId of application that queued
+ // the text contains this string. List may be single element of comma-separated values,
+ // or multiple elements.
+ QDomNodeList appIdList = doc.elementsByTagName( "appid" );
+ QString appIds;
+ for ( uint ndx=0; ndx < appIdList.count(); ++ndx )
+ {
+ QDomNode appIdNode = appIdList.item( ndx );
+ if (!appIds.isEmpty()) appIds += ",";
+ appIds += appIdNode.toElement().text();
+ }
+ if ( !clear ) appIds = m_widget->appIdLineEdit->text() + appIds;
+ m_widget->appIdLineEdit->setText( appIds );
+
+ // Word list.
+ QListViewItem* item = 0;
+ if ( !clear ) item = m_widget->substLView->lastChild();
+ QDomNodeList wordList = doc.elementsByTagName("word");
+ const int wordListCount = wordList.count();
+ for (int wordIndex = 0; wordIndex < wordListCount; ++wordIndex)
+ {
+ // kdDebug() << "StringReplacerConf::load: start parsing of word " << wordIndex << endl;
+ QDomNode wordNode = wordList.item(wordIndex);
+ QDomNodeList propList = wordNode.childNodes();
+ QString wordType;
+ QString matchCase = "No"; // Default for old (v<=3.5.3) config files with no <case/>.
+ QString match;
+ QString subst;
+ const int propListCount = propList.count();
+ for (int propIndex = 0; propIndex < propListCount; ++propIndex)
+ {
+ QDomNode propNode = propList.item(propIndex);
+ QDomElement prop = propNode.toElement();
+ if (prop.tagName() == "type") wordType = prop.text();
+ if (prop.tagName() == "case") matchCase = prop.text();
+ if (prop.tagName() == "match") match = prop.text();
+ if (prop.tagName() == "subst") subst = prop.text();
+ }
+ QString wordTypeStr =
+ (wordType=="RegExp"?i18n("Abbreviation for 'Regular Expression'", "RegExp"):i18n("Word"));
+ QString matchCaseStr =
+ (matchCase=="Yes"?i18n("Yes"):i18n("No"));
+ if (!item)
+ item = new KListViewItem(m_widget->substLView, wordTypeStr, matchCaseStr, match, subst);
+ else
+ item = new KListViewItem(m_widget->substLView, item, wordTypeStr, matchCaseStr, match, subst);
+ }
+
+ return QString::null;
+}
+
+/**
+* This function gets called when the user wants to save the settings in
+* the user interface, updating the config files or wherever the
+* configuration is stored. The method is called when the user clicks "Apply"
+* or "Ok". The plugin should save its configuration in the specified
+* group of the specified config file.
+* @param config Pointer to a KConfig object.
+* @param configGroup Call config->setGroup with this argument before
+* saving your configuration.
+*/
+void StringReplacerConf::save(KConfig* config, const QString& configGroup){
+ // kdDebug() << "StringReplacerConf::save: Running" << endl;
+ QString wordsFilename =
+ KGlobal::dirs()->saveLocation( "data" ,"kttsd/stringreplacer/", true );
+ if ( wordsFilename.isEmpty() )
+ {
+ kdDebug() << "StringReplacerConf::save: no save location" << endl;
+ return;
+ }
+ wordsFilename += configGroup;
+ QString errMsg = saveToFile( wordsFilename );
+ if ( errMsg.isEmpty() )
+ {
+ config->setGroup( configGroup );
+ config->writeEntry( "WordListFile", realFilePath(wordsFilename) );
+ }
+ else
+ kdDebug() << "StringReplacerConf::save: " << errMsg << endl;
+}
+
+// Saves word list and settings to a file.
+QString StringReplacerConf::saveToFile(const QString& filename)
+{
+ // kdDebug() << "StringReplacerConf::saveToFile: saving to file " << wordsFilename << endl;
+
+ QFile file( filename );
+ if ( !file.open( IO_WriteOnly ) )
+ return i18n("Unable to open file ") + filename;
+
+ // QDomDocument doc( "http://www.kde.org/share/apps/kttsd/stringreplacer/wordlist.dtd []" );
+ QDomDocument doc( "" );
+
+ QDomElement root = doc.createElement( "wordlist" );
+ doc.appendChild( root );
+
+ // Name.
+ QDomElement name = doc.createElement( "name" );
+ root.appendChild( name );
+ QDomText t = doc.createTextNode( m_widget->nameLineEdit->text() );
+ name.appendChild( t );
+
+ // Language code.
+ for ( uint ndx=0; ndx < m_languageCodeList.count(); ++ndx )
+ {
+ QDomElement languageCode = doc.createElement( "language-code" );
+ root.appendChild( languageCode );
+ t = doc.createTextNode( m_languageCodeList[ndx] );
+ languageCode.appendChild( t );
+ }
+
+ // Application ID
+ QString appId = m_widget->appIdLineEdit->text().replace(" ", "");
+ if ( !appId.isEmpty() )
+ {
+ QStringList appIdList = QStringList::split(",", appId);
+ for ( uint ndx=0; ndx < appIdList.count(); ++ndx )
+ {
+ QDomElement appIdElem = doc.createElement( "appid" );
+ root.appendChild( appIdElem );
+ t = doc.createTextNode( appIdList[ndx] );
+ appIdElem.appendChild( t );
+ }
+ }
+
+ // Words.
+ QListView* lView = m_widget->substLView;
+ QListViewItem* item = lView->firstChild();
+ while (item)
+ {
+ QDomElement wordTag = doc.createElement( "word" );
+ root.appendChild( wordTag );
+ QDomElement propTag = doc.createElement( "type" );
+ wordTag.appendChild( propTag);
+ QDomText t = doc.createTextNode( item->text(0)==i18n("Word")?"Word":"RegExp" );
+ propTag.appendChild( t );
+
+ propTag = doc.createElement( "case" );
+ wordTag.appendChild( propTag);
+ t = doc.createTextNode( item->text(1)==i18n("Yes")?"Yes":"No" );
+ propTag.appendChild( t );
+
+ propTag = doc.createElement( "match" );
+ wordTag.appendChild( propTag);
+ t = doc.createCDATASection( item->text(2) );
+ propTag.appendChild( t );
+
+ propTag = doc.createElement( "subst" );
+ wordTag.appendChild( propTag);
+ t = doc.createCDATASection( item->text(3) );
+ propTag.appendChild( t );
+
+ item = item->nextSibling();
+ }
+
+ // Write it all out.
+ QTextStream ts( &file );
+ ts.setEncoding( QTextStream::UnicodeUTF8 );
+ ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ ts << doc.toString();
+ // kdDebug() << "StringReplacerConf::saveToFile: writing out " << doc.toString() << endl;
+ file.close();
+
+ return QString::null;
+}
+
+/**
+* This function is called to set the settings in the module to sensible
+* default values. It gets called when hitting the "Default" button. The
+* default values should probably be the same as the ones the application
+* uses when started without a config file. Note that defaults should
+* be applied to the on-screen widgets; not to the config file.
+*/
+void StringReplacerConf::defaults(){
+ // kdDebug() << "StringReplacerConf::defaults: Running" << endl;
+ // Default language is none.
+ m_languageCodeList.clear();
+ m_widget->languageLineEdit->setText( "" );
+ // Default name.
+ m_widget->nameLineEdit->setText( i18n("String Replacer") );
+ m_widget->substLView->clear();
+ // Default App ID is blank.
+ m_widget->appIdLineEdit->setText( "" );
+ enableDisableButtons();
+ // kdDebug() << "StringReplacerConf::defaults: Exiting" << endl;
+}
+
+/**
+ * Indicates whether the plugin supports multiple instances. Return
+ * False if only one instance of the plugin can be configured.
+ * @return True if multiple instances are possible.
+ */
+bool StringReplacerConf::supportsMultiInstance() { return true; }
+
+/**
+ * Returns the name of the plugin. Displayed in Filters tab of KTTSMgr.
+ * If there can be more than one instance of a filter, it should return
+ * a unique name for each instance. The name should be translated for
+ * the user if possible. If the plugin is not correctly configured,
+ * return an empty string.
+ * @return Filter instance name.
+ */
+QString StringReplacerConf::userPlugInName()
+{
+ if ( m_widget->substLView->childCount() == 0 ) return QString::null;
+ QString instName = m_widget->nameLineEdit->text();
+ if ( instName.isEmpty() )
+ {
+ QString language;
+ if (m_languageCodeList.count() == 1)
+ language = KGlobal::locale()->twoAlphaToLanguageName(m_languageCodeList[0]);
+ if (m_languageCodeList.count() > 1)
+ language = i18n("Multiple Languages");
+ if (!language.isEmpty())
+ instName = i18n("String Replacer") + " (" + language + ")";
+ }
+ return instName;
+}
+
+void StringReplacerConf::slotLanguageBrowseButton_clicked()
+{
+ // Create a QHBox to host KListView.
+ QHBox* hBox = new QHBox(m_widget, "SelectLanguage_hbox");
+ // Create a KListView and fill with all known languages.
+ KListView* langLView = new KListView(hBox, "SelectLanguage_lview");
+ langLView->addColumn(i18n("Language"));
+ langLView->addColumn(i18n("Code"));
+ langLView->setSelectionMode(QListView::Extended);
+ QStringList allLocales = KGlobal::locale()->allLanguagesTwoAlpha();
+ QString locale;
+ QString languageCode;
+ QString countryCode;
+ QString charSet;
+ QString language;
+ // Blank line so user can select no language.
+ QListViewItem* item = new KListViewItem(langLView, "", "");
+ if (m_languageCodeList.isEmpty()) item->setSelected(true);
+ const int allLocalesCount = allLocales.count();
+ for (int ndx=0; ndx < allLocalesCount; ++ndx)
+ {
+ locale = allLocales[ndx];
+ KGlobal::locale()->splitLocale(locale, languageCode, countryCode, charSet);
+ language = KGlobal::locale()->twoAlphaToLanguageName(languageCode);
+ if (!countryCode.isEmpty()) language +=
+ " (" + KGlobal::locale()->twoAlphaToCountryName(countryCode)+")";
+ item = new KListViewItem(langLView, language, locale);
+ if (m_languageCodeList.contains(locale)) item->setSelected(true);
+ }
+ // Sort by language.
+ langLView->setSorting(0);
+ langLView->sort();
+ // Display the box in a dialog.
+ KDialogBase* dlg = new KDialogBase(
+ KDialogBase::Swallow,
+ i18n("Select Languages"),
+ KDialogBase::Help|KDialogBase::Ok|KDialogBase::Cancel,
+ KDialogBase::Cancel,
+ m_widget,
+ "SelectLanguage_dlg",
+ true,
+ true);
+ dlg->setMainWidget(hBox);
+ dlg->setHelp("", "kttsd");
+ dlg->setInitialSize(QSize(300, 500), false);
+ int dlgResult = dlg->exec();
+ languageCode = QString::null;
+ if (dlgResult == QDialog::Accepted)
+ {
+ m_languageCodeList.clear();
+ QListViewItem* item = langLView->firstChild();
+ while (item)
+ {
+ if (item->isSelected()) m_languageCodeList += item->text(1);
+ item = item->nextSibling();
+ }
+ }
+ delete dlg;
+ // TODO: Also delete KListView and QHBox?
+ if (dlgResult != QDialog::Accepted) return;
+ language = "";
+ for ( uint ndx=0; ndx < m_languageCodeList.count(); ++ndx)
+ {
+ if (!language.isEmpty()) language += ",";
+ language += KGlobal::locale()->twoAlphaToLanguageName(m_languageCodeList[ndx]);
+ }
+ QString s1 = m_widget->languageLineEdit->text();
+ m_widget->languageLineEdit->setText(language);
+ // Replace language in the user's filter name.
+ QString s2 = m_widget->nameLineEdit->text();
+ if (m_languageCodeList.count() > 1) language = i18n("Multiple Languages");
+ if ( !s1.isEmpty() )
+ {
+ s2.replace( s1, language );
+ s2.replace( i18n("Multiple Languages"), language );
+ }
+ s2.replace(" ()", "");
+ if ( !s2.contains("(") && !language.isEmpty() ) s2 += " (" + language + ")";
+ m_widget->nameLineEdit->setText(s2);
+ configChanged();
+}
+
+void StringReplacerConf::enableDisableButtons()
+{
+ bool enableBtn = (m_widget->substLView->selectedItem() != 0);
+ if (enableBtn)
+ {
+ m_widget->upButton->setEnabled(
+ m_widget->substLView->selectedItem()->itemAbove() != 0);
+ m_widget->downButton->setEnabled(
+ m_widget->substLView->selectedItem()->itemBelow() != 0);
+ } else {
+ m_widget->upButton->setEnabled(false);
+ m_widget->downButton->setEnabled(false);
+ }
+ m_widget->editButton->setEnabled(enableBtn);
+ m_widget->removeButton->setEnabled(enableBtn);
+ m_widget->clearButton->setEnabled(m_widget->substLView->firstChild());
+ m_widget->saveButton->setEnabled(m_widget->substLView->firstChild());
+}
+
+void StringReplacerConf::slotUpButton_clicked()
+{
+ QListViewItem* item = m_widget->substLView->selectedItem();
+ if (!item) return;
+ QListViewItem* prevItem = item->itemAbove();
+ if (!prevItem) return;
+ prevItem->moveItem(item);
+ m_widget->substLView->setSelected(item, true);
+ m_widget->substLView->ensureItemVisible(item);
+ enableDisableButtons();
+ configChanged();
+}
+
+void StringReplacerConf::slotDownButton_clicked()
+{
+ QListViewItem* item = m_widget->substLView->selectedItem();
+ if (!item) return;
+ QListViewItem* nextItem = item->itemBelow();
+ if (!nextItem) return;
+ item->moveItem(nextItem);
+ m_widget->substLView->setSelected(item, true);
+ m_widget->substLView->ensureItemVisible(item);
+ enableDisableButtons();
+ configChanged();
+}
+
+void StringReplacerConf::slotAddButton_clicked()
+{
+ addOrEditSubstitution( true );
+}
+
+void StringReplacerConf::slotEditButton_clicked()
+{
+ addOrEditSubstitution( false );
+}
+
+// Displays the add/edit string replacement dialog.
+void StringReplacerConf::addOrEditSubstitution(bool isAdd)
+{
+ QListViewItem* item = 0;
+ if (isAdd)
+ item = m_widget->substLView->lastChild();
+ else
+ {
+ item = m_widget->substLView->selectedItem();
+ if (!item) return;
+ }
+ // Create a QHBox to host widget.
+ QHBox* hBox = new QHBox(m_widget, "AddOrEditSubstitution_hbox" );
+ // Create widget.
+ m_editWidget = new EditReplacementWidget( hBox, "AddOrEditSubstitution_widget" );
+ // Set controls if editing existing.
+ m_editWidget->matchButton->setEnabled( false );
+ if (!isAdd)
+ {
+ if ( item->text(0) == i18n("Abbreviation for 'Regular Expression'", "RegExp") )
+ {
+ m_editWidget->regexpRadioButton->setChecked( true );
+ m_editWidget->matchButton->setEnabled( m_reEditorInstalled );
+ }
+ m_editWidget->caseCheckBox->setChecked( (item->text(1))==i18n("Yes") );
+ m_editWidget->matchLineEdit->setText( item->text(2) );
+ m_editWidget->substLineEdit->setText( item->text(3) );
+ }
+ // The match box may not be blank.
+ connect( m_editWidget->matchLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotMatchLineEdit_textChanged(const QString&)) );
+ connect( m_editWidget->regexpRadioButton, SIGNAL(clicked()),
+ this, SLOT(slotTypeButtonGroup_clicked()) );
+ connect( m_editWidget->wordRadioButton, SIGNAL(clicked()),
+ this, SLOT(slotTypeButtonGroup_clicked()) );
+ connect( m_editWidget->matchButton, SIGNAL(clicked()),
+ this, SLOT(slotMatchButton_clicked()) );
+ // Display the box in a dialog.
+ m_editDlg = new KDialogBase(
+ KDialogBase::Swallow,
+ i18n("Edit String Replacement"),
+ KDialogBase::Help|KDialogBase::Ok|KDialogBase::Cancel,
+ KDialogBase::Cancel,
+ m_widget,
+ "AddOrEditSubstitution_dlg",
+ true,
+ true);
+ // Disable OK button if match field blank.
+ m_editDlg->setMainWidget( hBox );
+ m_editDlg->setHelp( "", "kttsd" );
+ m_editDlg->enableButton( KDialogBase::Ok, !m_editWidget->matchLineEdit->text().isEmpty() );
+ int dlgResult = m_editDlg->exec();
+ QString substType = i18n( "Word" );
+ if ( m_editWidget->regexpRadioButton->isChecked() )
+ substType = i18n("Abbreviation for 'Regular Expression'", "RegExp");
+ QString matchCase = i18n("No");
+ if ( m_editWidget->caseCheckBox->isChecked() ) matchCase = i18n("Yes");
+ QString match = m_editWidget->matchLineEdit->text();
+ QString subst = m_editWidget->substLineEdit->text();
+ delete m_editDlg;
+ m_editDlg = 0;
+ m_editWidget = 0;
+ if (dlgResult != QDialog::Accepted) return;
+ // TODO: Also delete hBox and w?
+ if ( match.isEmpty() ) return;
+ if ( isAdd )
+ {
+ if ( item )
+ item = new KListViewItem( m_widget->substLView, item, substType, matchCase, match, subst );
+ else
+ item = new KListViewItem( m_widget->substLView, substType, matchCase, match, subst );
+ m_widget->substLView->setSelected( item, true );
+ }
+ else
+ {
+ item->setText( 0, substType );
+ item->setText( 1, matchCase );
+ item->setText( 2, match );
+ item->setText( 3, subst );
+ }
+ m_widget->substLView->ensureItemVisible( item );
+ enableDisableButtons();
+ configChanged();
+}
+
+void StringReplacerConf::slotMatchLineEdit_textChanged(const QString& text)
+{
+ // Disable OK button if match field blank.
+ if ( !m_editDlg ) return;
+ m_editDlg->enableButton( KDialogBase::Ok, !text.isEmpty() );
+}
+
+void StringReplacerConf::slotRemoveButton_clicked()
+{
+ QListViewItem* item = m_widget->substLView->selectedItem();
+ if (!item) return;
+ delete item;
+ enableDisableButtons();
+ configChanged();
+}
+
+void StringReplacerConf::slotTypeButtonGroup_clicked()
+{
+ // Enable Regular Expression Editor button if editor is installed (requires kdeutils).
+ if ( !m_editWidget ) return;
+ m_editWidget->matchButton->setEnabled( m_editWidget->regexpRadioButton->isOn() && m_reEditorInstalled );
+}
+
+void StringReplacerConf::slotMatchButton_clicked()
+{
+ // Show Regular Expression Editor dialog if it is installed.
+ if ( !m_editWidget ) return;
+ if ( !m_editDlg ) return;
+ if ( !m_reEditorInstalled ) return;
+ QDialog *editorDialog =
+ KParts::ComponentFactory::createInstanceFromQuery<QDialog>( "KRegExpEditor/KRegExpEditor" );
+ if ( editorDialog )
+ {
+ // kdeutils was installed, so the dialog was found. Fetch the editor interface.
+ KRegExpEditorInterface *reEditor =
+ static_cast<KRegExpEditorInterface *>(editorDialog->qt_cast( "KRegExpEditorInterface" ) );
+ Q_ASSERT( reEditor ); // This should not fail!// now use the editor.
+ reEditor->setRegExp( m_editWidget->matchLineEdit->text() );
+ int dlgResult = editorDialog->exec();
+ if ( dlgResult == QDialog::Accepted )
+ {
+ QString re = reEditor->regExp();
+ m_editWidget->matchLineEdit->setText( re );
+ m_editDlg->enableButton( KDialogBase::Ok, !re.isEmpty() );
+ }
+ delete editorDialog;
+ } else return;
+}
+
+void StringReplacerConf::slotLoadButton_clicked()
+{
+ // QString dataDir = KGlobal::dirs()->resourceDirs("data").last() + "/kttsd/stringreplacer/";
+ QString dataDir = KGlobal::dirs()->findAllResources("data", "kttsd/stringreplacer/").last();
+ QString filename = KFileDialog::getOpenFileName(
+ dataDir,
+ "*.xml|String Replacer Word List (*.xml)",
+ m_widget,
+ "stringreplacer_loadfile");
+ if ( filename.isEmpty() ) return;
+ QString errMsg = loadFromFile( filename, false );
+ enableDisableButtons();
+ if ( !errMsg.isEmpty() )
+ KMessageBox::sorry( m_widget, errMsg, i18n("Error Opening File") );
+ else
+ configChanged();
+}
+
+void StringReplacerConf::slotSaveButton_clicked()
+{
+ QString filename = KFileDialog::getSaveFileName(
+ KGlobal::dirs()->saveLocation( "data" ,"kttsd/stringreplacer/", false ),
+ "*.xml|String Replacer Word List (*.xml)",
+ m_widget,
+ "stringreplacer_savefile");
+ if ( filename.isEmpty() ) return;
+ QString errMsg = saveToFile( filename );
+ enableDisableButtons();
+ if ( !errMsg.isEmpty() )
+ KMessageBox::sorry( m_widget, errMsg, i18n("Error Opening File") );
+}
+
+void StringReplacerConf::slotClearButton_clicked()
+{
+ m_widget->substLView->clear();
+ enableDisableButtons();
+}
diff --git a/kttsd/filters/stringreplacer/stringreplacerconf.h b/kttsd/filters/stringreplacer/stringreplacerconf.h
new file mode 100644
index 0000000..f0312a6
--- /dev/null
+++ b/kttsd/filters/stringreplacer/stringreplacerconf.h
@@ -0,0 +1,158 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic String Replacement Filter Configuration class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+#ifndef _STRINGREPLACERCONF_H_
+#define _STRINGREPLACERCONF_H_
+
+// Qt includes.
+#include <qwidget.h>
+
+// KDE includes.
+#include <kconfig.h>
+#include <kdebug.h>
+
+// KTTS includes.
+#include "filterconf.h"
+
+// StringReplacer includes.
+#include "stringreplacerconfwidget.h"
+
+class KDialogBase;
+class EditReplacementWidget;
+
+class StringReplacerConf : public KttsFilterConf
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor
+ */
+ StringReplacerConf( QWidget *parent, const char *name, const QStringList &args = QStringList() );
+
+ /**
+ * Destructor
+ */
+ virtual ~StringReplacerConf();
+
+ enum SubstitutionType {
+ stWord, // Word
+ stRegExp // Regular Expression
+ };
+
+ /**
+ * This method is invoked whenever the module should read its
+ * configuration (most of the times from a config file) and update the
+ * user interface. This happens when the user clicks the "Reset" button in
+ * the control center, to undo all of his changes and restore the currently
+ * valid settings. Note that KTTSMGR calls this when the plugin is
+ * loaded, so it not necessary to call it in your constructor.
+ * The plugin should read its configuration from the specified group
+ * in the specified config file.
+ * @param config Pointer to a KConfig object.
+ * @param configGroup Call config->setGroup with this argument before
+ * loading your configuration.
+ *
+ * When a plugin is first added to KTTSMGR, @e load will be called with
+ * a Null @e configGroup. In this case, the plugin will not have
+ * any instance-specific parameters to load, but it may still wish
+ * to load parameters that apply to all instances of the plugin.
+ */
+ virtual void load(KConfig *config, const QString &configGroup);
+
+ /**
+ * This function gets called when the user wants to save the settings in
+ * the user interface, updating the config files or wherever the
+ * configuration is stored. The method is called when the user clicks "Apply"
+ * or "Ok". The plugin should save its configuration in the specified
+ * group of the specified config file.
+ * @param config Pointer to a KConfig object.
+ * @param configGroup Call config->setGroup with this argument before
+ * saving your configuration.
+ */
+ virtual void save(KConfig *config, const QString &configGroup);
+
+ /**
+ * This function is called to set the settings in the module to sensible
+ * default values. It gets called when hitting the "Default" button. The
+ * default values should probably be the same as the ones the application
+ * uses when started without a config file. Note that defaults should
+ * be applied to the on-screen widgets; not to the config file.
+ */
+ virtual void defaults();
+
+ /**
+ * Indicates whether the plugin supports multiple instances. Return
+ * False if only one instance of the plugin can be configured.
+ * @return True if multiple instances are possible.
+ */
+ virtual bool supportsMultiInstance();
+
+ /**
+ * Returns the name of the plugin. Displayed in Filters tab of KTTSMgr.
+ * If there can be more than one instance of a filter, it should return
+ * a unique name for each instance. The name should be translated for
+ * the user if possible. If the plugin is not correctly configured,
+ * return an empty string.
+ * @return Filter instance name.
+ */
+ virtual QString userPlugInName();
+
+ private slots:
+ void slotLanguageBrowseButton_clicked();
+ void slotAddButton_clicked();
+ void slotUpButton_clicked();
+ void slotDownButton_clicked();
+ void slotEditButton_clicked();
+ void slotRemoveButton_clicked();
+ void slotMatchLineEdit_textChanged(const QString& text);
+ void slotTypeButtonGroup_clicked();
+ void slotMatchButton_clicked();
+ void slotLoadButton_clicked();
+ void slotSaveButton_clicked();
+ void slotClearButton_clicked();
+
+ // EnablesDisables buttons depending upon current item in list view.
+ void enableDisableButtons();
+
+ private:
+ // Displays the add/edit string replacement dialog.
+ void addOrEditSubstitution(bool isAdd);
+ // Loads word list and settings from a file. Clearing configuration if clear is True.
+ QString loadFromFile( const QString& filename, bool clear);
+ // Saves word list and settings to a file.
+ QString saveToFile( const QString& filename );
+
+
+ // Configuration Widget.
+ StringReplacerConfWidget* m_widget;
+ // Edit Dialog and widget.
+ KDialogBase* m_editDlg;
+ EditReplacementWidget* m_editWidget;
+ // True if kdeutils Regular Expression Editor is installed.
+ bool m_reEditorInstalled;
+ // Language Codes.
+ QStringList m_languageCodeList;
+};
+
+#endif //_STRINGREPLACERCONF_H_
diff --git a/kttsd/filters/stringreplacer/stringreplacerconfwidget.ui b/kttsd/filters/stringreplacer/stringreplacerconfwidget.ui
new file mode 100644
index 0000000..e88307f
--- /dev/null
+++ b/kttsd/filters/stringreplacer/stringreplacerconfwidget.ui
@@ -0,0 +1,474 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>StringReplacerConfWidget</class>
+<comment>Widget for configuring String Replacer Filter for KTTSD.</comment>
+<author>Gary Cramblitt &lt;garycramblitt@comcast.net&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>StringReplacerConfWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>548</width>
+ <height>421</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Configure String Replacer</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>nameLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Name:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nameLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter any name you like for this filter.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>nameLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter any name you like for this filter.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox" row="3" column="0">
+ <property name="name">
+ <cstring>applyGroupBox</cstring>
+ </property>
+ <property name="title">
+ <string>Apply This &amp;Filter When</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>These settings determines when the filter is applied to text.</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>languageLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Lan&amp;guage is:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>languageLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter is applied to text jobs of the specified language. You may select more than one language by clicking the browse button and Ctrl-clicking on more than one in the list. If blank the filter applies to all text jobs of any language.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>appIdLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Application &amp;ID contains:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>appIdLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter a DCOP Application ID. This filter will only apply to text jobs queued by that application. You may enter more than one ID separated by commas. If blank, this filter applies to text jobs queued by all applications. Tip: Use kdcop from the command line to get the Application IDs of running applications. Example: "konversation, kvirc,ksirc,kopete"</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>languageLineEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter is applied to text jobs of the specified language. You may select more than one language by clicking the browse button and Ctrl-clicking on more than one in the list. If blank the filter applies to all text jobs of any language.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>languageBrowseButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to select one or more languages. This filter will be applied to text jobs of those languages.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>appIdLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter a DCOP Application ID. This filter will only apply to text jobs queued by that application. You may enter more than one ID separated by commas. Use &lt;b&gt;knotify&lt;/b&gt; to match all messages sent as KDE notifications. If blank, this filter applies to text jobs queued by all applications. Tip: Use kdcop from the command line to get the Application IDs of running applications. Example: "konversation, kvirc,ksirc,kopete"&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>loadButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Load...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to load a word list from a file.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>saveButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Save...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to save word list to a file.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>clearButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>C&amp;lear</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to empty the word list.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>layout24</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView" row="0" column="0">
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Match Case</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Match</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Replace With</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>substLView</cstring>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout23</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>addButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Add...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to add another word or regular expression to the list.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>upButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Up</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to move selected word up in the list. Words higher in the list are applied first.</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>downButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Do&amp;wn</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to move a word down in the list. Words lower in the list are applied last.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>editButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Edit...</string>
+ </property>
+ <property name="toggleButton">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to modify an existing word or regular expression in the list.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>removeButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ <property name="toggleButton">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to remove a word or regular expression from the list.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer13</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>nameLineEdit</tabstop>
+ <tabstop>substLView</tabstop>
+ <tabstop>addButton</tabstop>
+ <tabstop>upButton</tabstop>
+ <tabstop>downButton</tabstop>
+ <tabstop>editButton</tabstop>
+ <tabstop>removeButton</tabstop>
+ <tabstop>loadButton</tabstop>
+ <tabstop>saveButton</tabstop>
+ <tabstop>clearButton</tabstop>
+ <tabstop>languageLineEdit</tabstop>
+ <tabstop>languageBrowseButton</tabstop>
+ <tabstop>appIdLineEdit</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klistview.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kttsd/filters/stringreplacer/stringreplacerplugin.cpp b/kttsd/filters/stringreplacer/stringreplacerplugin.cpp
new file mode 100644
index 0000000..c3f9678
--- /dev/null
+++ b/kttsd/filters/stringreplacer/stringreplacerplugin.cpp
@@ -0,0 +1,32 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generating the factories so String Replacer Filter can be used as plug in.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+#include <kgenericfactory.h>
+
+#include "stringreplacerconf.h"
+#include "stringreplacerproc.h"
+
+typedef K_TYPELIST_2( StringReplacerProc, StringReplacerConf ) StringReplacerPlugin;
+K_EXPORT_COMPONENT_FACTORY( libkttsd_stringreplacerplugin,
+ KGenericFactory<StringReplacerPlugin>("kttsd_stringreplacer") )
+
diff --git a/kttsd/filters/stringreplacer/stringreplacerproc.cpp b/kttsd/filters/stringreplacer/stringreplacerproc.cpp
new file mode 100644
index 0000000..1b03810
--- /dev/null
+++ b/kttsd/filters/stringreplacer/stringreplacerproc.cpp
@@ -0,0 +1,231 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic String Replacement Filter Processing class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+// Qt includes.
+#include <qdom.h>
+#include <qfile.h>
+#include <qlistview.h>
+
+// KDE includes.
+#include <kdebug.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+// KTTS includes.
+#include "filterproc.h"
+#include "talkercode.h"
+
+// StringReplacer includes.
+#include "stringreplacerproc.h"
+#include "stringreplacerproc.moc"
+
+/**
+ * Constructor.
+ */
+StringReplacerProc::StringReplacerProc( QObject *parent, const char *name, const QStringList& ) :
+ KttsFilterProc(parent, name)
+{
+}
+
+/**
+ * Destructor.
+ */
+/*virtual*/ StringReplacerProc::~StringReplacerProc()
+{
+ m_matchList.clear();
+ m_caseList.clear();
+ m_substList.clear();
+}
+
+/**
+ * Initialize the filter.
+ * @param config Settings object.
+ * @param configGroup Settings Group.
+ * @return False if filter is not ready to filter.
+ *
+ * Note: The parameters are for reading from kttsdrc file. Plugins may wish to maintain
+ * separate configuration files of their own.
+ */
+bool StringReplacerProc::init(KConfig* config, const QString& configGroup){
+ // kdDebug() << "StringReplacerProc::init: Running" << endl;
+ QString wordsFilename =
+ KGlobal::dirs()->saveLocation( "data" ,"kttsd/stringreplacer/", false );
+ if ( wordsFilename.isEmpty() ) return false;
+ wordsFilename += configGroup;
+ config->setGroup( configGroup );
+ wordsFilename = config->readEntry( "WordListFile", wordsFilename );
+
+ // Open existing word list.
+ QFile file( wordsFilename );
+ if ( !file.open( IO_ReadOnly ) )
+ return false;
+ QDomDocument doc( "" );
+ if ( !doc.setContent( &file ) ) {
+ file.close();
+ return false;
+ }
+ file.close();
+
+ // Clear list.
+ m_matchList.clear();
+ m_caseList.clear();
+ m_substList.clear();
+
+ // Name setting.
+ // QDomNodeList nameList = doc.elementsByTagName( "name" );
+ // QDomNode nameNode = nameList.item( 0 );
+ // m_widget->nameLineEdit->setText( nameNode.toElement().text() );
+
+ // Language Codes setting. List may be single element of comma-separated values,
+ // or multiple elements.
+ m_languageCodeList.clear();
+ QDomNodeList languageList = doc.elementsByTagName( "language-code" );
+ for ( uint ndx=0; ndx < languageList.count(); ++ndx )
+ {
+ QDomNode languageNode = languageList.item( ndx );
+ m_languageCodeList += QStringList::split(',', languageNode.toElement().text(), false);
+ }
+
+ // AppId. Apply this filter only if DCOP appId of application that queued
+ // the text contains this string. List may be single element of comma-separated values,
+ // or multiple elements.
+ m_appIdList.clear();
+ QDomNodeList appIdList = doc.elementsByTagName( "appid" );
+ for ( uint ndx=0; ndx < appIdList.count(); ++ndx )
+ {
+ QDomNode appIdNode = appIdList.item( ndx );
+ m_appIdList += QStringList::split(',', appIdNode.toElement().text(), false);
+ }
+
+ // Word list.
+ QDomNodeList wordList = doc.elementsByTagName("word");
+ const int wordListCount = wordList.count();
+ for (int wordIndex = 0; wordIndex < wordListCount; ++wordIndex)
+ {
+ QDomNode wordNode = wordList.item(wordIndex);
+ QDomNodeList propList = wordNode.childNodes();
+ QString wordType;
+ QString matchCase = "No"; // Default for old (v<=3.5.3) config files with no <case/>.
+ QString match;
+ QString subst;
+ const int propListCount = propList.count();
+ for (int propIndex = 0; propIndex < propListCount; ++propIndex)
+ {
+ QDomNode propNode = propList.item(propIndex);
+ QDomElement prop = propNode.toElement();
+ if (prop.tagName() == "type") wordType = prop.text();
+ if (prop.tagName() == "case") matchCase = prop.text();
+ if (prop.tagName() == "match") match = prop.text();
+ if (prop.tagName() == "subst") subst = prop.text();
+ }
+ // Build Regular Expression for each word's match string.
+ QRegExp rx;
+ rx.setCaseSensitive(matchCase == "Yes");
+ if ( wordType == "Word" )
+ {
+ // TODO: Does \b honor strange non-Latin1 encodings?
+ rx.setPattern( "\\b" + match + "\\b" );
+ }
+ else
+ {
+ rx.setPattern( match );
+ }
+ // Add Regular Expression to list (if valid).
+ if ( rx.isValid() )
+ {
+ m_matchList.append( rx );
+ m_substList.append( subst );
+ }
+ }
+ return true;
+}
+
+/**
+ * Convert input, returning output.
+ * @param inputText Input text.
+ * @param talkerCode TalkerCode structure for the talker that KTTSD intends to
+ * use for synthing the text. Useful for extracting hints about
+ * how to filter the text. For example, languageCode.
+ * @param appId The DCOP appId of the application that queued the text.
+ * Also useful for hints about how to do the filtering.
+ */
+/*virtual*/ QString StringReplacerProc::convert(const QString& inputText, TalkerCode* talkerCode, const QCString& appId)
+{
+ m_wasModified = false;
+ // If language doesn't match, return input unmolested.
+ if ( !m_languageCodeList.isEmpty() )
+ {
+ QString languageCode = talkerCode->languageCode();
+ // kdDebug() << "StringReplacerProc::convert: converting " << inputText <<
+ // " if language code " << languageCode << " matches " << m_languageCodeList << endl;
+ if ( !m_languageCodeList.contains( languageCode ) )
+ {
+ if ( !talkerCode->countryCode().isEmpty() )
+ {
+ languageCode += '_' + talkerCode->countryCode();
+ // kdDebug() << "StringReplacerProc::convert: converting " << inputText <<
+ // " if language code " << languageCode << " matches " << m_languageCodeList << endl;
+ if ( !m_languageCodeList.contains( languageCode ) ) return inputText;
+ } else return inputText;
+ }
+ }
+ // If appId doesn't match, return input unmolested.
+ if ( !m_appIdList.isEmpty() )
+ {
+ // kdDebug() << "StringReplacerProc::convert: converting " << inputText << " if appId "
+ // << appId << " matches " << m_appIdList << endl;
+ bool found = false;
+ QString appIdStr = appId;
+ for ( uint ndx=0; ndx < m_appIdList.count(); ++ndx )
+ {
+ if ( appIdStr.contains(m_appIdList[ndx]) )
+ {
+ found = true;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ // kdDebug() << "StringReplacerProc::convert: appId not found" << endl;
+ return inputText;
+ }
+ }
+ QString newText = inputText;
+ const int listCount = m_matchList.count();
+ for ( int index = 0; index < listCount; ++index )
+ {
+ //kdDebug() << "newtext = " << newText << " matching " << m_matchList[index].pattern() << " replacing with " << m_substList[index] << endl;
+ newText.replace( m_matchList[index], m_substList[index] );
+ }
+ m_wasModified = true;
+ return newText;
+}
+
+/**
+ * Did this filter do anything? If the filter returns the input as output
+ * unmolested, it should return False when this method is called.
+ */
+/*virtual*/ bool StringReplacerProc::wasModified() { return m_wasModified; }
+
diff --git a/kttsd/filters/stringreplacer/stringreplacerproc.h b/kttsd/filters/stringreplacer/stringreplacerproc.h
new file mode 100644
index 0000000..114ebaf
--- /dev/null
+++ b/kttsd/filters/stringreplacer/stringreplacerproc.h
@@ -0,0 +1,97 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic String Replacement Filter Processing class.
+ This is the interface definition for text filters.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+#ifndef _STRINGREPLACERPROC_H_
+#define _STRINGREPLACERPROC_H_
+
+// Qt includes.
+#include <qobject.h>
+#include <qtextstream.h>
+#include <qvaluelist.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+
+// KTTS includes.
+#include "filterproc.h"
+
+class StringReplacerProc : virtual public KttsFilterProc
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ */
+ StringReplacerProc( QObject *parent, const char *name, const QStringList &args = QStringList() );
+
+ /**
+ * Destructor.
+ */
+ virtual ~StringReplacerProc();
+
+ /**
+ * Initialize the filter.
+ * @param config Settings object.
+ * @param configGroup Settings Group.
+ * @return False if filter is not ready to filter.
+ *
+ * Note: The parameters are for reading from kttsdrc file. Plugins may wish to maintain
+ * separate configuration files of their own.
+ */
+ virtual bool init(KConfig *config, const QString &configGroup);
+
+ /**
+ * Convert input, returning output.
+ * @param inputText Input text.
+ * @param talkerCode TalkerCode structure for the talker that KTTSD intends to
+ * use for synthing the text. Useful for extracting hints about
+ * how to filter the text. For example, languageCode.
+ * @param appId The DCOP appId of the application that queued the text.
+ * Also useful for hints about how to do the filtering.
+ */
+ virtual QString convert(const QString& inputText, TalkerCode* talkerCode, const QCString& appId);
+
+ /**
+ * Did this filter do anything? If the filter returns the input as output
+ * unmolested, it should return False when this method is called.
+ */
+ virtual bool wasModified();
+
+private:
+ // Language codes supported by the filter.
+ QStringList m_languageCodeList;
+ // If not empty, apply filter only to apps containing one or more of these strings.
+ QStringList m_appIdList;
+
+ // List of regular expressions to match.
+ QValueList<QRegExp> m_matchList;
+ // List of match case flag
+ QValueList<QString> m_caseList;
+ // List of substitutions to replace matches.
+ QValueList<QString> m_substList;
+ // True if this filter did anything to the text.
+ bool m_wasModified;
+};
+
+#endif // _STRINGREPLACERPROC_H_
diff --git a/kttsd/filters/talkerchooser/Makefile.am b/kttsd/filters/talkerchooser/Makefile.am
new file mode 100644
index 0000000..66f857d
--- /dev/null
+++ b/kttsd/filters/talkerchooser/Makefile.am
@@ -0,0 +1,25 @@
+INCLUDES = \
+ -I$(top_srcdir)/kttsd/libkttsd -I$(top_builddir)/kttsd/libkttsd \
+ $(all_includes)
+
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = libkttsd_talkerchooserplugin.la
+
+libkttsd_talkerchooserplugin_la_SOURCES = \
+ talkerchooserconfwidget.ui \
+ talkerchooserconf.cpp \
+ talkerchooserproc.cpp \
+ talkerchooserplugin.cpp
+libkttsd_talkerchooserplugin_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries)
+libkttsd_talkerchooserplugin_la_LIBADD = $(top_builddir)/kttsd/libkttsd/libkttsd.la
+
+services_DATA = kttsd_talkerchooserplugin.desktop
+servicesdir = $(kde_servicesdir)
+
+# Install data files.
+talkerchooserdatadir = $(kde_datadir)/kttsd/talkerchooser/
+talkerchooserdata_DATA = \
+ female_notifications_rc
+
+noinst_HEADERS = talkerchooserconfwidget.h
diff --git a/kttsd/filters/talkerchooser/female_notifications_rc b/kttsd/filters/talkerchooser/female_notifications_rc
new file mode 100644
index 0000000..1cbd94c
--- /dev/null
+++ b/kttsd/filters/talkerchooser/female_notifications_rc
@@ -0,0 +1,10 @@
+[Filter]
+AppIDs=knotify
+Gender=*female
+LanguageCode=
+MatchRegExp=
+Rate=
+SynthName=
+TalkerCode=<voice gender="*female" />
+UserFilterName=Obsolete. Use Notifications tab instead.
+Volume=
diff --git a/kttsd/filters/talkerchooser/kttsd_talkerchooserplugin.desktop b/kttsd/filters/talkerchooser/kttsd_talkerchooserplugin.desktop
new file mode 100644
index 0000000..cdf1e45
--- /dev/null
+++ b/kttsd/filters/talkerchooser/kttsd_talkerchooserplugin.desktop
@@ -0,0 +1,89 @@
+[Desktop Entry]
+Name=Talker Chooser
+Name[bg]=Избор на глас
+Name[ca]=Selector de parla
+Name[cs]=Výběr hlasu
+Name[da]=Vælger af oplæser
+Name[de]=Sprecherauswahl
+Name[el]=Επιλογή εκφωνητή
+Name[es]=Selector de lectores
+Name[et]=Kõneleja valimine
+Name[fa]=انتخاب‌کنندۀ گوینده
+Name[fi]=Puhujan valitsin
+Name[fr]=Sélecteur de voix
+Name[ga]=Roghnóir Cainteora
+Name[gl]=Escolla de Locutor
+Name[hu]=Hangválasztó
+Name[is]=Talveljari
+Name[it]=Selezione dell'oratore
+Name[ja]=話者選択
+Name[ka]=მოლაპარაკის ამომრჩეველი
+Name[km]=ឧបករណ៍​ជ្រើស​អ្នក​និយាយ
+Name[mk]=Избирач на говорникот
+Name[ms]=Pemilih Penutur
+Name[nb]=Snakkervelger
+Name[nds]=Snacker-Utwahl
+Name[ne]=वक्ता चयनकर्ता
+Name[nl]=Spreker kiezen
+Name[pa]=ਬੋਲਚਾਲ ਚੋਣਕਾਰ
+Name[pl]=Wybieranie Mówców
+Name[pt]=Escolha de Orador
+Name[pt_BR]=Escolha do Talker
+Name[ru]=Диктор
+Name[sk]=Voľba hovorcu
+Name[sl]=Izbirnik govornika
+Name[sr]=Бирач говорника
+Name[sr@Latn]=Birač govornika
+Name[sv]=Urval av talare
+Name[ta]=டாக்கர் தேர்ந்தெடுப்பான்
+Name[tg]=Диктор
+Name[tr]=Konuşmacı Seçici
+Name[uk]=Вибір диктора
+Name[vi]=Trình chọn Máy nói
+Name[zh_TW]=語音選擇器
+Comment=Generic Talker Chooser Filter Plugin for KTTS
+Comment[bg]=Приставка за избор на глас за KTTS
+Comment[ca]=Connector del filtre selector genèric de parla pel KTTS
+Comment[cs]=Modul filtru výběru hlasu KTTS
+Comment[da]=Generisk vælger af oplæser for KTTS
+Comment[de]=Generischer Sprecherauswahlfilter für KTTS
+Comment[el]=Γενικό φίλτρο πρόσθετο επιλογής εκφωνητή για το KTTS
+Comment[es]=Complemento de audio para KTTSD
+Comment[et]=KTTS-i üldine kõneleja valimise filtri plugin
+Comment[eu]=KTTS-ren hizlariak hautatzeko iragazk-plugin generikoa
+Comment[fa]=وصلۀ پالایۀ انتخاب‌کنندۀ گویندۀ عمومی برای KTTS
+Comment[fi]=Yleinen puhujan valitsin suodatin liitännäinen KTTS-ohjelmalle
+Comment[fr]=Module de filtrage de sélection de voix pour KTTS
+Comment[gl]=Plugin para Escoller o Locutor para KTTS
+Comment[hu]=Általános hangkiválasztó modul a KTTS-hez
+Comment[is]=Almennt talvalsíforrit fyrir KTTS
+Comment[it]=Plugin generico per il filtro di scelta dell'oratore per KTTS
+Comment[ja]=KTTS 用汎用話者選択フィルタプラグイン
+Comment[ka]=მოლაპარაკის ამომრჩეველის ზოგადი ფილტრის მოდული KTTS-სთვის
+Comment[km]=កម្មវិធី​ជំនួយ​ឧបករណ៍​ជ្រើស​រើស​អ្នក​និយាយ​ទូទៅ​សម្រាប់ KTTS
+Comment[mk]=Филтер за KTTS за избирач на општ говорник
+Comment[ms]=Plugin Penapis Pemilih Penutur Generik bagi KTTS
+Comment[nb]=Filter-programtillegg til KTTS for snakkervalg
+Comment[nds]=KTTS-Filtermoduul för dat Utsöken vun den Snacker
+Comment[ne]=KTTS का लागि जेनेरीक वक्ता चयनकर्ता फिल्टर प्लगइन
+Comment[nl]=Generieke plugin om de spreker te kiezen voor KTTS
+Comment[pa]=KTTS ਲਈ ਸਧਾਰਨ ਬੋਲੀ ਚੋਣਕਾਰ ਫਿਲਟਰ ਪਲੱਗਿੰਨ
+Comment[pl]=Wtyczka wyboru Mówców dla KTTS
+Comment[pt]='Plugin' Genérico de Escolha de Orador para o KTTS
+Comment[pt_BR]=Plug-in de Filtro Genérico Para Escolha do Talker do KTTS
+Comment[ru]=Фильтр выбора диктора для KTTS
+Comment[sk]=Všeobecný modul filra na voľbu hovorcu v KTTS
+Comment[sl]=Filtrni vstavek KTTS za generični izbirnik govorca
+Comment[sr]=Генерички филтерски прикључак KTTS-а за бирач говорника
+Comment[sr@Latn]=Generički filterski priključak KTTS-a za birač govornika
+Comment[sv]=Insticksprogram för KTTS med generellt urvalsfilter för talare
+Comment[ta]=KTTS க்கான ஜெனரிக் பேச்சாளர் தேர்ந்தெடுப்பான அலங்கார சொருகுப்பொருள்
+Comment[tg]=Филтри интихоби диктор барои KTTS
+Comment[tr]=KTTS için Genel Konuşma Seçici Süzgeci Eklentisi
+Comment[uk]=Загальний втулок Фільтра вибору диктора для KTTS
+Comment[vi]=Trình bổ sung Lọc Chọn Máy nói Chung cho KTTS
+Comment[zh_TW]=KTTS 使用的語音選擇外掛程式
+Type=Service
+ServiceTypes=KTTSD/FilterPlugin
+X-KDE-Library=libkttsd_talkerchooserplugin
+X-KDE-Languages=en,en_US,en_GB,en_CA,es,es_mx,cy,de,fi,cs,pl
diff --git a/kttsd/filters/talkerchooser/talkerchooserconf.cpp b/kttsd/filters/talkerchooser/talkerchooserconf.cpp
new file mode 100644
index 0000000..0dbf53f
--- /dev/null
+++ b/kttsd/filters/talkerchooser/talkerchooserconf.cpp
@@ -0,0 +1,269 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic Talker Chooser Filter Configuration class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+// Qt includes.
+#include <qstring.h>
+#include <qhbox.h>
+#include <qlayout.h>
+
+// KDE includes.
+#include <klocale.h>
+#include <klineedit.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+#include <kcombobox.h>
+#include <kpushbutton.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kregexpeditorinterface.h>
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+#include <kfiledialog.h>
+
+// KTTS includes.
+
+// TalkerChooser includes.
+#include "talkerchooserconf.h"
+#include "talkerchooserconf.moc"
+
+/**
+* Constructor
+*/
+TalkerChooserConf::TalkerChooserConf( QWidget *parent, const char *name, const QStringList& /*args*/) :
+ KttsFilterConf(parent, name)
+{
+ // kdDebug() << "TalkerChooserConf::TalkerChooserConf: Running" << endl;
+
+ // Create configuration widget.
+ QVBoxLayout *layout = new QVBoxLayout(this, KDialog::marginHint(),
+ KDialog::spacingHint(), "TalkerChooserConfigWidgetLayout");
+ layout->setAlignment (Qt::AlignTop);
+ m_widget = new TalkerChooserConfWidget(this, "TalkerChooserConfigWidget");
+ layout->addWidget(m_widget);
+
+ // Determine if kdeutils Regular Expression Editor is installed.
+ m_reEditorInstalled = !KTrader::self()->query("KRegExpEditor/KRegExpEditor").isEmpty();
+ m_widget->reEditorButton->setEnabled(m_reEditorInstalled);
+
+ connect(m_widget->nameLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()));
+ connect(m_widget->reLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()));
+ connect(m_widget->reEditorButton, SIGNAL(clicked()),
+ this, SLOT(slotReEditorButton_clicked()));
+ connect(m_widget->appIdLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()));
+ connect(m_widget->talkerButton, SIGNAL(clicked()),
+ this, SLOT(slotTalkerButton_clicked()));
+
+ connect(m_widget->loadButton, SIGNAL(clicked()),
+ this, SLOT(slotLoadButton_clicked()));
+ connect(m_widget->saveButton, SIGNAL(clicked()),
+ this, SLOT(slotSaveButton_clicked()));
+ connect(m_widget->clearButton, SIGNAL(clicked()),
+ this, SLOT(slotClearButton_clicked()));
+
+ // Set up defaults.
+ defaults();
+}
+
+/**
+* Destructor.
+*/
+TalkerChooserConf::~TalkerChooserConf(){
+ // kdDebug() << "TalkerChooserConf::~TalkerChooserConf: Running" << endl;
+}
+
+/**
+* This method is invoked whenever the module should read its
+* configuration (most of the times from a config file) and update the
+* user interface. This happens when the user clicks the "Reset" button in
+* the control center, to undo all of his changes and restore the currently
+* valid settings. Note that kttsmgr calls this when the plugin is
+* loaded, so it not necessary to call it in your constructor.
+* The plugin should read its configuration from the specified group
+* in the specified config file.
+* @param config Pointer to a KConfig object.
+* @param configGroup Call config->setGroup with this argument before
+* loading your configuration.
+*/
+void TalkerChooserConf::load(KConfig* config, const QString& configGroup){
+ // kdDebug() << "TalkerChooserConf::load: Running" << endl;
+ config->setGroup( configGroup );
+ m_widget->nameLineEdit->setText( config->readEntry( "UserFilterName", m_widget->nameLineEdit->text() ) );
+ m_widget->reLineEdit->setText(
+ config->readEntry("MatchRegExp", m_widget->reLineEdit->text()) );
+ m_widget->appIdLineEdit->setText(
+ config->readEntry("AppIDs", m_widget->appIdLineEdit->text()) );
+
+ m_talkerCode = TalkerCode(config->readEntry("TalkerCode"), false);
+ // Legacy settings.
+ QString s = config->readEntry( "LanguageCode" );
+ if (!s.isEmpty()) m_talkerCode.setFullLanguageCode(s);
+ s = config->readEntry( "SynthInName" );
+ if (!s.isEmpty()) m_talkerCode.setPlugInName(s);
+ s = config->readEntry( "Gender" );
+ if (!s.isEmpty()) m_talkerCode.setGender(s);
+ s = config->readEntry( "Volume" );
+ if (!s.isEmpty()) m_talkerCode.setVolume(s);
+ s = config->readEntry( "Rate" );
+ if (!s.isEmpty()) m_talkerCode.setRate(s);
+
+ m_widget->talkerLineEdit->setText(m_talkerCode.getTranslatedDescription());
+}
+
+/**
+* This function gets called when the user wants to save the settings in
+* the user interface, updating the config files or wherever the
+* configuration is stored. The method is called when the user clicks "Apply"
+* or "Ok". The plugin should save its configuration in the specified
+* group of the specified config file.
+* @param config Pointer to a KConfig object.
+* @param configGroup Call config->setGroup with this argument before
+* saving your configuration.
+*/
+void TalkerChooserConf::save(KConfig* config, const QString& configGroup){
+ // kdDebug() << "TalkerChooserConf::save: Running" << endl;
+ config->setGroup( configGroup );
+ config->writeEntry( "UserFilterName", m_widget->nameLineEdit->text() );
+ config->writeEntry( "MatchRegExp", m_widget->reLineEdit->text() );
+ config->writeEntry( "AppIDs", m_widget->appIdLineEdit->text().replace(" ", "") );
+ config->writeEntry( "TalkerCode", m_talkerCode.getTalkerCode());
+}
+
+/**
+* This function is called to set the settings in the module to sensible
+* default values. It gets called when hitting the "Default" button. The
+* default values should probably be the same as the ones the application
+* uses when started without a config file. Note that defaults should
+* be applied to the on-screen widgets; not to the config file.
+*/
+void TalkerChooserConf::defaults(){
+ // kdDebug() << "TalkerChooserConf::defaults: Running" << endl;
+ // Default name.
+ m_widget->nameLineEdit->setText( i18n("Talker Chooser") );
+ // Default regular expression is blank.
+ m_widget->reLineEdit->setText( "" );
+ // Default App ID is blank.
+ m_widget->appIdLineEdit->setText( "" );
+ // Default to using default Talker.
+ m_talkerCode = TalkerCode( QString::null, false );
+ m_widget->talkerLineEdit->setText( m_talkerCode.getTranslatedDescription() );
+}
+
+/**
+ * Indicates whether the plugin supports multiple instances. Return
+ * False if only one instance of the plugin can be configured.
+ * @return True if multiple instances are possible.
+ */
+bool TalkerChooserConf::supportsMultiInstance() { return true; }
+
+/**
+ * Returns the name of the plugin. Displayed in Filters tab of KTTSMgr.
+ * If there can be more than one instance of a filter, it should return
+ * a unique name for each instance. The name should be TalkerCode::translated for
+ * the user if possible. If the plugin is not correctly configured,
+ * return an empty string.
+ * @return Filter instance name.
+ */
+QString TalkerChooserConf::userPlugInName()
+{
+ if (m_widget->talkerLineEdit->text().isEmpty()) return QString::null;
+ if (m_widget->appIdLineEdit->text().isEmpty() &&
+ m_widget->reLineEdit->text().isEmpty()) return QString::null;
+ QString instName = m_widget->nameLineEdit->text();
+ if (instName.isEmpty()) return QString::null;
+ return instName;
+}
+
+void TalkerChooserConf::slotReEditorButton_clicked()
+{
+ // Show Regular Expression Editor dialog if it is installed.
+ if ( !m_reEditorInstalled ) return;
+ QDialog *editorDialog =
+ KParts::ComponentFactory::createInstanceFromQuery<QDialog>( "KRegExpEditor/KRegExpEditor" );
+ if ( editorDialog )
+ {
+ // kdeutils was installed, so the dialog was found. Fetch the editor interface.
+ KRegExpEditorInterface *reEditor =
+ static_cast<KRegExpEditorInterface *>(editorDialog->qt_cast( "KRegExpEditorInterface" ) );
+ Q_ASSERT( reEditor ); // This should not fail!// now use the editor.
+ reEditor->setRegExp( m_widget->reLineEdit->text() );
+ int dlgResult = editorDialog->exec();
+ if ( dlgResult == QDialog::Accepted )
+ {
+ QString re = reEditor->regExp();
+ m_widget->reLineEdit->setText( re );
+ }
+ delete editorDialog;
+ } else return;
+}
+
+void TalkerChooserConf::slotTalkerButton_clicked()
+{
+ QString talkerCode = m_talkerCode.getTalkerCode();
+ SelectTalkerDlg dlg( m_widget, "selecttalkerdialog", i18n("Select Talker"), talkerCode, true );
+ int dlgResult = dlg.exec();
+ if ( dlgResult != KDialogBase::Accepted ) return;
+ m_talkerCode = TalkerCode( dlg.getSelectedTalkerCode(), false );
+ m_widget->talkerLineEdit->setText( m_talkerCode.getTranslatedDescription() );
+ configChanged();
+}
+
+void TalkerChooserConf::slotLoadButton_clicked()
+{
+ QString dataDir = KGlobal::dirs()->findAllResources("data", "kttsd/talkerchooser/").last();
+ QString filename = KFileDialog::getOpenFileName(
+ dataDir,
+ "*rc|Talker Chooser Config (*rc)",
+ m_widget,
+ "talkerchooser_loadfile");
+ if ( filename.isEmpty() ) return;
+ KConfig* cfg = new KConfig( filename, true, false, 0 );
+ load( cfg, "Filter" );
+ delete cfg;
+ configChanged();
+}
+
+void TalkerChooserConf::slotSaveButton_clicked()
+{
+ QString filename = KFileDialog::getSaveFileName(
+ KGlobal::dirs()->saveLocation( "data" ,"kttsd/talkerchooser/", false ),
+ "*rc|Talker Chooser Config (*rc)",
+ m_widget,
+ "talkerchooser_savefile");
+ if ( filename.isEmpty() ) return;
+ KConfig* cfg = new KConfig( filename, false, false, 0 );
+ save( cfg, "Filter" );
+ delete cfg;
+}
+
+void TalkerChooserConf::slotClearButton_clicked()
+{
+ m_widget->nameLineEdit->setText( QString::null );
+ m_widget->reLineEdit->setText( QString::null );
+ m_widget->appIdLineEdit->setText( QString::null );
+ m_talkerCode = TalkerCode( QString::null, false );
+ m_widget->talkerLineEdit->setText( m_talkerCode.getTranslatedDescription() );
+ configChanged();
+}
diff --git a/kttsd/filters/talkerchooser/talkerchooserconf.h b/kttsd/filters/talkerchooser/talkerchooserconf.h
new file mode 100644
index 0000000..d6b3959
--- /dev/null
+++ b/kttsd/filters/talkerchooser/talkerchooserconf.h
@@ -0,0 +1,134 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic Talker Chooser Filter Configuration class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+#ifndef _TALKERCHOOSERCONF_H_
+#define _TALKERCHOOSERCONF_H_
+
+// Qt includes.
+#include <qwidget.h>
+
+// KDE includes.
+#include <kconfig.h>
+#include <kdebug.h>
+
+// KTTS includes.
+#include "filterconf.h"
+#include "talkercode.h"
+#include "selecttalkerdlg.h"
+
+// TalkerChooser includes.
+#include "talkerchooserconfwidget.h"
+
+class KDialogBase;
+class EditReplacementWidget;
+
+class TalkerChooserConf : public KttsFilterConf
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor
+ */
+ TalkerChooserConf( QWidget *parent, const char *name, const QStringList &args = QStringList() );
+
+ /**
+ * Destructor
+ */
+ virtual ~TalkerChooserConf();
+
+ /**
+ * This method is invoked whenever the module should read its
+ * configuration (most of the times from a config file) and update the
+ * user interface. This happens when the user clicks the "Reset" button in
+ * the control center, to undo all of his changes and restore the currently
+ * valid settings. Note that KTTSMGR calls this when the plugin is
+ * loaded, so it not necessary to call it in your constructor.
+ * The plugin should read its configuration from the specified group
+ * in the specified config file.
+ * @param config Pointer to a KConfig object.
+ * @param configGroup Call config->setGroup with this argument before
+ * loading your configuration.
+ *
+ * When a plugin is first added to KTTSMGR, @e load will be called with
+ * a Null @e configGroup. In this case, the plugin will not have
+ * any instance-specific parameters to load, but it may still wish
+ * to load parameters that apply to all instances of the plugin.
+ */
+ virtual void load(KConfig *config, const QString &configGroup);
+
+ /**
+ * This function gets called when the user wants to save the settings in
+ * the user interface, updating the config files or wherever the
+ * configuration is stored. The method is called when the user clicks "Apply"
+ * or "Ok". The plugin should save its configuration in the specified
+ * group of the specified config file.
+ * @param config Pointer to a KConfig object.
+ * @param configGroup Call config->setGroup with this argument before
+ * saving your configuration.
+ */
+ virtual void save(KConfig *config, const QString &configGroup);
+
+ /**
+ * This function is called to set the settings in the module to sensible
+ * default values. It gets called when hitting the "Default" button. The
+ * default values should probably be the same as the ones the application
+ * uses when started without a config file. Note that defaults should
+ * be applied to the on-screen widgets; not to the config file.
+ */
+ virtual void defaults();
+
+ /**
+ * Indicates whether the plugin supports multiple instances. Return
+ * False if only one instance of the plugin can be configured.
+ * @return True if multiple instances are possible.
+ */
+ virtual bool supportsMultiInstance();
+
+ /**
+ * Returns the name of the plugin. Displayed in Filters tab of KTTSMgr.
+ * If there can be more than one instance of a filter, it should return
+ * a unique name for each instance. The name should be translated for
+ * the user if possible. If the plugin is not correctly configured,
+ * return an empty string.
+ * @return Filter instance name.
+ */
+ virtual QString userPlugInName();
+
+ private slots:
+ void slotReEditorButton_clicked();
+ void slotTalkerButton_clicked();
+ void slotLoadButton_clicked();
+ void slotSaveButton_clicked();
+ void slotClearButton_clicked();
+
+ private:
+ // Configuration Widget.
+ TalkerChooserConfWidget* m_widget;
+ // True if kdeutils Regular Expression Editor is installed.
+ bool m_reEditorInstalled;
+ // User's chosen Talker Code.
+ TalkerCode m_talkerCode;
+};
+
+#endif //_TALKERCHOOSERCONF_H_
diff --git a/kttsd/filters/talkerchooser/talkerchooserconfwidget.ui b/kttsd/filters/talkerchooser/talkerchooserconfwidget.ui
new file mode 100644
index 0000000..3cdee2e
--- /dev/null
+++ b/kttsd/filters/talkerchooser/talkerchooserconfwidget.ui
@@ -0,0 +1,319 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>TalkerChooserConfWidget</class>
+<comment>Widget for configuring Talker Chooser Filter for KTTSD.</comment>
+<author>Gary Cramblitt &lt;garycramblitt@comcast.net&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>TalkerChooserConfWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>547</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Configure Talker Chooser</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>nameLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Name:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nameLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter any name you like for this filter.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>nameLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter any name you like for this filter.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>applyGroupBox</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Apply This Filter When</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>These settings determines when the filter is applied to text.</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>reLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Te&amp;xt contains:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>reLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter is applied to text jobs of the specified language. You may select more than one language by clicking the browse button and Ctrl-clicking on more than one in the list. If blank, the filter applies to all text jobs of any language.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>appIdLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Application &amp;ID contains:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>appIdLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter a DCOP Application ID. This filter will only apply to text jobs queued by that application. You may enter more than one ID separated by commas. If blank, this filter applies to text jobs queued by all applications. Tip: Use kdcop from the command line to get the Application IDs of running applications. Example: "konversation, kvirc,ksirc,kopete"</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>reLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter is applied to text jobs of the specified language. You may select more than one language by clicking the browse button and Ctrl-clicking on more than one in the list. If blank, the filter applies to all text jobs of any language.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>reEditorButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to select one or more languages. This filter will be applied to text jobs of those languages.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>appIdLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter a DCOP Application ID. This filter will only apply to text jobs queued by that application. You may enter more than one ID separated by commas. Use &lt;b&gt;knotify&lt;/b&gt; to match all messages sent as KDE notifications. If blank, this filter applies to text jobs queued by all applications. Tip: Use kdcop from the command line to get the Application IDs of running applications. Example: "konversation, kvirc,ksirc,kopete"&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout19_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>talkerLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Talker:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>talkerLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The new Talker that will be used when the conditions above are met. The default Talker is the topmost in the Talkers tab. Click the button to choose a Talker.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>talkerLineEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="paletteForegroundColor">
+ <color>
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The new Talker that will be used when the conditions above are met. The default Talker is the topmost in the Talkers tab. Click the button to choose a Talker.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>talkerButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to select a Talker.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="0">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>loadButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Load...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to load a Talker Chooser configuration from a file.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>saveButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Save...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to save this Talker Chooser to a file.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>clearButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Cl&amp;ear</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to clear everything.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>nameLineEdit</tabstop>
+ <tabstop>reLineEdit</tabstop>
+ <tabstop>reEditorButton</tabstop>
+ <tabstop>appIdLineEdit</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kttsd/filters/talkerchooser/talkerchooserplugin.cpp b/kttsd/filters/talkerchooser/talkerchooserplugin.cpp
new file mode 100644
index 0000000..4181f6a
--- /dev/null
+++ b/kttsd/filters/talkerchooser/talkerchooserplugin.cpp
@@ -0,0 +1,32 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generating the factories so Talker Chooser Filter can be used as plug in.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+#include <kgenericfactory.h>
+
+#include "talkerchooserconf.h"
+#include "talkerchooserproc.h"
+
+typedef K_TYPELIST_2( TalkerChooserProc, TalkerChooserConf ) TalkerChooserPlugin;
+K_EXPORT_COMPONENT_FACTORY( libkttsd_talkerchooserplugin,
+ KGenericFactory<TalkerChooserPlugin>("kttsd_talkerchooser") )
+
diff --git a/kttsd/filters/talkerchooser/talkerchooserproc.cpp b/kttsd/filters/talkerchooser/talkerchooserproc.cpp
new file mode 100644
index 0000000..628b68a
--- /dev/null
+++ b/kttsd/filters/talkerchooser/talkerchooserproc.cpp
@@ -0,0 +1,148 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic Talker Chooser Filter Configuration class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+// Qt includes.
+#include <qregexp.h>
+
+// KDE includes.
+#include <kdebug.h>
+#include <kconfig.h>
+
+// KTTS includes.
+#include "talkercode.h"
+
+// Talker Chooser includes.
+#include "talkerchooserproc.h"
+#include "talkerchooserproc.moc"
+
+/**
+ * Constructor.
+ */
+TalkerChooserProc::TalkerChooserProc( QObject *parent, const char *name, const QStringList& /*args*/ ) :
+ KttsFilterProc(parent, name)
+{
+ // kdDebug() << "TalkerChooserProc::TalkerChooserProc: Running" << endl;
+}
+
+/**
+ * Destructor.
+ */
+TalkerChooserProc::~TalkerChooserProc()
+{
+ // kdDebug() << "TalkerChooserProc::~TalkerChooserProc: Running" << endl;
+}
+
+/**
+ * Initialize the filter.
+ * @param config Settings object.
+ * @param configGroup Settings Group.
+ * @return False if filter is not ready to filter.
+ *
+ * Note: The parameters are for reading from kttsdrc file. Plugins may wish to maintain
+ * separate configuration files of their own.
+ */
+bool TalkerChooserProc::init(KConfig* config, const QString& configGroup){
+ // kdDebug() << "PlugInProc::init: Running" << endl;
+ config->setGroup( configGroup );
+ m_re = config->readEntry( "MatchRegExp" );
+ m_appIdList = config->readListEntry( "AppIDs" );
+ m_chosenTalkerCode = TalkerCode(config->readEntry("TalkerCode"), false);
+ // Legacy settings.
+ QString s = config->readEntry( "LanguageCode" );
+ if (!s.isEmpty()) m_chosenTalkerCode.setFullLanguageCode(s);
+ s = config->readEntry( "SynthInName" );
+ if (!s.isEmpty()) m_chosenTalkerCode.setPlugInName(s);
+ s = config->readEntry( "Gender" );
+ if (!s.isEmpty()) m_chosenTalkerCode.setGender(s);
+ s = config->readEntry( "Volume" );
+ if (!s.isEmpty()) m_chosenTalkerCode.setVolume(s);
+ s = config->readEntry( "Rate" );
+ if (!s.isEmpty()) m_chosenTalkerCode.setRate(s);
+ return true;
+}
+
+/**
+ * Returns True if the plugin supports asynchronous processing,
+ * i.e., supports asyncConvert method.
+ * @return True if this plugin supports asynchronous processing.
+ *
+ * If the plugin returns True, it must also implement @ref getState .
+ * It must also emit @ref filteringFinished when filtering is completed.
+ * If the plugin returns True, it must also implement @ref stopFiltering .
+ * It must also emit @ref filteringStopped when filtering has been stopped.
+ */
+/*virtual*/ bool TalkerChooserProc::supportsAsync() { return false; }
+
+/**
+ * Convert input, returning output. Runs synchronously.
+ * @param inputText Input text.
+ * @param talkerCode TalkerCode structure for the talker that KTTSD intends to
+ * use for synthing the text. Useful for extracting hints about
+ * how to filter the text. For example, languageCode.
+ * @param appId The DCOP appId of the application that queued the text.
+ * Also useful for hints about how to do the filtering.
+ */
+/*virtual*/ QString TalkerChooserProc::convert(const QString& inputText, TalkerCode* talkerCode,
+ const QCString& appId)
+{
+ if ( !m_re.isEmpty() )
+ {
+ int pos = inputText.find( QRegExp(m_re) );
+ if ( pos < 0 ) return inputText;
+ }
+ // If appId doesn't match, return input unmolested.
+ if ( !m_appIdList.isEmpty() )
+ {
+ // kdDebug() << "TalkerChooserProc::convert: converting " << inputText << " if appId "
+ // << appId << " matches " << m_appIdList << endl;
+ bool found = false;
+ QString appIdStr = appId;
+ for ( uint ndx=0; ndx < m_appIdList.count(); ++ndx )
+ {
+ if ( appIdStr.contains(m_appIdList[ndx]) )
+ {
+ found = true;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ // kdDebug() << "TalkerChooserProc::convert: appId not found" << endl;
+ return inputText;
+ }
+ }
+
+ // Set the talker.
+ // kdDebug() << "TalkerChooserProc::convert: setting lang " << m_languageCode <<
+ // " gender " << m_gender << " synth " << m_synth <<
+ // " volume " << m_volume << " rate " << m_rate << endl;
+ // Only override the language if user specified a language code.
+ if (!m_chosenTalkerCode.fullLanguageCode().isEmpty())
+ talkerCode->setFullLanguageCode(m_chosenTalkerCode.fullLanguageCode());
+ talkerCode->setVoice(m_chosenTalkerCode.voice());
+ talkerCode->setGender(m_chosenTalkerCode.gender());
+ talkerCode->setPlugInName(m_chosenTalkerCode.plugInName());
+ talkerCode->setVolume(m_chosenTalkerCode.volume());
+ talkerCode->setRate(m_chosenTalkerCode.rate());
+ return inputText;
+}
diff --git a/kttsd/filters/talkerchooser/talkerchooserproc.h b/kttsd/filters/talkerchooser/talkerchooserproc.h
new file mode 100644
index 0000000..07cde68
--- /dev/null
+++ b/kttsd/filters/talkerchooser/talkerchooserproc.h
@@ -0,0 +1,87 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic Talker Chooser Filter Configuration class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+#ifndef _TALKERCHOOSERPROC_H_
+#define _TALKERCHOOSERPROC_H_
+
+// KTTS includes.
+#include "filterproc.h"
+#include "talkercode.h"
+
+class TalkerChooserProc : virtual public KttsFilterProc
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ */
+ TalkerChooserProc( QObject *parent, const char *name, const QStringList &args = QStringList() );
+
+ /**
+ * Destructor.
+ */
+ virtual ~TalkerChooserProc();
+
+ /**
+ * Initialize the filter.
+ * @param config Settings object.
+ * @param configGroup Settings Group.
+ * @return False if filter is not ready to filter.
+ *
+ * Note: The parameters are for reading from kttsdrc file. Plugins may wish to maintain
+ * separate configuration files of their own.
+ */
+ virtual bool init(KConfig *config, const QString &configGroup);
+
+ /**
+ * Returns True if the plugin supports asynchronous processing,
+ * i.e., supports asyncConvert method.
+ * @return True if this plugin supports asynchronous processing.
+ *
+ * If the plugin returns True, it must also implement @ref getState .
+ * It must also emit @ref filteringFinished when filtering is completed.
+ * If the plugin returns True, it must also implement @ref stopFiltering .
+ * It must also emit @ref filteringStopped when filtering has been stopped.
+ */
+ virtual bool supportsAsync();
+
+ /**
+ * Convert input, returning output. Runs synchronously.
+ * @param inputText Input text.
+ * @param talkerCode TalkerCode structure for the talker that KTTSD intends to
+ * use for synthing the text. Useful for extracting hints about
+ * how to filter the text. For example, languageCode.
+ * @param appId The DCOP appId of the application that queued the text.
+ * Also useful for hints about how to do the filtering.
+ */
+ virtual QString convert(const QString& inputText, TalkerCode* talkerCode, const QCString& appId);
+
+private:
+
+ QString m_re;
+ QStringList m_appIdList;
+ TalkerCode m_chosenTalkerCode;
+};
+
+#endif // _TALKERCHOOSERPROC_H_
diff --git a/kttsd/filters/xhtml2ssml/Doxyfile b/kttsd/filters/xhtml2ssml/Doxyfile
new file mode 100644
index 0000000..0061358
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/Doxyfile
@@ -0,0 +1,266 @@
+# Doxyfile 1.3.7-KDevelop
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = xhtml2ssml.kdevelop
+PROJECT_NUMBER = $VERSION$
+OUTPUT_DIRECTORY =
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = /home/paul/
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = /home/paul/Kdecvs/kdeaccessibility/kttsd/filters
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.C \
+ *.CC \
+ *.C++ \
+ *.II \
+ *.I++ \
+ *.H \
+ *.HH \
+ *.H++ \
+ *.CS \
+ *.PHP \
+ *.PHP3 \
+ *.M \
+ *.MM \
+ *.C \
+ *.H \
+ *.tlh \
+ *.diff \
+ *.patch \
+ *.moc \
+ *.xpm \
+ *.dox
+RECURSIVE = yes
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = yes
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE = xhtml2ssml.tag
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/kttsd/filters/xhtml2ssml/demonstration.html b/kttsd/filters/xhtml2ssml/demonstration.html
new file mode 100644
index 0000000..89bf8a3
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/demonstration.html
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <p>Isn't it such a nice and <strong>bold</strong> day today?</p>
+ </body>
+</html>
diff --git a/kttsd/filters/xhtml2ssml/main.cpp b/kttsd/filters/xhtml2ssml/main.cpp
new file mode 100644
index 0000000..822d068
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/main.cpp
@@ -0,0 +1,22 @@
+
+#include <qapplication.h>
+#include <qfile.h>
+#include <qxml.h>
+#include <qmap.h>
+#include <iostream>
+#include "xhtml2ssml.h"
+#include "xmlelement.h"
+
+int main(int argc, char *argv[]) {
+ QApplication a(argc, argv);
+ QFile f("demonstration.html");
+ QXmlInputSource input(&f);
+ QXmlSimpleReader reader;
+ XHTMLToSSMLParser *parser = new XHTMLToSSMLParser();
+ reader.setContentHandler(parser);
+ reader.parse(input);
+ std::cout << parser->convertedText() << "\n";
+ delete parser;
+ return 0;
+}
+
diff --git a/kttsd/filters/xhtml2ssml/tagmappingrc b/kttsd/filters/xhtml2ssml/tagmappingrc
new file mode 100644
index 0000000..425af8e
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/tagmappingrc
@@ -0,0 +1,5 @@
+# This is a comment
+# and another one
+# a html 'b' or 'strong' tag is mapped to 'emphasis level="strong"'
+b:emphasis level="strong"
+strong:emphasis level="strong"
diff --git a/kttsd/filters/xhtml2ssml/xhtml2ssml.cpp b/kttsd/filters/xhtml2ssml/xhtml2ssml.cpp
new file mode 100644
index 0000000..7c77b9e
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/xhtml2ssml.cpp
@@ -0,0 +1,105 @@
+
+
+/****************************************************************************
+ XHTMLToSSMLParser class
+
+ Parses a piece of XHTML markup and converts into SSML.
+ -------------------
+ Copyright:
+ (C) 2004 by Paul Giannaros <ceruleanblaze@gmail.com>
+ -------------------
+ Original author: Paul Giannaros <ceruleanblaze@gmail.com>
+******************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#include <qstring.h>
+#include <qdict.h>
+#include <qxml.h>
+#include <qfile.h>
+#include <iostream>
+
+#include "xmlelement.h"
+#include "xhtml2ssml.h"
+
+
+/// Document parsing begin. Init stuff here.
+bool XHTMLToSSMLParser::startDocument() {
+ /// Read the file which maps xhtml tags -> ssml tags. Look at the file for more information.
+ QFile file("tagmappingrc");
+ if(!file.open(IO_ReadOnly)) {
+ std::cerr << "Could not read config file 'tagmappingrc'. Please check that it exists and is readable.\n";
+ // Kill further parsing
+ return false;
+ }
+ QTextStream stream(&file);
+ // File parsing.
+ bool linestatus = true;
+ while(!stream.atEnd()) {
+ linestatus = readFileConfigEntry(stream.readLine());
+ // If there's some syntactical error in the file then return false.
+ if(!linestatus)
+ return false;
+ /// Maybe call processEvents() to prevent GUI blockages?
+ }
+ return true;
+}
+
+bool XHTMLToSSMLParser::startElement(const QString &, const QString &, const QString &qName, const QXmlAttributes &atts) {
+ QString attributes = "";
+ if(atts.length() > 0) {
+ const int attsLength = atts.lenght();
+ for(int i = 0; i < attsLength; ++i)
+ attributes += " " + atts.qName(i) + "=\"" + atts.value(i) + "\"";
+ }
+ QString fromelement = qName + attributes;
+ // If this element is one of the keys that was specified in the configuration file, get what it should be converted to and
+ // append to the output string.
+ QString toelement = m_xhtml2ssml[fromelement];
+ if(toelement)
+ m_output.append(XMLElement::fromQString(toelement).startTag());
+ return true;
+}
+
+bool XHTMLToSSMLParser::endElement(const QString &, const QString &, const QString &qName) {
+ QString fromelement = qName;
+ QString toelement = m_xhtml2ssml[fromelement];
+ if(toelement)
+ m_output.append(XMLElement::fromQString(toelement).endTag());
+ return true;
+}
+
+bool XHTMLToSSMLParser::characters(const QString &characters) {
+ m_output.append(characters);
+ return true;
+}
+
+
+QString XHTMLToSSMLParser::convertedText() {
+ return m_output.simplifyWhiteSpace();
+}
+
+/// Parse a line from the configuration file which maps xhtml : ssml equivalent.
+/// It makes entries in the m_xhtml2ssml map accordingly.
+/// @param line A line from a file to parse
+/// @returns true if the syntax of the line was okay and the parsing succeeded - false otherwise.
+bool XHTMLToSSMLParser::readFileConfigEntry(const QString &line) {
+ // comments
+ if(line.stripWhiteSpace().startsWith("#")) {
+ return true;
+ }
+ // break into QStringList
+ // the second parameter to split is the string, with all space simplified and all space around the : removed, i.e
+ // "something : somethingelse" -> "something:somethingelse"
+ QStringList keyvalue = QStringList::split(":", line.simplifyWhiteSpace().replace(" :", ":").replace(": ", ":"));
+ if(keyvalue.count() != 2)
+ return false;
+ m_xhtml2ssml[keyvalue[0]] = keyvalue[1];
+ return true;
+}
diff --git a/kttsd/filters/xhtml2ssml/xhtml2ssml.h b/kttsd/filters/xhtml2ssml/xhtml2ssml.h
new file mode 100644
index 0000000..7271dc0
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/xhtml2ssml.h
@@ -0,0 +1,61 @@
+
+/****************************************************************************
+ XHTMLToSSMLParser class
+
+ Parses a piece of XHTML markup and converts into SSML.
+ -------------------
+ Copyright:
+ (C) 2004 by Paul Giannaros <ceruleanblaze@gmail.com>
+ -------------------
+ Original author: Paul Giannaros <ceruleanblaze@gmail.com>
+******************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef _XHTML2SSML_H_
+#define _XHTML2SSML_H_
+
+#include <qxml.h>
+#include <qmap.h>
+
+typedef QMap<QString, QString> QStringMap;
+class QString;
+
+class XHTMLToSSMLParser : public QXmlDefaultHandler {
+
+public:
+ /// No need to reimplement constructor..
+ /// The document parsing starts
+ bool startDocument();
+ /// start of an element encountered (<element foo="bar">)
+ bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts);
+ /// end of an element encountered (</element>)
+ bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
+ /// text encountered (blah bah blah)
+ bool characters(const QString &);
+
+ /// Get the output text that was generated during the parsing.
+ /// @returns The converted text.
+ QString convertedText();
+
+ /// Parse a line from the configuration file which maps xhtml : ssml equivalent.
+ /// It makes entries in the m_xhtml2ssml map accordingly.
+ /// @param line A line from a file to parse
+ /// @returns true if the syntax of the line was okay and the parsing succeeded - false otherwise.
+ bool readFileConfigEntry(const QString &line);
+
+private:
+ /// Dict of xhtml tags -> ssml tags
+ QStringMap m_xhtml2ssml;
+ /// The output of the conversion
+ QString m_output;
+};
+
+#endif
diff --git a/kttsd/filters/xhtml2ssml/xhtml2ssml.kdevelop b/kttsd/filters/xhtml2ssml/xhtml2ssml.kdevelop
new file mode 100644
index 0000000..691735f
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/xhtml2ssml.kdevelop
@@ -0,0 +1,112 @@
+<?xml version = '1.0'?>
+<kdevelop>
+ <general>
+ <author>Paul Giannaros</author>
+ <email>ceruleanblaze@gmail.com</email>
+ <version>$VERSION$</version>
+ <projectmanagement>KDevTrollProject</projectmanagement>
+ <primarylanguage>C++</primarylanguage>
+ <keywords>
+ <keyword>Qt</keyword>
+ </keywords>
+ </general>
+ <kdevfileview>
+ <groups>
+ <group pattern="*.cpp;*.cxx;*.h" name="Sources" />
+ <group pattern="*.ui" name="User Interface" />
+ <group pattern="*.png" name="Icons" />
+ <group pattern="*" name="Others" />
+ <hidenonprojectfiles>false</hidenonprojectfiles>
+ <hidenonlocation>false</hidenonlocation>
+ </groups>
+ <tree>
+ <hidepatterns>*.o,*.lo,CVS</hidepatterns>
+ <hidenonprojectfiles>false</hidenonprojectfiles>
+ </tree>
+ </kdevfileview>
+ <kdevdoctreeview>
+ <ignoretocs>
+ <toc>bash</toc>
+ <toc>bash_bugs</toc>
+ <toc>clanlib</toc>
+ <toc>w3c-dom-level2-html</toc>
+ <toc>fortran_bugs_gcc</toc>
+ <toc>gnome1</toc>
+ <toc>gnustep</toc>
+ <toc>gtk</toc>
+ <toc>gtk_bugs</toc>
+ <toc>haskell</toc>
+ <toc>haskell_bugs_ghc</toc>
+ <toc>java_bugs_gcc</toc>
+ <toc>java_bugs_sun</toc>
+ <toc>kde2book</toc>
+ <toc>opengl</toc>
+ <toc>pascal_bugs_fp</toc>
+ <toc>php</toc>
+ <toc>php_bugs</toc>
+ <toc>perl</toc>
+ <toc>perl_bugs</toc>
+ <toc>python</toc>
+ <toc>python_bugs</toc>
+ <toc>qt-kdev3</toc>
+ <toc>ruby</toc>
+ <toc>ruby_bugs</toc>
+ <toc>sdl</toc>
+ <toc>stl</toc>
+ <toc>w3c-svg</toc>
+ <toc>sw</toc>
+ <toc>w3c-uaag10</toc>
+ <toc>wxwidgets_bugs</toc>
+ </ignoretocs>
+ <ignoredoxygen>
+ <toc>KDE Libraries (Doxygen)</toc>
+ </ignoredoxygen>
+ </kdevdoctreeview>
+ <kdevdebugger>
+ <general>
+ <dbgshell/>
+ </general>
+ </kdevdebugger>
+ <kdevfilecreate>
+ <useglobaltypes>
+ <type ext="ui" />
+ <type ext="cpp" />
+ <type ext="h" />
+ </useglobaltypes>
+ </kdevfilecreate>
+ <kdevtrollproject>
+ <general>
+ <activedir></activedir>
+ </general>
+ <run>
+ <directoryradio>executable</directoryradio>
+ </run>
+ </kdevtrollproject>
+ <kdevcppsupport>
+ <references>
+ <pcs>kdeincludedb</pcs>
+ <pcs>qtincludedb</pcs>
+ <pcs>qtincludesdb</pcs>
+ <pcs>kgmailtoincludedb</pcs>
+ </references>
+ <codecompletion>
+ <includeGlobalFunctions>true</includeGlobalFunctions>
+ <includeTypes>true</includeTypes>
+ <includeEnums>true</includeEnums>
+ <includeTypedefs>false</includeTypedefs>
+ <automaticCodeCompletion>true</automaticCodeCompletion>
+ <automaticArgumentsHint>true</automaticArgumentsHint>
+ <automaticHeaderCompletion>true</automaticHeaderCompletion>
+ <codeCompletionDelay>250</codeCompletionDelay>
+ <argumentsHintDelay>400</argumentsHintDelay>
+ <headerCompletionDelay>250</headerCompletionDelay>
+ </codecompletion>
+ </kdevcppsupport>
+ <kdevcvsservice>
+ <recursivewhenupdate>true</recursivewhenupdate>
+ <prunedirswhenupdate>true</prunedirswhenupdate>
+ <createdirswhenupdate>true</createdirswhenupdate>
+ <recursivewhencommitremove>true</recursivewhencommitremove>
+ <revertoptions>-C</revertoptions>
+ </kdevcvsservice>
+</kdevelop>
diff --git a/kttsd/filters/xhtml2ssml/xhtml2ssml.kdevelop.pcs b/kttsd/filters/xhtml2ssml/xhtml2ssml.kdevelop.pcs
new file mode 100644
index 0000000..4cdb884
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/xhtml2ssml.kdevelop.pcs
Binary files differ
diff --git a/kttsd/filters/xhtml2ssml/xhtml2ssml.kdevses b/kttsd/filters/xhtml2ssml/xhtml2ssml.kdevses
new file mode 100644
index 0000000..7128bc6
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/xhtml2ssml.kdevses
@@ -0,0 +1,38 @@
+<?xml version = '1.0' encoding = 'UTF-8'?>
+<!DOCTYPE KDevPrjSession>
+<KDevPrjSession>
+ <DocsAndViews NumberOfDocuments="5" >
+ <Doc0 NumberOfViews="1" URL="file:/home/paul/Kdecvs/kdeaccessibility/kttsd/filters/xhtml2ssml.cpp" >
+ <View0 line="63" Type="Source" />
+ </Doc0>
+ <Doc1 NumberOfViews="1" URL="file:/home/paul/Kdecvs/kdeaccessibility/kttsd/filters/xhtml2ssml.h" >
+ <View0 line="21" Type="Source" />
+ </Doc1>
+ <Doc2 NumberOfViews="1" URL="file:/home/paul/Kdecvs/kdeaccessibility/kttsd/filters/main.cpp" >
+ <View0 line="17" Type="Source" />
+ </Doc2>
+ <Doc3 NumberOfViews="1" URL="file:/home/paul/Kdecvs/kdeaccessibility/kttsd/filters/xmlelement.cpp" >
+ <View0 line="72" Type="Source" />
+ </Doc3>
+ <Doc4 NumberOfViews="1" URL="file:/home/paul/Kdecvs/kdeaccessibility/kttsd/filters/xmlelement.h" >
+ <View0 line="75" Type="Source" />
+ </Doc4>
+ </DocsAndViews>
+ <pluginList>
+ <kdevbookmarks>
+ <bookmarks/>
+ </kdevbookmarks>
+ <kdevsubversion>
+ <subversion recurseresolve="1" recurserelocate="1" recursemerge="1" recursecommit="1" base="" recursepropget="1" recurseswitch="1" recurseupdate="1" recursepropset="1" recursediff="1" recurserevert="1" forcemove="1" recursecheckout="1" forceremove="1" recurseadd="1" recurseproplist="1" forcemerge="1" />
+ </kdevsubversion>
+ <kdevvalgrind>
+ <executable path="" params="" />
+ <valgrind path="" params="" />
+ <calltree path="" params="" />
+ <kcachegrind path="" />
+ </kdevvalgrind>
+ <kdevdebugger>
+ <breakpointList/>
+ </kdevdebugger>
+ </pluginList>
+</KDevPrjSession>
diff --git a/kttsd/filters/xhtml2ssml/xhtml2ssml.pro b/kttsd/filters/xhtml2ssml/xhtml2ssml.pro
new file mode 100644
index 0000000..a9b5a4a
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/xhtml2ssml.pro
@@ -0,0 +1,10 @@
+######################################################################
+# Automatically generated by qmake (1.07a) Tue Dec 21 21:18:47 2004
+######################################################################
+
+TEMPLATE = app
+INCLUDEPATH += .
+
+# Input
+HEADERS += xhtml2ssml.h xmlelement.h
+SOURCES += main.cpp xhtml2ssml.cpp xmlelement.cpp
diff --git a/kttsd/filters/xhtml2ssml/xmlelement.cpp b/kttsd/filters/xhtml2ssml/xmlelement.cpp
new file mode 100644
index 0000000..53fa4f6
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/xmlelement.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+ XMLElement class
+
+ Representation of an XML element with methods for getting/setting
+ attributes and generating "opening" and "closing" tags.
+ -------------------
+ Copyright:
+ (C) 2004 by Paul Giannaros <ceruleanblaze@gmail.com>
+ -------------------
+ Original author: Paul Giannaros <ceruleanblaze@gmail.com>
+******************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#include "xmlelement.h"
+#include <qstringlist.h>
+#include <iostream>
+
+/// Constructors
+XMLElement::XMLElement() {
+ m_name = "";
+ m_attrmapper = AttributeToValueMap();
+}
+XMLElement::XMLElement(const QString &name) {
+ m_name = name;
+ m_attrmapper = AttributeToValueMap();
+}
+/// Destructor
+XMLElement::~XMLElement() {
+ return;
+}
+
+/// Copy constructor
+XMLElement::XMLElement(const XMLElement &element) {
+ m_attrmapper = element.m_attrmapper;
+ m_name = element.m_name;
+}
+
+/// Assignement operator
+XMLElement XMLElement::operator=(const XMLElement &element) {
+ m_attrmapper = element.m_attrmapper;
+ m_name = element.m_name;
+ return *this;
+}
+
+QString XMLElement::name() {
+ return m_name;
+}
+QString XMLElement::startTag() {
+ QString output = "<" + m_name + " ";
+ for(AttributeToValueMap::Iterator it = m_attrmapper.begin(); it != m_attrmapper.end(); ++it) {
+ output.append(it.key() + "=\"" + it.data() + "\" ");
+ }
+ output = output.left(output.length() - 1);
+ // Get rid of the space at the end and then append a '>'
+ output.append(">");
+ return output;
+}
+
+QString XMLElement::endTag() {
+ return "</" + m_name + ">";
+}
+
+void XMLElement::setAttribute(const QString &attr, const QString &value) {
+ m_attrmapper[attr] = value;
+}
+QString XMLElement::attribute(const QString &attr) {
+ return m_attrmapper[attr];
+}
+
+QString XMLElement::toQString() {
+ QString tag = startTag();
+ return tag.left(tag.length() - 1).right(tag.length() - 2);
+}
+
+XMLElement XMLElement::fromQString(const QString &str) {
+ QStringList sections = QStringList::split(" ", str);
+ QString tagname = sections[0];
+ XMLElement e(tagname.latin1());
+
+ sections.pop_front();
+ // Loop over the remaining strings which are attributes="values"
+ if(sections.count()) {
+ const int sectionsCount = sections.count();
+ for(int i = 0; i < sectionsCount; ++i) {
+ QStringList list = QStringList::split("=", sections[i]);
+ if(list.count() != 2) {
+ std::cerr << "XMLElement::fromQString: Cannot convert list: " << list.join("|") << ". `" << str << "' is not in valid format.\n";
+ return XMLElement(" ");
+ }
+ e.setAttribute(list[0], list[1].left(list[1].length() - 1).right(list[1].length() -2));
+ }
+ }
+ return e;
+}
+
diff --git a/kttsd/filters/xhtml2ssml/xmlelement.h b/kttsd/filters/xhtml2ssml/xmlelement.h
new file mode 100644
index 0000000..c78cd6f
--- /dev/null
+++ b/kttsd/filters/xhtml2ssml/xmlelement.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+ XMLElement class
+
+ Representation of an XML element with methods for getting/setting
+ attributes and generating "opening" and "closing" tags.
+ -------------------
+ Copyright:
+ (C) 2004 by Paul Giannaros <ceruleanblaze@gmail.com>
+ -------------------
+ Original author: Paul Giannaros <ceruleanblaze@gmail.com>
+******************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef XMLELEMENT_H
+#define XMLELEMENT_H
+
+#include <qmap.h>
+
+class QString;
+
+typedef QMap<QString, QString> AttributeToValueMap;
+
+class XMLElement {
+public:
+ XMLElement();
+ XMLElement(const QString &name);
+ ~XMLElement();
+
+ /// Copy constructor
+ XMLElement(const XMLElement &);
+
+ /// Assignment operator
+ XMLElement operator=(const XMLElement &element);
+
+ /// Get the name of the tag (the text between the greater than and less than symbols).
+ /// @returns the name of the tag.
+ QString name();
+
+ /// set the name of the tag.
+ /// @param name the new name of the tag.
+ void setName(const QString &name);
+
+ /// Get a textual representation of the starting of the tag with all attributes and their values set out.
+ /// @verbatim
+ /// XMLElement element("elem");
+ /// element.addAttribute("foo", "bar");
+ /// element.startTag(); <- <elem foo="bar">
+ /// @endverbatim
+ /// @returns A textual representation of the start of the element.
+ QString startTag();
+
+ /// Get a textual representation of the closed tag that XMLElement represents.
+ /// @returns A textual representation of the closed tag represented by the XMLElement.
+ QString endTag();
+
+ /// Create an attribute and set its value.
+ /// @param attr The attribute.
+ /// @param value The value of the attribute.
+ void setAttribute(const QString &attr, const QString &value);
+
+ /// Get the value of an attribute.
+ /// @param attr The attribute.
+ /// @returns The value of @param attr
+ QString attribute(const QString &attr);
+
+ /// Convert to a QString.
+ /// Had issues with QMap and custom classes. For now you can just convert to/from QString and use
+ /// That as the key/value pair.
+ /// @returns A QString representation of the XMLAttribute.
+ QString toQString();
+
+ /// Create an XMLElement from a QString.
+ /// @param str The QString to convert from. Must be of the following syntax- "foo name=\"bar\""
+ static XMLElement fromQString(const QString &str);
+
+private:
+ /// The name of the tag.
+ QString m_name;
+ /// Attribute : value mappings.
+ AttributeToValueMap m_attrmapper;
+};
+
+#endif
diff --git a/kttsd/filters/xmltransformer/Makefile.am b/kttsd/filters/xmltransformer/Makefile.am
new file mode 100644
index 0000000..93577e5
--- /dev/null
+++ b/kttsd/filters/xmltransformer/Makefile.am
@@ -0,0 +1,24 @@
+INCLUDES = \
+ -I$(top_srcdir)/kttsd/libkttsd -I$(top_builddir)/kttsd/libkttsd \
+ $(all_includes)
+
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = libkttsd_xmltransformerplugin.la
+
+libkttsd_xmltransformerplugin_la_SOURCES = \
+ xmltransformerconfwidget.ui \
+ xmltransformerconf.cpp \
+ xmltransformerproc.cpp \
+ xmltransformerplugin.cpp
+libkttsd_xmltransformerplugin_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries)
+libkttsd_xmltransformerplugin_la_LIBADD = $(top_builddir)/kttsd/libkttsd/libkttsd.la
+
+services_DATA = kttsd_xmltransformerplugin.desktop
+servicesdir = $(kde_servicesdir)
+
+# Install data files.
+xmltransformerdatadir = $(kde_datadir)/kttsd/xmltransformer/
+xmltransformerdata_DATA = xhtml2ssml.xsl xhtml2ssml_simple.xsl
+
+noinst_HEADERS = xmltransformerconfwidget.h
diff --git a/kttsd/filters/xmltransformer/kttsd_xmltransformerplugin.desktop b/kttsd/filters/xmltransformer/kttsd_xmltransformerplugin.desktop
new file mode 100644
index 0000000..6935088
--- /dev/null
+++ b/kttsd/filters/xmltransformer/kttsd_xmltransformerplugin.desktop
@@ -0,0 +1,88 @@
+[Desktop Entry]
+Name=XML Transformer
+Name[bg]=Трансформиране на XML
+Name[bs]=XML transformacije
+Name[ca]=Transformador XML
+Name[cs]=XML transformace
+Name[da]=XML Transformatør
+Name[de]=XML-Umformer
+Name[el]=XML μεταμορφωτής
+Name[es]=Transformador XML
+Name[et]=XML-i teisendus
+Name[fa]=تبدیل‌کنندۀ XML
+Name[fi]=XML-muunnin
+Name[fr]=Transformation XML
+Name[ga]=Trasfhoirmeoir XML
+Name[gl]=Transformador XML
+Name[hu]=XML-átalakító
+Name[is]=XML ummyndari
+Name[it]=Trasformatore XML
+Name[ja]=XML 変換
+Name[ka]=XML გარდამქმნელი
+Name[km]= កម្មវិធី​ប្លែង​ XML
+Name[mk]=XML-трансформирач
+Name[ms]=Transformer XML
+Name[nds]=XML-Ümwanneln
+Name[ne]=XML रुपान्तरणकर्ता
+Name[nl]=XML-omvormer
+Name[pa]=XML ਤਬਦੀਲੀਕਾਰ
+Name[pl]=Transformacja XML
+Name[pt]=Transformação de XML
+Name[pt_BR]=Transformador XML
+Name[ru]=Преобразователь XML
+Name[sk]=Transformácia XML
+Name[sl]=Pretvornik XML
+Name[sr]=XML трансформатор
+Name[sr@Latn]=XML transformator
+Name[sv]=XML-transformering
+Name[tg]=Тағйирдиҳии XML
+Name[tr]=XML Dönüştürücü
+Name[uk]=Перетворення XML
+Name[vi]=Trình chuyển đổi XML
+Name[zh_TW]=XML 轉換器
+Comment=Generic XML Tranformation Filter Plugin for KTTS
+Comment[bg]=Приставка филтър за трансформиране на XML за KTTS
+Comment[ca]=Connector del filtre genèric del transformador XML pel KTTS
+Comment[cs]=Modul filtru obecné XML transformace KTTS
+Comment[da]=Generisk XML Tranformationsfilter-plugin for KTTS
+Comment[de]=Generisches XML-Umformungs-Filtermodul für KTTS
+Comment[el]=Γενικό φίλτρο πρόσθετο XML μεταμόρφωσης για το KTTS
+Comment[es]=Complemento de Audio para KTTSD
+Comment[et]=KTTS-i üldine XML-i teisenduse filtri plugin
+Comment[eu]=KTTS-ren XML transformazioen iragazki-plugin generikoa
+Comment[fa]=وصلۀ پالایۀ انتقال XML عمومی برای KTTS
+Comment[fi]=Yleinen XML-muuntimen suodatin liitännäinen KTTS-ohjelmalle
+Comment[fr]=Module de filtrage de transformation XML générique pour KTTS
+Comment[gl]=Plugin de Transformación de XML para KTTS
+Comment[hu]=Általános XML-átalakító modul a KTTS-hez
+Comment[is]=Almennt XML ummynda íforrit fyrir KTTS
+Comment[it]=Plugin generico per il filtro di trasformazione XML per KTTS
+Comment[ja]=KTTS 用汎用 XML 変換フィルタプラグイン
+Comment[ka]=ზოგადი XML გარდამქმნელის ფილტრის მოდული KTTS-სთვის
+Comment[km]=កម្មវិធី​ជំនួស​តម្រង​ការ​ប្លែង​ XML ទូទៅ​សម្រាប់ KTTS
+Comment[mk]=Филтер за KTTS за трансформација на општ XML
+Comment[ms]=Plugin Penapis Transformasi XML Generik bagi KTTS
+Comment[nb]=Filter-programtillegg til KTTS for alminnelig XML-transformasjon
+Comment[nds]=KTTS-Filtermoduul för dat Ümwanneln vun XML
+Comment[ne]=KTTS का लागि जेनेरीक XML रुपान्तरण फिल्टर प्लगइन
+Comment[nl]=Generieke filterplugin voor XML-omvorming voor KTTS
+Comment[pa]=KTTS ਲਈ XML ਸੰਚਾਰ ਫਿਲਟਰ
+Comment[pl]=Wtyczka transformacji XML dla KTTS
+Comment[pt]='Plugin' Genérico de Transformação de XML para o KTTS
+Comment[pt_BR]=Plug-in de Filtro Genérico de Transformação XML: para o KTTSD
+Comment[ru]=Фильтр XML для KTTS
+Comment[sk]=Všeobecný modul filtra pre transformáciu XML v KTTS
+Comment[sl]=Filtrni vstavek KTTS za generično preoblikovanje XML
+Comment[sr]=Генерички филтерски прикључак KTTS-а за трансформацију XML-а
+Comment[sr@Latn]=Generički filterski priključak KTTS-a za transformaciju XML-a
+Comment[sv]=Insticksprogram för KTTS med generellt XML-transformeringsfilter
+Comment[ta]=KTTSக்கான ஜெனரிக் XML மாற்று அலங்கார சொருகுப்பொருள்
+Comment[tg]=Филтри XMLбарои KTTS
+Comment[tr]=KTTS için genel XML Dönüştürücü Süzgeci Eklentisi
+Comment[uk]=Втулок загального фільтра перетворення XML для KTTS
+Comment[vi]=Trình bổ sung Lọc Chuyển đổi XML Chung cho KTTS
+Comment[zh_TW]=KTTS 使用的一般 XML 轉換外掛程式
+Type=Service
+ServiceTypes=KTTSD/FilterPlugin
+X-KDE-Library=libkttsd_xmltransformerplugin
+X-KDE-Languages=en,en_US,en_GB,en_CA,es,es_mx,cy,de,fi,cs,pl
diff --git a/kttsd/filters/xmltransformer/xhtml2ssml.xsl b/kttsd/filters/xmltransformer/xhtml2ssml.xsl
new file mode 100644
index 0000000..5c7ca33
--- /dev/null
+++ b/kttsd/filters/xmltransformer/xhtml2ssml.xsl
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ***********************************************************************
+ Stylesheet for transforming XHTML into SSML markup.
+ ============
+ Copyright : (C) 2005 by Gary Cramblitt
+ ============
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+ ***************************************************************************
+
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ *************************************************************************** -->
+
+<!-- ***********************************************************************
+ The rendering is roughly based on the stylesheet from Appendix A of the
+ CSS2 specification, http://www.w3.org/TR/REC-CSS2/sample.html
+
+ @media speech {
+ H1, H2, H3,
+ H4, H5, H6 { voice-family: paul, male; stress: 20; richness: 90 }
+ H1 { pitch: x-low; pitch-range: 90 }
+ H2 { pitch: x-low; pitch-range: 80 }
+ H3 { pitch: low; pitch-range: 70 }
+ H4 { pitch: medium; pitch-range: 60 }
+ H5 { pitch: medium; pitch-range: 50 }
+ H6 { pitch: medium; pitch-range: 40 }
+ LI, DT, DD { pitch: medium; richness: 60 }
+ DT { stress: 80 }
+ PRE, CODE, TT { pitch: medium; pitch-range: 0; stress: 0; richness: 80 }
+ EM { pitch: medium; pitch-range: 60; stress: 60; richness: 50 }
+ STRONG { pitch: medium; pitch-range: 60; stress: 90; richness: 90 }
+ DFN { pitch: high; pitch-range: 60; stress: 60 }
+ S, STRIKE { richness: 0 }
+ I { pitch: medium; pitch-range: 60; stress: 60; richness: 50 }
+ B { pitch: medium; pitch-range: 60; stress: 90; richness: 90 }
+ U { richness: 0 }
+ A:link { voice-family: harry, male }
+ A:visited { voice-family: betty, female }
+ A:active { voice-family: betty, female; pitch-range: 80; pitch: x-high }
+}
+
+As SSML does not seem to offer an equivalent for "stress" and "richness".
+They are mapped to rate and volume respectively.
+
+ H1 { male; pitch: x-low; range: x-high; rate: slow; volume: x-loud}
+ H2 { male; pitch: x-low; range: high; rate: slow; volume: x-loud }
+ H3 { male; pitch: low; range: high; rate: slow; volume: x-loud }
+ H4 { male; pitch: medium; range: medium; rate: slow; volume: x-loud }
+ H5 { male; pitch: medium; range: low; rate: slow; volume: x-loud }
+ H6 { male; pitch: medium; range: x-low; rate: slow; volume: x-loud }
+ LI, DD { pitch: medium; }
+ DT { pitch: medium; rate: x-fast }
+ PRE, CODE, TT { pitch: medium; range: x-low; rate: slow; volume: loud }
+ EM { pitch: medium; range: medium; rate: medium; volume: loud }
+ STRONG { pitch: medium; range: medium; rate: x-fast; volume: x-loud }
+ DFN { pitch: high; range: medium; rate: medium }
+ S, STRIKE { volume: x-soft }
+ I { pitch: high; range: medium; rate: fast; volume: medium }
+ B { pitch: high; range: medium; rate: x-fast; volume: x-loud }
+ U { volume: medium }
+ A { female }
+
+ *********************************************************************** -->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="xml" indent="no"/>
+
+<!-- root -->
+<xsl:template match="/">
+ <xsl:apply-templates/>
+</xsl:template>
+
+<!-- html -->
+<!-- local-name() must be used in order to ignore namespaces. -->
+<xsl:template match="*[local-name()='html' or local-name()='HTML']">
+ <xsl:apply-templates/>
+</xsl:template>
+
+<!-- Ignore header, speak the body of xhtml document. -->
+<xsl:template match="*[local-name()='head' or local-name()='HEAD']"/>
+<xsl:template match="*[local-name()='body' or local-name()='BODY']">
+ <xsl:element name="speak">
+ <xsl:copy-of select="/html/@lang"/>
+ <xsl:copy-of select="/HTML/@lang"/>
+ <xsl:apply-templates/>
+ </xsl:element>
+</xsl:template>
+
+<!-- Paragraph -->
+<xsl:template match="*[local-name()='p' or local-name()='P']">
+ <p><xsl:apply-templates/></p>
+</xsl:template>
+
+<!-- H1 { pitch: x-low; range: x-high; rate: slow; volume: x-loud } -->
+<xsl:template match="*[local-name()='h1' or local-name()='H1']">
+ <voice gender="male"><prosody pitch="x-low" range="x-high" rate="slow" volume="x-loud">
+ <xsl:apply-templates/>
+ </prosody></voice>
+</xsl:template>
+
+<!-- H2 { male; pitch: x-low; range: high; rate: slow; volume: x-loud } -->
+<xsl:template match="*[local-name()='h2' or local-name()='H2']">
+ <voice gender="male"><prosody pitch="x-low" range="high" rate="slow" volume="x-loud">
+ <xsl:apply-templates/>
+ </prosody></voice>
+</xsl:template>
+
+<!-- H3 { male; pitch: low; range: high; rate: slow; volume: x-loud } -->
+<xsl:template match="*[local-name()='h3' or local-name()='H3']">
+ <voice gender="male"><prosody pitch="low" range="high" rate="slow" volume="x-loud">
+ <xsl:apply-templates/>
+ </prosody></voice>
+</xsl:template>
+
+<!-- H4 { male; pitch: medium; range: medium; rate: slow; volume: x-loud } -->
+<xsl:template match="*[local-name()='h4' or local-name()='H4']">
+ <voice gender="male"><prosody pitch="medium" range="medium" rate="slow" volume="x-loud">
+ <xsl:apply-templates/>
+ </prosody></voice>
+</xsl:template>
+
+<!-- H5 { male; pitch: medium; range: low; rate: slow; volume: x-loud } -->
+<xsl:template match="*[local-name()='h5' or local-name()='H5']">
+ <voice gender="male"><prosody pitch="low" range="low" rate="slow" volume="x-loud">
+ <xsl:apply-templates/>
+ </prosody></voice>
+</xsl:template>
+
+<!-- H6 { male; pitch: medium; range: x-low; rate: slow; volume: x-loud } -->
+<xsl:template match="*[local-name()='h6' or local-name()='H6']">
+ <voice gender="male"><prosody pitch="medium" range="x-low" rate="slow" volume="x-loud">
+ <xsl:apply-templates/>
+ </prosody></voice>
+</xsl:template>
+
+<!-- LI, DD { pitch: medium; } -->
+<xsl:template match="*[local-name()='li' or local-name()='LI']">
+ <prosody pitch="medium">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+<xsl:template match="*[local-name()='dd' or local-name()='DD']">
+ <prosody pitch="medium">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- DT { pitch: medium; rate: x-fast } -->
+<xsl:template match="*[local-name()='dt' or local-name()='DT']">
+ <prosody pitch="medium" rate="x-fast">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- PRE, CODE, TT { pitch: medium; range: x-low; rate: slow; volume: loud } -->
+<xsl:template match="*[local-name()='pre' or local-name()='PRE']">
+ <prosody pitch="medium" range="x-low" rate="slow" volume="loud">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+<xsl:template match="*[local-name()='code' or local-name()='CODE']">
+ <prosody pitch="medium" range="x-low" rate="slow" volume="loud">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+<xsl:template match="*[local-name()='tt' or local-name()='TT']">
+ <prosody pitch="medium" range="x-low" rate="slow" volume="loud">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- EM { pitch: medium; range: medium; rate: medium; volume: loud } -->
+<xsl:template match="*[local-name()='em' or local-name()='EM']">
+ <prosody pitch="medium" range="medium" rate="medium" volume="loud">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- STRONG { pitch: medium; range: medium; rate: x-fast; volume: x-loud } -->
+<xsl:template match="*[local-name()='strong' or local-name()='STRONG']">
+ <prosody pitch="medium" range="medium" rate="x-fast" volume="x-loud">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- DFN { pitch: high; range: medium; rate: medium } -->
+<xsl:template match="*[local-name()='dfn' or local-name()='DFN']">
+ <prosody pitch="high" range="medium" rate="medium">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- S, STRIKE { volume: x-soft } -->
+<xsl:template match="*[local-name()='s' or local-name()='S']">
+ <prosody volume="x-soft">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+<xsl:template match="*[local-name()='strike' or local-name()='STRIKE']">
+ <prosody volume="x-soft">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- I { pitch: high; range: medium; rate: fast; volume: medium } -->
+<xsl:template match="*[local-name()='i' or local-name()='I']">
+ <prosody pitch="high" range="medium" rate="fast" volume="medium">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- B { pitch: high; range: medium; rate: x-fast; volume: x-loud } -->
+<xsl:template match="*[local-name()='b' or local-name()='B']">
+ <prosody pitch="high" range="medium" rate="x-fast" volume="x-loud">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- U { volume: medium } -->
+<xsl:template match="*[local-name()='u' or local-name()='U']">
+ <prosody pitch="medium">
+ <xsl:apply-templates/>
+ </prosody>
+</xsl:template>
+
+<!-- A { female } -->
+<xsl:template match="*[local-name()='a' or local-name()='A']">
+ <voice gender="female">
+ <xsl:apply-templates/>
+ </voice>
+</xsl:template>
+
+<!-- HREF attribute -->
+<xsl:template match="@href">
+ <prosody volume="soft">Address</prosody>
+ <prosody rate="x-fast">
+ <xsl:value-of select="."/>
+ </prosody>
+</xsl:template>
+
+<!-- Ignore scripts. -->
+<xsl:template match="*[local-name()='script' or local-name()='SCRIPT']"/>
+
+<!-- Ignore styles. -->
+<xsl:template match="*[local-name()='style' or local-name()='STYLE']"/>
+
+</xsl:stylesheet>
diff --git a/kttsd/filters/xmltransformer/xhtml2ssml_simple.xsl b/kttsd/filters/xmltransformer/xhtml2ssml_simple.xsl
new file mode 100644
index 0000000..2c1f3be
--- /dev/null
+++ b/kttsd/filters/xmltransformer/xhtml2ssml_simple.xsl
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ***********************************************************************
+ Stylesheet for transforming XHTML into SSML markup.
+ ============
+ Copyright : (C) 2005 by Gary Cramblitt
+ ============
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+ ***************************************************************************
+
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ *************************************************************************** -->
+
+<!-- ***********************************************************************
+ The rendering takes a minimalist approach, mapping <b>, <em>, <i>
+ etc. to louder voices. Everything else is pretty much mapped to just
+ paragraph and sentence tags. Hyperlink addresses are spoken fast.
+ *********************************************************************** -->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="xml" indent="no"/>
+
+<!-- root -->
+<xsl:template match="/">
+ <xsl:apply-templates/>
+</xsl:template>
+
+<!-- html -->
+<!-- local-name() must be used in order to ignore namespaces. -->
+<xsl:template match="*[local-name()='html' or local-name()='HTML']">
+ <xsl:apply-templates/>
+</xsl:template>
+
+<!-- Ignore header, speak the body of xhtml document. -->
+<xsl:template match="*[local-name()='head' or local-name()='HEAD']"/>
+<xsl:template match="*[local-name()='body' or local-name()='BODY']">
+ <xsl:element name="speak">
+ <xsl:copy-of select="/html/@lang"/>
+ <xsl:copy-of select="/HTML/@lang"/>
+ <xsl:apply-templates/>
+ </xsl:element>
+</xsl:template>
+
+<!-- Paragraph -->
+<xsl:template match="*[local-name()='p' or local-name()='P']">
+ <xsl:apply-templates/>
+</xsl:template>
+
+<!-- H1, H2, H3, H4, H5, H6: ignore tag, speak content as sentence. -->
+<xsl:template match="*[contains('h1|h2|h3|h4|h5|h6|H1|H2|H3|H4|H5|H6|',concat(local-name(),'|'))]">
+ <xsl:apply-templates/>
+</xsl:template>
+
+<!-- DFN, LI, DD, DT: ignore tag, speak content. -->
+<xsl:template match="*[contains('dfn|li|dd|dt|DFN|LI|DD|DT|',concat(local-name(),'|'))]">
+ <xsl:apply-templates/>
+</xsl:template>
+
+<!-- PRE, CODE, TT; ignore tag, speak content. -->
+<xsl:template match="*[contains('pre|code|tt|PRE|CODE|TT|',concat(local-name(),'|'))]">
+ <xsl:apply-templates/>
+</xsl:template>
+
+<!-- EM, STRONG, I, B, S, STRIKE, U: speak emphasized. -->
+<xsl:template match="*[contains('em|strong|i|b|s|strike|EM|STRONG|I|B|S|STRIKE|',concat(local-name(),'|'))]">
+ <emphasis level="strong">
+ <xsl:apply-templates/>
+ </emphasis>
+</xsl:template>
+
+<!-- A: speak hyperlink emphasized, address fast. -->
+<xsl:template match="*[local-name()='a' or local-name()='A']">
+ <xsl:if test="@href">
+ <emphasis level="moderate">
+ <xsl:apply-templates/>
+ </emphasis>
+ <prosody rate="fast" volume="soft">
+ <xsl:value-of select="'Link to. '"/>
+ <xsl:value-of select="@href"/>
+ </prosody>
+ </xsl:if>
+</xsl:template>
+
+<!-- Ignore scripts. -->
+<xsl:template match="*[local-name()='script' or local-name()='SCRIPT']"/>
+
+<!-- Ignore styles. -->
+<xsl:template match="*[local-name()='style' or local-name()='STYLE']"/>
+
+</xsl:stylesheet>
diff --git a/kttsd/filters/xmltransformer/xmltransformerconf.cpp b/kttsd/filters/xmltransformer/xmltransformerconf.cpp
new file mode 100644
index 0000000..76cfd70
--- /dev/null
+++ b/kttsd/filters/xmltransformer/xmltransformerconf.cpp
@@ -0,0 +1,182 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic XML Transformation Filter Configuration class.
+ -------------------
+ Copyright:
+ (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
+ -------------------
+ Original author: Gary Cramblitt <garycramblitt@comcast.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ******************************************************************************/
+
+// Qt includes.
+#include <qstring.h>
+#include <qlayout.h>
+
+// KDE includes.
+#include <klocale.h>
+#include <klineedit.h>
+#include <kconfig.h>
+#include <kdialog.h>
+#include <kurlrequester.h>
+#include <kstandarddirs.h>
+
+// KTTS includes.
+#include "filterconf.h"
+
+// XmlTransformer includes.
+#include "xmltransformerconf.h"
+#include "xmltransformerconf.moc"
+
+/**
+* Constructor
+*/
+XmlTransformerConf::XmlTransformerConf( QWidget *parent, const char *name, const QStringList& /*args*/) :
+ KttsFilterConf(parent, name)
+{
+ // kdDebug() << "XmlTransformerConf::XmlTransformerConf: Running" << endl;
+
+ // Create configuration widget.
+ QVBoxLayout *layout = new QVBoxLayout(this, KDialog::marginHint(),
+ KDialog::spacingHint(), "XmlTransformerConfWidgetLayout");
+ layout->setAlignment (Qt::AlignTop);
+ m_widget = new XmlTransformerConfWidget(this, "XmlTransformerConfigWidget");
+ layout->addWidget(m_widget);
+
+ // Set up defaults.
+ defaults();
+
+ // Connect signals.
+ connect( m_widget->nameLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()));
+ connect( m_widget->xsltPath, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()) );
+ connect( m_widget->xsltprocPath, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()) );
+ connect( m_widget->rootElementLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()) );
+ connect( m_widget->doctypeLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()) );
+ connect( m_widget->appIdLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()) );
+}
+
+/**
+* Destructor.
+*/
+XmlTransformerConf::~XmlTransformerConf(){
+ // kdDebug() << "XmlTransformerConf::~XmlTransformerConf: Running" << endl;
+}
+
+/**
+* This method is invoked whenever the module should read its
+* configuration (most of the times from a config file) and update the
+* user interface. This happens when the user clicks the "Reset" button in
+* the control center, to undo all of his changes and restore the currently
+* valid settings. Note that kttsmgr calls this when the plugin is
+* loaded, so it not necessary to call it in your constructor.
+* The plugin should read its configuration from the specified group
+* in the specified config file.
+* @param config Pointer to a KConfig object.
+* @param configGroup Call config->setGroup with this argument before
+* loading your configuration.
+*/
+void XmlTransformerConf::load(KConfig* config, const QString& configGroup){
+ // kdDebug() << "XmlTransformerConf::load: Running" << endl;
+ config->setGroup( configGroup );
+ m_widget->nameLineEdit->setText( config->readEntry( "UserFilterName", m_widget->nameLineEdit->text() ) );
+ m_widget->xsltPath->setURL( config->readEntry( "XsltFilePath", m_widget->xsltPath->url() ) );
+ m_widget->xsltprocPath->setURL( config->readEntry( "XsltprocPath", m_widget->xsltprocPath->url() ) );
+ m_widget->rootElementLineEdit->setText(
+ config->readEntry( "RootElement", m_widget->rootElementLineEdit->text() ) );
+ m_widget->doctypeLineEdit->setText(
+ config->readEntry( "DocType", m_widget->doctypeLineEdit->text() ) );
+ m_widget->appIdLineEdit->setText(
+ config->readEntry( "AppID", m_widget->appIdLineEdit->text() ) );
+}
+
+/**
+* This function gets called when the user wants to save the settings in
+* the user interface, updating the config files or wherever the
+* configuration is stored. The method is called when the user clicks "Apply"
+* or "Ok". The plugin should save its configuration in the specified
+* group of the specified config file.
+* @param config Pointer to a KConfig object.
+* @param configGroup Call config->setGroup with this argument before
+* saving your configuration.
+*/
+void XmlTransformerConf::save(KConfig* config, const QString& configGroup){
+ // kdDebug() << "XmlTransformerConf::save: Running" << endl;
+ config->setGroup( configGroup );
+ config->writeEntry( "UserFilterName", m_widget->nameLineEdit->text() );
+ config->writeEntry( "XsltFilePath", realFilePath( m_widget->xsltPath->url() ) );
+ config->writeEntry( "XsltprocPath", realFilePath( m_widget->xsltprocPath->url() ) );
+ config->writeEntry( "RootElement", m_widget->rootElementLineEdit->text() );
+ config->writeEntry( "DocType", m_widget->doctypeLineEdit->text() );
+ config->writeEntry( "AppID", m_widget->appIdLineEdit->text().replace(" ", "") );
+}
+
+/**
+* This function is called to set the settings in the module to sensible
+* default values. It gets called when hitting the "Default" button. The
+* default values should probably be the same as the ones the application
+* uses when started without a config file. Note that defaults should
+* be applied to the on-screen widgets; not to the config file.
+*/
+void XmlTransformerConf::defaults(){
+ // kdDebug() << "XmlTransformerConf::defaults: Running" << endl;
+ // Default name.
+ m_widget->nameLineEdit->setText(i18n( "XML Transformer" ));
+ // Default XSLT path to installed xsl files.
+ m_widget->xsltPath->setURL( locate("data", "kttsd/xmltransformer/") );
+ // Default path to xsltproc.
+ m_widget->xsltprocPath->setURL( "xsltproc" );
+ // Default root element to "html".
+ m_widget->rootElementLineEdit->setText( "html" );
+ // Default doctype to blank.
+ m_widget->doctypeLineEdit->setText( "" );
+ // Default App ID to blank.
+ m_widget->appIdLineEdit->setText( "" );
+ // kdDebug() << "XmlTransformerConf::defaults: Exiting" << endl;
+}
+
+/**
+ * Indicates whether the plugin supports multiple instances. Return
+ * False if only one instance of the plugin can be configured.
+ * @return True if multiple instances are possible.
+ */
+bool XmlTransformerConf::supportsMultiInstance() { return true; }
+
+/**
+ * Returns the name of the plugin. Displayed in Filters tab of KTTSMgr.
+ * If there can be more than one instance of a filter, it should return
+ * a unique name for each instance. The name should be translated for
+ * the user if possible. If the plugin is not correctly configured,
+ * return an empty string.
+ * @return Filter instance name.
+ */
+QString XmlTransformerConf::userPlugInName()
+{
+ QString filePath = realFilePath(m_widget->xsltprocPath->url());
+ if (filePath.isEmpty()) return QString::null;
+ if (getLocation(filePath).isEmpty()) return QString::null;
+
+ filePath = realFilePath(m_widget->xsl