summaryrefslogtreecommitdiffstats
path: root/kttsd/filters/xmltransformer
diff options
context:
space:
mode:
Diffstat (limited to 'kttsd/filters/xmltransformer')
-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
10 files changed, 1593 insertions, 0 deletions
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->xsltPath->url());
+ if (filePath.isEmpty()) return QString::null;
+ if (getLocation(filePath).isEmpty()) return QString::null;
+ if (!QFileInfo(filePath).isFile()) return QString::null;
+
+ return m_widget->nameLineEdit->text();
+}
diff --git a/kttsd/filters/xmltransformer/xmltransformerconf.h b/kttsd/filters/xmltransformer/xmltransformerconf.h
new file mode 100644
index 0000000..86df0e2
--- /dev/null
+++ b/kttsd/filters/xmltransformer/xmltransformerconf.h
@@ -0,0 +1,120 @@
+/***************************************************** 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.
+ ******************************************************************************/
+
+#ifndef _XMLTRANSFORMERCONF_H_
+#define _XMLTRANSFORMERCONF_H_
+
+// Qt includes.
+#include <qwidget.h>
+
+// KDE includes.
+#include <kconfig.h>
+#include <kdebug.h>
+
+// KTTS includes.
+#include "filterconf.h"
+
+// XmlTransformer includes.
+#include "xmltransformerconfwidget.h"
+
+class XmlTransformerConf : public KttsFilterConf
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor
+ */
+ XmlTransformerConf( QWidget *parent, const char *name, const QStringList &args = QStringList() );
+
+ /**
+ * Destructor
+ */
+ virtual ~XmlTransformerConf();
+
+ /**
+ * 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:
+
+ private:
+ // Configuration Widget.
+ XmlTransformerConfWidget* m_widget;
+};
+
+#endif //_XMLTRANSFORMERCONF_H_
diff --git a/kttsd/filters/xmltransformer/xmltransformerconfwidget.ui b/kttsd/filters/xmltransformer/xmltransformerconfwidget.ui
new file mode 100644
index 0000000..4975d9c
--- /dev/null
+++ b/kttsd/filters/xmltransformer/xmltransformerconfwidget.ui
@@ -0,0 +1,249 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>XmlTransformerConfWidget</class>
+<author>Gary Cramblitt &lt;garycramblitt@comcast.net&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>XmlTransformerConfWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>548</width>
+ <height>256</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Configure XML Transformer</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>nameLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter any descriptive name you like for this filter.</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>xsltPath</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the full path to an XML Style Language - Transforms (XSLT) stylesheet file. XSLT files usually end with extension .xsl.</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>xsltprocPath</cstring>
+ </property>
+ <property name="url" stdset="0">
+ <string>xsltproc</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the path to the xsltproc executable program. If it is in the PATH environment variable, just enter "xsltproc".</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <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 descriptive name you like for this filter.</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>xsltLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;XSLT file:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>xsltPath</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the full path to an XML Style Language - Transforms (XSLT) stylesheet file. XSLT files usually end with extension .xsl.</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>xsltprocLabel</cstring>
+ </property>
+ <property name="text">
+ <string>xsltproc &amp;executable:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>xsltprocPath</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the path to the xsltproc executable program. If it is in the PATH environment variable, just enter "xsltproc".</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="2">
+ <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="1">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>rootElementLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter will be applied only to text having the specified XML root element. If blank, applies to all text. You may enter more than one root element separated by commas. Example: "html".</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>doctypeLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter will be applied only to text having the specified DOCTYPE specification. If blank, applies to all text. You may enter more than one DOCTYPE separated by commas. Example: "xhtml".</string>
+ </property>
+ </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 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 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>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>rootElementLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Root element is:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>rootElementLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter will be applied only to text having the specified XML root element. If blank, applies to all text. You may enter more than one root element separated by commas. Example: "html".</string>
+ <comment>What's this text</comment>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>doctypeLabel</cstring>
+ </property>
+ <property name="text">
+ <string>or DOC&amp;TYPE is:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>doctypeLineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This filter will be applied only to text having the specified DOCTYPE specification. If blank, applies to all text. You may enter more than one DOCTYPE separated by commas. Example: "xhtml".</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>appIdLabel</cstring>
+ </property>
+ <property name="text">
+ <string>and 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>&lt;qt&gt;Enter a DCOP Application ID. This filter will only apply to text 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 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>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/kttsd/filters/xmltransformer/xmltransformerplugin.cpp b/kttsd/filters/xmltransformer/xmltransformerplugin.cpp
new file mode 100644
index 0000000..c76c889
--- /dev/null
+++ b/kttsd/filters/xmltransformer/xmltransformerplugin.cpp
@@ -0,0 +1,31 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generating the factories so XML Transformer 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 "xmltransformerconf.h"
+#include "xmltransformerproc.h"
+
+typedef K_TYPELIST_2( XmlTransformerProc, XmlTransformerConf ) XmlTransformerPlugin;
+K_EXPORT_COMPONENT_FACTORY( libkttsd_xmltransformerplugin,
+ KGenericFactory<XmlTransformerPlugin>("kttsd_xmltransformer") )
diff --git a/kttsd/filters/xmltransformer/xmltransformerproc.cpp b/kttsd/filters/xmltransformer/xmltransformerproc.cpp
new file mode 100644
index 0000000..d4aa1c5
--- /dev/null
+++ b/kttsd/filters/xmltransformer/xmltransformerproc.cpp
@@ -0,0 +1,385 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic XML Transformation 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 <qfile.h>
+#include <qregexp.h>
+
+// KDE includes.
+#include <kdeversion.h>
+#include <kconfig.h>
+#include <ktempfile.h>
+#include <kstandarddirs.h>
+#include <kprocess.h>
+#include <kdebug.h>
+
+// KTTS includes.
+#include "filterproc.h"
+#include "utils.h"
+
+// XmlTransformer includes.
+#include "xmltransformerproc.h"
+#include "xmltransformerproc.moc"
+
+/**
+ * Constructor.
+ */
+XmlTransformerProc::XmlTransformerProc( QObject *parent, const char *name, const QStringList& ) :
+ KttsFilterProc(parent, name)
+{
+ m_xsltProc = 0;
+}
+
+/**
+ * Destructor.
+ */
+/*virtual*/ XmlTransformerProc::~XmlTransformerProc()
+{
+ delete m_xsltProc;
+ if (!m_inFilename.isEmpty()) QFile::remove(m_inFilename);
+ if (!m_outFilename.isEmpty()) QFile::remove(m_outFilename);
+}
+
+/**
+ * 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 XmlTransformerProc::init(KConfig* config, const QString& configGroup)
+{
+ // kdDebug() << "XmlTransformerProc::init: Running." << endl;
+ config->setGroup( configGroup );
+ m_UserFilterName = config->readEntry( "UserFilterName" );
+ m_xsltFilePath = config->readEntry( "XsltFilePath" );
+ m_xsltprocPath = config->readEntry( "XsltprocPath" );
+ m_rootElementList = config->readListEntry( "RootElement", ',' );
+ m_doctypeList = config->readListEntry( "DocType", ',' );
+ m_appIdList = config->readListEntry( "AppID", ',' );
+ kdDebug() << "XmlTransformerProc::init: m_xsltprocPath = " << m_xsltprocPath << endl;
+ kdDebug() << "XmlTransformerProc::init: m_xsltFilePath = " << m_xsltFilePath << endl;
+ return ( m_xsltFilePath.isEmpty() || m_xsltprocPath.isEmpty() );
+}
+
+/**
+ * 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 XmlTransformerProc::supportsAsync() { 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 XmlTransformerProc::convert(const QString& inputText, TalkerCode* talkerCode,
+ const QCString& appId)
+{
+ // kdDebug() << "XmlTransformerProc::convert: Running." << endl;
+ // If not properly configured, do nothing.
+ if ( m_xsltFilePath.isEmpty() || m_xsltprocPath.isEmpty() )
+ {
+ kdDebug() << "XmlTransformerProc::convert: not properly configured" << endl;
+ return inputText;
+ }
+ // Asynchronously convert and wait for completion.
+ if (asyncConvert(inputText, talkerCode, appId))
+ {
+ waitForFinished();
+ m_state = fsIdle;
+ return m_text;
+ } 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 XmlTransformerProc::asyncConvert(const QString& inputText, TalkerCode* /*talkerCode*/,
+ const QCString& appId)
+{
+ m_wasModified = false;
+
+ // kdDebug() << "XmlTransformerProc::asyncConvert: Running." << endl;
+ m_text = inputText;
+ // If not properly configured, do nothing.
+ if ( m_xsltFilePath.isEmpty() || m_xsltprocPath.isEmpty() )
+ {
+ kdDebug() << "XmlTransformerProc::asyncConvert: not properly configured." << endl;
+ return false;
+ }
+
+ bool found = false;
+ // If not correct XML type, or DOCTYPE, do nothing.
+ if ( !m_rootElementList.isEmpty() )
+ {
+ // kdDebug() << "XmlTransformerProc::asyncConvert:: searching for root elements " << m_rootElementList << endl;
+ for ( uint ndx=0; ndx < m_rootElementList.count(); ++ndx )
+ {
+ if ( KttsUtils::hasRootElement( inputText, m_rootElementList[ndx] ) )
+ {
+ found = true;
+ break;
+ }
+ }
+ if ( !found && m_doctypeList.isEmpty() )
+ {
+ kdDebug() << "XmlTransformerProc::asyncConvert: Did not find root element(s)" << m_rootElementList << endl;
+ return false;
+ }
+ }
+ if ( !found && !m_doctypeList.isEmpty() )
+ {
+ for ( uint ndx=0; ndx < m_doctypeList.count(); ++ndx )
+ {
+ if ( KttsUtils::hasDoctype( inputText, m_doctypeList[ndx] ) )
+ {
+ found = true;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ // kdDebug() << "XmlTransformerProc::asyncConvert: Did not find doctype(s)" << m_doctypeList << endl;
+ return false;
+ }
+ }
+
+ // If appId doesn't match, return input unmolested.
+ if ( !m_appIdList.isEmpty() )
+ {
+ QString appIdStr = appId;
+ // kdDebug() << "XmlTransformrProc::convert: converting " << inputText << " if appId "
+ // << appId << " matches " << m_appIdList << endl;
+ found = false;
+ for ( uint ndx=0; ndx < m_appIdList.count(); ++ndx )
+ {
+ if ( appIdStr.contains(m_appIdList[ndx]) )
+ {
+ found = true;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ // kdDebug() << "XmlTransformerProc::asyncConvert: Did not find appId(s)" << m_appIdList << endl;
+ return false;
+ }
+ }
+
+ /// Write @param text to a temporary file.
+ KTempFile inFile(locateLocal("tmp", "kttsd-"), ".xml");
+ m_inFilename = inFile.file()->name();
+ QTextStream* wstream = inFile.textStream();
+ if (wstream == 0) {
+ /// wtf...
+ kdDebug() << "XmlTransformerProc::convert: Can't write to " << m_inFilename << endl;;
+ return false;
+ }
+ // TODO: Is encoding an issue here?
+ // If input does not have xml processing instruction, add it.
+ if (!inputText.startsWith("<?xml")) *wstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+ // FIXME: Temporary Fix until Konqi returns properly formatted xhtml with & coded as &amp;
+ // This will change & inside a CDATA section, which is not good, and also within comments and
+ // processing instructions, which is OK because we don't speak those anyway.
+ QString text = inputText;
+ text.replace(QRegExp("&(?!amp;)"),"&amp;");
+ *wstream << text;
+ inFile.close();
+#if KDE_VERSION >= KDE_MAKE_VERSION (3,3,0)
+ inFile.sync();
+#endif
+
+ // Get a temporary output file name.
+ KTempFile outFile(locateLocal("tmp", "kttsd-"), ".output");
+ m_outFilename = outFile.file()->name();
+ outFile.close();
+ // outFile.unlink(); // only activate this if necessary.
+
+ /// Spawn an xsltproc process to apply our stylesheet to input file.
+ m_xsltProc = new KProcess;
+ *m_xsltProc << m_xsltprocPath;
+ *m_xsltProc << "-o" << m_outFilename << "--novalid"
+ << m_xsltFilePath << m_inFilename;
+ // Warning: This won't compile under KDE 3.2. See FreeTTS::argsToStringList().
+ // kdDebug() << "SSMLConvert::transform: executing command: " <<
+ // m_xsltProc->args() << endl;
+
+ m_state = fsFiltering;
+ connect(m_xsltProc, SIGNAL(processExited(KProcess*)),
+ this, SLOT(slotProcessExited(KProcess*)));
+ connect(m_xsltProc, SIGNAL(receivedStdout(KProcess*, char*, int)),
+ this, SLOT(slotReceivedStdout(KProcess*, char*, int)));
+ connect(m_xsltProc, SIGNAL(receivedStderr(KProcess*, char*, int)),
+ this, SLOT(slotReceivedStderr(KProcess*, char*, int)));
+ if (!m_xsltProc->start(KProcess::NotifyOnExit,
+ static_cast<KProcess::Communication>(KProcess::Stdout | KProcess::Stderr)))
+ {
+ kdDebug() << "XmlTransformerProc::convert: Error starting xsltproc" << endl;
+ m_state = fsIdle;
+ return false;
+ }
+ return true;
+}
+
+// Process output when xsltproc exits.
+void XmlTransformerProc::processOutput()
+{
+ QFile::remove(m_inFilename);
+
+ int exitStatus = 11;
+ if (m_xsltProc->normalExit())
+ exitStatus = m_xsltProc->exitStatus();
+ else
+ kdDebug() << "XmlTransformerProc::processOutput: xsltproc was killed." << endl;
+
+ delete m_xsltProc;
+ m_xsltProc = 0;
+
+ if (exitStatus != 0)
+ {
+ kdDebug() << "XmlTransformerProc::processOutput: xsltproc abnormal exit. Status = " << exitStatus << endl;
+ m_state = fsFinished;
+ QFile::remove(m_outFilename);
+ emit filteringFinished();
+ return;
+ }
+
+ /// Read back the data that was written to /tmp/fileName.output.
+ QFile readfile(m_outFilename);
+ if(!readfile.open(IO_ReadOnly)) {
+ /// uhh yeah... Issues writing to the output file.
+ kdDebug() << "XmlTransformerProc::processOutput: Could not read file " << m_outFilename << endl;
+ m_state = fsFinished;
+ emit filteringFinished();
+ }
+ QTextStream rstream(&readfile);
+ m_text = rstream.read();
+ readfile.close();
+
+ kdDebug() << "XmlTransformerProc::processOutput: Read file at " + m_inFilename + " and created " + m_outFilename + " based on the stylesheet at " << m_xsltFilePath << endl;
+
+ // Clean up.
+ QFile::remove(m_outFilename);
+
+ m_state = fsFinished;
+ m_wasModified = true;
+ emit filteringFinished();
+}
+
+/**
+ * Waits for a previous call to asyncConvert to finish.
+ */
+/*virtual*/ void XmlTransformerProc::waitForFinished()
+{
+ if (m_xsltProc)
+ {
+ if (m_xsltProc->isRunning())
+ {
+ if ( !m_xsltProc->wait( 15 ) )
+ {
+ m_xsltProc->kill();
+ kdDebug() << "XmlTransformerProc::waitForFinished: After waiting 15 seconds, xsltproc process seems to hung. Killing it." << endl;
+ processOutput();
+ }
+ }
+ }
+}
+
+/**
+ * Returns the state of the Filter.
+ */
+/*virtual*/ int XmlTransformerProc::getState() { return m_state; }
+
+/**
+ * Returns the filtered output.
+ */
+/*virtual*/ QString XmlTransformerProc::getOutput() { return m_text; }
+
+/**
+ * Acknowledges the finished filtering.
+ */
+/*virtual*/ void XmlTransformerProc::ackFinished()
+{
+ m_state = fsIdle;
+ m_text = QString::null;
+}
+
+/**
+ * Stops filtering. The filteringStopped signal will emit when filtering
+ * has in fact stopped and state returns to fsIdle;
+ */
+/*virtual*/ void XmlTransformerProc::stopFiltering()
+{
+ m_state = fsStopping;
+ m_xsltProc->kill();
+}
+
+/**
+ * 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 XmlTransformerProc::wasModified() { return m_wasModified; }
+
+void XmlTransformerProc::slotProcessExited(KProcess*)
+{
+ // kdDebug() << "XmlTransformerProc::slotProcessExited: xsltproc has exited." << endl;
+ processOutput();
+}
+
+void XmlTransformerProc::slotReceivedStdout(KProcess*, char* /*buffer*/, int /*buflen*/)
+{
+ // QString buf = QString::fromLatin1(buffer, buflen);
+ // kdDebug() << "XmlTransformerProc::slotReceivedStdout: Received from xsltproc: " << buf << endl;
+}
+
+void XmlTransformerProc::slotReceivedStderr(KProcess*, char* buffer, int buflen)
+{
+ QString buf = QString::fromLatin1(buffer, buflen);
+ kdDebug() << "XmlTransformerProc::slotReceivedStderr: Received error from xsltproc: " << buf << endl;
+}
+
diff --git a/kttsd/filters/xmltransformer/xmltransformerproc.h b/kttsd/filters/xmltransformer/xmltransformerproc.h
new file mode 100644
index 0000000..7c88dd1
--- /dev/null
+++ b/kttsd/filters/xmltransformer/xmltransformerproc.h
@@ -0,0 +1,167 @@
+/***************************************************** vim:set ts=4 sw=4 sts=4:
+ Generic XML Transformation 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.
+ ******************************************************************************/
+
+#ifndef _XMLTRANSFORMERPROC_H_
+#define _XMLTRANSFORMERPROC_H_
+
+// Qt includes.
+#include <qobject.h>
+#include <qstringlist.h>
+
+// KTTS includes.
+#include "filterproc.h"
+
+class KProcess;
+
+class XmlTransformerProc : virtual public KttsFilterProc
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ */
+ XmlTransformerProc( QObject *parent, const char *name, const QStringList &args = QStringList() );
+
+ /**
+ * Destructor.
+ */
+ virtual ~XmlTransformerProc();
+
+ /**
+ * 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.
+ * @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();
+
+private slots:
+ void slotProcessExited(KProcess*);
+ void slotReceivedStdout(KProcess* proc, char* buffer, int buflen);
+ void slotReceivedStderr(KProcess* proc, char* buffer, int buflen);
+
+private:
+ // Process output when xsltproc exits.
+ void processOutput();
+
+ // If not empty, only apply to text queued by an applications containing one of these strings.
+ QStringList m_appIdList;
+ // If not empty, only apply to XML that has the specified root element.
+ QStringList m_rootElementList;
+ // If not empty, only apply to XML that has the specified DOCTYPE spec.
+ QStringList m_doctypeList;
+ // The text that is being filtered.
+ QString m_text;
+ // Processing state.
+ int m_state;
+ // xsltproc process.
+ KProcess* m_xsltProc;
+ // Input and Output filenames.
+ QString m_inFilename;
+ QString m_outFilename;
+ // User's name for the filter.
+ QString m_UserFilterName;
+ // XSLT file.
+ QString m_xsltFilePath;
+ // Path to xsltproc processor.
+ QString m_xsltprocPath;
+ // Did this filter modify the text?
+ bool m_wasModified;
+};
+
+#endif // _XMLTRANSFORMERPROC_H_