Logo Search packages:      
Sourcecode: kmess version File versions

kmessviewdelegate.cpp

/***************************************************************************
                          kmessviewdelegate.cpp - description
                             -------------------
    begin                : Sat Feb 16 2008
    copyright            : (C) 2008 by Valerio Pilo
    email                : valerio@kmess.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "kmessviewdelegate.h"

#include "currentaccount.h"
#include "emoticonmanager.h"
#include "contact/msnstatus.h"
#include "contact/specialgroups.h"
#include "model/contactlistmodelitem.h"
#include "utils/richtextparser.h"
#include "kmessdebug.h"

#include <QModelIndex>
#include <QPainter>
#include <QTextDocument>

#include <KIconLoader>
#include <KLocale>



/**
 * Constructor
 *
 * Creates two labels which will be used to paint the contact list elements at the location of every item
 *
 * @param parent  The parent object, usually a QTreeView
 */
00044 KMessViewDelegate::KMessViewDelegate( QWidget *parent )
    : QStyledItemDelegate( parent )
    , iconLoader_( KIconLoader::global() )
{
  // Create test document
  textDocument_ = new QTextDocument();

  // Save the current account's reference
  currentAccount_ = CurrentAccount::instance();

  fontBold_.setBold( true );

  // Cache the icons for the various media types
  mediaEmoticonMusic_  = EmoticonManager::instance()->getReplacement( "(8)",  true );
  mediaEmoticonGaming_ = EmoticonManager::instance()->getReplacement( "(xx)", true );
}



/**
 * Destructor
 */
00066 KMessViewDelegate::~KMessViewDelegate()
{
  delete textDocument_;
}



/**
 * Paint an item of the contact list
 *
 * This method is called whenever a contact list item needs do be drawn.
 * The 'index' parameter is used to extract the data from the list item, and depending on the list item type
 * (contact or group mainly) it decides what needs to be drawn and how.
 *
 * @param painter Painter item, we'll use it to draw our item's contents
 * @param option  Contains some details about the item we have to draw
 * @param index   Points to the actual data to be represented
 */
00084 void KMessViewDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
  QStyledItemDelegate::paint( painter, option, index );
  // Only render column zero
  if( index.column() != 0 )
  {
    return;
  }

  QString text;

  // Save the painter state to avoid messing up further painting operations with it
  painter->save();

  // Reset coordinate translation in the painter (defaults are relative to the parent's window) - and make rendering prettier possibly
  painter->translate( 0, 0 );
  painter->setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform |
                           QPainter::TextAntialiasing , true );

  // Read the actual data off the model index
  const ModelDataList& itemData( index.data().toMap() );

  // Set the initial position where to paint.
  // Leave one pixel above, and one on the left, to help spacing.
  QPoint position( option.rect.topLeft() );
  position.rx()++;
  position.ry()++;

  // Paint the different types of list items
  switch( itemData[ "type" ].toInt() )
  {
    case ContactListModelItem::ItemGroup:
    {
      QString groupIconName;
      bool showOfflineContacts = currentAccount_->getShowOfflineContacts();

      // Only show the expansion arrow if there are contacts to show
      if( (   showOfflineContacts && itemData[ "totalContacts"  ].toInt() > 0 )
      ||  ( ! showOfflineContacts && itemData[ "onlineContacts" ].toInt() > 0 ) )
      {
        groupIconName = ( itemData[ "isExpanded" ].toBool() ? "arrow-down" : "arrow-right" );
      }
      else
      {
        // Show only arrow down if there aren't contacts to show in group
        groupIconName = "arrow-down";
      }

      // Get the contact's picture
      const QPixmap& pixmap( iconLoader_->loadIcon( groupIconName
                             , KIconLoader::NoGroup
                             , KIconLoader::SizeSmall ) );

      painter->drawPixmap( position, pixmap );

      // Leave a small margin next to the arrow (even if it's not drawn, so we align the group names anyway)
      position.rx() += pixmap.width() + 2;
      position.ry() += pixmap.height() -3;

      // Prepare and paint the group name
      if( ! itemData[ "isSpecialGroup" ].toBool()
      ||    itemData[ "id" ] == SpecialGroups::INDIVIDUALS )
      {
        text =  i18nc( "Group name in the contact list with online/total contacts of that group"
                      , "%1 (%2/%3)"
                      , Qt::escape( itemData[ "name" ].toString() )
                      , itemData[ "onlineContacts" ].toString()
                      , itemData[ "totalContacts"  ].toString() );
      }
      else
      {
        text =  i18nc( "Group name in the contact list with total contacts of that group"
                      , "%1 (%2)"
                      , Qt::escape( itemData[ "name" ].toString() )
                      , itemData[ "totalContacts"  ].toString() );
      }

      // Set bold font
      painter->setFont( fontBold_ );
      painter->drawText( position, text );
      break;
    }


    case ContactListModelItem::ItemContact:
    {
      int displayPictureSize = currentAccount_->getListPictureSize();

      // Use this variable to store the position when we draw the icon status on bottom edge.
      QPoint oldPosition;

      // If the contact hasn't us in its CL, colorize the line
      if( ! itemData[ "isReverse" ].toBool() ) // The contact does not have us in its list
      {
        painter->fillRect( option.rect, QColor( 255,0,0,20 ) );
      }

      // Only show the picture if it's been enabled by the user
      if( displayPictureSize != 0 )
      {
        QPixmap pixmap( itemData[ "displayPicture" ].toString() );
        // Fast scaled
        pixmap = pixmap.scaled( displayPictureSize,  displayPictureSize,
                                Qt::KeepAspectRatio );

        painter->drawPixmap( position, pixmap );

        // If the display picture is enough, show small status icon over the picture
        if( displayPictureSize >= 48 )
        {
          oldPosition = position;
          position.ry() += displayPictureSize - KIconLoader::SizeSmall;
        }
        else
        {
          // Leave a small margin next to the display picture
          position.rx() += displayPictureSize + 2;
        }
      }

      // Determine which status image to load
      Flags statusFlags = FlagNone;
      if( itemData[ "isBlocked" ].toBool() )
      {
        statusFlags = FlagBlocked;
      }

      painter->drawPixmap( position, MsnStatus::getIcon( (Status) itemData[ "status" ].toInt(), statusFlags ) );

      if( displayPictureSize >= 48 )
      {
        position = oldPosition;
        position.rx() += displayPictureSize + 4;
      }
      else
      {
        // Leave a small margin next to the status picture
        position.rx() += KIconLoader::SizeSmall + 4;
      }

      // Get the contact information.
      QString friendlyName, personalMessage;

      // Parse the name and message of the contact, adding emoticons and formatting
      if( currentAccount_->getUseListFormatting() )
      {
        if( ! currentAccount_->getShowContactEmail() )
        {
          friendlyName  = itemData[ "friendlyFormatted" ].toString();
        }
        else
        {
          friendlyName = itemData[ "handle" ].toString();
        }

        personalMessage = itemData[ "personalMessageFormatted" ].toString();
      }
      else
      {
        if( ! currentAccount_->getShowContactEmail() )
        {
          friendlyName = itemData[ "friendly" ].toString();
          RichTextParser::parseMsnString( friendlyName, true, true, false, false );
        }
        else
        {
          friendlyName = itemData[ "handle" ].toString();
        }

        // Display the emoticons alone when MSN Plus formatting is disabled: the formatted
        // version has emoticons already.
        personalMessage = itemData[ "personalMessage" ].toString();
        RichTextParser::parseMsnString( personalMessage, true, true, false, false );
      }

      // If it's empty, then the user wants to see the email in the contact list
      if( friendlyName.isEmpty() )
      {
        friendlyName = itemData[ "handle" ].toString();
      }

      QString messageString;

      const QString& mediaString( itemData[ "mediaString"     ].toString() );
      if( ! mediaString.isEmpty() )
      {
        // Determine icon for the various media types
        const QString& mediaType  ( itemData[ "mediaType" ].toString() );
        if( mediaType == "Music" )
        {
          messageString = mediaEmoticonMusic_ + "<i>" + Qt::escape( mediaString ) + "</i>";
        }
        else if( mediaType == "Gaming" )
        {
          messageString = mediaEmoticonGaming_ + "<i>" + Qt::escape( mediaString ) + "</i>";
        }
      }
      else if( ! personalMessage.isEmpty() ) // When there's no media, show the PM
      {
        messageString = "<i>" + personalMessage + "</i>";
      }

      // Draw the text widget
      if( messageString.isEmpty() )
      {
        // Only person name
        text = friendlyName;
      }
      else if( ! displayPictureSize )
      {
        // Person with message after it
        text = friendlyName + "<small><font style='color:palette(window-text)'> - " + messageString + "</font></small>";
      }
      else
      {
        // Message below, 
        text = friendlyName + "<br /><small><font style='color:palette(window-text)'>" + messageString + "</font></small>";
      }

      textDocument_->setHtml( text );
      painter->translate( position.x(), option.rect.topLeft().y() - 2 );
      textDocument_->drawContents( painter );
      break;
    }

    default:
      kWarning() << "Unknown type of item:" << itemData[ "type" ].toInt();
      kWarning() << "Index:" << index;
      kWarning() << "Data:" << itemData;
      break;
  }

  // Restore the painter to the previous state
  painter->restore();
}



/**
 * Return an hint about the size of an item
 *
 * @param option  Contains some details about the item we have to determine size of
 * @param index   Points to the actual list item
 * @return The ize for the given index
 */
00329 QSize KMessViewDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
  Q_UNUSED( option );

  // Read the actual data off the model index
  const ModelDataList& itemData( index.data().toMap() );

  const QSize size( KIconLoader::SizeSmall + 2, KIconLoader::SizeSmall + 4 );

  if( itemData.isEmpty() )
  {
    return size;
  }

  int picturesDimension = currentAccount_->getListPictureSize();
  switch( itemData[ "type" ].toInt() )
  {
    case ContactListModelItem::ItemContact:
      if( picturesDimension > 0 )
      {
        QSize pictureSize( size );
        if( picturesDimension <= 32 )
        {
          // Fix the margin
          pictureSize.rheight() = 36;
        }
        else
        {
          pictureSize.rheight() = picturesDimension + 2;
        }

        return pictureSize;
      }
      else
      {
        return size;
      }

    case ContactListModelItem::ItemGroup:
    default:
      return size;
  }
}


Generated by  Doxygen 1.6.0   Back to index