KUtils
kemoticonstheme.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kemoticonstheme.h"
00023 #include "kemoticons.h"
00024
00025 #include <QtCore/QFileInfo>
00026 #include <QtCore/QDir>
00027 #include <QtGui/QTextDocument>
00028 #include <QtCore/QtAlgorithms>
00029
00030 #include <kio/netaccess.h>
00031 #include <kstandarddirs.h>
00032 #include <kdebug.h>
00033
00034 class KEmoticonsTheme::KEmoticonsThemeData : public QSharedData
00035 {
00036 public:
00037 KEmoticonsThemeData();
00038 ~KEmoticonsThemeData();
00039 KEmoticonsProvider *provider;
00040 };
00041
00042
00043 KEmoticonsTheme::KEmoticonsThemeData::KEmoticonsThemeData()
00044 {
00045 provider = 0;
00046 }
00047
00048 KEmoticonsTheme::KEmoticonsThemeData::~KEmoticonsThemeData()
00049 {
00050
00051 }
00052
00053 KEmoticonsTheme::KEmoticonsTheme()
00054 {
00055 d = new KEmoticonsThemeData;
00056 }
00057
00058 KEmoticonsTheme::KEmoticonsTheme(const KEmoticonsTheme &ket)
00059 {
00060 d = ket.d;
00061 }
00062
00063 KEmoticonsTheme::KEmoticonsTheme(KEmoticonsProvider *p)
00064 {
00065 d = new KEmoticonsThemeData;
00066 d->provider = p;
00067 }
00068
00069 KEmoticonsTheme::~KEmoticonsTheme()
00070 {
00071 }
00072
00073 bool KEmoticonsTheme::loadTheme(const QString &path)
00074 {
00075 if (!d->provider) {
00076 return false;
00077 }
00078
00079 return d->provider->loadTheme(path);
00080 }
00081
00082 bool KEmoticonsTheme::removeEmoticon(const QString &emo)
00083 {
00084 if (!d->provider) {
00085 return false;
00086 }
00087
00088 return d->provider->removeEmoticon(emo);
00089 }
00090
00091 bool KEmoticonsTheme::addEmoticon(const QString &emo, const QString &text, KEmoticonsProvider::AddEmoticonOption option)
00092 {
00093 if (!d->provider) {
00094 return false;
00095 }
00096
00097 return d->provider->addEmoticon(emo, text, option);
00098 }
00099
00100 void KEmoticonsTheme::save()
00101 {
00102 if (!d->provider) {
00103 return;
00104 }
00105
00106 d->provider->save();
00107 }
00108
00109 QString KEmoticonsTheme::themeName() const
00110 {
00111 if (!d->provider) {
00112 return QString();
00113 }
00114
00115 return d->provider->themeName();
00116 }
00117
00118 void KEmoticonsTheme::setThemeName(const QString &name)
00119 {
00120 if (!d->provider) {
00121 return;
00122 }
00123
00124 d->provider->setThemeName(name);
00125 }
00126
00127 QString KEmoticonsTheme::themePath() const
00128 {
00129 if (!d->provider) {
00130 return QString();
00131 }
00132
00133 return d->provider->themePath();
00134 }
00135
00136 QString KEmoticonsTheme::fileName() const
00137 {
00138 if (!d->provider) {
00139 return QString();
00140 }
00141
00142 return d->provider->fileName();
00143 }
00144
00145 QHash<QString, QStringList> KEmoticonsTheme::emoticonsMap() const
00146 {
00147 if (!d->provider) {
00148 return QHash<QString, QStringList>();
00149 }
00150
00151 return d->provider->emoticonsMap();
00152 }
00153
00154 void KEmoticonsTheme::createNew()
00155 {
00156 if (!d->provider) {
00157 return;
00158 }
00159
00160 d->provider->createNew();
00161 }
00162
00163 QString KEmoticonsTheme::parseEmoticons(const QString &text, ParseMode mode, const QStringList &exclude) const
00164 {
00165 QList<Token> tokens = tokenize(text, mode | SkipHTML);
00166 if (tokens.isEmpty() && !text.isEmpty())
00167 return text;
00168
00169 QString result;
00170
00171 foreach(const Token &token , tokens) {
00172 switch (token.type) {
00173 case Text:
00174 result += token.text;
00175 break;
00176 case Image:
00177 if (!exclude.contains(token.text)) {
00178 result += token.picHTMLCode;
00179 } else {
00180 result += token.text;
00181 }
00182 break;
00183 default:
00184 kWarning() << "Unknown token type. Something's broken.";
00185 break;
00186 }
00187 }
00188 return result;
00189 }
00190
00191 bool EmoticonCompareEscaped( const KEmoticonsProvider::Emoticon &s1, const KEmoticonsProvider::Emoticon &s2)
00192 {
00193 return s1.matchTextEscaped.length()>s2.matchTextEscaped.length();
00194 }
00195 bool EmoticonCompare( const KEmoticonsProvider::Emoticon &s1, const KEmoticonsProvider::Emoticon &s2)
00196 {
00197 return s1.matchText.length()>s2.matchText.length();
00198 }
00199
00200
00201 QList<KEmoticonsTheme::Token> KEmoticonsTheme::tokenize(const QString &message, ParseMode mode) const
00202 {
00203 if (!d->provider) {
00204 return QList<KEmoticonsTheme::Token>();
00205 }
00206
00207 if (!(mode & (StrictParse | RelaxedParse))) {
00208
00209 mode |= KEmoticons::parseMode();
00210 }
00211
00212 QList<Token> result;
00213
00214
00215
00216 QChar p = ' ';
00217 QChar c;
00218 QChar n;
00219
00220
00221 typedef QPair<KEmoticonsProvider::Emoticon, int> EmoticonNode;
00222 QList<EmoticonNode> foundEmoticons;
00223
00224 QList<KEmoticonsProvider::Emoticon> emoticonList;
00225 QList<KEmoticonsProvider::Emoticon>::const_iterator it;
00226 int pos;
00227
00228 bool inHTMLTag = false;
00229 bool inHTMLLink = false;
00230 bool inHTMLEntity = false;
00231 QString needle;
00232
00233 for (pos = 0; pos < message.length(); ++pos) {
00234 c = message[pos];
00235
00236 if (mode & SkipHTML) {
00237 if (!inHTMLTag) {
00238 if (c == '<') {
00239 inHTMLTag = true;
00240 p = c;
00241 continue;
00242 }
00243 } else {
00244 if (c == '>') {
00245 inHTMLTag = false;
00246
00247 if (p == 'a') {
00248 inHTMLLink = false;
00249 }
00250 } else if (c == 'a' && p == '<') {
00251 inHTMLLink = true;
00252 }
00253 p = c;
00254 continue;
00255 }
00256
00257 if (!inHTMLEntity) {
00258 if (c == '&') {
00259 inHTMLEntity = true;
00260 }
00261 }
00262 }
00263
00264 if (inHTMLLink) {
00265 p = c;
00266 continue;
00267 }
00268
00269 if ((mode & StrictParse) && !p.isSpace() && p != '>') {
00270 p = c;
00271 continue;
00272 }
00273
00274 if (d->provider->emoticonsIndex().contains(c)) {
00275 emoticonList = d->provider->emoticonsIndex().value(c);
00276 if (mode & SkipHTML)
00277 qSort(emoticonList.begin(),emoticonList.end(),EmoticonCompareEscaped);
00278 else
00279 qSort(emoticonList.begin(),emoticonList.end(),EmoticonCompare);
00280 bool found = false;
00281 for (it = emoticonList.constBegin(); it != emoticonList.constEnd(); ++it) {
00282
00283
00284 needle = (mode & SkipHTML) ? (*it).matchTextEscaped : (*it).matchText;
00285 if ((pos == message.indexOf(needle, pos))) {
00286 if (mode & StrictParse) {
00287
00288 if (message.length() > pos + needle.length()) {
00289 n = message[pos + needle.length()];
00290
00291 if (n != '<' && !n.isSpace() && !n.isNull() && n != '&') {
00292 break;
00293 }
00294 }
00295 }
00296
00297 foundEmoticons.append(EmoticonNode((*it), pos));
00298 found = true;
00299
00300 pos += needle.length() - 1;
00301 break;
00302 }
00303
00304 if (found) {
00305 break;
00306 }
00307 }
00308
00309 if (!found) {
00310 if (inHTMLEntity) {
00311
00312 int htmlEnd = message.indexOf(';', pos);
00313
00314 if (htmlEnd == -1) {
00315
00316
00317 kDebug() << "Broken HTML entity, trying to recover.";
00318 inHTMLEntity = false;
00319 pos++;
00320 } else {
00321 pos = htmlEnd;
00322 inHTMLEntity = false;
00323 }
00324 }
00325 }
00326 }
00327 p = c;
00328 }
00329
00330
00331 if (foundEmoticons.isEmpty()) {
00332 result.append(Token(Text, message));
00333 return result;
00334 }
00335
00336
00337
00338 pos = 0;
00339 int length;
00340
00341 for (int i = 0; i < foundEmoticons.size(); ++i) {
00342 EmoticonNode itFound = foundEmoticons.at(i);
00343 needle = (mode & SkipHTML) ? itFound.first.matchTextEscaped : itFound.first.matchText;
00344
00345 if ((length = (itFound.second - pos))) {
00346 result.append(Token(Text, message.mid(pos, length)));
00347 result.append(Token(Image, itFound.first.matchTextEscaped, itFound.first.picPath, itFound.first.picHTMLCode));
00348 pos += length + needle.length();
00349 } else {
00350 result.append(Token(Image, itFound.first.matchTextEscaped, itFound.first.picPath, itFound.first.picHTMLCode));
00351 pos += needle.length();
00352 }
00353 }
00354
00355 if (message.length() - pos) {
00356 result.append(Token(Text, message.mid(pos)));
00357 }
00358
00359 return result;
00360 }
00361
00362 bool KEmoticonsTheme::isNull() const
00363 {
00364 return d->provider ? false : true;
00365 }
00366
00367 KEmoticonsTheme& KEmoticonsTheme::operator=(const KEmoticonsTheme &ket)
00368 {
00369 if (d == ket.d) {
00370 return *this;
00371 }
00372
00373 d = ket.d;
00374 return *this;
00375 }
00376
00377