Logo Search packages:      
Sourcecode: kmess version File versions  Download package

emoticontheme.cpp

/***************************************************************************
                          emoticontheme.cpp - holds a collection of emoticons
                             -------------------
    begin                : Tue April 10 2007
    copyright            : (C) 2007 by Valerio Pilo
    email                : amroth@coldshock.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 "emoticontheme.h"
#include "kmessdebug.h"

#include <qfile.h>
#include <qdir.h>
#include <qdom.h>
#include <qmap.h>
#include <qstylesheet.h>
#include <qtextcodec.h>

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

#ifdef KMESSDEBUG_EMOTICONS
#define KMESSDEBUG_EMOTICON_THEMES
#endif



/**
 * Constructor
 */
00043 EmoticonTheme::EmoticonTheme()
  : QPtrList<Emoticon>()
  , loadingTheme_(false)
  , isCustomTheme_(false)
{
  clear();
  setAutoDelete( true );
}



/**
 * Copy constructor
 *
 * Also duplicates the list of emoticons: simply copying the source's list would cause our list to be deleted
 * when the source theme is deleted
 *
 * @param other  The theme to duplicate
 */
00062 EmoticonTheme::EmoticonTheme( const EmoticonTheme &other )
  : QObject()
  , QPtrList<Emoticon>()
  , loadingTheme_(other.loadingTheme_)
  , isCustomTheme_(other.isCustomTheme_)
  , themePath_(other.themePath_)
{
  clear();
  setAutoDelete( true );

  // Duplicate one by one the other theme's emoticons
  Emoticon *emoticon;
  QPtrListIterator<Emoticon>it( other );
  while( ( emoticon = it.current() ) != 0 )
  {
    ++it;

    emoticon = new Emoticon( *emoticon );
    emoticon->update();

    append( emoticon );
  }

  // The caches cannot be easily copied (due to QMaps being implicitly shared), so regenerate them.
  updateCache();
}



/**
 * Destructor
 */
00094 EmoticonTheme::~EmoticonTheme()
{
}



/**
 * Create a new emoticon and add it to the theme
 *
 * Finds out by itself if we're adding a custom emoticon or a standard one.
 *
 * @param pictureFile  The file name of the emoticon, without path and without extension (will be guessed)
 * @param shortcuts    A list of text shortcuts which will be translated to the pictureFile image
 */
00108 void EmoticonTheme::addEmoticon( QString pictureFile, QStringList shortcuts )
{
  Emoticon *emoticon;

  if( isCustomTheme_ )
  {
    emoticon = new Emoticon( pictureFile, shortcuts.first(), themePath_ );
  }
  else
  {
    emoticon = new Emoticon( pictureFile, shortcuts.first() );
  }

  emoticon->setShortcuts( shortcuts );

  append( emoticon );

  // Only update the caches if we're adding a new custom emoticon
  if( ! loadingTheme_ && isCustomTheme_ )
  {
    updateCache();
  }
}



/**
 * Check if the theme contains a certain emoticon
 *
 * @param shortcut    The shortcut text to search for
 */
00139 bool EmoticonTheme::contains( QString shortcut )
{
  Emoticon *emoticon;
  for( emoticon = first(); emoticon != 0; emoticon = next() )
  {
    if( emoticon->getShortcuts().contains( shortcut ) )
    {
      return true;
    }
  }

  return false;
}



/**
 * Create the theme from nothing
 *
 * Any emoticons currently in the theme will be discarded!
 *
 * @param themeDir  The absolute path where the theme's emoticons.xml definition file is located
 */
00162 bool EmoticonTheme::createTheme( QString themeDir )
{
  QString themeFileName( themeDir + "emoticons.xml" );
  QFile xmlFile( themeFileName );

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::createTheme() - Loading emoticons from theme XML: '" << themeFileName << "'" << endl;
#endif

  // Try to read the XML
  if( ! xmlFile.open( IO_ReadOnly ) )
  {
#ifdef KMESSDEBUG_EMOTICON_THEMES
    kdDebug() << "EmoticonTheme::createTheme() - Could not open '" << themeFileName << "'" << endl;
#endif
    return false;
  }

  // Then try to parse it
  QDomDocument xml;
  QString      xmlError;
  if( ! xml.setContent( xmlFile.readAll(), false, &xmlError ) )
  {
#ifdef KMESSDEBUG_EMOTICON_THEMES
    kdDebug() << "EmoticonTheme::createTheme() - Failure parsing '" << themeFileName << "': " << xmlError << endl;
#endif
    xmlFile.close();
    return false;
  }

  clear();

  // 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" )
    {
      QString emoticonFile = emoticonTag.attribute( "file" );

      // Loop through all <string> tags
      QStringList shortcuts;
      QDomNode xmlChild2 = emoticonTag.firstChild();
      while( ! xmlChild2.isNull() )
      {
        // <string> tag found
        QDomElement stringTag = xmlChild2.toElement();
        if( ! stringTag.isNull() && stringTag.tagName() == "string" )
        {
          // Force the shortcuts to be at most 7 characters long, as MSN does.
          stringTag.text().truncate( 7 );
          shortcuts.append( stringTag.text() );
        }
        xmlChild2 = xmlChild2.nextSibling();
      }

      addEmoticon( emoticonFile, shortcuts );
    }
    xmlChild = xmlChild.nextSibling();
  }

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::createTheme() - Added " << count() << " emoticons." << endl;
#endif

  return true;
}



/**
 * Return the picture file names of all emoticons, mapped by their first shortcut code
 */
00237 const QMap<QString,QString>& EmoticonTheme::getFileNames() const
{
  return themeFileNames_;
}



/**
 * Return the search pattern to find emoticons in an HTML text
 */
00247 const QRegExp& EmoticonTheme::getHtmlPattern() const
{
  return patternHtml_;
}



/**
 * Return the HTML replacement codes for all emoticons
 */
00257 const QMap<QString,QString>& EmoticonTheme::getHtmlReplacements( bool small ) const
{
  if( small )
  {
    return smallHtmlReplacements_;
  }
  else
  {
    return largeHtmlReplacements_;
  }
}



/**
 * Return the search pattern to find emoticons in a text
 */
00274 const QRegExp& EmoticonTheme::getPattern() const
{
  return patternText_;
}



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



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



/**
 * Return the full path of the first emoticon of the specified theme
 *
 * This method is used by EmoticonWidget. You use it to get a "quick preview" of how a theme
 * looks like.
 *
 * @param themeDir  The absolute path where the theme's emoticons.xml definition file is located
 * @return          The absolute path of the first emoticon in the theme, or null value on error
 */
00324 QString EmoticonTheme::getThemeIcon( QString themeDir )
{
  // Add a trailing slash if the specified path doesn't have it
  if( themeDir.right( 1 ) != "/" )
  {
    themeDir += "/";
  }

  QString themeFileName( themeDir + "emoticons.xml" );
  QFile xmlFile( themeFileName );

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::getThemeIcon() - Getting first emoticon from theme XML: '" << themeFileName << "'" << endl;
#endif

  // Try to read the XML
  if( ! xmlFile.open( IO_ReadOnly ) )
  {
#ifdef KMESSDEBUG_EMOTICON_THEMES
    kdDebug() << "EmoticonTheme::getThemeIcon() - Could not open '" << themeFileName << "'" << endl;
#endif
    return QString::null;
  }

  // Then try to parse it
  QDomDocument xml;
  QString      xmlError;
  if( ! xml.setContent( xmlFile.readAll(), false, &xmlError ) )
  {
#ifdef KMESSDEBUG_EMOTICON_THEMES
    kdDebug() << "EmoticonTheme::getThemeIcon() - Failure parsing '" << themeFileName << "': " << xmlError << endl;
#endif
    xmlFile.close();
    return QString::null;
  }

  // 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" )
    {
      Emoticon *emoticon = new Emoticon( emoticonTag.attribute( "file" ), "", themeDir );

      // Search the theme until a valid emoticon is found, and return it
      if( emoticon->isValid() )
      {
        return emoticon->getPicturePath();
      }
    }
    xmlChild = xmlChild.nextSibling();
  }

  // The theme contained no valid emoticons
  return QString::null;
}



