Files
kmess/src/chat/contactswidget.cpp
T
2009-07-17 15:44:01 +00:00

495 lines
13 KiB
C++

/***************************************************************************
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 "../network/msnswitchboardconnection.h"
#include <QDockWidget>
#include <KIconEffect>
// The constructor
ContactsWidget::ContactsWidget( QWidget *parent )
: QWidget( parent )
, Ui::ContactsWidget()
, wasVisible_( false )
{
setupUi( this );
container_->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
// 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
ContactFrame *contactFrame = getContactFrameByHandle( contact->getHandle() );
if ( contactFrame != 0 )
{
contactFrame->activate( contact );
}
}
// 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 = createContactFrame();
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
ContactFrame *contactFrame = getContactFrameByHandle( contact->getHandle() );
if ( contactFrame != 0 )
{
contactFrame->activate( 0 );
}
}
// 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 one new contact frame
ContactFrame* ContactsWidget::createContactFrame()
{
ContactFrame *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 = 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"