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

contactframe.cpp

/***************************************************************************
                          contactframe.cpp  -  description
                             -------------------
    begin                : Thu Jan 16 2003
    copyright            : (C) 2003 by Mike K. Bennett
    email                : mkb137b@hotmail.com
 ***************************************************************************/

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

#include <qclipboard.h>
#include <qdatetime.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qpixmap.h>
#include <qpushbutton.h>
#include <qtoolbutton.h>
#include <qtooltip.h>
#include <qfileinfo.h>

#include <kaction.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconeffect.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kpopupmenu.h>
#include <krun.h>
#include <kstddirs.h>
#include <kurl.h>
#include <ksqueezedtextlabel.h>

#include "../contact/contact.h"
#include "../contact/contactlist.h"
#include "../currentaccount.h"
#include "../kmessdebug.h"

// The constructor
ContactFrame::ContactFrame(QWidget *parent, const char *name )
 : ContactFrameInterface(parent,name)
 , activated_(false)
 , contact_(0)
 , detailedContact_(0)
 , handle_(QString::null)
{
  KStandardDirs *dirs   = KGlobal::dirs();
  QPixmap        pixmap;
  QString        path;

  // Just for show
  path = dirs->findResource( "data", "kmess/pics/unknown.png" );
  pixmap.load( path );
  contactPixmapLabel_->setPixmap( pixmap );
  contactPixmapLabel_->setMinimumSize( pixmap.width(), pixmap.height() );
  nowListeningPixmapLabel_->setPixmap( KGlobal::iconLoader()->loadIcon("knotify", KIcon::NoGroup, KIcon::SizeSmall ) );
  nowListeningPixmapLabel_->hide();

  handleLabel_       ->installEventFilter( this );
  contactPixmapLabel_->installEventFilter( this );
  installEventFilter( this );

  // Connect up the typing timer
  connect( &typingTimer_,  SIGNAL(     timeout() ),
           this,           SLOT  (  stopTyping() ) );
}



ContactFrame::~ContactFrame()
{
}



// Activate the frame by giving it a contact
void ContactFrame::activate( ContactBase *contact )
{
  if ( contact_ != 0 )
  {
    kdWarning() << "ContactFrame::activate() - Already got a contact (" << contact_->getHandle() << "), refusing new one (" << contact->getHandle() << ")." << endl;
    return;
  }

  contact_ = contact;
  handle_ = contact_->getHandle();
  detailedContact_ = CurrentAccount::instance()->getContactList()->getContactByHandle( handle_ );

  // Connect up the contact to update the frame on name, status, and picture changes
  connect( contact_, SIGNAL(    changedFriendlyName()         ),
           this,     SLOT  (    updateStatusWidgets()         ) );
  connect( contact_, SIGNAL(          changedStatus()         ),
           this,     SLOT  (    updateStatusWidgets()         ) );
  connect( contact_, SIGNAL(         changedPicture()         ),
           this,     SLOT  (          updatePicture()         ) );

  if( detailedContact_ )
  {
    connect( detailedContact_, SIGNAL( changedPersonalMessage(Contact*) ),
             this,             SLOT  (    updateStatusWidgets()         ) );
    connect( detailedContact_, SIGNAL(            changedList(Contact*) ),
             this,             SLOT  (    updateStatusWidgets()         ) );
  }

  activated_ = true;
  show();

  // Update the widget based on the contact's settings
  updateWidgets();

  // Activate the right-click context menu
  initContactPopup();
}



// Allow this contact to see our MSN status
void ContactFrame::allowContact()
{
  if ( detailedContact_ == 0 )
  {
    return;
  }

  emit setContactAllowed( handle_ );

  updateStatusWidgets();
}



// Copy some details of the contact to the clipboard.
// Only one method is used to copy all different details, and that's to avoid having three identical methods which only copy different
// text bits on the clipboard.
void  ContactFrame::copyText()
{
  // Get the signal sender to find out who called us
  KAction *action = static_cast<KAction*>( const_cast<QObject*>( sender() ) );
  if(KMESS_NULL(action)) return;

  if( action == popupCopyFriendlyName_ )
  {
    kapp->clipboard()->setText( contact_->getFriendlyName() );
  }
  else if( action == popupCopyHandle_ )
  {
    kapp->clipboard()->setText( handle_ );
  }
  else if( action == popupCopyPersonalMessage_ && detailedContact_ )
  {
    kapp->clipboard()->setText( detailedContact_->getPersonalMessage() );
  }
}



