Logo Search packages:      
Sourcecode: kmess version File versions

contactswidget.cpp

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

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

#include <QDockWidget>

#include <KIconEffect>



// The constructor
ContactsWidget::ContactsWidget( QWidget *parent )
: QWidget( parent )
, Ui::ContactsWidget()
, wasVisible_( false )
{
  setupUi( this );

  // Create the layout which will organize the contact frames
  layout_ = new QBoxLayout( QBoxLayout::TopToBottom, container_ );
  layout_->setSpacing( 2 );
  layout_->setContentsMargins( 0, 0, 0, 0 );
  layout_->setSizeConstraint( QLayout::SetMinAndMaxSize );
  layout_->setAlignment( Qt::AlignTop | Qt::AlignLeft );

  // The scroll area background should mimetize with the rest of the app
  area_->setBackgroundRole( QPalette::Window );

  // Initialize the user picture frame
  userPixmapLabel_->installEventFilter( this );
  CurrentAccount *account = CurrentAccount::instance();
  connect( account, SIGNAL(         changedMsnObject() ),
           this,    SLOT  ( slotUpdateDisplayPicture() ) );
  slotUpdateDisplayPicture();
}



// The destructor
ContactsWidget::~ContactsWidget()
{
  // Remove all contact frames
  qDeleteAll( contactFrames_ );
  contactFrames_.clear();

#ifdef KMESSDEBUG_CONTACTSWIDGET
  kDebug() << "DESTROYED.";
#endif
}



// A contact was added to the contact list
void ContactsWidget::contactAdded( Contact *contact )
{
  // Update any invited contact frame
  foreach( ContactFrame *frame, contactFrames_ )
  {
    if( frame->getHandle() == contact->getHandle() )
    {
      frame->activate( contact );
      break;
    }
  }
}



// A contact joined the chat
void ContactsWidget::contactJoined( ContactBase* contact )
{
  // See if the contact already has a frame
  const QString& handle( contact->getHandle() );
  ContactFrame *contactFrame = getContactFrameByHandle( handle );

  if( contactFrame != 0 )
  {
    // Reactivate the contact's frame
    contactFrame->setEnabled( true );
    return;
  }

#ifdef KMESSDEBUG_CONTACTSWIDGET
  kDebug() << handle;
#endif

  ContactFrame::DisplayMode frameMode;

  // Get the first available contact frame
  contactFrame = getFirstInactiveContactFrame();
  if( KMESS_NULL(contactFrame) ) return;

  // Activate the frame
  contactFrame->activate( contact );

  // Find the most suitable frame display mode
  frameMode = getBestFrameMode();

  // Set it to all the frames, including the new one
  foreach( ContactFrame *frame, contactFrames_ )
  {
    frame->setDisplayMode( frameMode );
  }
}



// A contact left the chat
void ContactsWidget::contactLeft( ContactBase *contact, bool /*isChatIdle*/ )
{
  const QString& handle( contact->getHandle() );
  ContactFrame *contactFrame = getContactFrameByHandle( handle );

  if ( contactFrame == 0 )
  {
    return;
  }

#ifdef KMESSDEBUG_CONTACTSWIDGET
  kDebug() << handle;
#endif

  ContactFrame::DisplayMode frameMode;

  // Delete the frames whenever there is more than one; when only one is left, grey it out instead.
  if( contactFrames_.count() > 1 )
  {
    contactFrames_.removeAll( contactFrame );
    delete contactFrame;

    // Find the most suitable frame mode
    frameMode = getBestFrameMode();

    // Set it to all the frames
    foreach( ContactFrame *frame, contactFrames_ )
    {
      frame->setDisplayMode( frameMode );
    }
  }
  else
  {
    // Deactivate the contact frame
    contactFrame->setEnabled( false );
  }
}



// A contact was removed from the contact list
void ContactsWidget::contactRemoved( Contact *contact )
{
  // Update any invited contact frame
  foreach( ContactFrame *frame, contactFrames_ )
  {
    if( frame->getHandle() == contact->getHandle() )
    {
      frame->activate( 0 );
      break;
    }
  }
}



// A contact is typing
void ContactsWidget::contactTyping( ContactBase *contact )
{
  ContactFrame *contactFrame = getContactFrameByHandle( contact->getHandle() );
  if ( contactFrame != 0 )
  {
    contactFrame->startTyping();
  }
}



// The user picture frame received an event
bool ContactsWidget::eventFilter( QObject *obj, QEvent *event )
{
  QEvent::Type eventType = event->type();

  if( obj != userPixmapLabel_ )
  {
#ifdef KMESSDEBUG_CONTACTSWIDGET
    kWarning() << "Received event '" << eventType << "' from object '" << obj->objectName() << "'.";
#endif
    return false;
  }

  CurrentAccount *currentAccount = CurrentAccount::instance();

  // Avoid wasting time :)
  if( ! userPictureFrame_->isVisible() )
  {
    return false;
  }

  switch( eventType )
  {
    // Make the picture to glow when hovered
    case QEvent::Enter:
    {
      QImage glowingImage( currentAccount->getPicturePath() );
      KIconEffect::toGamma( glowingImage, 0.8f );
      userPixmapLabel_->setPixmap( QPixmap::fromImage( glowingImage ) );
    }
    break;

    // Restore the picture when the mouse is not hovering over it anymore
    case QEvent::Leave:
    {
      userPixmapLabel_->setPixmap( QPixmap( currentAccount->getPicturePath() ) );
    }
    break;

    // When the picture is clicked, show the account settings
    case QEvent::MouseButtonRelease:
    {
      AccountsManager::instance()->showAccountSettings( currentAccount );
      return true;
    }
    break;

    default:
      break;
  }

  return false;
}



// Get the most suitable frame size, depending on how many contacts are currently in chat with us
inline ContactFrame::DisplayMode ContactsWidget::getBestFrameMode()
{
  // Find out how many are chatting at the moment
  int count = contactFrames_.count();


  if( count > 5 )
  {
    // More than 5 contacts in chat with us: it's a big group chat and we need to be able to display as many frames as possible
    return ContactFrame::ModeTiny;
  }
  else if( count > 2 )
  {
    // A normal group chat: reduce the size of the frames to be able to see all of our contacts at once
    return ContactFrame::ModeSmall;
  }
  else if( count == 2 )
  {
    // A small group chat: Show all details, there's still a lot of space
    return ContactFrame::ModeNormal;
  }

  // A simple 1-on-1 chat: we can show as much detail as possible
  return ContactFrame::ModeSingle;
}



// Find the contact frame with the given handle
ContactFrame* ContactsWidget::getContactFrameByHandle(const QString& handle)
{
  foreach( ContactFrame *contactFrame, contactFrames_ )
  {
    if( contactFrame->getHandle() == handle )
    {
      return contactFrame;
    }
  }

  return 0;
}



// Return the first inactive contact frame
ContactFrame* ContactsWidget::getFirstInactiveContactFrame()
{
  ContactFrame *contactFrame;

  // If there's an inactive frame, use it
  foreach( contactFrame, contactFrames_ )
  {
    if( ! contactFrame->isActivated() )
    {
      return contactFrame;
    }
  }

  // Well we don't have any, so make another.
  contactFrame = new ContactFrame( container_ );

  connect( contactFrame,   SIGNAL( startPrivateChat( const QString& )  ),
           this,           SIGNAL( startPrivateChat( const QString& )  ) );
  connect( contactFrame,   SIGNAL( contactAllowed( QString )  ),
           this,           SIGNAL( contactAllowed( QString )  ) );
  connect( contactFrame,   SIGNAL(   contactAdded( QString, bool )  ),
           this,           SIGNAL(   contactAdded( QString, bool )  ) );
  connect( contactFrame,   SIGNAL( contactBlocked( QString, bool )  ),
           this,           SIGNAL( contactBlocked( QString, bool )  ) );

  // Add it to the viewBox so it appears in the widget
  layout_->insertWidget( children().count() - 2, contactFrame );

  // put it in the list of frames so we can find it again.
  contactFrames_.append( contactFrame );

  return contactFrame;
}



// A message was received from one of the contacts... notify its frame
void ContactsWidget::messageReceived(const QString& handle)
{
  ContactFrame *frame;
  frame = getContactFrameByHandle( handle );
  if ( frame != 0 )
  {
    frame->messageReceived();
  }
}