/**
 * Return where the picture files for this theme are located
 */
00388 const QString &EmoticonTheme::getThemePath()
{
  return themePath_;
}



/**
 * Load a theme, by creating it anew or by refreshing the current one
 *
 * @param themeName      The name of the theme, must be the same as the name of the folder which directly contains
 *                       emoticons.xml and the pictures
 * @param isCustomTheme  False if loading a standard theme, true if loading a custom theme
 */
00402 bool EmoticonTheme::loadTheme( QString themeName, bool isCustomTheme )
{
  bool           success = false;
  KStandardDirs *dirs = KGlobal::dirs();

  themePath_ = QString::null;
  isCustomTheme_ = isCustomTheme;

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::loadTheme() - Loading " << themeName << " as " << (isCustomTheme?"custom":"default") << " theme." << endl;
#endif

  // Try to find the theme between all possible locations
  QString resourceType, resourceDir;
  if( isCustomTheme_ )
  {
    // Custom themes are located in: [kmess app data folder]/customemoticons/[account email]
    // This call creates missing directories.
    themePath_ = locateLocal( "data", "kmess/customemoticons/" + themeName + "/emoticons.xml", true );

    QFileInfo pathInfo( themePath_ );

    // locateLocal() also returns the file name, which we don't need.
    themePath_ = pathInfo.dirPath( true ) + "/";

    // Check if the folder exists
    pathInfo.setFile( themePath_ );
    if( ! pathInfo.isDir() )
    {
      // The theme hasn't been created!
      kdWarning() << "EmoticonTheme::loadTheme() - Couldn't create the new theme folder '" << themePath_ << "'!" << endl;

      return false;
    }
  }
  else
  {
    // Standard themes can be in the KDE global emoticons dir, or in the ~/.kde/share/emoticons folder, and possibly elsewhere
    themePath_ = dirs->findResourceDir( "emoticons", themeName + "/emoticons.xml" );

    // The theme hasn't been found!
    if( themePath_.isNull() )
    {
      return false;
    }

    // findResourceDir() only returns the base path for the file you pass to it.
    themePath_ += themeName + "/";
  }


  // Set the theme loading status, needed by addEmoticon()
  loadingTheme_ = true;

  if( isCustomTheme || count() == 0 )
  {
    // If we're loading a standard theme, but there's none to update, we need to create it from scratch.
    success = createTheme( themePath_ );
  }
  else
  {
    // If loading a standard theme, always update the current one.
    success = updateTheme( themePath_ );
  }

  // Update the search&replace caches
  updateCache();

  // Reset the theme loading status, needed by addEmoticon()
  loadingTheme_ = false;

  return success;
}



/**
 * Delete a custom emoticon from the theme
 *
 * @param shortcut  The shortcut of the emoticon to remove
 */
00483 bool EmoticonTheme::removeEmoticon( QString shortcut )
{
  // Can't remove emoticons from a standard theme
  if( ! isCustomTheme_ )
  {
    return false;
  }

  Emoticon *emoticon;
  for( emoticon = first(); emoticon != 0; emoticon = next() )
  {
    if( emoticon->getShortcuts().contains( shortcut ) )
    {
      // Delete the file
      QFile( emoticon->getPicturePath() ).remove();

      // Remove the emoticon from the theme
      remove( emoticon );

      // Removing a custom emoticon, update the cache
      updateCache();

      return true;
    }
  }

  return false;
}



/**
 * Save the current theme to its XML theme definition file
 *
 * See the attached URL to view the specification for the XML emoticon definitions file.
 * We deliberately chose not to save the pictures' extensions.
 *
 * @see http://kopete.kde.org/emoticons/emoticonspec.html
 */
00522 bool EmoticonTheme::saveTheme()
{
  // Standard emoticons sets do not get changed, so there is no need to save them.
  if( ! isCustomTheme_ )
  {
    return true;
  }

  QString themeFileName( themePath_ + "emoticons.xml" );
  QFile xmlFile( themeFileName );

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::saveTheme() - Saving emoticons to theme XML: '" << themeFileName << "'" << endl;
#endif


  // Open the destination XML file
  if( ! xmlFile.open( IO_WriteOnly ) )
  {
    kdWarning() << "EmoticonTheme::saveTheme() - Save failed - couldn't open file '" << themeFileName << "'." << endl;
    KMessageBox::sorry( 0, i18n("Could not save the emoticon theme. Make sure you have permission to write to the theme folder '%1'.").arg( themePath_ ) );
    return false;
  }

  // Get encoding
  QTextCodec *codec = QTextCodec::codecForLocale();
  if( codec == 0 )
  {
    kdWarning() << "EmoticonTheme::saveTheme() - Could not find codec '" << QTextCodec::codecForLocale() << "', special characters might not be saved correctly!" << endl;
  }

  // Start the XML output using the right text encoding
  QTextStream xmlOutput( &xmlFile );
  if( codec != 0 )
  {
    xmlOutput.setCodec( codec );
  }

  // Start the XML tree by writing the root tag
  xmlOutput << "<?xml version=\"1.0\"?>" << endl << "<messaging-emoticon-map>" << endl << endl;

  // Keeping those here, could maybe be useful at a later moment for the encoding process
  // .replace("\"", "&quot;").replace("'", "&apos;").replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")

  Emoticon *emoticon;
  for( emoticon = first(); emoticon != 0; emoticon = next() )
  {
    if( ! emoticon->isValid() )
    {
      continue;
    }

    // We only need base names of the emoticons: the specs 
    QString file = QFileInfo( emoticon->getPicturePath() ).baseName( true );

    // New emoticon: the file name is encoded as HTML to avoid XML parsing errors
    xmlOutput << "\t<emoticon file=\"" << QStyleSheet::escape( file ) << "\">" << endl;

    // Add a <string> for each shortcut which maps to this emoticon,
    const QStringList &codes = emoticon->getShortcuts();
    for( QStringList::ConstIterator it = codes.begin(); it != codes.end(); ++it )
    {
      // Encode the shortcuts as HTML to avoid XML parsing errors
      QString code = *it;
      code.replace( "&", "&amp;" )
          .replace( "<", "&lt;" )
          .replace( ">", "&gt;" )
          .replace( "'", "&#39;" )
          .replace( '"', "&#34;" );

      xmlOutput << "\t\t<string>" << code << "</string>" << endl;
    }

    // End of emoticon
    xmlOutput << "\t</emoticon>" << endl << endl;
  }

  // Close the XML tree by closing the root
  xmlOutput << "</messaging-emoticon-map>" << endl;

  // Close the file, we're done
  xmlFile.close();

  return true;
}



/**
 * Rebuild the search&replace caches
 */