// Deactivate (grey-out) the frame when a contact leaves the chat
void ContactFrame::deactivate()
{
  enableWidgets( false );
}



// Set whether or not the widgets are enabled or disabled
void ContactFrame::enableWidgets(bool doEnable)
{
  contactPixmapLabel_      ->setEnabled( doEnable );
  handleLabel_             ->setEnabled( doEnable );
  statusPixmapLabel_       ->setEnabled( doEnable );
  statusLabel_             ->setEnabled( doEnable );
  personalMessageLabel_    ->setEnabled( doEnable );
  nowListeningPixmapLabel_ ->setEnabled( doEnable );
}



// The personal status message received an event.
bool ContactFrame::eventFilter( QObject *obj, QEvent *event )
{
  if( event->type() != QEvent::MouseButtonRelease )
  {
    return false;  // don't stop processing.
  }

  QMouseEvent *mouseEvent = static_cast<QMouseEvent*>( event );

  if( mouseEvent->button() == Qt::RightButton )
  {
    showContactPopup( mouseEvent->globalPos() );
  }
  else if( obj == handleLabel_ )
  {
    sendEmail();
  }
  else if( obj == contactPixmapLabel_ )
  {
    showProfile();
  }

  return false;  // don't stop processing.
}



// Return the handle of this frame's contact
QString ContactFrame::getHandle() const
{
  return handle_;
}



// Initialize the contact popup
bool ContactFrame::initContactPopup()
{
  if ( contact_ == 0 )
  {
    return false;
  }

  // Initialize context popup actions
  popupEmailContact_        = new KAction( i18n("&Send email"),        "mail_generic",     0, this, "email"           );
  popupMsnProfile_          = new KAction( i18n("&View Profile"),      "identity",         0, this, "profile"         );

  popupAddContact_          = new KAction( i18n("&Add Contact"),       "add",              0, this, "add"             );
  popupAllowContact_        = new KAction( i18n("A&llow Contact"),     "apply",            0, this, "allow"           );
  popupRemoveContact_       = new KAction( i18n("&Delete Contact"),    "delete_user",      0, this, "remove"          );

  popupBlockContact_        = new KAction( i18n("&Block Contact"),     "button_cancel",    0, this, "block"           );
  popupUnblockContact_      = new KAction( i18n("&Unblock Contact"),   "button_ok",        0, this, "unblock"         );

  popupCopyFriendlyName_    = new KAction( i18n("&Friendly Name"),     "",                 0, this, "copyfriendly"    );
  popupCopyPersonalMessage_ = new KAction( i18n("&Personal Message"),  "",                 0, this, "copypm"          );
  popupCopyHandle_          = new KAction( i18n("&Email Address"),     "",                 0, this, "copyemail"       );


  // Connect the actions
  connect( popupEmailContact_,        SIGNAL(activated()),   this,  SLOT( sendEmail()             ) );
  connect( popupMsnProfile_,          SIGNAL(activated()),   this,  SLOT( showProfile()           ) );

  connect( popupAddContact_,          SIGNAL(activated()),   this,  SLOT( toggleContactAdded()    ) );
  connect( popupAllowContact_,        SIGNAL(activated()),   this,  SLOT( allowContact()          ) );
  connect( popupRemoveContact_,       SIGNAL(activated()),   this,  SLOT( toggleContactAdded()    ) );

  connect( popupBlockContact_,        SIGNAL(activated()),   this,  SLOT( toggleContactBlocked()  ) );
  connect( popupUnblockContact_,      SIGNAL(activated()),   this,  SLOT( toggleContactBlocked()  ) );

  connect( popupCopyFriendlyName_,    SIGNAL(activated()),   this,  SLOT( copyText()              ) );
  connect( popupCopyPersonalMessage_, SIGNAL(activated()),   this,  SLOT( copyText()              ) );
  connect( popupCopyHandle_,          SIGNAL(activated()),   this,  SLOT( copyText()              ) );


  // Initialize sub popups
  popupCopyMenu_ = new KActionMenu( i18n("&Copy..."), 0, 0, "copy" );
  popupCopyMenu_ ->insert( popupCopyFriendlyName_ );
  popupCopyMenu_ ->insert( popupCopyPersonalMessage_ );
  popupCopyMenu_ ->insert( popupCopyHandle_ );

  // Initialize the popup popup
  contactActionPopup_ = new KPopupMenu( this );
  contactActionPopup_->insertTitle( contact_->getHandle(), 0 );

  // Attach the actions to the menu
  popupEmailContact_   ->plug( contactActionPopup_ );
  popupMsnProfile_     ->plug( contactActionPopup_ );
  contactActionPopup_  ->insertSeparator();
  popupAddContact_     ->plug( contactActionPopup_ );
  popupAllowContact_   ->plug( contactActionPopup_ );
  popupRemoveContact_  ->plug( contactActionPopup_ );
  contactActionPopup_  ->insertSeparator();
  popupBlockContact_   ->plug( contactActionPopup_ );
  popupUnblockContact_ ->plug( contactActionPopup_ );
  contactActionPopup_  ->insertSeparator();
  popupCopyMenu_       ->plug( contactActionPopup_ );

  return true;
}



