00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <qdom.h>
00023 #include <QFile>
00024 #include <QTextCodec>
00025 #include <QString>
00026
00027 #include <klocale.h>
00028 #include <kapplication.h>
00029 #include <kstandarddirs.h>
00030 #include <kstaticdeleter.h>
00031
00032 #include "kohyphen.h"
00033 #include <kdebug.h>
00034
00035
00036
00037
00038 KoHyphenator* KoHyphenator::s_self;
00039 static KStaticDeleter<KoHyphenator> kohyphensd;
00040
00041 KoHyphenator* KoHyphenator::self()
00042 {
00043 if ( !s_self )
00044 kohyphensd.setObject( s_self, new KoHyphenator );
00045 return s_self;
00046 }
00047
00048 KoHyphenator::KoHyphenator()
00049 {
00050
00051
00052 QString path = kapp->dirs()->findResource("data", "koffice/hyphdicts/dicts.xml");
00053 #ifdef DEBUG_HYPHENATOR
00054 kDebug() << path << endl;
00055 #endif
00056
00057 QFile *f;
00058 if (!path.isNull())
00059 f = new QFile(path);
00060 else
00061 throw KoHyphenatorException( "Could not create KoHyphenator instance." );
00062
00063 QDomDocument config;
00064 QDomNodeList records;
00065 config.setContent(f);
00066
00067 for (QDomNode n = config.firstChild(); !n.isNull(); n = n.nextSibling())
00068 if (n.nodeName() == "dicts")
00069 {
00070 records = n.childNodes();
00071 for (uint i = 0; i < records.count(); i++)
00072 {
00073 QDomNamedNodeMap attr = records.item(i).attributes();
00074 if (attr.contains("lang") && attr.contains("encoding")) {
00075 QString lang = attr.namedItem("lang").nodeValue();
00076 QString encoding = attr.namedItem("encoding").nodeValue();
00077 #ifdef DEBUG_HYPHENATOR
00078 kDebug() << "KoHyphenator: found lang=" << lang << " encoding=" << encoding << endl;
00079 #endif
00080 encodings.insert( lang,
00081 EncodingStruct( encoding.latin1() ) );
00082 }
00083 }
00084 }
00085
00086 delete f;
00087 }
00088
00089 KoHyphenator::~KoHyphenator()
00090 {
00091 for (QMap<QString, HyphenDict*>::iterator it = dicts.begin(); it != dicts.end(); ++it)
00092 {
00093 if ((*it) != 0)
00094 hnj_hyphen_free((*it));
00095 }
00096 }
00097
00098 char *KoHyphenator::hyphens(const QString& str, const QString& lang) const
00099 {
00100 char *x = new char[str.length()+1];
00101 try
00102 {
00103 QTextCodec *codec = codecForLang(lang);
00104 hnj_hyphen_hyphenate(dict(lang), (const char *)(codec->fromUnicode(str)), str.length(), x);
00105 }
00106 catch (KoHyphenatorException &e)
00107 {
00108 #ifdef DEBUG_HYPHENATOR
00109 kDebug() << e.message().latin1() << endl;
00110 #endif
00111 for (uint j = 0; j < str.length(); j++)
00112 x[j] = '0';
00113 x[str.length()] = '\0';
00114 }
00115 return x;
00116 }
00117
00118 QString KoHyphenator::hyphenate(const QString& str, const QString& lang) const
00119 {
00120 char* x = new char[str.length()+1];
00121 QString res = str;
00122 try
00123 {
00124 QTextCodec *codec = codecForLang(lang);
00125 hnj_hyphen_hyphenate(dict(lang), (const char *)(codec->fromUnicode(str)), str.length(), x);
00126 }
00127 catch (KoHyphenatorException &e)
00128 {
00129 #ifdef DEBUG_HYPHENATOR
00130 kDebug() << e.message() << endl;
00131 #endif
00132 delete[] x;
00133 return str;
00134 }
00135 int i = 0, j = 0;
00136 int len = strlen(x);
00137 for (; i < len; i++)
00138 {
00139 #ifdef DEBUG_HYPHENATOR
00140 kDebug() << "loop: i=" << i << ", j=" << j << ", x=" << x << ", res=" << res << endl;
00141 #endif
00142 if ((x[i] % 2) != 0)
00143 {
00144 res.insert(j+1, QChar(0xad));
00145 j++;
00146 }
00147 j++;
00148 }
00149 delete[] x;
00150 return res;
00151 }
00152
00153 bool KoHyphenator::checkHyphenPos(const QString& str, int pos, const QString& lang) const
00154 {
00155 #ifdef DEBUG_HYPHENATOR
00156 kDebug() << "string: " << str << endl;
00157 #endif
00158
00159 char *hyph = hyphens(str, lang);
00160
00161 #ifdef DEBUG_HYPHENATOR
00162 kDebug() << "result: " << hyph << endl;
00163 kDebug() << "checked position: " << pos << endl;
00164 #endif
00165 bool ret = ((hyph[pos] % 2) != 0);
00166 delete[] hyph;
00167 return ret;
00168 }
00169
00170 HyphenDict *KoHyphenator::dict(const QString &_lang) const
00171 {
00172 QString lang( _lang );
00173
00174 if (encodings.find(lang) == encodings.end())
00175 {
00176 int underscore = lang.find('_');
00177 if ( underscore > -1 ) {
00178 lang.truncate( underscore );
00179 if (encodings.find(lang) == encodings.end())
00180 throw KoHyphenatorException( QString("No dictionary for %1").arg(lang) );
00181 }
00182 else
00183 throw KoHyphenatorException( QString("No dictionary for %1").arg(lang) );
00184 }
00185 if (dicts.find(lang) == dicts.end())
00186 {
00187 #ifdef DEBUG_HYPHENATOR
00188 kDebug() << "Searching dictionary for '" << lang << "' language..." << endl;
00189 #endif
00190 QString path = kapp->dirs()->findResource("data", "koffice/hyphdicts/hyph_" + lang + ".dic");
00191 if (!path.isNull())
00192 {
00193 #ifdef DEBUG_HYPHENATOR
00194 kDebug() << "Loading dictionary for '" << lang << "' language: path = " << path << endl;
00195 #endif
00196 const_cast<KoHyphenator*>(this)->dicts.insert( lang, hnj_hyphen_load(QFile::encodeName(path)) );
00197 if (dicts.find(lang) == dicts.end())
00198 {
00199 #ifdef DEBUG_HYPHENATOR
00200 kDebug() << "No dictionary loaded" << endl;
00201 #endif
00202 throw(KoHyphenatorException( QString("Could not load dictionary for the language: %1").arg(lang) ));
00203 }
00204 }
00205 else
00206 throw(KoHyphenatorException( QString("Could not load dictionary for the language: %1").arg(lang) ));
00207 }
00208 return dicts[lang];
00209 }
00210
00211 QTextCodec* KoHyphenator::codecForLang(const QString& lang) const
00212 {
00213 EncodingMap::Iterator it = encodings.find(lang);
00214 if (it == encodings.end())
00215 {
00216 int underscore = lang.find('_');
00217 if ( underscore > -1 ) {
00218 QString _lang( lang );
00219 _lang.truncate( underscore );
00220 it = encodings.find(_lang);
00221 }
00222 }
00223 if (it != encodings.end())
00224 {
00225 if ( (*it).codec )
00226 return (*it).codec;
00227 (*it).codec = QTextCodec::codecForName((*it).encoding);
00228 return (*it).codec;
00229 }
00230 return QTextCodec::codecForMib(106);
00231 }