make webinterface translatable. there are around 20 short strings, all with context...
[kdenetwork.git] / kopete / libkopete / kopetechatsession.cpp
blobd4923383ba3ce8937d7cc15213cfcb1c5b233929
1 /*
2 kopetechatsession.cpp - Manages all chats
4 Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>
5 Copyright (c) 2002 by Daniel Stone <dstone@kde.org>
6 Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
7 Copyright (c) 2002-2004 by Olivier Goffart <ogoffart@kde.org>
8 Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
9 Copyright (c) 2005 by Michaƫl Larouche <larouche@kde.org>
11 Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org>
13 *************************************************************************
14 * *
15 * This library is free software; you can redistribute it and/or *
16 * modify it under the terms of the GNU Lesser General Public *
17 * License as published by the Free Software Foundation; either *
18 * version 2 of the License, or (at your option) any later version. *
19 * *
20 *************************************************************************
23 #include "kopetechatsession.h"
25 #include <qapplication.h>
26 #include <qregexp.h>
28 #include <kdebug.h>
29 #include <kdeversion.h>
30 #include <kglobal.h>
31 #include <klocale.h>
32 #include <kmessagebox.h>
33 #include <knotification.h>
35 #include "kopeteaccount.h"
36 #include "kopetebehaviorsettings.h"
37 #include "kopetecommandhandler.h"
38 #include "kopetechatsessionmanager.h"
39 #include "kopetemessagehandlerchain.h"
40 #include "kopetemetacontact.h"
41 #include "kopeteuiglobal.h"
42 #include "kopeteglobal.h"
43 #include "kopeteview.h"
44 #include "kopetecontact.h"
46 class KMMPrivate
48 public:
49 Kopete::ContactPtrList mContactList;
50 const Kopete::Contact *mUser;
51 QMap<const Kopete::Contact *, Kopete::OnlineStatus> contactStatus;
52 Kopete::Protocol *mProtocol;
53 bool isEmpty;
54 bool mCanBeDeleted;
55 unsigned int refcount;
56 bool customDisplayName;
57 QDateTime awayTime;
58 QString displayName;
59 KopeteView *view;
60 bool mayInvite;
61 Kopete::MessageHandlerChain::Ptr chains[3];
62 Kopete::ChatSession::Form form;
65 Kopete::ChatSession::ChatSession( const Kopete::Contact *user,
66 Kopete::ContactPtrList others, Kopete::Protocol *protocol, Kopete::ChatSession::Form form )
67 : QObject( user->account())
69 int i;
71 d = new KMMPrivate;
72 d->mUser = user;
73 d->mProtocol = protocol;
74 d->isEmpty = others.isEmpty();
75 d->mCanBeDeleted = true;
76 d->refcount = 0;
77 d->view = 0L;
78 d->customDisplayName = false;
79 d->mayInvite = false;
80 d->form = form;
82 for ( i = 0; others.size() != i; i++ )
83 addContact( others[i], true );
85 connect( user, SIGNAL(contactDestroyed(Kopete::Contact*)), this, SLOT(slotMyselfDestroyed(Kopete::Contact*)) );
86 connect( user, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ), this,
87 SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ) );
89 if( user->metaContact() )
90 connect( user->metaContact(), SIGNAL( photoChanged() ), this, SIGNAL( photoChanged() ) );
92 slotUpdateDisplayName();
95 Kopete::ChatSession::~ChatSession()
97 //for ( Kopete::Contact *c = d->mContactList.first(); c; c = d->mContactList.next() )
98 // c->setConversations( c->conversations() - 1 );
100 if ( !d )
101 return;
102 d->mCanBeDeleted = false; //prevent double deletion
103 Kopete::ChatSessionManager::self()->removeSession( this );
104 emit closing( this );
105 delete d;
108 void Kopete::ChatSession::slotOnlineStatusChanged( Kopete::Contact *c, const Kopete::OnlineStatus &status, const Kopete::OnlineStatus &oldStatus )
110 slotUpdateDisplayName();
111 emit onlineStatusChanged((Kopete::Contact*)c, status, oldStatus);
114 void Kopete::ChatSession::setContactOnlineStatus( const Kopete::Contact *contact, const Kopete::OnlineStatus &status )
116 Kopete::OnlineStatus oldStatus = d->contactStatus[ contact ];
117 d->contactStatus[ contact ] = status;
118 disconnect( contact, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
119 this, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &) ) );
120 emit onlineStatusChanged( (Kopete::Contact*)contact, status, oldStatus );
123 const Kopete::OnlineStatus Kopete::ChatSession::contactOnlineStatus( const Kopete::Contact *contact ) const
125 if ( d->contactStatus.contains( contact ) )
126 return d->contactStatus[ contact ];
128 return contact->onlineStatus();
131 const QString Kopete::ChatSession::displayName()
133 if ( d->displayName.isNull() )
135 slotUpdateDisplayName();
138 return d->displayName;
141 void Kopete::ChatSession::setDisplayName( const QString &newName )
143 d->displayName = newName;
144 d->customDisplayName = true;
145 emit displayNameChanged();
148 void Kopete::ChatSession::slotUpdateDisplayName()
150 if( d->customDisplayName )
151 return;
154 //If there is no member yet, don't try to update the display name
155 if ( d->mContactList.isEmpty() )
156 return;
158 d->displayName.clear();
159 for(int i = 0; i != d->mContactList.size(); i++ )
161 Kopete::Contact * c = d->mContactList[i];
162 if(! d->displayName.isNull() )
163 d->displayName.append( QString::fromLatin1( ", " ) ) ;
165 if ( c->metaContact() )
166 d->displayName.append( c->metaContact()->displayName() );
167 else
169 QString nick=c->property(Kopete::Global::Properties::self()->nickName()).value().toString();
170 d->displayName.append( nick.isEmpty() ? c->contactId() : nick );
174 //If we have only 1 contact, add the status of him
175 if ( d->mContactList.count() == 1 )
177 d->displayName.append( QString::fromLatin1( " (%1)" ).arg( d->mContactList.first()->onlineStatus().description() ) );
180 emit displayNameChanged();
183 const Kopete::ContactPtrList& Kopete::ChatSession::members() const
185 return d->mContactList;
188 const Kopete::Contact* Kopete::ChatSession::myself() const
190 return d->mUser;
193 Kopete::Protocol* Kopete::ChatSession::protocol() const
195 return d->mProtocol;
199 #include "kopetemessagehandler.h"
200 #include "kopetemessageevent.h"
202 // FIXME: remove this and the friend decl in KMM
203 class Kopete::TemporaryKMMCallbackAppendMessageHandler : public Kopete::MessageHandler
205 Kopete::ChatSession *manager;
206 public:
207 TemporaryKMMCallbackAppendMessageHandler( Kopete::ChatSession *manager )
208 : manager(manager)
211 void handleMessage( Kopete::MessageEvent *event )
213 Kopete::Message message = event->message();
214 emit manager->messageAppended( message, manager );
215 delete event;
219 class TempFactory : public Kopete::MessageHandlerFactory
221 public:
222 Kopete::MessageHandler *create( Kopete::ChatSession *manager, Kopete::Message::MessageDirection )
224 return new Kopete::TemporaryKMMCallbackAppendMessageHandler( manager );
226 int filterPosition( Kopete::ChatSession *, Kopete::Message::MessageDirection )
228 // FIXME: somewhere after everyone else.
229 return 100000;
233 Kopete::MessageHandlerChain::Ptr Kopete::ChatSession::chainForDirection( Kopete::Message::MessageDirection dir )
235 if( dir < 0 || dir > 2)
236 kFatal(14000) << "invalid message direction " << dir;
237 if( !d->chains[dir] )
239 TempFactory theTempFactory;
240 d->chains[dir] = Kopete::MessageHandlerChain::create( this, dir );
242 return d->chains[dir];
245 void Kopete::ChatSession::sendMessage( Kopete::Message &message )
247 message.setManager( this );
248 Kopete::Message sentMessage = message;
249 if ( !Kopete::CommandHandler::commandHandler()->processMessage( message, this ) )
251 emit messageSent( sentMessage, this );
252 if ( !account()->isAway() || Kopete::BehaviorSettings::self()->enableEventsWhileAway() )
254 KNotification::event(QString::fromLatin1( "kopete_outgoing" ), i18n( "Outgoing Message Sent" ) );
257 else
259 messageSucceeded();
263 void Kopete::ChatSession::messageSucceeded()
265 emit messageSuccess();
268 void Kopete::ChatSession::emitNudgeNotification()
270 KNotification::event( QString::fromLatin1("buzz_nudge"), i18n("A contact sent you a buzz/nudge.") );
273 void Kopete::ChatSession::appendMessage( Kopete::Message &msg )
275 msg.setManager( this );
277 if ( msg.direction() == Kopete::Message::Inbound )
279 QString nick=myself()->property(Kopete::Global::Properties::self()->nickName()).value().toString();
280 if ( Kopete::BehaviorSettings::self()->highlightEnabled() && !nick.isEmpty() &&
281 msg.plainBody().contains( QRegExp( QString::fromLatin1( "\\b(%1)\\b" ).arg( nick ), Qt::CaseInsensitive ) ) )
283 msg.setImportance( Kopete::Message::Highlight );
286 emit messageReceived( msg, this );
289 // outbound messages here are ones the user has sent that are now
290 // getting reflected back to the chatwindow. they should go down
291 // the incoming chain.
292 Kopete::Message::MessageDirection chainDirection = msg.direction();
293 if( chainDirection == Kopete::Message::Outbound )
294 chainDirection = Kopete::Message::Inbound;
296 chainForDirection( chainDirection )->processMessage( msg );
297 // emit messageAppended( msg, this );
300 void Kopete::ChatSession::addContact( const Kopete::Contact *c, const Kopete::OnlineStatus &initialStatus, bool suppress )
302 if( !d->contactStatus.contains(c) )
303 d->contactStatus[ c ] = initialStatus;
304 addContact( c, suppress );
307 void Kopete::ChatSession::addContact( const Kopete::Contact *c, bool suppress )
309 //kDebug( 14010 ) ;
310 if ( d->mContactList.contains( (Kopete::Contact*)(Kopete::Contact*)(Kopete::Contact*)(Kopete::Contact*)(Kopete::Contact*)(Kopete::Contact*)(Kopete::Contact*)(Kopete::Contact*)(Kopete::Contact*)c ) )
312 kDebug( 14010 ) << "Contact already exists";
313 emit contactAdded( c, suppress );
315 else
317 if ( d->mContactList.count() == 1 && d->isEmpty )
319 kDebug( 14010 ) << " FUCKER ZONE ";
320 /* We have only 1 contact before, so the status of the
321 message manager was given from that contact status */
322 Kopete::Contact *old = d->mContactList.first();
323 d->mContactList.removeAll( old );
324 d->mContactList.append( (Kopete::Contact*)c );
326 disconnect( old, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
327 this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &) ) );
329 if ( old->metaContact() )
331 disconnect( old->metaContact(), SIGNAL( displayNameChanged( const QString &, const QString & ) ), this, SLOT( slotUpdateDisplayName() ) );
332 disconnect( old->metaContact(), SIGNAL( photoChanged() ), this, SIGNAL( photoChanged() ) );
334 else
335 disconnect( old, SIGNAL( propertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ), this, SLOT( slotUpdateDisplayName() ) );
336 emit contactAdded( c, suppress );
337 emit contactRemoved( old, QString() );
339 else
341 d->mContactList.append( (Kopete::Contact*)c );
342 emit contactAdded( c, suppress );
345 connect( c, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
346 this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &) ) );
348 if ( c->metaContact() )
350 connect( c->metaContact(), SIGNAL( displayNameChanged( const QString &, const QString & ) ), this, SLOT( slotUpdateDisplayName() ) );
351 connect( c->metaContact(), SIGNAL( photoChanged() ), this, SIGNAL( photoChanged() ) );
353 else
354 connect( c, SIGNAL( propertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ), this, SLOT( slotUpdateDisplayName() ) );
355 connect( c, SIGNAL( contactDestroyed( Kopete::Contact * ) ), this, SLOT( slotContactDestroyed( Kopete::Contact * ) ) );
357 slotUpdateDisplayName();
359 d->isEmpty = false;
362 void Kopete::ChatSession::removeContact( const Kopete::Contact *c, const QString& reason, Qt::TextFormat format, bool suppressNotification )
364 kDebug( 14010 ) ;
365 if ( !c || !d->mContactList.contains( (Kopete::Contact*)c ) )
366 return;
368 if ( d->mContactList.count() == 1 )
370 kDebug( 14010 ) << "Contact not removed. Keep always one contact";
371 d->isEmpty = true;
373 else
375 d->mContactList.removeAll( (Kopete::Contact*)c );
377 disconnect( c, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
378 this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &) ) );
380 if ( c->metaContact() )
382 disconnect( c->metaContact(), SIGNAL( displayNameChanged( const QString &, const QString & ) ), this, SLOT( slotUpdateDisplayName() ) );
383 disconnect( c->metaContact(), SIGNAL( photoChanged() ), this, SIGNAL( photoChanged() ) );
385 else
386 disconnect( c, SIGNAL( propertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ), this, SLOT( slotUpdateDisplayName() ) );
387 disconnect( c, SIGNAL( contactDestroyed( Kopete::Contact * ) ), this, SLOT( slotContactDestroyed( Kopete::Contact * ) ) );
389 slotUpdateDisplayName();
392 d->contactStatus.remove( c );
394 emit contactRemoved( c, reason, format, suppressNotification );
397 void Kopete::ChatSession::receivedTypingMsg( const Kopete::Contact *c, bool t )
399 emit remoteTyping( c, t );
402 void Kopete::ChatSession::receivedTypingMsg( const QString &contactId, bool t )
404 int i;
406 // FIXME: this needs better design. We can't iterate through List to find out who got what ID
407 // hash will be better for that, right ?
408 for ( i=0; i != d->mContactList.size(); i++ )
410 if ( (d->mContactList[i])->contactId() == contactId )
412 receivedTypingMsg( d->mContactList[i], t );
413 return;
418 void Kopete::ChatSession::typing( bool t )
420 emit myselfTyping( t );
423 void Kopete::ChatSession::receivedEventNotification( const QString& notificationText)
425 emit eventNotification( notificationText );
428 void Kopete::ChatSession::setCanBeDeleted ( bool b )
430 d->mCanBeDeleted = b;
431 if (d->refcount < (b?1:0) && !d->view )
432 deleteLater();
435 void Kopete::ChatSession::ref ()
437 d->refcount++;
439 void Kopete::ChatSession::deref ()
441 d->refcount--;
442 if ( d->refcount < 1 && d->mCanBeDeleted && !d->view )
443 deleteLater();
446 KopeteView* Kopete::ChatSession::view( bool canCreate, const QString &requestedPlugin )
448 if ( !d->view && canCreate )
450 d->view = Kopete::ChatSessionManager::self()->createView( this, requestedPlugin );
451 if ( d->view )
453 connect( d->view->mainWidget(), SIGNAL( closing( KopeteView * ) ), this, SLOT( slotViewDestroyed( ) ) );
455 else
457 KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Error,
458 i18n( "<qt>An error has occurred while creating a new chat window. The chat window has not been created.</qt>" ),
459 i18n( "Error While Creating Chat Window" ) );
462 return d->view;
465 void Kopete::ChatSession::slotViewDestroyed()
467 d->view = 0L;
468 if ( d->mCanBeDeleted && d->refcount < 1)
469 deleteLater();
472 Kopete::Account *Kopete::ChatSession::account() const
474 if ( !myself() )
475 return 0;
477 return myself()->account();
480 void Kopete::ChatSession::slotContactDestroyed( Kopete::Contact *contact )
482 if( !contact || !d->mContactList.contains( contact ) )
483 return;
485 //This is a workaround to prevent crash if the contact get deleted.
486 // in the best case, we should ask the protocol to recreate a temporary contact.
487 // (remember: the contact may be deleted when the users removes it from the contact list, or when closing kopete )
488 d->mContactList.removeAll( contact );
489 emit contactRemoved( contact, QString() );
491 if ( d->mContactList.isEmpty() )
492 deleteLater();
495 void Kopete::ChatSession::slotMyselfDestroyed( Kopete::Contact *contact )
497 d->mUser = 0;
498 deleteLater();
501 bool Kopete::ChatSession::mayInvite() const
503 return d->mayInvite;
506 void Kopete::ChatSession::inviteContact(const QString& )
508 //default implementation do nothing
511 void Kopete::ChatSession::setMayInvite( bool b )
513 d->mayInvite=b;
516 void Kopete::ChatSession::raiseView()
518 KopeteView *v=view(true, Kopete::BehaviorSettings::self()->viewPlugin() );
519 if(v)
520 v->raise(true);
523 Kopete::ChatSession::Form Kopete::ChatSession::form() const
525 return d->form;
528 #include "kopetechatsession.moc"
532 // vim: set noet ts=4 sts=4 sw=4: