Hi,
   this patch adds a new feature: emoticons (nobody seems to use this 
word...all is about smiles) can be seen as pictures. Which emoticons do we 
translate? User-defined ones. That means that you can map what ever you want 
to an image. How do you define a new theme? The theme is defined in an XML 
file. The format is the same as kopete. Why? Because i didn't want to find 
images to test.

The patch still has some room to performance gain. Also i didn't test if it 
compiles on another version of QT of my system ( qt2 handles XML?). If you 
like the patch, and you want it on qt2, we can add in configure a test for 
libxml2 and implement it also over that.

Also, I thought in building an finite state machine (with output) dinamicaly 
(at SetTheme) to parse the message in O(n) where n = characters of message, 
instead of O(n*m) where m is the number of files available in the theme (i 
consider m lineal because i bet that each QRegExp is an state machine).

To apply please do:
[EMAIL PROTECTED]:/tmp$ cd licq
[EMAIL PROTECTED]:/tmp/licq$ tar vxjf ../emoticons.tar.bz2
plugins/qt-gui/share/qt-gui/emoticons/
plugins/qt-gui/share/qt-gui/emoticons/None/
plugins/qt-gui/share/qt-gui/emoticons/None/emoticon
....
[EMAIL PROTECTED]:/tmp/licq$ patch -p0 < ../emoticons.diff
patching file plugins/qt-gui/share/Makefile.am
patching file plugins/qt-gui/src/Makefile.am
patching file plugins/qt-gui/src/gui-defines.h
...
[EMAIL PROTECTED]:/tmp/licq$ cd plugins/qt-gui/
[EMAIL PROTECTED]:/tmp/licq/plugins/qt-gui$ make
...
[EMAIL PROTECTED]:/tmp/licq/plugins/qt-gui$ make install

(so the emoticons themes are installed).

To disable this, just select the theme None.

What format are available? I don't know. It depends of your qt installation. 
Maybe it support animated gifs.

I have 15 icons themes in my harddisk that came from kopete. Some dont have a 
license notice in them, and some do (an even somes says you can redistribute 
it only for noncomercial ...). So for this mail i have only included the few 
that made sense.

Now that i remember...emoticons at ~/.licq/qt-gui... are not supported (hey! i 
install licq on my home).

-- 
Buenos Aires, Argentina                          8°C with winds at 25 km/h ESE
? plugins/qt-gui/src/emoticon.cpp
? plugins/qt-gui/src/emoticon.h
Index: plugins/qt-gui/share/Makefile.am
===================================================================
RCS file: /cvsroot/licq/qt-gui/share/Makefile.am,v
retrieving revision 1.11
diff -u -d -p -r1.11 Makefile.am
--- plugins/qt-gui/share/Makefile.am	8 Nov 2002 01:01:01 -0000	1.11
+++ plugins/qt-gui/share/Makefile.am	23 Aug 2003 01:26:29 -0000
@@ -55,4 +55,12 @@ install-data-local:
             fi \
           done; \
 	done
-
+	@for j in qt-gui/emoticons/*; do \
+	  echo "Installing emoticon $$j"; \
+	  $(mkinstalldirs) $(DESTDIR)$(sharedir)/$$j; \
+	  for i in $$j/*; do \
+	    if test -f $$i; then \
+	      $(INSTALL_DATA) $$i $(DESTDIR)$(sharedir)/$$j; \
+	    fi \
+	  done; \
+	done
Index: plugins/qt-gui/src/Makefile.am
===================================================================
RCS file: /cvsroot/licq/qt-gui/src/Makefile.am,v
retrieving revision 1.39
diff -u -d -p -r1.39 Makefile.am
--- plugins/qt-gui/src/Makefile.am	11 Feb 2003 19:40:25 -0000	1.39
+++ plugins/qt-gui/src/Makefile.am	23 Aug 2003 01:26:42 -0000
@@ -9,6 +9,8 @@ INCLUDES = -D_REENTRANT \
 
 EXTRA_LTLIBRARIES = licq_qt-gui.la licq_kde-gui.la
 
+# EXTRA_PROGRAMS = testemoticons
+
 lib_LTLIBRARIES = @LIB_NAME@
 
 noinst_HEADERS = adduserdlg.h authuserdlg.h awaymsgdlg.h refusedlg.h \
@@ -20,7 +22,7 @@ noinst_HEADERS = adduserdlg.h authuserdl
 	utilitydlg.h wharf.h randomchatdlg.h forwarddlg.h chatjoin.h \
 	mmlistview.h mmsenddlg.h userinfodlg.h usereventdlg.h keyrequestdlg.h \
   jfcstyle.h usercodec.h reqauthdlg.h licqdialog.h userselectdlg.h \
-  editfilelistdlg.h
+  editfilelistdlg.h emoticon.h
 
 licq_gui = adduserdlg.cpp authuserdlg.cpp awaymsgdlg.cpp \
 	refusedlg.cpp chatdlg.cpp editgrp.cpp editfile.cpp eventdesc.cpp \
@@ -32,7 +34,7 @@ licq_gui = adduserdlg.cpp authuserdlg.cp
 	wharf.cpp randomchatdlg.cpp forwarddlg.cpp chatjoin.cpp mmlistview.cpp \
   mmsenddlg.cpp userinfodlg.cpp usereventdlg.cpp keyrequestdlg.cpp \
   jfcstyle.cpp usercodec.cpp reqauthdlg.cpp licqdialog.cpp userselectdlg.cpp \
-  editfilelistdlg.cpp
+  editfilelistdlg.cpp emoticon.cpp
 
 licq_qt_gui_la_SOURCES = $(licq_gui)
 licq_kde_gui_la_SOURCES = $(licq_gui) wrap_kde_malloc.cpp
@@ -49,3 +51,7 @@ licq_kde_gui_la_LIBADD = $(KDE_LIBS) $(X
 
 METASOURCES = AUTO
 KDE_OPTIONS = qtonly
+
+# testemoticons_SOURCES = emoticon.cpp ../../../src/log.cpp
+# testemoticons_CFLAGS  = -DEMOTICON_TEST_DRIVER $(LICQ_INCLUDES)
+# testemoticons_LDADD = -L$(QT_LIBDIR) $(LIB_QT)
Index: plugins/qt-gui/src/gui-defines.h
===================================================================
RCS file: /cvsroot/licq/qt-gui/src/gui-defines.h,v
retrieving revision 1.20
diff -u -d -p -r1.20 gui-defines.h
--- plugins/qt-gui/src/gui-defines.h	11 Sep 2002 01:50:47 -0000	1.20
+++ plugins/qt-gui/src/gui-defines.h	23 Aug 2003 01:26:42 -0000
@@ -2,6 +2,7 @@
 #define GUIDEFINES_H
 
 #define QTGUI_DIR "qt-gui/"
+#define EMOTICONS_DIR "emoticons/"
 
 #define NUM_MSG_PER_HISTORY 40
 #define COLOR_SENT "blue"
Index: plugins/qt-gui/src/licq_qt-gui.conf.h
===================================================================
RCS file: /cvsroot/licq/qt-gui/src/licq_qt-gui.conf.h,v
retrieving revision 1.8
diff -u -d -p -r1.8 licq_qt-gui.conf.h
--- plugins/qt-gui/src/licq_qt-gui.conf.h	8 Nov 2002 00:59:41 -0000	1.8
+++ plugins/qt-gui/src/licq_qt-gui.conf.h	23 Aug 2003 01:26:42 -0000
@@ -2,6 +2,7 @@ static const char QTGUI_CONF[] =
 "[appearance]\n"
 "Skin = basic\n"
 "Icons = computer\n"
+"Emoticons = Default\n"
 "ExtendedIcons = basic\n"
 "Font = default\n"
 "GridLines = 0\n"
Index: plugins/qt-gui/src/mainwin.cpp
===================================================================
RCS file: /cvsroot/licq/qt-gui/src/mainwin.cpp,v
retrieving revision 1.294
diff -u -d -p -r1.294 mainwin.cpp
--- plugins/qt-gui/src/mainwin.cpp	9 Jul 2003 16:33:26 -0000	1.294
+++ plugins/qt-gui/src/mainwin.cpp	23 Aug 2003 01:26:44 -0000
@@ -80,6 +80,7 @@
 #include "wharf.h"
 #include "keyrequestdlg.h"
 #include "usercodec.h"
+#include "emoticon.h"
 
 #include "xpm/history.xpm"
 #include "xpm/info.xpm"
@@ -93,7 +94,6 @@
 #include "xpm/pixCellular.xpm"
 #include "xpm/pixBirthday.xpm"
 #include "xpm/pixInvisible.xpm"
-
 #include "licq_qt-gui.conf.h"
 
 extern "C" {
@@ -367,8 +367,7 @@ CMainWindow::CMainWindow(CICQDaemon *the
   licqConf.ReadBool("showPopLastOnelin",m_bPopLastOnline, false);
   licqConf.ReadBool("showPopOnlineSince", m_bPopOnlineSince, false);
   licqConf.ReadBool("showPopIdleTime", m_bPopIdleTime, true);
-
-
+  
   unsigned short nFlash;
   licqConf.ReadNum("Flash", nFlash, FLASH_URGENT);
   m_nFlash = (FlashType)nFlash;
@@ -448,6 +447,15 @@ CMainWindow::CMainWindow(CICQDaemon *the
     strcpy(szExtendedIcons, extendedIconsName);
   m_szExtendedIconSet = NULL;
 
+  // Load the Emoticons
+  char szEmoticons[MAX_FILENAME_LEN];
+  licqConf.ReadStr("Emoticons", szEmoticons, "Default" );
+  QString s =  QString::fromAscii(SHARE_DIR) + QTGUI_DIR + EMOTICONS_DIR;
+  emoticons = new CEmoticons(s.latin1());
+  if( *szEmoticons )
+     if( emoticons->SetTheme(szEmoticons) < 0 )
+	 gLog.Error("%s Loading emoticons theme `%s'",L_ERRORxSTR, szEmoticons);
+
   // Load the skin
   char szSkin[MAX_FILENAME_LEN] = "basic";
   if (strlen(skinName) == 0)
@@ -3297,6 +3305,8 @@ void CMainWindow::saveOptions()
   licqConf.WriteStr("Skin", skin->szSkinName);
   licqConf.WriteStr("Icons", m_szIconSet);
   licqConf.WriteStr("ExtendedIcons", m_szExtendedIconSet);
+  licqConf.WriteStr("Emoticons", emoticons->Theme() ? emoticons->Theme() : "");
+  
 #if QT_VERSION >= 300
   licqConf.WriteStr("Font", qApp->font() == defaultFont ?
                     "default" : qApp->font().toString().latin1());
Index: plugins/qt-gui/src/mainwin.h
===================================================================
RCS file: /cvsroot/licq/qt-gui/src/mainwin.h,v
retrieving revision 1.112
diff -u -d -p -r1.112 mainwin.h
--- plugins/qt-gui/src/mainwin.h	8 Jul 2003 11:37:52 -0000	1.112
+++ plugins/qt-gui/src/mainwin.h	23 Aug 2003 01:26:44 -0000
@@ -32,6 +32,7 @@ class QTextView;
 class CSignalManager;
 class CQtLogWindow;
 class CSkin;
+class CEmoticons;
 class CICQDaemon;
 class ICQEvent;
 class OptionsDlg;
@@ -96,7 +97,6 @@ public:
     m_nUserMenuPPID = n;
     m_nUserMenuUin = strtoul(s, (char **)NULL, 10);
   }
-
   static QPixmap &iconForStatus(unsigned long FullStatus);
   static QPixmap &iconForEvent(unsigned short SubCommand);
 
@@ -143,6 +143,7 @@ public:
   ColumnInfos colInfo;
   FlashType m_nFlash;
   CSkin *skin;
+  CEmoticons *emoticons;
 
   unsigned long m_nCurrentGroup, m_nGroupStates;
   unsigned short m_nSortByStatus,
@@ -209,7 +210,8 @@ public:
   QPixmap pmOnline, pmOffline, pmAway, pmDnd, pmOccupied, pmNa,
           pmPrivate, pmFFC, pmMessage, pmUrl, pmChat, pmFile, pmContact, pmSms,
           pmAuthorize, pmSMS, pmSecureOn, pmSecureOff, pmHistory, pmInfo, pmEncoding,
-          pmBirthday, pmPhone, pmCellular, pmInvisible, pmCustomAR, pmCollapsed, pmExpanded;
+          pmBirthday, pmPhone, pmCellular, pmInvisible, pmCustomAR, pmCollapsed,
+	  pmExpanded;
   unsigned long m_nUserMenuUin;
   unsigned int positionChanges;
   unsigned long m_nProtoNum;
Index: plugins/qt-gui/src/mlview3.cpp
===================================================================
RCS file: /cvsroot/licq/qt-gui/src/mlview3.cpp,v
retrieving revision 1.15
diff -u -d -p -r1.15 mlview3.cpp
--- plugins/qt-gui/src/mlview3.cpp	2 Jul 2003 04:41:02 -0000	1.15
+++ plugins/qt-gui/src/mlview3.cpp	23 Aug 2003 01:26:46 -0000
@@ -73,6 +73,9 @@ void MLView::append(const QString& s)
   }
 }
 
+#include "emoticon.h"
+#include "mainwin.h" // for the CEmoticon instance
+
 QString MLView::toRichText(const QString& s, bool highlightURLs)
 {
   // We cannot use QStyleSheet::convertFromPlainText
@@ -123,6 +126,8 @@ QString MLView::toRichText(const QString
      text.replace(pos+1, longSpaces.matchedLength()-1, cap);
   }
   text.replace(QRegExp("\t"), " &nbsp;&nbsp;&nbsp;");
+
+  gMainWindow->emoticons->ParseMessage(text);
 
   return text;
 }
Index: plugins/qt-gui/src/skinbrowser.cpp
===================================================================
RCS file: /cvsroot/licq/qt-gui/src/skinbrowser.cpp,v
retrieving revision 1.23
diff -u -d -p -r1.23 skinbrowser.cpp
--- plugins/qt-gui/src/skinbrowser.cpp	24 Mar 2003 15:33:53 -0000	1.23
+++ plugins/qt-gui/src/skinbrowser.cpp	23 Aug 2003 01:26:46 -0000
@@ -35,6 +35,12 @@
 #include "mainwin.h"
 #include "skin.h"
 #include "skinbrowser.h"
+#include "mainwin.h" /* to get the CMainWindow::emoticons */
+#include "emoticon.h"
+
+enum {
+	MAX_HEIGHT = 170
+};
 
 SkinBrowserDlg::SkinBrowserDlg(CMainWindow *_mainwin, QWidget *parent)
 	: LicqDialog(parent, "SkinBrowserDialog")
@@ -43,9 +49,10 @@ SkinBrowserDlg::SkinBrowserDlg(CMainWind
 	pmSkin = new QPixmap();
 	lstIcons = new QValueList<QPixmap>;
 	lstExtIcons = new QValueList<QPixmap>;
+	lstEmoticons = new QValueList<QPixmap>;
 	lstAIcons = new QStringList();
 	lstAExtIcons = new QStringList();
-
+	
 	// Setup a list of previewable icons
 	// The strings reflect what we exptect to find in the *.icons files.
 	// The result of these two lists is used to load the icons, the order of
@@ -76,22 +83,30 @@ SkinBrowserDlg::SkinBrowserDlg(CMainWind
 	cmbSkin = new QComboBox(boxSkin);
 	QWhatsThis::add(cmbSkin, tr("Use this combo box to select one of the available skins"));
 	lblSkin->setBuddy(cmbSkin);
+	
 	QLabel *lblIcon = new QLabel(tr("&Icons:"), boxSkin);
 	cmbIcon = new QComboBox(boxSkin);
 	QWhatsThis::add(cmbIcon, tr("Use this combo box to select one of the available icon sets"));
 	lblIcon->setBuddy(cmbIcon);
+	
 	QLabel *lblExtIcon = new QLabel(tr("E&xtended Icons:"), boxSkin);
 	cmbExtIcon = new QComboBox(boxSkin);
 	QWhatsThis::add(cmbExtIcon, tr("Use this combo box to select one of the available extended icon sets"));
 	lblExtIcon->setBuddy(cmbExtIcon);
-
+	
+	QLabel *lblEmoticons = new QLabel(tr("E&moticons"), boxSkin);
+	cmbEmoticon = new QComboBox(boxSkin);
+	QWhatsThis::add(cmbEmoticon, tr("Use this combo box to select one of "
+	                                "the available emoticon icon sets"));
+  	lblEmoticons->setBuddy(cmbEmoticon);
+	
 	// Preview Box
 	QFrame *frmPrevSkin = new QFrame(boxPreview);
 	QVBoxLayout *layPrevSkin = new QVBoxLayout(frmPrevSkin);
 	QLabel *lblPrevSkin = new QLabel(tr("Skin:"), frmPrevSkin);
 	lblPrevSkin->setAlignment(Qt::AlignHCenter);
 	lblPaintSkin = new QLabel(frmPrevSkin);
-	lblPaintSkin->setFixedSize(75, 130);
+	lblPaintSkin->setFixedSize(75, MAX_HEIGHT);
 	layPrevSkin->addWidget(lblPrevSkin, 0, Qt::AlignHCenter);
 	layPrevSkin->addWidget(lblPaintSkin, 0, Qt::AlignHCenter);
 	layPrevSkin->addStretch();
@@ -101,7 +116,7 @@ SkinBrowserDlg::SkinBrowserDlg(CMainWind
 	QLabel *lblPrevIcon = new QLabel(tr("Icons:"), frmPrevIcon);
 	lblPrevIcon->setAlignment(Qt::AlignHCenter);
 	lblPaintIcon = new SkinBrowserPreviewArea(frmPrevIcon);
-	lblPaintIcon->setFixedSize(54, 130);
+	lblPaintIcon->setFixedSize(54, MAX_HEIGHT);
 	layPrevIcon->addWidget(lblPrevIcon, 0, Qt::AlignHCenter);
 	layPrevIcon->addWidget(lblPaintIcon, 0, Qt::AlignHCenter);
 	layPrevIcon->addStretch();
@@ -111,10 +126,20 @@ SkinBrowserDlg::SkinBrowserDlg(CMainWind
 	QLabel *lblPrevExtIcon = new QLabel(tr("Extended Icons:"), frmPrevExtIcon);
 	lblPrevExtIcon->setAlignment(Qt::AlignHCenter);
 	lblPaintExtIcon = new SkinBrowserPreviewArea(frmPrevExtIcon);
-	lblPaintExtIcon->setFixedSize(54, 130);
+	lblPaintExtIcon->setFixedSize(54, MAX_HEIGHT);
 	layPrevExtIcon->addWidget(lblPrevExtIcon, 0, Qt::AlignHCenter);
 	layPrevExtIcon->addWidget(lblPaintExtIcon, 0, Qt::AlignHCenter);
 	layPrevExtIcon->addStretch();
+	
+	QFrame *frmPrevEmoticon= new QFrame(boxPreview);
+	QVBoxLayout *layPrevEmoticon = new QVBoxLayout(frmPrevEmoticon);
+	QLabel *lblPrevEmoticon = new QLabel(tr("Emoticons:"), frmPrevEmoticon);
+	lblPrevEmoticon->setAlignment(Qt::AlignHCenter);
+	lblPaintEmoticon= new SkinBrowserPreviewArea(frmPrevEmoticon);
+	lblPaintEmoticon->setFixedSize(54, MAX_HEIGHT);
+	layPrevEmoticon->addWidget(lblPrevEmoticon, 0, Qt::AlignHCenter);
+	layPrevEmoticon->addWidget(lblPaintEmoticon, 0, Qt::AlignHCenter);
+	layPrevEmoticon->addStretch();
 
 	// Buttons
 	QHBoxLayout *layButtons = new QHBoxLayout(frmButtons, 8, 4);
@@ -301,6 +326,19 @@ SkinBrowserDlg::SkinBrowserDlg(CMainWind
 			}
 		}
 	}
+	
+	CEmoticons *emoticons = gMainWindow->emoticons;
+	QStringList themes = emoticons->Themes();
+	const char *selected  = emoticons->Theme();
+	int i=0, emoticonid= 0;
+	for ( QStringList::Iterator it = themes.begin(); 
+	      it != themes.end(); ++it, i++ )
+	{
+		cmbEmoticon->insertItem(*it, i);
+		if( selected && !strcmp(selected, (*it).ascii() ))
+				emoticonid = i;
+	}
+	cmbEmoticon->setCurrentItem(emoticonid);
 
 	// setup connections
 	connect(btnEdit, SIGNAL(clicked()), this, SLOT(slot_edtSkin()));
@@ -310,11 +348,13 @@ SkinBrowserDlg::SkinBrowserDlg(CMainWind
 	connect(cmbSkin, SIGNAL(highlighted(const QString &)), this, SLOT(slot_loadSkin(const QString &)));
 	connect(cmbIcon, SIGNAL(highlighted(const QString &)), this, SLOT(slot_loadIcons(const QString &)));
 	connect(cmbExtIcon, SIGNAL(highlighted(const QString &)), this, SLOT(slot_loadExtIcons(const QString &)));
+	connect(cmbEmoticon, SIGNAL(highlighted(const QString&)), this, SLOT(slot_loadEmoticons(const QString &)));
 
 	// Create initial preview
 	slot_loadSkin(cmbSkin->currentText());
 	slot_loadIcons(cmbIcon->currentText());
 	slot_loadExtIcons(cmbExtIcon->currentText());
+	slot_loadEmoticons(cmbEmoticon->currentText());
 
 	setCaption(tr("Licq Skin Browser"));
 	show();
@@ -357,6 +397,8 @@ void SkinBrowserDlg::slot_apply()
 
 	if (cmbExtIcon->currentText() != mainwin->m_szExtendedIconSet)
 		mainwin->ApplyExtendedIcons(cmbExtIcon->currentText().local8Bit());
+	if (cmbEmoticon->currentText() != mainwin->emoticons->Theme())
+		mainwin->emoticons->SetTheme(cmbEmoticon->currentText());
 }
 
 /*!	\brief Creates a new skin editor dialog
@@ -456,6 +498,36 @@ void SkinBrowserDlg::slot_loadExtIcons(c
 	}
 	lblPaintExtIcon->setPixmapList(lstExtIcons);
 }
+/*! \brief Reloads the current preview emoticons
+ *
+ *	This slot reloads all preview emoicons. It loads the complete
+ *	set of emoticons that is currently highlighted in the relevant combo
+ *	box.
+ *	If it was successful it makes these icons to be rendered in the preview.
+ */
+void SkinBrowserDlg::slot_loadEmoticons(const QString &emoticon)
+{
+	lstEmoticons->clear();
+	CEmoticons *e = gMainWindow->emoticons;
+	QStringList files = e->fileList(emoticon);
+	for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it)
+	{
+		QImage img = QImage(*it);
+		/* hack: SkinBrowserPreviewArea only draws the 
+		 * first 16 pixels
+		 */
+		int max_area = 16;
+		QSize size = img.size();
+		if( size.isValid() && 
+		    size.width() > max_area && size.height() > max_area )
+			img = img.scale(max_area, max_area, QImage::ScaleFree);
+
+		QPixmap pm(img);
+		if( ! pm.isNull())
+			lstEmoticons->append(pm);
+	}
+	lblPaintEmoticon->setPixmapList(lstEmoticons);
+}
 
 /*! \brief provide correct repainting when resizing the main widget
  *
@@ -661,7 +733,7 @@ QPixmap SkinBrowserDlg::renderSkin(const
 
 	QPixmap tmp(QPixmap::grabWidget(&w));
 	QPixmap ret;
-	ret.convertFromImage(QImage(tmp.convertToImage().smoothScale(75, 130)));
+	ret.convertFromImage(QImage(tmp.convertToImage().smoothScale(75, MAX_HEIGHT)));
 
 	// Reset origin colors
 	userView.setColors(c_online, c_away, c_offline, c_newuser, c_background, c_gridlines);
Index: plugins/qt-gui/src/skinbrowser.h
===================================================================
RCS file: /cvsroot/licq/qt-gui/src/skinbrowser.h,v
retrieving revision 1.8
diff -u -d -p -r1.8 skinbrowser.h
--- plugins/qt-gui/src/skinbrowser.h	18 Jan 2003 16:25:07 -0000	1.8
+++ plugins/qt-gui/src/skinbrowser.h	23 Aug 2003 01:26:46 -0000
@@ -42,12 +42,16 @@ private:
 	QComboBox *cmbIcon;
 	/*! This Combo contains all available extended icon packs */
 	QComboBox *cmbExtIcon;
+	/*! This Combo contains all available emoticons themes */
+	QComboBox *cmbEmoticon;
 	/*! This QLabel contains the skin preview pixmap (75 x 130 Pixel)*/
 	QLabel *lblPaintSkin;
 	/*! This SkinBrowserPreviewArea contains the icon pixmaps (54 x 130 Pixel)*/
 	SkinBrowserPreviewArea *lblPaintIcon;
 	/*! This SkinBrowserPreviewArea contains the extended icons pixmaps (54 x 130 Pixel)*/
 	SkinBrowserPreviewArea *lblPaintExtIcon;
+	/*! This SkinBrowserPreviewArea contains the emoticons pixmaps (54x130 Px) */
+	SkinBrowserPreviewArea *lblPaintEmoticon;
 	/*! Holds the list of possible themeable icons in normal icon sets */
 	QStringList *lstAIcons;
 	/*! Holds the list of possible themeable icons in extended icon sets */
@@ -58,6 +62,8 @@ private:
 	QValueList<QPixmap> *lstIcons;
 	/*! Stores the list of the current QPixmaps for the Extended Icons preview */
 	QValueList<QPixmap> *lstExtIcons;
+	/*! Stores the list of the current QPixmaps for the emoticons preview */
+	QValueList<QPixmap> *lstEmoticons;
 	/*! Renders a dynamic skin preview */
 	QPixmap renderSkin(const QString &skin);
 	CSkin *skin;
@@ -73,6 +79,7 @@ protected slots:
 	void slot_loadSkin(const QString &skin);
 	void slot_loadIcons(const QString &icon);
 	void slot_loadExtIcons(const QString &extIcon);
+	void slot_loadEmoticons(const QString &emoticon);
 };
 
 /*!	\brief Helper class to provide a preview area for our icons using a modified QFrame
--- /dev/null	1969-12-31 21:00:00.000000000 -0300
+++ plugins/qt-gui/src/emoticon.h	2003-08-19 21:41:47.000000000 -0300
@@ -0,0 +1,40 @@
+#ifndef zE1D68C95080DE073514FA90C07628F92
+#define zE1D68C95080DE073514FA90C07628F92
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+class CEmoticons {
+
+public:
+	/*!
+	 * \param basedir  base dir for icons
+	 * \param theme    sets the current theme
+	 */
+	CEmoticons(const char *basedir, const char *theme = 0 );
+	~CEmoticons();
+
+	/*! \returns the list of themes available */
+	QStringList Themes();
+	
+	/*!
+	 * sets the current theme
+	 * \retuns a negative number on error
+	 */
+	int SetTheme(const char *theme);
+	
+	/*! \returns the current theme */
+	const char *Theme(void);
+	
+	/*! \returns the list of files of the current emoticon theme */
+	QStringList fileList();
+	
+	/*! \returns the list of files for `theme` */
+	QStringList fileList(const char *theme);
+	
+	void ParseMessage(QString &msg);
+
+private:
+	struct Emoticons *data;
+};
+#endif
--- /dev/null	1969-12-31 21:00:00.000000000 -0300
+++ plugins/qt-gui/src/emoticon.cpp	2003-08-22 20:08:12.000000000 -0300
@@ -0,0 +1,314 @@
+/*
+ * Licq - A ICQ Client for Unix
+ *
+ * Copyright (C) 2003 Licq developers <[EMAIL PROTECTED]>
+ *
+ * This program is licensed under the terms found in the LICENSE file.
+ *
+ * \file support for emoticons themes. Compatible with kopete 0.6 format.
+ * \todo lot of improvents (memory vs time)
+ */
+
+#include <list>
+#include <qmap.h>
+#include <qdir.h>
+#include <qdom.h>
+#include <qregexp.h>
+
+#include "licq_log.h"
+
+#include "emoticon.h"
+
+struct node
+{	QStringList  emoticon;
+	QString      file;
+	QRegExp      reg;
+};
+
+typedef std::list<struct node> node_list_t;
+
+/*! private definition of CEmotions */
+struct Emoticons
+{	
+	QString basedir;  /* base directory for resourses */
+	QString theme;    /* current theme */
+
+	node_list_t emoticons;
+};
+
+CEmoticons::CEmoticons(const char *basedir, const char *theme  )
+{
+	this->data = new struct Emoticons;
+	data->basedir = basedir;
+}
+
+CEmoticons::~CEmoticons()
+{
+	delete this->data;
+}
+
+QStringList CEmoticons::Themes()
+{	
+	QDir dir(data->basedir, "*", 0, QDir::Dirs);
+
+	return dir.entryList().grep(QRegExp("^[^.].*"));
+}
+
+/*! 
+ * helper funcction of #loadFile. Try to add file to the list of emoticons
+ *
+ * \returns true on success
+ */
+static QString realFile(const struct Emoticons *data, const QString &theme,
+                     const QString &file)
+{
+	QString s;
+	
+	if( file != QString::null )
+	{
+		 s= data->basedir + "/" +  theme + "/" + file  + ".png";
+
+		if( !QFile(s).exists() )
+		{	gLog.Warn("%sWarning unknown file `%s'\n", L_WARNxSTR,
+			        s.ascii());
+			s = QString::null;
+		}
+	}
+	
+	return s;
+}
+
+/*!
+ * helper function for #loadFile
+ * 
+ * \return a list of characters
+ *
+ * <string>:^)</string>
+ * <string>:)</string>
+ * <string>:-)</string>
+ */
+static QStringList loadStrings(const struct Emoticons *data, QDomNode node, 
+                               unsigned *n)
+{	QStringList ret;
+
+	*n = 0U;
+
+	for( ; !node.isNull() ; node=node.nextSibling() )
+	{
+		QDomElement emo = node.toElement();
+		if( !emo.isNull() && emo.tagName() == "string" )
+		{
+			(*n) +=1;
+			ret << emo.text();
+		}
+		else
+			gLog.Warn("%sWarning element `%s'", L_WARNxSTR,
+			       emo.tagName().ascii());
+	}
+	
+	return ret;
+}
+
+static void create_regexp(QStringList &list, QRegExp &reg)
+{	
+	unsigned n = 0;
+	QString s = "(^|\\W)(";
+	
+	for ( QStringList::Iterator it = list.begin(); it!=list.end(); ++it)
+	{
+		if( n != 0)
+			s += "|";
+		s += QRegExp::escape(*it);
+		n++;
+	}
+	s += ")($|\\W)";
+
+	reg = QRegExp(s);
+}
+	
+static unsigned loadFile(const struct Emoticons *data,
+                         const QString &theme, const char *szfile,
+                         node_list_t &list)
+{
+	struct node node;
+	unsigned size;
+	QDomDocument doc("doc");
+	QFile file(szfile);
+	unsigned ret = 0;
+	
+	if ( file.open( IO_ReadOnly ) && doc.setContent( &file ) )
+	{
+		QDomElement elem = doc.documentElement();
+		QDomNode n = elem.firstChild();
+		for( ; !n.isNull() ; n= n.nextSibling() )
+		{
+			if ( n.isElement() )
+			{
+				elem = n.toElement();
+				if( !elem.isNull() && elem.tagName() ==
+				     QString::fromAscii("emoticon") )
+				{
+					QString file = elem.attribute("file");
+					QString f;
+					QStringList items= loadStrings(data,
+					                        n.firstChild(),
+					                        &size);
+					if( size && 
+					   (f=realFile(data,theme, file))
+					   !=QString::null)
+					{
+								
+						node.emoticon = items;
+						node.file = f;
+						create_regexp(items, node.reg);
+						list.push_back(node);
+						ret +=size;
+					}	
+				}
+			}
+		}
+	}
+
+	file.close();
+	return ret;
+};
+
+int CEmoticons::SetTheme(const char *theme)
+{	QString szdir = data->basedir + "/" + theme + "/";
+	node_list_t list;
+	QDir d(szdir);
+	int ret = -1;
+	unsigned n;
+	
+	if( d.exists() )
+	{	
+		szdir += "emoticons.xml";
+		n = loadFile(data, theme, szdir.ascii(), list);
+		ret = n;
+		data->theme = theme; 
+		data->emoticons = list;
+	}
+
+	return ret;
+}
+	
+const char *CEmoticons::Theme(void)
+{
+	return data->theme == QString::null ? 0 : data->theme.ascii() ;
+}
+	
+QStringList CEmoticons::fileList()
+{	
+	node_list_t::iterator iter;
+	QStringList ret;
+	struct node n;
+	
+	for( iter  = data->emoticons.begin();
+	     iter != data->emoticons.end() ;
+	     iter++ )
+	{
+		n = *iter;
+		ret << n.file;
+	}
+	
+	return ret;
+}
+
+QStringList CEmoticons::fileList(const char *theme)
+{	QString szdir = data->basedir + "/" + theme + "/";
+	QStringList ret;
+	QDir d(szdir);
+	node_list_t list;
+	node_list_t::iterator iter;
+	struct node n;
+	
+	if( d.exists() )
+	{	
+		szdir += "emoticons.xml";
+		loadFile(data, theme, szdir.ascii(), list);
+		
+		for( iter  = list.begin();
+		     iter != list.end() ; iter++ )
+		{
+			n = *iter;
+			ret << n.file;
+		}
+	}
+
+	return ret;
+}
+
+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 )
+	{
+		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+"\"/> ");
+			}
+		}
+	}
+}
+
+#ifdef EMOTICON_TEST_DRIVER
+#include <stdio.h>
+#include <iostream>
+
+int 
+main(int argc, char **argv)
+{
+	CEmoticons e = CEmoticons("/tmp/emoticons/");
+	QStringList themes = e.Themes();
+
+	std::cout << "Themes available:\n";
+	for ( QStringList::Iterator it = themes.begin();
+	       it != themes.end(); ++it )
+		std::cout << "\t" << *it << "\n";
+
+	std::cout << "\n";
+	printf("Current theme %s\n",e.Theme());
+	std::cout << "Set Theme: to abcde(" << e.SetTheme("abcde") << ")\n";
+	printf("Current theme %s\n",e.Theme());
+	
+	std::cout << "\n";
+	printf("Current theme %s\n",e.Theme());
+	
+	const char *d = argc != 1 ? argv[1] :"Default";
+	std::cout << "Set Theme: to (" << d << e.SetTheme(d) << ")\n";
+	printf("Current theme %s\n",e.Theme());
+
+	std::cout << "\n";
+	std::cout << "Filelist:\n";
+	QStringList files = e.fileList();
+	for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it)
+		std::cout << "\t" << *it << "\n";
+
+	std::cout << "\nFilelist for theme: KMess\n";
+	files = e.fileList("KMess");
+	for( QStringList::Iterator it = files.begin(); it != files.end(); ++it)
+		std::cout << "\t" << *it << "\n";
+
+	QString s = "hello word :) :( :P :-) :P";
+	std::cout << "-- Before\n";
+	std::cout << s;
+	e.ParseMessage(s);
+	std::cout << "\n-- After\n";
+	std::cout << s;
+	std::cout << "\n";
+
+	return 0;
+}
+#endif

Attachment: emoticons.tar.bz2
Description: application/tbz

<<inline: 82.png>>

<<inline: 81.png>>

Attachment: pgp00000.pgp
Description: signature

Reply via email to