-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi
At the moment there are some problems with the smily system.
1. bug 1224036 - > does not work in emoticons.xml
http://sourceforge.net/tracker/index.php?func=detail&aid=1224036&group_id=254&atid=100254
2. at the moment there is simply a replacement of the smily symbols with
the image even in urls
3. if I have 100 smilies, there will be 100 times "search and replace"
for one message
To solve these problems I wrote this patch. It arranges the smilies
internally in a tree. Urls are handled as protected content where no
replacement of smily should be done.
For example if there are the smilies :) and :-) the tree would look like
:
/ \
) -
|
)
So I search in the message only the ':' symbol and look whether is is
part of the smily. If it is a smily and not part of an url it is
replaces by an image.
Additionally the bug mentioned above is fixed here.
regars,
rsLeo
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFESTwmuFcJvHsEu9gRAsFIAJsEqn6jWES4NP1dzh8xGXoYMshihgCfUbRV
2MXGuRsvAnTOJH4wYxyARnU=
=crJ0
-----END PGP SIGNATURE-----
--- licq/plugins/qt-gui/src/emoticon.h 2006-03-10 12:24:35.000000000 +0100
+++ licq_patched/plugins/qt-gui/src/emoticon.h 2006-04-09 17:17:44.000000000
+0200
@@ -4,6 +4,7 @@
#include <qmap.h>
#include <qstring.h>
#include <qstringlist.h>
+#include "emotnode.h"
class CEmoticons {
--- licq/plugins/qt-gui/src/emoticon.cpp 2006-03-10 12:24:35.000000000
+0100
+++ licq_patched/plugins/qt-gui/src/emoticon.cpp 2006-04-09
17:19:27.000000000 +0200
@@ -23,7 +23,6 @@
{
QStringList emoticon;
QString file;
- QRegExp reg;
};
typedef std::list<struct node> node_list_t;
@@ -36,6 +35,7 @@
QString theme; /* current theme */
node_list_t emoticons;
+ EmotNode *emoticonsTree;
};
CEmoticons::CEmoticons(const char *basedir, const char *altbasedir,
@@ -44,10 +44,12 @@
this->data = new struct Emoticons;
data->basedir = basedir;
data->altbasedir = altbasedir;
+ data->emoticonsTree = NULL;
}
CEmoticons::~CEmoticons()
{
+ delete this->data->emoticonsTree;
delete this->data;
}
@@ -140,52 +142,20 @@
return ret;
}
-static void create_regexp(QStringList &list, QRegExp ®)
-{
- unsigned n = 0;
- QString s = "(";
-
- for (QStringList::Iterator it = list.begin(); it!=list.end(); ++it)
- {
- if (n != 0)
- s += "|";
-#if QT_VERSION < 0x030100
- // we have to implement the functionality of QRegExp::escape()
- // ourself since qt 3.0.x is missing it.
- // Our goal is to escape all special characters with a backslash:
- // The special characters are $, (, ), *, +, ., ?, [, \, ], ^, {, | and }.
- // The implementation is heavily inspired by QT QRegExp sources ;-)
-
- static const char *c = "\\$()*+.?[]^{}|";
- int i = 0;
- QString tmp = (*it).latin1();
- while (i < (int)tmp.length())
- {
- if (strstr(c, tmp.mid(i,1).latin1()) != 0)
- tmp.insert( i++, "\\");
- i++;
- }
- s += tmp;
-#else
- s += QRegExp::escape(*it);
-#endif
- n++;
- }
- s += ")";
- reg = QRegExp(s);
-}
/*!
*
* \param data CDT for the CEmoticon class
* \param themedir path to the theme directory
* \param list list where the results are stored
+ * \param emoticonsTree tree where the smilies are stored
*
* \returns the number of loaded emoticons
*/
static unsigned loadTheme(const struct Emoticons *data,
const QString &themedir,
- node_list_t &list)
+ node_list_t &list,
+ EmotNode *emoticonsTree = NULL)
{
QDomDocument doc("doc");
QFile file(themedir + "/emoticons.xml");
@@ -210,13 +180,14 @@
unsigned size;
node.emoticon = loadStrings(data, n.firstChild(), &size);
- if (size)
- {
- node.file = f;
- create_regexp(node.emoticon, node.reg);
- list.push_back(node);
- ret += size;
- }
+ if (size)
+ {
+ node.file = f;
+ list.push_back(node);
+ if (emoticonsTree != NULL)
+ emoticonsTree->insert(node.emoticon, f, true);
+ ret += size;
+ }
}
}
}
@@ -240,13 +211,14 @@
QDir d1(szdir1);
QDir d2(szdir2);
node_list_t list;
+ EmotNode *emoTree = new EmotNode();
int ret = -1;
unsigned n = 0;
if (d1.exists())
- n = loadTheme(data, szdir1.ascii(), list);
+ n = loadTheme(data, szdir1.ascii(), list, emoTree);
else if(d2.exists())
- n = loadTheme(data, szdir2.ascii(), list);
+ n = loadTheme(data, szdir2.ascii(), list, emoTree);
if (n)
@@ -254,7 +226,10 @@
ret = n;
data->theme = theme;
data->emoticons = list;
+ data->emoticonsTree = emoTree;
}
+ else
+ delete emoTree;
return ret;
}
@@ -326,26 +301,9 @@
void CEmoticons::ParseMessage(QString &msg)
{
- /**
- * \todo this sucks: solution create a finite state machine to parse
- * the message
- */
- node_list_t::iterator iter;
- struct node n;
-
if (data->theme != QString::null && data->theme != "None")
{
- QString r;
- for( iter = data->emoticons.begin();
- iter != data->emoticons.end() ; iter++ )
- {
- n = *iter;
- for ( QStringList::Iterator it = n.emoticon.begin();
- it != n.emoticon.end(); ++it)
- {
- msg.replace(n.reg," <img src=\""+n.file+"\"/> ");
- }
- }
+ msg = data->emoticonsTree->replaceSmilies(msg);
}
}
--- licq/plugins/qt-gui/src/Makefile.am 2006-03-10 12:24:35.000000000 +0100
+++ licq_patched/plugins/qt-gui/src/Makefile.am 2006-04-09 20:33:12.578165592
+0200
@@ -21,7 +21,7 @@
mmlistview.h mmsenddlg.h userinfodlg.h usereventdlg.h keyrequestdlg.h \
jfcstyle.h usercodec.h reqauthdlg.h licqdialog.h userselectdlg.h \
editfilelistdlg.h emoticon.h catdlg.h phonedlg.h ownermanagerdlg.h \
- gpgkeyselect.h gpgkeymanager.h licqkimiface.h kimiface.h
+ gpgkeyselect.h gpgkeymanager.h licqkimiface.h kimiface.h emotnode.h
licq_gui = adduserdlg.cpp authuserdlg.cpp awaymsgdlg.cpp \
refusedlg.cpp chatdlg.cpp editgrp.cpp editfile.cpp eventdesc.cpp \
@@ -34,7 +34,7 @@
mmsenddlg.cpp userinfodlg.cpp usereventdlg.cpp keyrequestdlg.cpp \
jfcstyle.cpp usercodec.cpp reqauthdlg.cpp licqdialog.cpp
userselectdlg.cpp \
editfilelistdlg.cpp emoticon.cpp catdlg.cpp phonedlg.cpp \
- ownermanagerdlg.cpp gpgkeyselect.cpp gpgkeymanager.cpp
+ ownermanagerdlg.cpp gpgkeyselect.cpp gpgkeymanager.cpp emotnode.cpp
licq_qt_gui_la_SOURCES = $(licq_gui)
licq_kde_gui_la_SOURCES = $(licq_gui) wrap_kde_malloc.cpp \
--- /dev/null 2005-08-09 09:06:25.000000000 +0200
+++ licq_patched/plugins/qt-gui/src/emotnode.h 2006-04-06 00:23:05.000000000
+0200
@@ -0,0 +1,71 @@
+#ifndef EMOTNODE_H
+#define EMOTNODE_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <string>
+#include <map>
+
+
+class EmotNode{
+private:
+ struct file_child_t {
+ QString m_file; //every node can have a filename (image)
+ EmotNode* mp_child; //every node may link to other nodes
+
+ };
+
+ typedef std::map<QChar,file_child_t> node_t;
+ typedef std::map<QChar,file_child_t>::const_iterator node_iter_t;
+
+ node_t m_node; //m_node[symbol_x], m_node[symbol_y] are all nodes
+ //example with smily :-)
+ //m_node[:].mp_child[-].mp_child[)].m_file = smily.jpg
+
+ /**
+ * Check whether at a given position in a message a smily can be found.
+ * @param msg message with smilies
+ * @param spos position of possible smily
+ * @param endPos returns the end position of a smily if one is found
+ * @return If a smily was found then the filename is returned. Else NULL ist
returned.
+ */
+ QString searchSmilyInTree(QString msg, int spos, int &endPos);
+
+ /**
+ * Parse the msg for contents which should not be replaced with smilies
+ * @param msg
+ */
+ QString createSpecialContentSafe(QString msg);
+
+public:
+ EmotNode();
+ EmotNode(QString icons, QString filename);
+
+ ~EmotNode();
+
+ /**
+ * Insert one smily with all his representatives.
+ * @param iconList list of representatives of the smily
+ * @param filename name of image file
+ * @param doEncodeSmily (optional, default=false) encode the smilies e.g. >:)
will be >:)
+ */
+ void insert(QStringList iconList, QString filename, bool doEncode);
+
+ /**
+ * Insert a new smily in the tree.
+ * @param icons the test of the smily
+ * @param filename the image name of the smily
+ * @param depth used internally because of recursive behaviour
+ */
+ void insert(QString icons, QString filename, unsigned int depth = 0);
+
+ /**
+ * Replace all smilies in a message and return the resulting message.
+ * @param msg message with smilies to replace
+ * @return message with replaced smilies
+ */
+ QString replaceSmilies(QString msg);
+};
+
+#endif
--- /dev/null 2005-08-09 09:06:25.000000000 +0200
+++ licq_patched/plugins/qt-gui/src/emotnode.cpp 2006-04-09
19:06:43.549017928 +0200
@@ -0,0 +1,221 @@
+/* Licq - A ICQ Client for Unix
+
+ Copyright (C) 2006 Martin Garbe <[EMAIL PROTECTED]>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+ * \file Build a tree with smily symbols. Every node has one symbol of
+ * a smily and maybe a filename to an image. There is a filename
+ * if the symbols on the path from the root node to this node
+ * builds a smily.
+ */
+
+#include <qregexp.h>
+#include <qstylesheet.h>
+
+#include "licq_log.h"
+
+#include "emotnode.h"
+
+
+EmotNode::EmotNode()
+{
+
+}
+
+
+/*
+ * Insert one smily with all his representatives.
+ */
+void EmotNode::insert(QStringList iconList, QString filename, bool
doEncodeSmily = false)
+{
+ for (QStringList::Iterator iter = iconList.begin(); iter != iconList.end();
iter++)
+ {
+ if (doEncodeSmily)
+ {
+ insert(QStyleSheet::escape(*iter), filename);
+ }
+ else
+ {
+ insert(*iter, filename);
+ }
+ }
+}
+
+
+/*
+ * Insert a new smily in the tree.
+ */
+void EmotNode::insert(QString icons, QString filename, unsigned int depth )
+{
+ QChar sym = icons.at(depth);
+ node_iter_t iter = m_node.find(sym);
+ if (iter != m_node.end())
+ {
+ //symbol already exists here
+ if ((depth+1) == icons.length())
+ {
+ //if end of symbol is reached then insert file
+ m_node[sym].m_file = filename;
+ }
+ else
+ {
+ //end of symbol not reached -> go deeper
+ m_node[sym].mp_child->insert(icons, filename, depth+1);
+ }
+ }
+ else
+ {
+ //add symbol here
+ m_node[sym].mp_child = new EmotNode();
+ if ((depth+1) == icons.length())
+ {
+ //end of smily reached, insert image here
+ m_node[sym].m_file = filename;
+ }
+ else
+ {
+ m_node[sym].m_file = "";
+ m_node[sym].mp_child->insert(icons, filename, depth+1);
+ }
+ }
+}
+
+
+//
+//Check whether at a given position in a message a smily can be found.
+//
+QString EmotNode::searchSmilyInTree(QString msg, int spos, int &endPos)
+{
+ QChar curSym = msg.at(spos);
+ node_iter_t iter = m_node.find(curSym);
+ if (iter != m_node.end())
+ {
+ //found symbol in node, so go deeper
+ QString s = m_node[curSym].mp_child->searchSmilyInTree(msg, spos+1,
endPos);
+ if (s == NULL)
+ {
+ //is here any file for the smily?
+ if (m_node[curSym].m_file.length() != 0)
+ {
+ endPos = spos;
+ return m_node[curSym].m_file;
+ }
+ }
+ else
+ {
+ return s;
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ * Replace all smilies in a message and return the resulting message.
+ */
+QString EmotNode::replaceSmilies(QString msg)
+{
+ int pos = 0;
+ int tmppos;
+ int max = msg.length()+1;
+ int spos = -1; //smallest position
+ int nextToCopyPos = 0; //saves the next position to copy from msg to
newMsg
+ QString contentSafe;
+ QString newMsg = "";
+
+ contentSafe = createSpecialContentSafe(msg);
+
+ while (spos != max)
+ {
+ spos = max;
+ //search for the first possible smily symbol
+ for ( node_iter_t i = m_node.begin(); i != m_node.end(); ++i)
+ {
+ tmppos = contentSafe.find(i->first, pos);
+ if (tmppos != -1 && tmppos < spos)
+ {
+ //found a position, remember it and try to find one more left
+ spos = tmppos;
+ }
+ }
+ if (spos != max)
+ {
+ //check if at this position is a smily in msg
+ int endPos = -1;
+ QString f = searchSmilyInTree(contentSafe, spos, endPos);
+ if (f != NULL)
+ {
+ //replace
+ newMsg.append(msg.mid(nextToCopyPos, spos-nextToCopyPos) + " <img
src=\"" + f + "\"/> ");
+ nextToCopyPos = endPos + 1;
+ pos = endPos + 1;
+ }
+ else
+ {
+ //it's beginning with a smily symbol but it's no smily
+ pos = spos + 1;
+ }
+ }
+ }
+
+ if (nextToCopyPos != contentSafe.length())
+ {
+ newMsg.append(msg.right(contentSafe.length() - nextToCopyPos));
+ }
+
+ return newMsg;
+}
+
+
+/*
+ * Parse the msg for content which should not be replaced with smilies
+ */
+QString EmotNode::createSpecialContentSafe(QString msg)
+{
+ QString contentSafe = msg;
+ QString fill;
+ int bpos = 0;
+ int epos = 0;
+ QRegExp
reURL("(\\b|^)((https?|ftp)://([-a-z0-9]+(:[-a-z0-9]+)?@)?[-a-z0-9.]+[-a-z0-9](:[0-9]+)?(/([-a-z0-9%{}|\\\\^~`;/?:@=&$_.+!*'(),]|\\[|\\])*)?)");
+ reURL.setMinimal(false);
+ reURL.setCaseSensitive(false);
+ do
+ {
+ bpos = contentSafe.find(reURL);
+ if (bpos != -1)
+ {
+ //find end position
+ epos = bpos + reURL.cap(2).length();
+ //replace content area with spaces (mark as content area)
+ contentSafe = contentSafe.replace(bpos, epos - bpos, fill.fill(' ', epos
- bpos));
+ }
+ }
+ while (bpos != -1);
+
+ return contentSafe;
+}
+
+
+EmotNode::~EmotNode()
+{
+ for ( node_iter_t i = m_node.begin(); i != m_node.end(); ++i)
+ {
+ delete(i->second.mp_child);
+ }
+}
+
+