diff options
Diffstat (limited to 'kopete/libkopete/private/kopeteviewmanager.cpp')
-rw-r--r-- | kopete/libkopete/private/kopeteviewmanager.cpp | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/kopete/libkopete/private/kopeteviewmanager.cpp b/kopete/libkopete/private/kopeteviewmanager.cpp new file mode 100644 index 00000000..c6d295fd --- /dev/null +++ b/kopete/libkopete/private/kopeteviewmanager.cpp @@ -0,0 +1,364 @@ +/* + kopeteviewmanager.cpp - View Manager + + Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org> + Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.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 <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <qptrlist.h> +#include <qstylesheet.h> +#include <kplugininfo.h> +#include <knotification.h> +#include <kglobal.h> +#include <kwin.h> + +#include "kopeteprefs.h" +#include "kopeteaccount.h" +#include "kopetepluginmanager.h" +#include "kopeteviewplugin.h" +#include "kopetechatsessionmanager.h" +#include "kopetemetacontact.h" +#include "kopetenotifyevent.h" +#include "kopetemessageevent.h" +#include "kopeteview.h" +//#include "systemtray.h" + +#include "kopeteviewmanager.h" + +typedef QMap<Kopete::ChatSession*,KopeteView*> ManagerMap; +typedef QPtrList<Kopete::MessageEvent> EventList; + +struct KopeteViewManagerPrivate +{ + ManagerMap managerMap; + EventList eventList; + KopeteView *activeView; + + bool useQueueOrStack; + bool raiseWindow; + bool queueUnreadMessages; + bool queueOnlyHighlightedMessagesInGroupChats; + bool queueOnlyMessagesOnAnotherDesktop; + bool balloonNotifyIgnoreClosesChatView; + bool foreignMessage; +}; + +KopeteViewManager *KopeteViewManager::s_viewManager = 0L; + +KopeteViewManager *KopeteViewManager::viewManager() +{ + if( !s_viewManager ) + s_viewManager = new KopeteViewManager(); + return s_viewManager; +} + +KopeteViewManager::KopeteViewManager() +{ + s_viewManager=this; + d = new KopeteViewManagerPrivate; + d->activeView = 0L; + d->foreignMessage=false; + + connect( KopetePrefs::prefs(), SIGNAL( saved() ), this, SLOT( slotPrefsChanged() ) ); + + connect( Kopete::ChatSessionManager::self() , SIGNAL( display( Kopete::Message &, Kopete::ChatSession *) ), + this, SLOT ( messageAppended( Kopete::Message &, Kopete::ChatSession *) ) ); + + connect( Kopete::ChatSessionManager::self() , SIGNAL( readMessage() ), + this, SLOT ( nextEvent() ) ); + + slotPrefsChanged(); +} + +KopeteViewManager::~KopeteViewManager() +{ +// kdDebug(14000) << k_funcinfo << endl; + + //delete all open chatwindow. + ManagerMap::Iterator it; + for ( it = d->managerMap.begin(); it != d->managerMap.end(); ++it ) + it.data()->closeView( true ); //this does not clean the map, but we don't care + + delete d; +} + +void KopeteViewManager::slotPrefsChanged() +{ + d->useQueueOrStack = KopetePrefs::prefs()->useQueue() || KopetePrefs::prefs()->useStack(); + d->raiseWindow = KopetePrefs::prefs()->raiseMsgWindow(); + d->queueUnreadMessages = KopetePrefs::prefs()->queueUnreadMessages(); + d->queueOnlyHighlightedMessagesInGroupChats = KopetePrefs::prefs()->queueOnlyHighlightedMessagesInGroupChats(); + d->queueOnlyMessagesOnAnotherDesktop = KopetePrefs::prefs()->queueOnlyMessagesOnAnotherDesktop(); + d->balloonNotifyIgnoreClosesChatView = KopetePrefs::prefs()->balloonNotifyIgnoreClosesChatView(); +} + +KopeteView *KopeteViewManager::view( Kopete::ChatSession* session, const QString &requestedPlugin ) +{ +// kdDebug(14000) << k_funcinfo << endl; + + if( d->managerMap.contains( session ) && d->managerMap[ session ] ) + { + return d->managerMap[ session ]; + } + else + { + Kopete::PluginManager *pluginManager = Kopete::PluginManager::self(); + Kopete::ViewPlugin *viewPlugin = 0L; + + QString pluginName = requestedPlugin.isEmpty() ? KopetePrefs::prefs()->interfacePreference() : requestedPlugin; + if( !pluginName.isEmpty() ) + { + viewPlugin = (Kopete::ViewPlugin*)pluginManager->loadPlugin( pluginName ); + + if( !viewPlugin ) + { + kdWarning(14000) << "Requested view plugin, " << pluginName << + ", was not found. Falling back to chat window plugin" << endl; + } + } + + if( !viewPlugin ) + viewPlugin = (Kopete::ViewPlugin*)pluginManager->loadPlugin( QString::fromLatin1("kopete_chatwindow") ); + + if( viewPlugin ) + { + KopeteView *newView = viewPlugin->createView(session); + + d->foreignMessage = false; + d->managerMap.insert( session, newView ); + + connect( session, SIGNAL( closing(Kopete::ChatSession *) ), + this, SLOT(slotChatSessionDestroyed(Kopete::ChatSession*)) ); + + return newView; + } + else + { + kdError(14000) << "Could not create a view, no plugins available!" << endl; + return 0L; + } + } +} + + +void KopeteViewManager::messageAppended( Kopete::Message &msg, Kopete::ChatSession *manager) +{ +// kdDebug(14000) << k_funcinfo << endl; + + bool outgoingMessage = ( msg.direction() == Kopete::Message::Outbound ); + + if( !outgoingMessage || d->managerMap.contains( manager ) ) + { + d->foreignMessage=!outgoingMessage; //let know for the view we are about to create + manager->view(true,msg.requestedPlugin())->appendMessage( msg ); + d->foreignMessage=false; //the view is created, reset the flag + + bool appendMessageEvent = d->useQueueOrStack; + + QWidget *w; + if( d->queueUnreadMessages && ( w = dynamic_cast<QWidget*>(view( manager )) ) ) + { + // append msg event to queue if chat window is active but not the chat view in it... + appendMessageEvent = appendMessageEvent && !(w->isActiveWindow() && manager->view() == d->activeView); + // ...and chat window is on another desktop + appendMessageEvent = appendMessageEvent && (!d->queueOnlyMessagesOnAnotherDesktop || !KWin::windowInfo( w->topLevelWidget()->winId(), NET::WMDesktop ).isOnCurrentDesktop()); + } + else + { + // append if no chat window exists already + appendMessageEvent = appendMessageEvent && !view( manager )->isVisible(); + } + + // in group chats always append highlighted messages to queue + appendMessageEvent = appendMessageEvent && (!d->queueOnlyHighlightedMessagesInGroupChats || manager->members().count() == 1 || msg.importance() == Kopete::Message::Highlight); + + if( appendMessageEvent ) + { + if ( !outgoingMessage ) + { + Kopete::MessageEvent *event=new Kopete::MessageEvent(msg,manager); + d->eventList.append( event ); + connect(event, SIGNAL(done(Kopete::MessageEvent *)), this, SLOT(slotEventDeleted(Kopete::MessageEvent *))); + Kopete::ChatSessionManager::self()->postNewEvent(event); + } + } + else if( d->eventList.isEmpty() ) + { + readMessages( manager, outgoingMessage ); + } + + if ( !outgoingMessage && ( !manager->account()->isAway() || KopetePrefs::prefs()->soundIfAway() ) + && msg.direction() != Kopete::Message::Internal ) + { + QWidget *w=dynamic_cast<QWidget*>(manager->view(false)); + KConfig *config = KGlobal::config(); + config->setGroup("General"); + if( (!manager->view(false) || !w || manager->view() != d->activeView || + config->readBoolEntry("EventIfActive", true) || !w->isActiveWindow()) + && msg.from()) + { + QString msgFrom = QString::null; + if( msg.from()->metaContact() ) + msgFrom = msg.from()->metaContact()->displayName(); + else + msgFrom = msg.from()->contactId(); + + QString msgText = msg.plainBody(); + if( msgText.length() > 90 ) + msgText = msgText.left(88) + QString::fromLatin1("..."); + + QString event; + QString body =i18n( "<qt>Incoming message from %1<br>\"%2\"</qt>" ); + + switch( msg.importance() ) + { + case Kopete::Message::Low: + event = QString::fromLatin1( "kopete_contact_lowpriority" ); + break; + case Kopete::Message::Highlight: + event = QString::fromLatin1( "kopete_contact_highlight" ); + body = i18n( "<qt>A highlighted message arrived from %1<br>\"%2\"</qt>" ); + break; + default: + event = QString::fromLatin1( "kopete_contact_incoming" ); + } + KNotification *notify=KNotification::event(msg.from()->metaContact() , event, body.arg( QStyleSheet::escape(msgFrom), QStyleSheet::escape(msgText) ), 0, /*msg.from()->metaContact(),*/ + w , i18n("View") ); + + connect(notify,SIGNAL(activated(unsigned int )), manager , SLOT(raiseView()) ); + } + } + } +} + +void KopeteViewManager::readMessages( Kopete::ChatSession *manager, bool outgoingMessage, bool activate ) +{ +// kdDebug( 14000 ) << k_funcinfo << endl; + d->foreignMessage=!outgoingMessage; //let know for the view we are about to create + KopeteView *thisView = manager->view( true ); + d->foreignMessage=false; //the view is created, reset the flag + if( ( outgoingMessage && !thisView->isVisible() ) || d->raiseWindow || activate ) + thisView->raise( activate ); + else if( !thisView->isVisible() ) + thisView->makeVisible(); + + QPtrListIterator<Kopete::MessageEvent> it( d->eventList ); + Kopete::MessageEvent* event; + while ( ( event = it.current() ) != 0 ) + { + ++it; + if ( event->message().manager() == manager ) + { + event->apply(); + d->eventList.remove( event ); + } + } +} + +void KopeteViewManager::slotEventDeleted( Kopete::MessageEvent *event ) +{ +// kdDebug(14000) << k_funcinfo << endl; + Kopete::ChatSession *kmm=event->message().manager(); + if(!kmm) + return; + + d->eventList.remove( event ); + + if ( event->state() == Kopete::MessageEvent::Applied ) + { + readMessages( kmm, false, true ); + } + else if ( event->state() == Kopete::MessageEvent::Ignored && d->balloonNotifyIgnoreClosesChatView ) + { + bool bAnotherWithThisManager = false; + for( QPtrListIterator<Kopete::MessageEvent> it( d->eventList ); it; ++it ) + { + Kopete::MessageEvent *event = it.current(); + if ( event->message().manager() == kmm ) + bAnotherWithThisManager = true; + } + if ( !bAnotherWithThisManager && kmm->view( false ) ) + kmm->view()->closeView( true ); + } +} + +void KopeteViewManager::nextEvent() +{ +// kdDebug( 14000 ) << k_funcinfo << endl; + + if( d->eventList.isEmpty() ) + return; + + Kopete::MessageEvent* event = d->eventList.first(); + + if ( event ) + event->apply(); +} + +void KopeteViewManager::slotViewActivated( KopeteView *view ) +{ +// kdDebug( 14000 ) << k_funcinfo << endl; + d->activeView = view; + + QPtrListIterator<Kopete::MessageEvent> it ( d->eventList ); + Kopete::MessageEvent* event; + while ( ( event = it.current() ) != 0 ) + { + ++it; + if ( event->message().manager() == view->msgManager() ) + event->deleteLater(); + } + +} + +void KopeteViewManager::slotViewDestroyed( KopeteView *closingView ) +{ +// kdDebug( 14000 ) << k_funcinfo << endl; + + if( d->managerMap.contains( closingView->msgManager() ) ) + { + d->managerMap.remove( closingView->msgManager() ); +// closingView->msgManager()->setCanBeDeleted( true ); + } + + if( closingView == d->activeView ) + d->activeView = 0L; +} + +void KopeteViewManager::slotChatSessionDestroyed( Kopete::ChatSession *manager ) +{ +// kdDebug( 14000 ) << k_funcinfo << endl; + + if( d->managerMap.contains( manager ) ) + { + KopeteView *v=d->managerMap[ manager ]; + v->closeView( true ); + delete v; //closeView call deleteLater, but in this case this is not enough, because some signal are called that case crash + d->managerMap.remove( manager ); + } +} + +KopeteView* KopeteViewManager::activeView() const +{ + return d->activeView; +} + + +#include "kopeteviewmanager.moc" + +// vim: set noet ts=4 sts=4 sw=4: + |