-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Philip Nelson wrote: > > This all looks good and I like the idea. Your patch applies fine and compiles > ok but when I run licq I get: > > [ERR] Unable to load plugin (kde-gui): /usr/local/lib/licq/licq_kde-gui.so: > undefined symbol: _ZN8EmotNodeD1Ev. > > This was after a distclean.. so I don't know if something isn't getting > linked > or what, don't have time at the moment to investigate. >
I tested it again and for me it works. In the patch a Makefile.am is changed. So you need to do "make -f Makefile.cvs" after applying the patch. After running "configure" the file src/Makefile should contain "emotnode.cpp". Now building and running should work without problems. I attach the patch to this mail again because I corrected the spelling of smiley and smileys. regards, rsLeo -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFESgMPuFcJvHsEu9gRAoR2AJ0VhLzFLgUrC+izZ+x8FZkfrEyacACdHGjQ Y1iWs0zOPsrxUoMhRXMjwGQ= =eUg6 -----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 smileys 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->replaceSmileys(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 smiley :-) + //m_node[:].mp_child[-].mp_child[)].m_file = smiley.jpg + + /** + * Check whether at a given position in a message a smiley can be found. + * @param msg message with smileys + * @param spos position of possible smiley + * @param endPos returns the end position of a smiley if one is found + * @return If a smiley was found then the filename is returned. Else NULL ist returned. + */ + QString searchSmileyInTree(QString msg, int spos, int &endPos); + + /** + * Parse the msg for contents which should not be replaced with smileys + * @param msg + */ + QString createSpecialContentSafe(QString msg); + +public: + EmotNode(); + EmotNode(QString icons, QString filename); + + ~EmotNode(); + + /** + * Insert one smiley with all his representatives. + * @param iconList list of representatives of the smiley + * @param filename name of image file + * @param doEncode (optional, default=false) encode the smileys e.g. >:) will be >:) + */ + void insert(QStringList iconList, QString filename, bool doEncode); + + /** + * Insert a new smiley in the tree. + * @param icons the test of the smiley + * @param filename the image name of the smiley + * @param depth used internally because of recursive behaviour + */ + void insert(QString icons, QString filename, unsigned int depth = 0); + + /** + * Replace all smileys in a message and return the resulting message. + * @param msg message with smileys to replace + * @return message with replaced smileys + */ + QString replaceSmileys(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 smiley symbols. Every node has one symbol of + * a smiley 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 smiley. + */ + +#include <qregexp.h> +#include <qstylesheet.h> + +#include "licq_log.h" + +#include "emotnode.h" + + +EmotNode::EmotNode() +{ + +} + + +/* + * Insert one smiley with all his representatives. + */ +void EmotNode::insert(QStringList iconList, QString filename, bool doEncodeSmiley = false) +{ + for (QStringList::Iterator iter = iconList.begin(); iter != iconList.end(); iter++) + { + if (doEncodeSmiley) + { + insert(QStyleSheet::escape(*iter), filename); + } + else + { + insert(*iter, filename); + } + } +} + + +/* + * Insert a new smiley 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 smiley 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 smiley can be found. +// +QString EmotNode::searchSmileyInTree(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->searchSmileyInTree(msg, spos+1, endPos); + if (s == NULL) + { + //is here any file for the smiley? + if (m_node[curSym].m_file.length() != 0) + { + endPos = spos; + return m_node[curSym].m_file; + } + } + else + { + return s; + } + } + return NULL; +} + + +/* + * Replace all smileys in a message and return the resulting message. + */ +QString EmotNode::replaceSmileys(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 smiley 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 smiley in msg + int endPos = -1; + QString f = searchSmileyInTree(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 smiley symbol but it's no smiley + 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 smileys + */ +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); + } +} + +