1 /***************************************************** vim:set ts=4 sw=4 sts=4:
2 Generic String Replacement Filter Processing class.
5 (C) 2005 by Gary Cramblitt <garycramblitt@comcast.net>
7 Original author: Gary Cramblitt <garycramblitt@comcast.net>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 ******************************************************************************/
24 // StringReplacer includes.
25 #include "stringreplacerproc.h"
26 #include "stringreplacerproc.moc"
29 #include <QtXml/QDomDocument>
30 #include <QtCore/QFile>
36 #include <kconfiggroup.h>
38 #include <kstandarddirs.h>
41 #include "filterproc.h"
42 #include "talkercode.h"
47 StringReplacerProc::StringReplacerProc( QObject
*parent
, QVariantList list
) :
48 KttsFilterProc(parent
, list
)
55 /*virtual*/ StringReplacerProc::~StringReplacerProc()
62 * Initialize the filter.
63 * @param config Settings object.
64 * @param configGroup Settings Group.
65 * @return False if filter is not ready to filter.
67 * Note: The parameters are for reading from kttsdrc file. Plugins may wish to maintain
68 * separate configuration files of their own.
70 bool StringReplacerProc::init(KConfig
* c
, const QString
& configGroup
){
71 //kDebug() << "StringReplacerProc::init: Running";
72 QString wordsFilename
=
73 KGlobal::dirs()->saveLocation( "data" ,"kttsd/stringreplacer/", false );
74 if ( wordsFilename
.isEmpty() ) return false;
75 wordsFilename
+= configGroup
;
76 KConfigGroup
config( c
, configGroup
);
77 wordsFilename
= config
.readEntry( "WordListFile", wordsFilename
);
79 // Open existing word list.
80 QFile
file( wordsFilename
);
81 if ( !file
.open( QIODevice::ReadOnly
) )
83 //kDebug() << "StringReplacerProc::init: couldn't open file " << wordsFilename;
86 QDomDocument
doc( "" );
87 if ( !doc
.setContent( &file
) ) {
88 //kDebug() << "StringReplacerProc::init: couldn't get xml from file " << wordsFilename;
99 // QDomNodeList nameList = doc.elementsByTagName( "name" );
100 // QDomNode nameNode = nameList.item( 0 );
101 // m_widget->nameLineEdit->setText( nameNode.toElement().text() );
103 // Language Codes setting. List may be single element of comma-separated values,
104 // or multiple elements.
105 m_languageCodeList
.clear();
106 QDomNodeList languageList
= doc
.elementsByTagName( "language-code" );
107 for ( int ndx
=0; ndx
< languageList
.count(); ++ndx
)
109 QDomNode languageNode
= languageList
.item( ndx
);
110 m_languageCodeList
+= languageNode
.toElement().text().split( ',', QString::SkipEmptyParts
);
113 // AppId. Apply this filter only if DCOP appId of application that queued
114 // the text contains this string. List may be single element of comma-separated values,
115 // or multiple elements.
117 QDomNodeList appIdList
= doc
.elementsByTagName( "appid" );
118 for ( int ndx
=0; ndx
< appIdList
.count(); ++ndx
)
120 QDomNode appIdNode
= appIdList
.item( ndx
);
121 m_appIdList
+= appIdNode
.toElement().text().split( ',', QString::SkipEmptyParts
);
125 QDomNodeList wordList
= doc
.elementsByTagName("word");
126 const int wordListCount
= wordList
.count();
127 for (int wordIndex
= 0; wordIndex
< wordListCount
; ++wordIndex
)
129 QDomNode wordNode
= wordList
.item(wordIndex
);
130 QDomNodeList propList
= wordNode
.childNodes();
132 QString matchCase
= "No"; // Default for old (v<=3.5.3) config files with no <case/>.
135 const int propListCount
= propList
.count();
136 for (int propIndex
= 0; propIndex
< propListCount
; ++propIndex
)
138 QDomNode propNode
= propList
.item(propIndex
);
139 QDomElement prop
= propNode
.toElement();
140 if (prop
.tagName() == "type") wordType
= prop
.text();
141 if (prop
.tagName() == "case") matchCase
= prop
.text();
142 if (prop
.tagName() == "match") match
= prop
.text();
143 if (prop
.tagName() == "subst") subst
= prop
.text();
145 // Build Regular Expression for each word's match string.
147 rx
.setCaseSensitivity(matchCase
== "Yes"?Qt::CaseInsensitive
:Qt::CaseSensitive
);
148 if ( wordType
== "Word" )
150 // TODO: Does \b honor strange non-Latin1 encodings?
151 rx
.setPattern( "\\b" + match
+ "\\b" );
155 rx
.setPattern( match
);
157 // Add Regular Expression to list (if valid).
160 m_matchList
.append( rx
);
161 m_substList
.append( subst
);
168 * Convert input, returning output.
169 * @param inputText Input text.
170 * @param talkerCode TalkerCode structure for the talker that KTTSD intends to
171 * use for synthing the text. Useful for extracting hints about
172 * how to filter the text. For example, languageCode.
173 * @param appId The DCOP appId of the application that queued the text.
174 * Also useful for hints about how to do the filtering.
176 /*virtual*/ QString
StringReplacerProc::convert(const QString
& inputText
, TalkerCode
* talkerCode
,
177 const QString
& appId
)
179 m_wasModified
= false;
180 // If language doesn't match, return input unmolested.
181 if ( !m_languageCodeList
.isEmpty() )
183 QString languageCode
= talkerCode
->languageCode();
184 //kDebug() << "StringReplacerProc::convert: converting " << inputText <<
185 // " if language code " << languageCode << " matches " << m_languageCodeList << endl;
186 if ( !m_languageCodeList
.contains( languageCode
) )
188 if ( !talkerCode
->countryCode().isEmpty() )
190 languageCode
+= '_' + talkerCode
->countryCode();
191 //kDebug() << "StringReplacerProc::convert: converting " << inputText <<
192 // " if language code " << languageCode << " matches " << m_languageCodeList << endl;
193 if ( !m_languageCodeList
.contains( languageCode
) ) return inputText
;
194 } else return inputText
;
197 // If appId doesn't match, return input unmolested.
198 if ( !m_appIdList
.isEmpty() )
200 //kDebug() << "StringReplacerProc::convert: converting " << inputText << " if appId "
201 // << appId << " matches " << m_appIdList << endl;
203 QString appIdStr
= appId
;
204 for ( int ndx
=0; ndx
< m_appIdList
.count(); ++ndx
)
206 if ( appIdStr
.contains(m_appIdList
[ndx
]) )
214 //kDebug() << "StringReplacerProc::convert: appId not found";
218 QString newText
= inputText
;
219 const int listCount
= m_matchList
.count();
220 for ( int index
= 0; index
< listCount
; ++index
)
222 //kDebug() << "newtext = " << newText << " matching " << m_matchList[index].pattern() << " replacing with " << m_substList[index];
223 newText
.replace( m_matchList
[index
], m_substList
[index
] );
225 m_wasModified
= true;
230 * Did this filter do anything? If the filter returns the input as output
231 * unmolested, it should return False when this method is called.
233 /*virtual*/ bool StringReplacerProc::wasModified() { return m_wasModified
; }