• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KUtils

kemoticonstheme.cpp

Go to the documentation of this file.
00001 /**********************************************************************************
00002  *   Copyright (C) 2008 by Carlo Segato <brandon.ml@gmail.com>                    *
00003  *   Copyright (c) 2002-2003 by Stefan Gehn            <metz@gehn.net>            *
00004  *   Kopete    (c) 2002-2008 by the Kopete developers  <kopete-devel@kde.org>     *
00005  *   Copyright (c) 2005      by Engin AYDOGAN          <engin@bzzzt.biz>          *
00006  *                                                                                *
00007  *   This library is free software; you can redistribute it and/or                *
00008  *   modify it under the terms of the GNU Lesser General Public                   *
00009  *   License as published by the Free Software Foundation; either                 *
00010  *   version 2.1 of the License, or (at your option) any later version.           *
00011  *                                                                                *
00012  *   This library is distributed in the hope that it will be useful,              *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of               *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU            *
00015  *   Lesser General Public License for more details.                              *
00016  *                                                                                *
00017  *   You should have received a copy of the GNU Lesser General Public             *
00018  *   License along with this library.  If not, see <http://www.gnu.org/licenses/>.*
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 //     delete provider;
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         //if none of theses two mode are selected, use the mode from the config
00209         mode |=  KEmoticons::parseMode();
00210     }
00211 
00212     QList<Token> result;
00213 
00214     /* previous char, in the firs iteration assume that it is space since we want
00215      * to let emoticons at the beginning, the very first previous QChar must be a space. */
00216     QChar p = ' ';
00217     QChar c; /* current char */
00218     QChar n;
00219 
00220     /* This is the EmoticonNode container, it will represent each matched emoticon */
00221     typedef QPair<KEmoticonsProvider::Emoticon, int> EmoticonNode;
00222     QList<EmoticonNode> foundEmoticons;
00223     /* First-pass, store the matched emoticon locations in foundEmoticons */
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; // search for this
00232 
00233     for (pos = 0; pos < message.length(); ++pos) {
00234         c = message[pos];
00235 
00236         if (mode & SkipHTML) { // Shall we skip HTML ?
00237             if (!inHTMLTag) { // Are we already in an HTML tag ?
00238                 if (c == '<') { // If not check if are going into one
00239                     inHTMLTag = true; // If we are, change the state to inHTML
00240                     p = c;
00241                     continue;
00242                 }
00243             } else { // We are already in a HTML tag
00244                 if (c == '>') { // Check if it ends
00245                     inHTMLTag = false;   // If so, change the state
00246 
00247                     if (p == 'a') {
00248                         inHTMLLink = false;
00249                     }
00250                 } else if (c == 'a' && p == '<') { // check if we just entered an achor tag
00251                     inHTMLLink = true; // don't put smileys in urls
00252                 }
00253                 p = c;
00254                 continue;
00255             }
00256 
00257             if (!inHTMLEntity) { // are we
00258                 if (c == '&') {
00259                     inHTMLEntity = true;
00260                 }
00261             }
00262         }
00263 
00264         if (inHTMLLink) { // i can't think of any situation where a link address might need emoticons
00265             p = c;
00266             continue;
00267         }
00268 
00269         if ((mode & StrictParse)  &&  !p.isSpace() && p != '>') {  // '>' may mark the end of an html tag
00270             p = c;
00271             continue;
00272         } /* strict requires space before the emoticon */
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                 // If this is an HTML, then search for the HTML form of the emoticon.
00283                 // For instance <o) => &gt;o)
00284                 needle = (mode & SkipHTML) ? (*it).matchTextEscaped : (*it).matchText;
00285                 if ((pos == message.indexOf(needle, pos))) {
00286                     if (mode & StrictParse) {
00287                         /* check if the character after this match is space or end of string*/
00288                         if (message.length() > pos + needle.length()) {
00289                             n = message[pos + needle.length()];
00290                             //<br/> marks the end of a line
00291                             if (n != '<' && !n.isSpace() &&  !n.isNull() && n != '&') {
00292                                 break;
00293                             }
00294                         }
00295                     }
00296                     /* Perfect match */
00297                     foundEmoticons.append(EmoticonNode((*it), pos));
00298                     found = true;
00299                     /* Skip the matched emoticon's matchText */
00300                     pos += needle.length() - 1;
00301                     break;
00302                 }
00303 
00304                 if (found) {
00305                     break;
00306                 }
00307             }
00308 
00309             if (!found) {
00310                 if (inHTMLEntity) {
00311                     // If we are in an HTML entitiy such as &gt;
00312                     int htmlEnd = message.indexOf(';', pos);
00313                     // Search for where it ends
00314                     if (htmlEnd == -1) {
00315                         // Apparently this HTML entity isn't ended, something is wrong, try skip the '&'
00316                         // and continue
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         } /* else no emoticons begin with this character, so don't do anything */
00327         p = c;
00328     }
00329 
00330     /* if no emoticons found just return the text */
00331     if (foundEmoticons.isEmpty()) {
00332         result.append(Token(Text, message));
00333         return result;
00334     }
00335 
00336     /* Second-pass, generate tokens based on the matches */
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) { // if there is remaining regular text
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 // kate: space-indent on; indent-width 4; replace-tabs on;

KUtils

Skip menu "KUtils"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal