Logo Search packages:      
Sourcecode: kmess version File versions

emoticoncollection.cpp

/***************************************************************************
                          emoticoncollection.cpp  -  description
                             -------------------
    begin                : Mon Apr 15 2002
    copyright            : (C) 2003 by Michael Curtis
    email                : mdcurtis@users.sourceforge.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 **************************************************************************/

#include "emoticoncollection.h"

#include <qcolor.h>
#include <qptrlist.h>
#include <qregexp.h>
#include <qfile.h>
#include <qdom.h>
#include <qstringlist.h>

#include <kdebug.h>
#include <klocale.h>
#include <kstddirs.h>

#include "emoticon.h"
#include "kmessdebug.h"
#include "currentaccount.h"

#ifdef KMESSDEBUG_EMOTICONS
#define KMESSDEBUG_EMOTICONS_GENERAL
#endif


// Initialize the instance to zero
EmoticonCollection* EmoticonCollection::instance_(0);


// The constructor
EmoticonCollection::EmoticonCollection()
  : QObject(0, "EmoticonCollection")
  , QPtrList<Emoticon>()
{
#ifdef KMESSDEBUG_EMOTICONS_GENERAL
  kdDebug() << "EmoticonCollection: initializing MSN emoticon list." << endl;
#endif

  Emoticon *emoticon;

  clear();
  setAutoDelete( true );

  // MSN6 Smiley definitions added by Mokoshi

  // put some emoticons in our collection
  emoticon = new Emoticon( "smile", i18n("Smile") );
  emoticon->addText( ":)"  );
  emoticon->addText( ":-)" );
  append( emoticon );

  emoticon = new Emoticon( "wink", i18n("Wink") );
  emoticon->addText( ";)"  );
  emoticon->addText( ";-)" );
  append( emoticon );

  emoticon = new Emoticon( "tongue", i18n("Tongue out") );
  emoticon->addText( ":P"  );
  emoticon->addText( ":p"  );
  emoticon->addText( ":-P" );
  emoticon->addText( ":-p" );
  append( emoticon );

  emoticon = new Emoticon( "teeth", i18n("Big smile") );
  emoticon->addText( ":D"      );
  emoticon->addText( ":d"      );
  emoticon->addText( ":-D"     );
  emoticon->addText( ":-d"     );
  emoticon->addText( ":>"      );
  emoticon->addText( ":->"     );
  emoticon->addText( ":&gt;"   );
  emoticon->addText( ":-&gt;"  );
  append( emoticon );

  emoticon = new Emoticon( "sad", i18n("Sad") );
  emoticon->addText( ":("   );
  emoticon->addText( ":-("  );
  emoticon->addText( ":<"     );
  emoticon->addText( ":-<"    );
  emoticon->addText( ":&lt;"  );
  emoticon->addText( ":-&lt;" );
  append( emoticon );

  emoticon = new Emoticon( "cry", i18n("Crying") );
  emoticon->addText( ":'(" );
  append( emoticon );

  emoticon = new Emoticon( "angry", i18n("Angry") );
  emoticon->addText( ":@" );
  emoticon->addText( ":-@" );
  append( emoticon );

  emoticon = new Emoticon( "confused", i18n("Confused") );
  emoticon->addText( ":S"  );
  emoticon->addText( ":s"  );
  emoticon->addText( ":-S" );
  emoticon->addText( ":-s" );
  append( emoticon );

  emoticon = new Emoticon( "embarrassed", i18n("Embarrassed") );
  emoticon->addText( ":$"  );
  emoticon->addText( ":-$" );
  append( emoticon );

  emoticon = new Emoticon( "ugly", i18n("Disappointed") );
  emoticon->addText( ":|"  );
  emoticon->addText( ":-|" );
  append( emoticon );

  emoticon = new Emoticon( "shade", i18n("Hot") );
  emoticon->addText( "(H)" );
  emoticon->addText( "(h)" );
  append( emoticon );

  emoticon = new Emoticon( "baringteeth", i18n("Baring teeth") );
  emoticon->addText( "8o|" );
  append( emoticon );

  emoticon = new Emoticon( "nerd", i18n("Nerd") );
  emoticon->addText( "8-|" );
  append( emoticon );

  emoticon = new Emoticon( "sick", i18n("Sick") );
  emoticon->addText( "+o(" );
  append( emoticon );

  emoticon = new Emoticon( "omg", i18n("Surprised") );
  emoticon->addText( ":O"  );
  emoticon->addText( ":o"  );
  emoticon->addText( ":-O" );
  emoticon->addText( ":-o" );
  append( emoticon );

  emoticon = new Emoticon( "party", i18n("Party") );
  emoticon->addText( "<:o)"    );
  emoticon->addText( "&lt;:o)" );
  append( emoticon );

  emoticon = new Emoticon( "sleepy", i18n("Sleepy") );
  emoticon->addText( "|-)" );
  append( emoticon );

  emoticon = new Emoticon( "thinking", i18n("Thinking") );
  emoticon->addText( "*-)" );
  append( emoticon );

  emoticon = new Emoticon( "sshh", i18n("Don't tell anyone") );
  emoticon->addText( ":-#" );
  append( emoticon );

  emoticon = new Emoticon( "secret", i18n("Secret telling") );
  emoticon->addText( ":-*" );
  append( emoticon );

  emoticon = new Emoticon( "eyeroll", i18n("Eye-rolling") );
  emoticon->addText( "8-)" );
  append( emoticon );

  emoticon = new Emoticon( "sarcastic", i18n("Sarcastic") );
  emoticon->addText( "^o)" );
  append( emoticon );

  emoticon =  new Emoticon( "huh", i18n("I don't know") );
  emoticon->addText( ":^)" );
  append( emoticon );

  emoticon = new Emoticon( "brb", i18n("Be right back") );
  emoticon->addText( "(brb)" );
  append( emoticon );

  emoticon = new Emoticon( "angel", i18n("Angel") );
  emoticon->addText( "(A)" );
  emoticon->addText( "(a)" );
  append( emoticon );

  emoticon = new Emoticon( "dude_hug", i18n("Left hug") );
  emoticon->addText( "({)" );
  append( emoticon );

  emoticon = new Emoticon( "boy", i18n("Boy") );
  emoticon->addText( "(Z)" );
  emoticon->addText( "(z)" );
  append( emoticon );

  emoticon = new Emoticon( "love", i18n("Red heart") );
  emoticon->addText( "(L)" );
  emoticon->addText( "(l)" );
  append( emoticon );

  emoticon = new Emoticon( "rose", i18n("Red rose") );
  emoticon->addText( "(F)" );
  emoticon->addText( "(f)" );
  append( emoticon );

  emoticon = new Emoticon( "thumbs_up", i18n("Thumby up") );
  emoticon->addText( "(Y)" );
  emoticon->addText( "(y)" );
  append( emoticon );

  emoticon = new Emoticon( "dog", i18n("Dog face") );
  emoticon->addText( "(&)"     );
  emoticon->addText( "(&amp;)" );
  append( emoticon );

  emoticon = new Emoticon( "sun", i18n("Sun") );
  emoticon->addText( "(#)" );
  append( emoticon );

  emoticon = new Emoticon( "devil", i18n("Devil") );
  emoticon->addText( "(6)" );
  append( emoticon );

  emoticon = new Emoticon( "girl_hug", i18n("Right hug") );
  emoticon->addText( "(})" );
  append( emoticon );

  emoticon = new Emoticon( "girl", i18n("Girl") );
  emoticon->addText( "(X)" );
  emoticon->addText( "(x)" );
  append( emoticon );

  emoticon = new Emoticon( "unlove", i18n("Broken heart") );
  emoticon->addText( "(U)" );
  emoticon->addText( "(u)" );
  append( emoticon );

  emoticon = new Emoticon( "wilted_rose", i18n("Wilted rose") );
  emoticon->addText( "(W)" );
  emoticon->addText( "(w)" );
  append( emoticon );

  emoticon = new Emoticon( "thumbs_down", i18n("Thumbs down") );
  emoticon->addText( "(N)" );
  emoticon->addText( "(n)" );
  append( emoticon );

  emoticon = new Emoticon( "cat", i18n("Cat face") );
  emoticon->addText( "(@)" );
  append( emoticon );

  emoticon = new Emoticon( "moon", i18n("Sleeping half-moon") );
  emoticon->addText( "(S)" );
  append( emoticon );

  emoticon = new Emoticon( "kiss", i18n("Red lips") );
  emoticon->addText( "(K)" );
  emoticon->addText( "(k)" );
  append( emoticon );

  emoticon = new Emoticon( "highfive", i18n("Clapping") );
  emoticon->addText( "(h5)" );
  append( emoticon );

  emoticon = new Emoticon( "fingerscrossed", i18n("Crossed fingers") );
  emoticon->addText( "(yn)" );
  append( emoticon );

  emoticon = new Emoticon( "automobile", i18n("Auto") );
  emoticon->addText( "(au)" );
  append( emoticon );

  emoticon = new Emoticon( "airplane", i18n("Airplane") );
  emoticon->addText( "(ap)" );
  append( emoticon );

  emoticon = new Emoticon( "turtle", i18n("Turtle") );
  emoticon->addText( "(tu)" );
  append( emoticon );

  emoticon = new Emoticon( "snail", i18n("Snail") );
  emoticon->addText( "(sn)" );
  append( emoticon );

  emoticon = new Emoticon( "sheep", i18n("Black sheep") );
  emoticon->addText( "(bah)" );
  append( emoticon );

  emoticon = new Emoticon( "goat", i18n("Goat") );
  emoticon->addText( "(nah)" );
  append( emoticon );

  emoticon = new Emoticon( "bat", i18n("Vampire bat") );
  emoticon->addText( ":["  );
  emoticon->addText( ":-[" );
  append( emoticon );

  emoticon = new Emoticon( "pizza", i18n("Pizza") );
  emoticon->addText( "(pi)" );
  append( emoticon );

  emoticon = new Emoticon( "beer", i18n( "Beer mug" ) );
  emoticon->addText( "(B)" );
  emoticon->addText( "(b)" );
  append( emoticon );

  emoticon = new Emoticon( "cocktail", i18n("Martini glass") );
  emoticon->addText( "(D)" );
  emoticon->addText( "(d)" );
  append( emoticon );

  emoticon = new Emoticon( "cup", i18n("Coffee cup") );
  emoticon->addText( "(C)" );
  emoticon->addText( "(c)" );
  append( emoticon );

  emoticon = new Emoticon( "cake", i18n("Birthday cake") );
  emoticon->addText( "(^)" );
  append( emoticon );

  emoticon = new Emoticon( "plate", i18n("Plate") );
  emoticon->addText( "(pl)" );
  append( emoticon );

  emoticon = new Emoticon( "bowl", i18n("Bowl") );
  emoticon->addText( "(||)" );
  append( emoticon );

  emoticon =  new Emoticon( "star", i18n("Star") );
  emoticon->addText( "(*)" );
  append( emoticon );

  emoticon = new Emoticon( "rainbow", i18n("Rainbow") );
  emoticon->addText( "(R)" );
  emoticon->addText( "(r)" );
  append( emoticon );

  emoticon = new Emoticon( "storm", i18n("Stormy cloud") );
  emoticon->addText( "(st)" );
  append( emoticon );

  emoticon = new Emoticon( "lightning", i18n("Lightning") );
  emoticon->addText( "(li)" );
  append( emoticon );

  emoticon = new Emoticon( "umbrella", i18n("Umbrella") );
  emoticon->addText( "(um)" );
  append( emoticon );

  emoticon = new Emoticon( "island", i18n("Island with a palm tree") );
  emoticon->addText( "(ip)" );
  append( emoticon );

  emoticon = new Emoticon( "phone", i18n("Telephone receiver") );
  emoticon->addText( "(T)" );
  emoticon->addText( "(t)" );
  append( emoticon );

  emoticon = new Emoticon( "mobilephone", i18n("Mobile Phone") );
  emoticon->addText( "(mp)" );
  append( emoticon );

  emoticon = new Emoticon( "envelope", i18n("Email") );
  emoticon->addText( "(E)" );
  emoticon->addText( "(e)" );
  append( emoticon );

  emoticon = new Emoticon( "clock", i18n("Clock") );
  emoticon->addText( "(O)" );
  emoticon->addText( "(o)" );
  emoticon->addText( "(0)" ); // a zero, not O
  append( emoticon );

  emoticon = new Emoticon( "camera", i18n("Camera") );
  emoticon->addText( "(P)" );
  emoticon->addText( "(p)" );
  append( emoticon );

  emoticon = new Emoticon( "film", i18n("Filmstrip") );
  emoticon->addText( "(~)" );
  append( emoticon );

  emoticon = new Emoticon( "note", i18n("Note") );
  emoticon->addText( "(8)" );
  append( emoticon );

  emoticon = new Emoticon( "handcuffs", i18n("Handcuffs") );
  emoticon->addText( "(%)" );
  append( emoticon );

  emoticon = new Emoticon( "money", i18n("Money") );
  emoticon->addText( "(mo)" );
  append( emoticon );

  emoticon = new Emoticon( "lightbulb", i18n("Light bulb") );
  emoticon->addText( "(I)" );
  emoticon->addText( "(i)" );
  append( emoticon );

  emoticon = new Emoticon( "cigarette", i18n("Cigarrette") );
  emoticon->addText( "(ci)" );
  append( emoticon  );

  emoticon = new Emoticon( "soccer", i18n("Soccer ball") );
  emoticon->addText( "(so)" );
  append( emoticon );

  emoticon = new Emoticon( "present", i18n("Gift with a bow") );
  emoticon->addText( "(G)" );
  emoticon->addText( "(g)" );
  append( emoticon );

  emoticon = new Emoticon( "gameconsole", i18n("X-Box") );
  emoticon->addText( "(xx)" );
  append( emoticon );

  emoticon = new Emoticon( "computer", i18n("Computer") );
  emoticon->addText( "(co)" );
  append( emoticon );

  emoticon = new Emoticon( "messenger", i18n("KMess Icon") );
  emoticon->addText( "(M)" );
  emoticon->addText( "(m)" );
  append( emoticon );

  /*
    // Trick to generate the emoticons.xml file:

  for( emoticon = first(); emoticon != 0; emoticon = next() )
  {
    kdDebug() << "<emoticon file=\"" << emoticon->getFileTitle() << "\">" << endl;
    const QStringList &codes = emoticon->getTextList();
    for( QStringList::ConstIterator it = codes.begin(); it != codes.end(); ++it )
    {
      kdDebug() << "\t<string>" << QString( *it ).replace("&amp;", "&").replace("<", "&lt;").replace(">", "&gt;") << "</string>" << endl;
    }
    kdDebug() << "</emoticon>\n" << endl;
  }
  */


  // Build a search-pattern for the regexp.
  updateCache();
}



// The destructor
EmoticonCollection::~EmoticonCollection()
{
}



// Delete the instance of the emoticon collection
void EmoticonCollection::destroy()
{
  delete instance_;
  instance_ = 0;
}



// Return the search pattern to find emoticons in the text
const QRegExp& EmoticonCollection::getPattern() const
{
  return pattern_;
}



// Return one replacement code for the given emoticons
const QString & EmoticonCollection::getReplacement(const QString &code, bool small) const
{
  if( small )
  {
    return smallReplacements_[code];
  }
  else
  {
    return largeReplacements_[code];
  }
}


// Return the replacement codes for all emoticons
const QMap<QString,QString>& EmoticonCollection::getReplacements(bool small) const
{
  if( small )
  {
    return smallReplacements_;
  }
  else
  {
    return largeReplacements_;
  }
}



// Return a singleton instance of the emoticon collection
EmoticonCollection* EmoticonCollection::instance()
{
  // If the instance is null, create a new emoticon collection and return that.
  if ( instance_ == 0 )
  {
    instance_ = new EmoticonCollection();
    connect( CurrentAccount::instance(), SIGNAL(changedEmoticonSettings()     ),
             instance_,                    SLOT(slotChangedEmoticonSettings() ) );
  }
  return instance_;
}



// Replace the emoticons in the text with the urls to the emoticon pngs.
void EmoticonCollection::parseEmoticons( QString &text, bool small )
{
  int pos = 0;
  const QMap<QString,QString> &replacements = getReplacements(small);

  while( pos != -1 )
  {
    pos = pattern_.search(text, pos);

    if( pos != -1 )
    {
      // Found a emoticon
      QString code = text.mid(pos, pattern_.matchedLength());
      if( replacements.contains(code) )
      {
        QString replacement = replacements[code];
        text = text.replace(pos, pattern_.matchedLength(), replacement);
        pos += replacement.length();
      }
      else
      {
        // No replacement found, preserve original code, move to next
        pos++;
      }
    }
  }
}



// The emoticon theme has changed
void EmoticonCollection::slotChangedEmoticonSettings()
{
#ifdef KMESSDEBUG_EMOTICONS_GENERAL
  kdDebug() << "EmoticonCollection: emoticon style changed, updating emoticons." << endl;
#endif

  // First try to open the theme.
  // This collection won't be replaced with the emoticon definitions from the theme file,
  // since KMess is an MSN-only client and other clients don't support these special emoticons.
  // Instead, the current emoticon collection is kept, and the code tries to detect which
  // filenames the theme uses for certain emoticon codes.
  Emoticon *emoticon;

  // Find out which theme is used now.
  const QString &currentStyle = CurrentAccount::instance()->getEmoticonStyle();
  QString xmlFileName = KGlobal::dirs()->findResource("emoticons", currentStyle + "/emoticons.xml");
  QFile xmlFile(xmlFileName);

  // Try to read the XML
  if( ! xmlFile.open(IO_ReadOnly) )
  {
    kdWarning() << "EmoticonCollection: could not open '" << xmlFileName << "'" << endl;
  }
  else
  {
    // Try to parse XML
    QDomDocument xml;
    QString      xmlError;
    if( ! xml.setContent(xmlFile.readAll(), false, &xmlError) )
    {
      kdWarning() << "EmoticonCollection: parsing '" << xmlFileName << "' failed: " << xmlError << endl;
      xmlFile.close();
    }
    else
    {
      // Load the codes in a map for efficient lookup
      QMap<QString,QString> themeFiles;

      // Loop through all <emoticon> tags
      QDomNode xmlChild = xml.documentElement().firstChild();
      while( ! xmlChild.isNull() )
      {
        // <emoticon> tag found
        QDomElement emoticonTag = xmlChild.toElement();
        if( ! emoticonTag.isNull() && emoticonTag.tagName() == "emoticon" )
        {
          // Loop through all <string> tags
          QString emoticonFile = emoticonTag.attribute("file");
          QDomNode xmlChild2 = emoticonTag.firstChild();
          while( ! xmlChild2.isNull() )
          {
            // <string> tag found
            QDomElement stringTag = xmlChild2.toElement();
            if( ! stringTag.isNull() && stringTag.tagName() == "string" )
            {
              // Insert code in the map
              themeFiles.insert( stringTag.text(), emoticonFile );
            }
            xmlChild2 = xmlChild2.nextSibling();
          }
        }
        xmlChild = xmlChild.nextSibling();
      }

      // Loop through all current emoticons.
      for( emoticon = last(); emoticon != 0; emoticon = prev() )
      {
        // Loop through all codes of the emoticon
        bool  codeFound = false;
        const QStringList &codes = emoticon->getTextList();

        for( QStringList::ConstIterator it = codes.begin(); it != codes.end(); ++it )
        {
          const QString &code = *it;
          // If the emoticon uses that code, set it.
          if( themeFiles.contains(code) )
          {
            emoticon->setFileTitle( themeFiles[code] );    // already calls updatePath()
            codeFound = true;
            break;
          }
        }

        // If the code was not found, the file still needs to be updated manually.
        if(! codeFound)
        {
          emoticon->updatePath();
        }
      }

      // Update the search-replace cache
      updateCache();

      // Each emoticon is updated, the function is done now.
      return;
    }
  }


  // Tell each emoticon to update their path
  // This is only called when the emoticon set can't be loaded.
  for( emoticon = last(); emoticon != 0; emoticon = prev() )
  {
    emoticon->updatePath();
  }

  // Update the search-replace cache
  updateCache();
}



// Build the search-replace cache
void EmoticonCollection::updateCache()
{
  QStringList::const_iterator it;
  Emoticon *emoticon;
  QString   emoticonPattern;

  // Remove all replacements, some emoticons are no longer valid
  smallReplacements_.clear();
  largeReplacements_.clear();

  for( emoticon = first(); emoticon != 0; emoticon = next() )
  {
    // Traverse all codes of the emoticon
    if( emoticon->isValid() )
    {
      const QStringList &codes = emoticon->getTextList();
      for( it = codes.begin(); it != codes.end(); ++it)
      {
        // Add the emoticon to the replacement list.
        const QString &code = *it;
        largeReplacements_.insert(code, emoticon->getHtml(false));
        smallReplacements_.insert(code, emoticon->getHtml(true));

        // Add the emoticon pattern to the regexp
        // The code is already escaped
        if( emoticonPattern.length() > 0 )
        {
          emoticonPattern += "|";
        }
        emoticonPattern += QRegExp::escape(code);
      }
    }
  }

  // Cache the pattern.
  pattern_.setPattern(emoticonPattern);
}


#include "emoticoncollection.moc"

Generated by  Doxygen 1.6.0   Back to index