00613 void EmoticonTheme::updateCache()
{
  QStringList::const_iterator it;
  Emoticon *emoticon;
  QString   emoticonHtmlPattern;
  QString   emoticonTextPattern;
  QFileInfo file;

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::updateCache() - Updating the caches." << endl;
#endif

  // Remove all replacements, some emoticons may be no longer valid
  smallReplacements_.clear();
  largeReplacements_.clear();
  smallHtmlReplacements_.clear();
  largeHtmlReplacements_.clear();
  themeFileNames_.clear();

  // HACK: Find all HTML entities followed by ")" or "-)". Since there is no replacement for this match, text
  // like "&amp;)" will not be replaced by "&amp<img..alt=';)'..>" but will be skipped. See the pertinent hack
  // at ChatMessageStyle::parseMsnPlus().
  // TODO: Check if this is avoidable with Qt4's HTML implementation
  emoticonHtmlPattern = "\x26#?[a-z0-9]+;-?\\)|";

  for( emoticon = first(); emoticon != 0; emoticon = next() )
  {
    if( ! emoticon->isValid() )
    {
#ifdef KMESSDEBUG_EMOTICON_THEMES
      kdDebug() << "EmoticonTheme::updateCache() - Invalid emoticon '" << emoticon->getPicturePath()
                << "' with code: " << emoticon->getShortcut() << endl;
#endif
      continue;
    }

    // Generate the HTML tag which represents the emoticon
    QString htmlSmall = emoticon->getHtml( true );
    QString htmlLarge = emoticon->getHtml( false );

    // Traverse all shortcuts of this emoticon
    const QStringList &codes = emoticon->getShortcuts();
    for( it = codes.begin(); it != codes.end(); ++it)
    {
      const QString &code = *it;

      // Convert to HTML the main significant HTML control characters
      QString htmlCode = code;
      htmlCode.replace( "&", "&amp;" )
              .replace( "<", "&lt;" )
              .replace( ">", "&gt;" )
              .replace( "'", "&#39;" )
              .replace( '"', "&#34;" );

      // Add the current code to the replacement lists..
      smallReplacements_.insert(code, htmlSmall);
      largeReplacements_.insert(code, htmlLarge);
      smallHtmlReplacements_.insert(htmlCode, htmlSmall);
      largeHtmlReplacements_.insert(htmlCode, htmlLarge);

      // ..to the filenames list..
      file.setFile( emoticon->getPicturePath() );
      themeFileNames_.insert( code, file.fileName() );

      // ..and to the emoticon regexp patterns
      if( emoticonTextPattern.length() > 0 )
      {
        // The code is already escaped
        emoticonHtmlPattern += "|";
        emoticonTextPattern += "|";
      }

      emoticonHtmlPattern += QRegExp::escape( htmlCode );
      emoticonTextPattern += QRegExp::escape( code );
    }
  }

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::updateCache() - Cache contains " << largeReplacements_.count() << " emoticons." << endl;
#endif

  // Cache the patterns.
  if( emoticonHtmlPattern.isEmpty() || emoticonTextPattern.isEmpty() )
  {
    patternHtml_.setPattern( "\0" );
    patternText_.setPattern( "\0" );
  }
  else
  {
    patternHtml_.setPattern( emoticonHtmlPattern );
    patternText_.setPattern( emoticonTextPattern );
  }

  // Update the emoticon titles (only for standard themes)
  if( ! isCustomTheme_ )
  {
    updateTitles();
  }

  emit updated();
}



/**
 * Update a standard theme with names for the standard MSN emoticons
 */
00720 void EmoticonTheme::updateTitles()
{
  // Preset titles are only valid for standard themes
  if( isCustomTheme_ )
  {
    return;
  }

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::updateTitles() - Updating standard emoticons names..." << endl;
#endif

  QString name;
  Emoticon *emoticon;
  QMap<QString,QString> emoticonTitles;

  emoticonTitles[ "smile"          ] = i18n( "Smile"                   );
  emoticonTitles[ "wink"           ] = i18n( "Wink"                    );
  emoticonTitles[ "tongue"         ] = i18n( "Tongue out"              );
  emoticonTitles[ "teeth"          ] = i18n( "Big smile"               );
  emoticonTitles[ "sad"            ] = i18n( "Sad"                     );
  emoticonTitles[ "cry"            ] = i18n( "Crying"                  );
  emoticonTitles[ "angry"          ] = i18n( "Angry"                   );
  emoticonTitles[ "confused"       ] = i18n( "Confused"                );
  emoticonTitles[ "embarrassed"    ] = i18n( "Embarrassed"             );
  emoticonTitles[ "ugly"           ] = i18n( "Disappointed"            );
  emoticonTitles[ "shade"          ] = i18n( "Hot"                     );
  emoticonTitles[ "baringteeth"    ] = i18n( "Baring teeth"            );
  emoticonTitles[ "nerd"           ] = i18n( "Nerd"                    );
  emoticonTitles[ "sick"           ] = i18n( "Sick"                    );
  emoticonTitles[ "omg"            ] = i18n( "Surprised"               );
  emoticonTitles[ "party"          ] = i18n( "Party"                   );
  emoticonTitles[ "sleepy"         ] = i18n( "Sleepy"                  );
  emoticonTitles[ "thinking"       ] = i18n( "Thinking"                );
  emoticonTitles[ "sshh"           ] = i18n( "Don't tell anyone"       );
  emoticonTitles[ "secret"         ] = i18n( "Secret telling"          );
  emoticonTitles[ "eyeroll"        ] = i18n( "Eye-rolling"             );
  emoticonTitles[ "sarcastic"      ] = i18n( "Sarcastic"               );
  emoticonTitles[ "huh"            ] = i18n( "I don't know"            );
  emoticonTitles[ "brb"            ] = i18n( "Be right back"           );
  emoticonTitles[ "angel"          ] = i18n( "Angel"                   );
  emoticonTitles[ "dude_hug"       ] = i18n( "Left hug"                );
  emoticonTitles[ "boy"            ] = i18n( "Boy"                     );
  emoticonTitles[ "love"           ] = i18n( "Red heart"               );
  emoticonTitles[ "rose"           ] = i18n( "Red rose"                );
  emoticonTitles[ "thumbs_up"      ] = i18n( "Thumby up"               );
  emoticonTitles[ "dog"            ] = i18n( "Dog face"                );
  emoticonTitles[ "sun"            ] = i18n( "Sun"                     );
  emoticonTitles[ "devil"          ] = i18n( "Devil"                   );
  emoticonTitles[ "girl_hug"       ] = i18n( "Right hug"               );
  emoticonTitles[ "girl"           ] = i18n( "Girl"                    );
  emoticonTitles[ "unlove"         ] = i18n( "Broken heart"            );
  emoticonTitles[ "wilted_rose"    ] = i18n( "Wilted rose"             );
  emoticonTitles[ "thumbs_down"    ] = i18n( "Thumbs down"             );
  emoticonTitles[ "cat"            ] = i18n( "Cat face"                );
  emoticonTitles[ "moon"           ] = i18n( "Sleeping half-moon"      );
  emoticonTitles[ "kiss"           ] = i18n( "Red lips"                );
  emoticonTitles[ "highfive"       ] = i18n( "Clapping"                );
  emoticonTitles[ "fingerscrossed" ] = i18n( "Crossed fingers"         );
  emoticonTitles[ "automobile"     ] = i18n( "Auto"                    );
  emoticonTitles[ "airplane"       ] = i18n( "Airplane"                );
  emoticonTitles[ "turtle"         ] = i18n( "Turtle"                  );
  emoticonTitles[ "snail"          ] = i18n( "Snail"                   );
  emoticonTitles[ "sheep"          ] = i18n( "Black sheep"             );
  emoticonTitles[ "goat"           ] = i18n( "Goat"                    );
  emoticonTitles[ "bat"            ] = i18n( "Vampire bat"             );
  emoticonTitles[ "pizza"          ] = i18n( "Pizza"                   );
  emoticonTitles[ "beer"           ] = i18n( "Beer mug"                );
  emoticonTitles[ "cocktail"       ] = i18n( "Martini glass"           );
  emoticonTitles[ "cup"            ] = i18n( "Coffee cup"              );
  emoticonTitles[ "cake"           ] = i18n( "Birthday cake"           );
  emoticonTitles[ "plate"          ] = i18n( "Plate"                   );
  emoticonTitles[ "bowl"           ] = i18n( "Bowl"                    );
  emoticonTitles[ "star"           ] = i18n( "Star"                    );
  emoticonTitles[ "rainbow"        ] = i18n( "Rainbow"                 );
  emoticonTitles[ "storm"          ] = i18n( "Stormy cloud"            );
  emoticonTitles[ "lightning"      ] = i18n( "Lightning"               );
  emoticonTitles[ "umbrella"       ] = i18n( "Umbrella"                );
  emoticonTitles[ "island"         ] = i18n( "Island with a palm tree" );
  emoticonTitles[ "phone"          ] = i18n( "Telephone receiver"      );
  emoticonTitles[ "mobilephone"    ] = i18n( "Mobile Phone"            );
  emoticonTitles[ "envelope"       ] = i18n( "Email"                   );
  emoticonTitles[ "clock"          ] = i18n( "Clock"                   );
  emoticonTitles[ "camera"         ] = i18n( "Camera"                  );
  emoticonTitles[ "film"           ] = i18n( "Filmstrip"               );
  emoticonTitles[ "note"           ] = i18n( "Note"                    );
  emoticonTitles[ "handcuffs"      ] = i18n( "Handcuffs"               );
  emoticonTitles[ "money"          ] = i18n( "Money"                   );
  emoticonTitles[ "lightbulb"      ] = i18n( "Light bulb"              );
  emoticonTitles[ "cigarette"      ] = i18n( "Cigarrette"              );
  emoticonTitles[ "soccer"         ] = i18n( "Soccer ball"             );
  emoticonTitles[ "present"        ] = i18n( "Gift with a bow"         );
  emoticonTitles[ "gameconsole"    ] = i18n( "X-Box"                   );
  emoticonTitles[ "computer"       ] = i18n( "Computer"                );
  emoticonTitles[ "messenger"      ] = i18n( "KMess Icon"              );

  for( emoticon = first(); emoticon != 0; emoticon = next() )
  {
    name = emoticon->getPictureName();
    if( emoticonTitles.contains( name ) )
    {
      emoticon->setTooltip( emoticonTitles[ name ] );
    }
  }
}