// Enable/disable the frames
void ContactsWidget::setEnabled( bool isEnabled )
{
  ContactBase *contact;
  CurrentAccount *account = CurrentAccount::instance();

  if( isEnabled )
  {
    // Loop through all frames
    foreach( ContactFrame *frame, contactFrames_ )
    {
      contact = account->getContactByHandle( frame->getHandle() );

      // Only reactivate frames for contacts which exist in the account
      if( contact )
      {
        // Reactivate the frame
        frame->activate( contact );
      }
    }
  }
  else
  {
    // Loop through all frames
    foreach( ContactFrame *frame, contactFrames_ )
    {
      // Remove the activation status
      frame->activate( 0 );
    }
  }
}



// Connect the widget to a dock
void ContactsWidget::setDockWidget( QDockWidget *dockWidget, Qt::DockWidgetArea initialArea )
{
#ifdef KMESSTEST
  KMESS_ASSERT( dockWidget );
#endif

  // We need to change layout when the dock moves
  connect( dockWidget, SIGNAL( dockLocationChanged(Qt::DockWidgetArea) ),
           this,       SLOT  ( slotLocationChanged(Qt::DockWidgetArea) ) );
  connect( dockWidget, SIGNAL(     topLevelChanged(bool)               ),
           this,       SLOT  ( slotTopLevelChanged(bool)               ) );

  slotLocationChanged( initialArea );
}



// The location of the parent dock widget has changed
void ContactsWidget::slotLocationChanged( Qt::DockWidgetArea area )
{
#ifdef KMESSDEBUG_CONTACTSWIDGET
  kDebug() << "Changing location to" << area;
#endif

  switch( area )
  {
    case Qt::TopDockWidgetArea:
    case Qt::BottomDockWidgetArea:

      // Loop through all frames to switch the layout mode for frames
      foreach( ContactFrame *frame, contactFrames_ )
      {
        frame->setDisplayMode( ContactFrame::ModeSmall );
      }

      layout_->setDirection( QBoxLayout::LeftToRight );
      area_->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded  );
      area_->setVerticalScrollBarPolicy  ( Qt::ScrollBarAlwaysOff );
      userPictureFrame_->setVisible( false );
      break;

    case Qt::LeftDockWidgetArea:
    case Qt::RightDockWidgetArea:
    default:

      // Loop through all frames to switch the layout mode for frames
      ContactFrame::DisplayMode mode = getBestFrameMode();
      foreach( ContactFrame *frame, contactFrames_ )
      {
        frame->setDisplayMode( mode );
      }

      layout_->setDirection( QBoxLayout::TopToBottom );
      area_->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
      area_->setVerticalScrollBarPolicy  ( Qt::ScrollBarAsNeeded  );

      // Determine if the user picture needs to be shown
      slotUpdateDisplayPicture();
      break;
  }

  // Ensure that the view shows the top left corner
  area_->ensureVisible( 0, 0 );
}



// The parent dock widget floating status has changed
void ContactsWidget::slotTopLevelChanged( bool isTopLevel )
{
  // Moving has started
  if( isTopLevel )
  {
    wasVisible_ = isVisible();
    setVisible( false );
  }
  // The widget has been dropped somewhere
  else
  {
    setVisible( wasVisible_ );
  }

  adjustSize();
}



// Update the user's display picture
void ContactsWidget::slotUpdateDisplayPicture()
{
  CurrentAccount *currentAccount = CurrentAccount::instance();

  bool isVisible = currentAccount->getShowChatUserPicture();

  userPictureFrame_->setVisible( isVisible );

  // Don't update it if it's not even visible
  if( ! isVisible )
  {
#ifdef KMESSDEBUG_CONTACTSWIDGET
    kDebug() << "Not updating hidden user picture widget";
#endif
    return;
  }

  // The picture is unchanged, do nothing
  const QString &pictureFileName( currentAccount->getPicturePath() );
  if( userPixmapLabel_->property( "PictureFileName" ) == pictureFileName )
  {
#ifdef KMESSDEBUG_CONTACTSWIDGET
    kDebug() << "User picture unchanged, not updating widget";
#endif
    return;
  }

#ifdef KMESSDEBUG_CONTACTSWIDGET
  kDebug() << "Updating user picture widget";
#endif

  // Change the picture
  const QPixmap& image( pictureFileName );
  userPixmapLabel_->setPixmap( image );
  userPixmapLabel_->setProperty( "PictureFileName", pictureFileName );
}



#include "contactswidget.moc"

Generated by  Doxygen 1.6.0   Back to index