// Whether or not the frame has been activated
bool ContactFrame::isActivated() const
{
  return activated_;
}



// The user received a message from this contact
void ContactFrame::messageReceived()
{
  // Stop the "user is typing" glow
  typingTimer_.stop();
  stopTyping();

}



// Reactivate the frame when a contact rejoins the chat
void ContactFrame::reactivate()
{
  enableWidgets( true );
}



// Email the contact
void ContactFrame::sendEmail()
{
  if ( contact_ != 0 )
  {
    CurrentAccount::instance()->openMailAtCompose( handle_ );
  }
}



// Update and show the contact popup menu
void ContactFrame::showContactPopup( const QPoint &point )
{
  if ( contact_ == 0 )
  {
    return;
  }

  bool isAdded = false;
  bool isAddable = false;
  bool isAllowed = false;
  bool isBlocked = false;
  bool isBlockable = false;
  bool hasPersonalMessage = false;

  if( detailedContact_ )
  {
    isAddable = true;
    isBlockable = true;

    isAdded = detailedContact_->isFriend();
    isAllowed = detailedContact_->isAllowed();
    isBlocked = detailedContact_->isBlocked();
    hasPersonalMessage = ! detailedContact_->getPersonalMessage().isEmpty();
  }

  popupAllowContact_       ->setEnabled( ! isAllowed );
  popupCopyPersonalMessage_->setEnabled( hasPersonalMessage );

  popupAddContact_         ->setEnabled( isAddable   && ! isAdded   );
  popupRemoveContact_      ->setEnabled( isAddable   &&   isAdded   );

  popupBlockContact_       ->setEnabled( isBlockable && ! isBlocked );
  popupUnblockContact_     ->setEnabled( isBlockable &&   isBlocked );

  contactActionPopup_->popup( point );
}



// Show the contact's profile
void ContactFrame::showProfile()
{
  QString    urlPath;
  KURL      *url;
  KRun      *run;

  if ( contact_ != 0 )
  {
    // Set a path to the msn profile page.  Unfortunately, this isn't
    //  internationalized.
    urlPath = "http://members.msn.com/default.msnw?mem=" + handle_;
    // Create a URL to the given path
    url = new KURL( urlPath );
    // Launch the default html program for the given URL
      run = new KRun( *url );
  }
}



// Receive notice that the contact is typing
void ContactFrame::startTyping()
{
  contactPixmapLabel_->setPixmap( contactTypingPicture_ );

  // Make the contact picture glow
  // Start the timer to disable the label
  typingTimer_.start(5000, true);
}



// Disable the typing label when the timer has timed out
void ContactFrame::stopTyping()
{
  contactPixmapLabel_->setPixmap( contactPicture_ );
}



// Add or remove the contact from the contact list
void ContactFrame::toggleContactAdded()
{
  if ( detailedContact_ == 0 )
  {
    return;
  }

  emit setContactAdded( handle_, ! detailedContact_->isFriend() );

  updateStatusWidgets();
}



// Change the contact's blocked/unblocked status
void ContactFrame::toggleContactBlocked()
{
  if ( detailedContact_ == 0 )
  {
    return;
  }

  emit setContactBlocked( handle_, ! detailedContact_->isBlocked() );

  updateStatusWidgets();
}



// Update the contact picture
void ContactFrame::updatePicture()
{
  if ( contact_ == 0 )
  {
    return;
  }

#ifdef KMESSDEBUG_CONTACTFRAME
  kdDebug() << "ContactFrame::UpdatePicture(): Contact picture path is " << contact_->getContactPicturePath() << endl;
#endif

  // See if the contact picture is not updated. Avoid Qt 3.3 GUI flash.
  QString contactPicturePath = contact_->getContactPicturePath();
  QFileInfo contactPictureInfo( contactPicturePath );
  QDateTime contactPictureDate = contactPictureInfo.lastModified();

  if( contactPicturePath == contactPicturePath_
  &&  contactPictureDate == contactPictureDate_ )
  {
#ifdef KMESSDEBUG_CONTACTFRAME
    kdDebug() << "ContactFrame::UpdatePicture(): image is already loaded, avoiding GUI flashing." << endl;
#endif
    return;
  }

  QImage contactImage;
  bool loaded = contactImage.load( contactPicturePath );
  if( loaded )
  {
    // Loaded
    contactPicturePath_ = contactPicturePath;
    contactPictureDate_ = contactPictureDate;
  }
  else
  {
    // Not laoded (PNG error?). load default if custom image could not be loaded
    loaded = contactImage.load( contact_->getContactDefaultPicturePath() );

    if( ! loaded )
    {
      return;
    }
  }

  // Setup the normal and typing pixmaps
  contactPicture_.convertFromImage( contactImage );
  KIconEffect::toGamma( contactImage, 0.8 );
  contactTypingPicture_.convertFromImage( contactImage );

  // Display the image
  contactPixmapLabel_->setPixmap( contactPicture_ );
  contactPixmapLabel_->setMinimumSize( contactImage.width(), contactImage.height() );
}



// Update the status widgets
void ContactFrame::updateStatusWidgets()
{
  KIconLoader *loader = KGlobal::iconLoader();
  QString      label, statusIdentifier, iconName;
  QString      status;

  if ( contact_ == 0 )
  {
    return;
  }

  status = contact_->getStatus();

  if(detailedContact_ && detailedContact_->isBlocked())
  {
    // Show blocked regardless of status
    statusIdentifier = i18n( "Blocked" );
    iconName          = "blocked";
  }
  else if ( status == "AWY" )
  {
    statusIdentifier = i18n( "Away" );
    iconName = "away";
  }
  else if ( status == "BRB" )
  {
    statusIdentifier = i18n( "Be Right Back" );
    iconName = "berightback";
  }
  else if ( status == "BSY" )
  {
    statusIdentifier = i18n( "Busy" );
    iconName = "busy";
  }
  else if ( status == "FLN" )
  {
    statusIdentifier = i18n("Offline");
    iconName = "offline";
  }
  else if ( status == "IDL" )
  {
    statusIdentifier = i18n( "Away - Idle" );
    iconName = "away";
  }
  else if ( status == "LUN" )
  {
    statusIdentifier = i18n( "Out to Lunch" );
    iconName = "lunch";
  }
  else if ( status == "NLN" )
  {
    statusIdentifier = i18n( "Online" );
    iconName = "online";
  }
  else if ( status == "PHN" )
  {
    statusIdentifier = i18n( "On the Phone" );
    iconName = "onthephone";
  }

  label = contact_->getFriendlyName() + "  (" + statusIdentifier + ")";
  statusLabel_->setText( label );

  statusPixmapLabel_->setPixmap( loader->loadIcon( iconName, KIcon::User ) );

  // Update the detailed info widgets, if available
  if( detailedContact_ == 0 )
  {
    return;
  }

  // Update the label with currently playing media
  label = detailedContact_->getCurrentMediaString();

  // If the contact has no media playing, show the personal message
  if( label.isEmpty() )
  {
    nowListeningPixmapLabel_->hide();
    label = detailedContact_->getPersonalMessage();
  }
  else
  {
    nowListeningPixmapLabel_->show();
  }

  // If neither the media nor the message are available, hide the label
  if( ! label.isEmpty() )
  {

    personalMessageLabel_->show();
    personalMessageLabel_->setText( label );
  }
  else
  {
    personalMessageLabel_->hide();
  }
}



// Update all the widgets based on the given contact
void ContactFrame::updateWidgets()
{

  if ( contact_ == 0 )
  {
    kdDebug() << "ContactFrame::updateWidgets() - This contact frame hasn't been activated properly." << endl;
    return;
  }

  updatePicture();
  updateStatusWidgets();
  handleLabel_->setText( handle_ );

}

#include "contactframe.moc"

Generated by  Doxygen 1.6.0   Back to index