/**
 * Update the currently loaded theme with new images
 *
 * The existing emoticons are not deleted: every emoticon in the new theme which matches a
 * shortcut in the current one will have the corresponding image updated.
 *
 * @param themeDir  The absolute path where the theme's emoticons.xml definition file is located
 */
00836 bool EmoticonTheme::updateTheme( QString themeDir )
{
  Emoticon *emoticon;
  QString themeFileName( themeDir + "emoticons.xml" );
  QFile xmlFile( themeFileName );

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::updateTheme() - Updating emoticons from theme XML: '" << themeFileName << "'" << endl;
#endif


  // Try to read the XML
  if( ! xmlFile.open( IO_ReadOnly ) )
  {
#ifdef KMESSDEBUG_EMOTICON_THEMES
    kdDebug() << "EmoticonTheme::updateTheme() - Could not open '" << themeFileName << "'" << endl;
#endif
    return false;
  }

  // Try to parse XML
  QDomDocument xml;
  QString      xmlError;
  if( ! xml.setContent( xmlFile.readAll(), false, &xmlError ) )
  {
#ifdef KMESSDEBUG_EMOTICON_THEMES
    kdDebug() << "EmoticonTheme::updateTheme() - Failure parsing '" << themeFileName << "': " << xmlError << endl;
#endif

    xmlFile.close();
    return false;
  }


  // 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" )
        {
          // Force the shortcuts to be at most 7 characters long, as MSN does.
          stringTag.text().truncate( 7 );

          // Insert code in the map
          themeFiles.insert( stringTag.text(), emoticonFile );
        }
        xmlChild2 = xmlChild2.nextSibling();
      }
    }
    xmlChild = xmlChild.nextSibling();
  }

#ifdef KMESSDEBUG_EMOTICON_THEMES
  kdDebug() << "EmoticonTheme::updateTheme() - Updated " << themeFiles.count() << " emoticons, setting them up." << endl;
#endif

  // 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->getShortcuts();

    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->setPictureName( themeFiles[code] );    // already calls update()
        codeFound = true;
        break;
      }
    }

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

  return true;
}



#include "emoticontheme.moc"

Generated by  Doxygen 1.6.0   Back to index