• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdenetwork
  • Sitemap
  • Contact Us
 

kopete/kopete

chatview.cpp

Go to the documentation of this file.
00001 /*
00002     chatview.cpp - Chat View
00003 
00004     Copyright (c) 2002-2004 by Olivier Goffart       <ogoffart@kde.org>
00005     Copyright (c) 2002-2003 by Martijn Klingens      <klingens@kde.org>
00006 
00007     Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
00008 
00009     *************************************************************************
00010     *                                                                       *
00011     * This program is free software; you can redistribute it and/or modify  *
00012     * it under the terms of the GNU General Public License as published by  *
00013     * the Free Software Foundation; either version 2 of the License, or     *
00014     * (at your option) any later version.                                   *
00015     *                                                                       *
00016     *************************************************************************
00017 */
00018 
00019 #include "chatview.h"
00020 
00021 #include "chatmessagepart.h"
00022 #include "chattexteditpart.h"
00023 #include "kopetechatwindow.h"
00024 #include "kopetechatsession.h"
00025 #include "kopetemetacontact.h"
00026 #include "kopetepluginmanager.h"
00027 #include "kopeteprotocol.h"
00028 #include "kopeteaccount.h"
00029 #include "kopeteglobal.h"
00030 #include "kopetecontactlist.h"
00031 #include "kopeteviewmanager.h"
00032 #include "kopetebehaviorsettings.h"
00033 
00034 #include <kconfig.h>
00035 #include <ktabwidget.h>
00036 #include <kdebug.h>
00037 #include <klocale.h>
00038 #include <kmessagebox.h>
00039 #include <kmenu.h>
00040 #include <kstringhandler.h>
00041 #include <kwindowsystem.h>
00042 #include <kglobalsettings.h>
00043 #include <kgenericfactory.h>
00044 #include <khtmlview.h>
00045 
00046 #include <QTimer>
00047 #include <QSplitter>
00048 #include <Q3UriDrag>
00049 
00050 K_PLUGIN_FACTORY( ChatWindowPluginFactory, registerPlugin<ChatWindowPlugin>(); )
00051 K_EXPORT_PLUGIN( ChatWindowPluginFactory( "kopete_chatwindow" ) )
00052 
00053 ChatWindowPlugin::ChatWindowPlugin(QObject *parent, const QVariantList &) :
00054     Kopete::ViewPlugin( ChatWindowPluginFactory::componentData(), parent )
00055 {}
00056 
00057 KopeteView* ChatWindowPlugin::createView( Kopete::ChatSession *manager )
00058 {
00059     return new ChatView(manager,this);
00060 }
00061 
00062 class KopeteChatViewPrivate
00063 {
00064 public:
00065     QString captionText;
00066     QString statusText;
00067     bool isActive;
00068     bool sendInProgress;
00069     bool visibleMembers;
00070     QSplitter * splitter;
00071 };
00072 
00073 ChatView::ChatView( Kopete::ChatSession *mgr, ChatWindowPlugin *parent )
00074      : KVBox( 0l ), KopeteView( mgr, parent )
00075          , d(new KopeteChatViewPrivate)
00076 {
00077     int i;
00078 
00079     d->isActive = false;
00080     d->visibleMembers = false;
00081     d->sendInProgress = false;
00082 
00083     KVBox *vbox=this;
00084 
00085     m_mainWindow = 0L;
00086     m_tabState = Normal;
00087 
00088 
00089     //FIXME: don't widgets start off hidden anyway?
00090     hide();
00091 
00092     d->splitter = new QSplitter( Qt::Vertical, vbox );
00093 
00094     //Create the view dock widget (KHTML Part), and set it to no docking (lock it in place)
00095     m_messagePart = new ChatMessagePart( mgr , this );
00096 
00097     //Create the bottom dock widget, with the edit area, statusbar and send button
00098     m_editPart = new ChatTextEditPart( mgr, vbox );
00099 
00100     d->splitter->addWidget(m_messagePart->view());
00101     d->splitter->addWidget(m_editPart->widget());
00102     d->splitter->setChildrenCollapsible( false );
00103     QList<int> sizes;
00104     sizes << 240 << 40;
00105     d->splitter->setSizes( sizes );
00106 
00107     // FIXME: is this used these days? it seems totally unnecessary
00108     connect( editPart(), SIGNAL( toolbarToggled(bool)), this, SLOT(slotToggleRtfToolbar(bool)) );
00109 
00110     connect( editPart(), SIGNAL( messageSent( Kopete::Message & ) ),
00111              this, SIGNAL( messageSent( Kopete::Message & ) ) );
00112     connect( editPart(), SIGNAL( canSendChanged( bool ) ),
00113              this, SIGNAL( canSendChanged(bool) ) );
00114     connect( editPart(), SIGNAL( typing(bool) ),
00115          mgr, SLOT( typing(bool) ) );
00116 
00117     //Set the view as the main widget
00118 //  setView(viewDock);
00119 
00120     //It is possible to drag and drop on this widget.
00121     // I had to disable the acceptDrop in the khtml widget to be able to intercept theses events.
00122     setAcceptDrops(true);
00123 //  viewDock->setAcceptDrops(false);
00124 
00125     //Manager signals
00126     connect( mgr, SIGNAL( displayNameChanged() ),
00127              this, SLOT( slotChatDisplayNameChanged() ) );
00128     connect( mgr, SIGNAL( contactAdded(const Kopete::Contact*, bool) ),
00129              this, SLOT( slotContactAdded(const Kopete::Contact*, bool) ) );
00130     connect( mgr, SIGNAL( contactRemoved(const Kopete::Contact*, const QString&, Qt::TextFormat, bool) ),
00131              this, SLOT( slotContactRemoved(const Kopete::Contact*, const QString&, Qt::TextFormat, bool) ) );
00132     connect( mgr, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus & , const Kopete::OnlineStatus &) ),
00133              this, SLOT( slotContactStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ) );
00134     connect( mgr, SIGNAL( remoteTyping( const Kopete::Contact *, bool) ),
00135          this, SLOT( remoteTyping(const Kopete::Contact *, bool) ) );
00136     connect( mgr, SIGNAL( eventNotification( const QString& ) ),
00137          this, SLOT( setStatusText( const QString& ) ) );
00138 
00139     //Connections to the manager and the ViewManager that every view should have
00140     connect( this, SIGNAL( closing( KopeteView * ) ),
00141          KopeteViewManager::viewManager(), SLOT( slotViewDestroyed( KopeteView * ) ) );
00142     connect( this, SIGNAL( activated( KopeteView * ) ),
00143          KopeteViewManager::viewManager(), SLOT( slotViewActivated( KopeteView * ) ) );
00144     connect( this, SIGNAL( messageSent(Kopete::Message &) ),
00145          mgr, SLOT( sendMessage(Kopete::Message &) ) );
00146     connect( mgr, SIGNAL( messageSuccess() ),
00147          this, SLOT( messageSentSuccessfully() ));
00148 
00149     // add contacts
00150     slotContactAdded( mgr->myself(), true );
00151     for ( i = 0; i != mgr->members().size(); i++ )
00152     {
00153         slotContactAdded( mgr->members()[i], true );
00154     }
00155 
00156     setFocusProxy( editPart()->widget() );
00157     m_messagePart->widget()->setFocusProxy( editPart()->widget() );
00158     editPart()->widget()->setFocus();
00159 
00160     slotChatDisplayNameChanged();
00161 
00162     // restore docking positions
00163     readOptions();
00164 }
00165 
00166 ChatView::~ChatView()
00167 {
00168     emit( closing( static_cast<KopeteView*>(this) ) );
00169 
00170     saveOptions();
00171 
00172     delete d;
00173 }
00174 
00175 KTextEdit *ChatView::editWidget()
00176 {
00177     return editPart()->textEdit();
00178 }
00179 
00180 QWidget *ChatView::mainWidget()
00181 {
00182     return this;
00183 }
00184 
00185 bool ChatView::canSend()
00186 {
00187     return editPart()->canSend();
00188 }
00189 
00190 Kopete::Message ChatView::currentMessage()
00191 {
00192     return editPart()->contents();
00193 }
00194 
00195 void ChatView::setCurrentMessage( const Kopete::Message &message )
00196 {
00197     editPart()->setContents( message );
00198 }
00199 
00200 void ChatView::cut()
00201 {
00202     editPart()->textEdit()->cut();
00203 }
00204 
00205 void ChatView::copy()
00206 {
00207     if ( messagePart()->hasSelection() )
00208         messagePart()->copy();
00209     else
00210         editPart()->textEdit()->copy();
00211 }
00212 
00213 void ChatView::paste()
00214 {
00215     editPart()->textEdit()->paste();
00216 }
00217 
00218 void ChatView::nickComplete()
00219 {
00220     return editPart()->complete();
00221 }
00222 
00223 void ChatView::addText( const QString &text )
00224 {
00225     editPart()->addText( text );
00226 }
00227 
00228 void ChatView::clear()
00229 {
00230     messagePart()->clear();
00231 }
00232 
00233 void ChatView::setBgColor( const QColor &newColor )
00234 {
00235     Q_UNUSED(newColor);
00236 //  editPart()->setBackgroundColorColor( newColor );
00237 }
00238 
00239 void ChatView::setFont()
00240 {
00241     editPart()->setFont();
00242 }
00243 
00244 QFont ChatView::font()
00245 {
00246     return editPart()->font();
00247 }
00248 
00249 void ChatView::setFont( const QFont &font )
00250 {
00251     editPart()->setFont( font );
00252 }
00253 
00254 void ChatView::setFgColor( const QColor &newColor )
00255 {
00256     if ( newColor.isValid() )
00257     {
00258         editPart()->setTextColor( newColor );
00259     }
00260     else
00261     {
00262         editPart()->setTextColor();
00263     }
00264 }
00265 
00266 void ChatView::raise( bool activate )
00267 {
00268     // this shouldn't change the focus. When the window is raised when a new message arrives
00269     // if i am coding, or talking to someone else, i want to end my sentence before switching to
00270     // the other chat. i just want to KNOW and SEE the other chat to switch to it later
00271     // (except if activate==true)
00272 
00273     if ( !m_mainWindow || !m_mainWindow->isActiveWindow() || activate )
00274         makeVisible();
00275 #ifdef Q_WS_X11
00276     if ( !KWindowSystem::windowInfo( m_mainWindow->winId(), NET::WMDesktop ).onAllDesktops() )
00277         if( Kopete::BehaviorSettings::self()->trayflashNotifySetCurrentDesktopToChatView() && activate )
00278             KWindowSystem::setCurrentDesktop( KWindowSystem::windowInfo( m_mainWindow->winId(), NET::WMDesktop ).desktop() );
00279         else
00280             KWindowSystem::setOnDesktop( m_mainWindow->winId(), KWindowSystem::currentDesktop() );
00281 #endif
00282     if(m_mainWindow->isMinimized())
00283     {
00284         KWindowSystem::unminimizeWindow( m_mainWindow->winId());
00285     }
00286 
00287 
00288     m_mainWindow->raise();
00289 
00290     //Will not activate window if user was typing
00291     if ( activate )
00292         KWindowSystem::activateWindow( m_mainWindow->winId() );
00293 
00294 }
00295 
00296 void ChatView::makeVisible()
00297 {
00298     if ( !m_mainWindow )
00299     {
00300         m_mainWindow = KopeteChatWindow::window( m_manager );
00301         m_mainWindow->setObjectName( QLatin1String("KopeteChatWindow") );
00302 //      if ( root )
00303 //          root->repaint( true );
00304         emit windowCreated();
00305     }
00306 
00307     if ( !m_mainWindow->isVisible() )
00308     {
00309         m_mainWindow->show();
00310         // scroll down post show and layout, otherwise the geometry is wrong to scroll to the bottom.
00311         m_messagePart->keepScrolledDown();
00312     }
00313 
00314 
00315 
00316     m_mainWindow->setActiveView( this );
00317 }
00318 
00319 bool ChatView::isVisible()
00320 {
00321     return ( m_mainWindow && m_mainWindow->isVisible() );
00322 }
00323 
00324 bool ChatView::sendInProgress()
00325 {
00326     return d->sendInProgress;
00327 }
00328 
00329 bool ChatView::closeView( bool force )
00330 {
00331     int response = KMessageBox::Continue;
00332 
00333     if ( !force )
00334     {
00335         if ( m_manager->members().count() > 1 )
00336         {
00337             QString shortCaption = d->captionText;
00338             shortCaption = KStringHandler::rsqueeze( shortCaption );
00339 
00340             response = KMessageBox::warningContinueCancel( this, i18n("<qt>You are about to leave the groupchat session <b>%1</b>.<br />"
00341                 "You will not receive future messages from this conversation.</qt>", shortCaption ), i18n( "Closing Group Chat" ),
00342                 KGuiItem( i18nc( "@action:button", "Close Chat" ) ), KStandardGuiItem::cancel(), QLatin1String( "AskCloseGroupChat" ) );
00343         }
00344 
00345         if ( !unreadMessageFrom.isNull() && ( response == KMessageBox::Continue ) )
00346         {
00347             response = KMessageBox::warningContinueCancel( this, i18n("<qt>You have received a message from <b>%1</b> in the last "
00348                 "second. Are you sure you want to close this chat?</qt>", unreadMessageFrom ), i18n( "Unread Message" ),
00349                 KGuiItem( i18nc( "@action:button", "Close Chat" ) ), KStandardGuiItem::cancel(), QLatin1String("AskCloseChatRecentMessage" ) );
00350         }
00351 
00352         if ( d->sendInProgress && ( response == KMessageBox::Continue ) )
00353         {
00354             response = KMessageBox::warningContinueCancel( this, i18n( "You have a message send in progress, which will be "
00355                 "aborted if this chat is closed. Are you sure you want to close this chat?" ), i18n( "Message in Transit" ),
00356                 KGuiItem( i18nc( "@action:button", "Close Chat" ) ), KStandardGuiItem::cancel(), QLatin1String( "AskCloseChatMessageInProgress" ) );
00357         }
00358     }
00359 
00360     if( response == KMessageBox::Continue )
00361     {
00362         // Remove the widget from the window it's attached to
00363         // and schedule it for deletion
00364         if( m_mainWindow )
00365             m_mainWindow->detachChatView( this );
00366         deleteLater();
00367 
00368         return true;
00369     }
00370 
00371     return false;
00372 }
00373 
00374 ChatView::KopeteTabState ChatView::tabState() const
00375 {
00376     return m_tabState;
00377 }
00378 
00379 void ChatView::updateChatState( KopeteTabState newState )
00380 {
00381     if ( newState == Undefined )
00382         newState = m_tabState;
00383     else if ( newState != Typing && ( newState != Changed || ( m_tabState != Message && m_tabState != Highlighted ) )
00384         && ( newState != Message ||  m_tabState != Highlighted ) )
00385     { //if the new state is not a typing state and we don't already have a message or a highlighted message
00386       //change the tab state
00387         m_tabState = newState;
00388     }
00389 
00390     newState = m_remoteTypingMap.isEmpty() ? m_tabState : Typing ;
00391 
00392     emit updateChatState( this, newState );
00393 
00394     if( newState != Typing )
00395     {
00396         setStatusText( i18np( "One other person in the chat",
00397                    "%1 other people in the chat", m_manager->members().count() ) );
00398     }
00399 }
00400 
00401 void ChatView::setMainWindow( KopeteChatWindow* parent )
00402 {
00403     m_mainWindow = parent;
00404 }
00405 
00406 void ChatView::remoteTyping( const Kopete::Contact *contact, bool isTyping )
00407 {
00408     TypingMap::iterator it = m_remoteTypingMap.find(contact);
00409     if (it != m_remoteTypingMap.end())
00410     {
00411         if (it.value()->isActive())
00412             it.value()->stop();
00413         delete it.value();
00414         m_remoteTypingMap.erase(it);
00415     }
00416     if( isTyping )
00417     {
00418         m_remoteTypingMap.insert( contact, new QTimer(this) );
00419         connect( m_remoteTypingMap[ contact ], SIGNAL( timeout() ), SLOT( slotRemoteTypingTimeout() ) );
00420 
00421         m_remoteTypingMap[ contact ]->setSingleShot( true );
00422         m_remoteTypingMap[ contact ]->start( 6000 );
00423     }
00424 
00425     // Loop through the map, constructing a string of people typing
00426     QStringList typingList;
00427 
00428     for( it = m_remoteTypingMap.begin(); it != m_remoteTypingMap.end(); ++it )
00429     {
00430         const Kopete::Contact *c = it.key();
00431         typingList.append( m_messagePart->formatName(c, Qt::PlainText) );
00432     }
00433 
00434     // Update the status area
00435     if( !typingList.isEmpty() )
00436     {
00437         if ( typingList.count() == 1 )
00438             setStatusText( i18n( "%1 is typing a message", typingList.first() ) );
00439         else
00440         {
00441             QString statusTyping = typingList.join( QLatin1String( ", " ) );
00442             setStatusText( i18nc( "%1 is a list of names", "%1 are typing a message", statusTyping ) );
00443         }
00444         updateChatState( Typing );
00445     }
00446     else
00447     {
00448         updateChatState();
00449     }
00450 }
00451 
00452 void ChatView::setStatusText( const QString &status )
00453 {
00454     d->statusText = status;
00455     if ( d->isActive )
00456         m_mainWindow->setStatus( status );
00457 }
00458 
00459 const QString& ChatView::statusText()
00460 {
00461     return d->statusText;
00462 }
00463 
00464 void ChatView::slotChatDisplayNameChanged()
00465 {
00466     // This fires whenever a contact or MC changes displayName, so only
00467     // update the caption if it changed to avoid unneeded updates that
00468     // could cause flickering
00469     QString chatName = m_manager->displayName();
00470 
00471     foreach (const Kopete::Contact *c, msgManager()->members())
00472     {
00473         QString contactName = m_messagePart->formatName(c, Qt::PlainText);
00474         if ( c->metaContact() )
00475         {
00476             chatName.replace( c->metaContact()->displayName(), contactName );
00477         }
00478         else
00479         {
00480             chatName.replace( c->nickName(), contactName );
00481         }
00482     }
00483 
00484 
00485     if ( chatName != d->captionText )
00486         setCaption( chatName, true );
00487 }
00488 
00489 void ChatView::slotPropertyChanged( Kopete::PropertyContainer*, const QString &key,
00490         const QVariant& oldValue, const QVariant &newValue  )
00491 {
00492     if ( key == Kopete::Global::Properties::self()->nickName().key() )
00493     {
00494         QString newName=newValue.toString();
00495         QString oldName=oldValue.toString();
00496 
00497         if(Kopete::BehaviorSettings::self()->showEvents())
00498             if ( oldName != newName && !oldName.isEmpty())
00499                 sendInternalMessage( i18n( "%1 is now known as %2", oldName, newName ) );
00500     }
00501 }
00502 
00503 void ChatView::slotDisplayNameChanged( const QString &oldValue, const QString &newValue )
00504 {
00505     if( Kopete::BehaviorSettings::self()->showEvents() )
00506     {
00507         if( oldValue != newValue )
00508             sendInternalMessage( i18n( "%1 is now known as %2", oldValue, newValue ) );
00509     }
00510 }
00511 
00512 void ChatView::slotContactAdded(const Kopete::Contact *contact, bool suppress)
00513 {
00514     if( contact->metaContact() && contact->metaContact() != Kopete::ContactList::self()->myself() )
00515     {
00516         connect( contact->metaContact(), SIGNAL( displayNameChanged(const QString&, const QString&) ),
00517             this, SLOT( slotDisplayNameChanged(const QString &, const QString &) ) );
00518     }
00519     else
00520     {
00521         connect( contact, SIGNAL( propertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ),
00522         this, SLOT( slotPropertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ) ) ;
00523     }
00524 
00525     QString contactName = m_messagePart->formatName(contact, Qt::PlainText);
00526     if( !suppress && m_manager->members().count() > 1 )
00527         sendInternalMessage(  i18n("%1 has joined the chat.", contactName) );
00528 
00529     updateChatState();
00530     emit updateStatusIcon( this );
00531 }
00532 
00533 void ChatView::slotContactRemoved( const Kopete::Contact *contact, const QString &reason, Qt::TextFormat format, bool suppressNotification )
00534 {
00535 //  kDebug(14000) ;
00536     if ( contact != m_manager->myself() )
00537     {
00538         TypingMap::iterator it = m_remoteTypingMap.find( contact );
00539         if ( it != m_remoteTypingMap.end() )
00540         {
00541             if ((*it)->isActive())
00542                 (*it)->stop();
00543             delete (*it);
00544             m_remoteTypingMap.remove( contact );
00545         }
00546 
00547         // When the last person leaves, don't disconnect the signals, since we're in a one-to-one chat
00548         if ( m_manager->members().count() > 0 )
00549         {
00550             if( contact->metaContact() )
00551             {
00552                 disconnect( contact->metaContact(), SIGNAL( displayNameChanged(const QString&, const QString&) ),
00553                 this, SLOT( slotDisplayNameChanged(const QString&, const QString&) ) );
00554             }
00555             else
00556             {
00557                 disconnect(contact,SIGNAL(propertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & )),
00558                 this, SLOT( slotPropertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & ) ) ) ;
00559             }
00560         }
00561 
00562         if ( !suppressNotification )
00563         {
00564             QString contactName = m_messagePart->formatName(contact, Qt::PlainText);
00565             if ( reason.isEmpty() )
00566                 sendInternalMessage( i18n( "%1 has left the chat.", contactName ), format ) ;
00567             else
00568                 sendInternalMessage( i18n( "%1 has left the chat (%2).", contactName, reason ), format);
00569         }
00570     }
00571 
00572     updateChatState();
00573     emit updateStatusIcon( this );
00574 }
00575 
00576 QString& ChatView::caption() const
00577 {
00578      return d->captionText;
00579 }
00580 
00581 void ChatView::setCaption( const QString &text, bool modified )
00582 {
00583 //  kDebug(14000) ;
00584     QString newCaption = text;
00585 
00586     //Save this caption
00587     d->captionText = text;
00588 
00589     //Turncate if needed
00590     newCaption = KStringHandler::rsqueeze( d->captionText, 20 );
00591 
00592     //Call the original set caption
00593     QWidget::setWindowTitle( newCaption );
00594 
00595     emit updateChatTooltip( this, QString::fromLatin1("<qt>%1</qt>").arg( d->captionText ) );
00596     emit updateChatLabel( this, newCaption );
00597     //Blink icon if modified and not active
00598     if( !d->isActive && modified )
00599         updateChatState( Changed );
00600     else
00601         updateChatState();
00602 
00603     //Tell the parent we changed our caption
00604     emit( captionChanged( d->isActive ) );
00605 }
00606 
00607 void ChatView::appendMessage(Kopete::Message &message)
00608 {
00609     remoteTyping( message.from(), false );
00610 
00611     messagePart()->appendMessage(message);
00612 
00613     if( !d->isActive )
00614     {
00615         switch ( message.importance() )
00616         {
00617             case Kopete::Message::Highlight:
00618                 updateChatState( Highlighted );
00619                 break;
00620             case Kopete::Message::Normal:
00621                 if ( message.direction() == Kopete::Message::Inbound )
00622                 {
00623                     updateChatState( Message );
00624                     break;
00625                 } // if it's an enternal message or a outgoing, fall thought
00626             default:
00627                 updateChatState( Changed );
00628         }
00629     }
00630 
00631     if( message.direction() == Kopete::Message::Inbound )
00632     {
00633         unreadMessageFrom = m_messagePart->formatName ( message.from(), Qt::PlainText );
00634         QTimer::singleShot( 1000, this, SLOT( slotMarkMessageRead() ) );
00635     }
00636     else
00637         unreadMessageFrom.clear();
00638 }
00639 
00640 void ChatView::slotMarkMessageRead()
00641 {
00642     unreadMessageFrom.clear();
00643 }
00644 
00645 void ChatView::slotToggleRtfToolbar( bool enabled )
00646 {
00647     emit rtfEnabled( this, enabled );
00648 }
00649 
00650 void ChatView::slotContactStatusChanged( Kopete::Contact *contact, const Kopete::OnlineStatus &newStatus, const Kopete::OnlineStatus &oldStatus )
00651 {
00652     kDebug(14000) << contact;
00653     bool inhibitNotification = ( newStatus.status() == Kopete::OnlineStatus::Unknown ||
00654                                  oldStatus.status() == Kopete::OnlineStatus::Unknown );
00655     if ( contact && Kopete::BehaviorSettings::self()->showEvents() && !inhibitNotification )
00656     {
00657         if ( contact->account() && contact == contact->account()->myself() )
00658         {
00659             // Separate notification for the 'self' contact
00660             if ( newStatus.status() != Kopete::OnlineStatus::Connecting )
00661                 sendInternalMessage( i18n( "You are now marked as %1.", newStatus.description() ) );
00662         }
00663         else if ( !contact->account() || !contact->account()->suppressStatusNotification() )
00664         {
00665             QString contactName = m_messagePart->formatName(contact, Qt::PlainText);
00666             sendInternalMessage( i18n( "%2 is now %1.",
00667                 newStatus.description(), contactName ) );
00668         }
00669     }
00670 
00671     // update the windows caption
00672     slotChatDisplayNameChanged();
00673     emit updateStatusIcon( this );
00674 }
00675 
00676 void ChatView::sendInternalMessage(const QString &msg, Qt::TextFormat format )
00677 {
00678     // When closing kopete, some internal message may be sent because some contact are deleted
00679     // these contacts can already be deleted
00680     Kopete::Message message = Kopete::Message();
00681     message.setDirection( Kopete::Message::Internal );
00682     switch(format)
00683     {
00684         default:
00685         case Qt::PlainText:
00686             message.setPlainBody( msg );
00687             break;
00688         case Qt::RichText:
00689             message.setHtmlBody( msg );
00690             break;
00691     }
00692 
00693     // (in many case, this is useless to set myself as contact)
00694     // TODO: set the contact which initiate the internal message,
00695     // so we can later show a icon of it (for example, when he join a chat)
00696     messagePart()->appendMessage( message );
00697 }
00698 
00699 void ChatView::sendMessage()
00700 {
00701     d->sendInProgress = true;
00702     editPart()->sendMessage();
00703 }
00704 
00705 void ChatView::messageSentSuccessfully()
00706 {
00707     d->sendInProgress = false;
00708     emit messageSuccess( this );
00709 }
00710 
00711 void ChatView::saveOptions()
00712 {
00713     KSharedConfig::Ptr config = KGlobal::config();
00714     KConfigGroup kopeteChatWindowMainWinSettings( config, ( msgManager()->form() == Kopete::ChatSession::Chatroom ? QLatin1String( "KopeteChatWindowGroupMode" ) : QLatin1String( "KopeteChatWindowIndividualMode" ) ) );
00715     kopeteChatWindowMainWinSettings.writeEntry( QLatin1String("ChatViewSplitter"), d->splitter->saveState().toBase64() );
00716     saveChatSettings();
00717     config->sync();
00718 }
00719 
00720 void ChatView::saveChatSettings()
00721 {
00722     Kopete::ContactPtrList contacts = msgManager()->members();
00723 
00724     if ( contacts.count() == 0 )
00725         return;
00726 
00727     Kopete::MetaContact* mc = contacts.first()->metaContact();
00728 
00729     if ( contacts.count() > 1 )
00730         return; //can't save with more than one person in chatview
00731 
00732     if ( !mc )
00733         return;
00734 
00735     QString contactListGroup = QLatin1String("chatwindow_") +
00736                                mc->metaContactId();
00737     KConfigGroup config = KGlobal::config()->group(contactListGroup);
00738     config.writeEntry( "EnableRichText", editPart()->isRichTextEnabled() );
00739     config.writeEntry( "EnableAutoSpellCheck", editPart()->checkSpellingEnabled() );
00740     config.sync();
00741 }
00742 
00743 void ChatView::loadChatSettings()
00744 {
00745     Kopete::ContactPtrList contacts = msgManager()->members();
00746     if ( contacts.count() > 1 )
00747         return; //can't load with more than one other person in the chat
00748 
00749     //read settings for metacontact
00750     QString contactListGroup = QLatin1String("chatwindow_") +
00751                                contacts.first()->metaContact()->metaContactId();
00752     KConfigGroup config(KGlobal::config(), contactListGroup );
00753     bool enableRichText = config.readEntry( "EnableRichText", true );
00754     editPart()->setRichTextEnabled( enableRichText );
00755     emit rtfEnabled( this, editPart()->isRichTextEnabled() );
00756     bool enableAutoSpell = config.readEntry( "EnableAutoSpellCheck", Kopete::BehaviorSettings::self()->spellCheck() );
00757     emit autoSpellCheckEnabled( this, enableAutoSpell );
00758 }
00759 
00760 void ChatView::readOptions()
00761 {
00762     KConfigGroup kopeteChatWindowMainWinSettings( KGlobal::config(), ( msgManager()->form() == Kopete::ChatSession::Chatroom ? QLatin1String( "KopeteChatWindowGroupMode" ) : QLatin1String( "KopeteChatWindowIndividualMode" ) ) );
00763     //kDebug(14000) << "reading splitterpos from key: " << dockKey;
00764     QByteArray state;
00765     state = kopeteChatWindowMainWinSettings.readEntry( QLatin1String("ChatViewSplitter"), state );
00766     d->splitter->restoreState( QByteArray::fromBase64( state ) );
00767 }
00768 
00769 void ChatView::setActive( bool value )
00770 {
00771     d->isActive = value;
00772     if ( d->isActive )
00773     {
00774         updateChatState( Normal );
00775         emit( activated( static_cast<KopeteView*>(this) ) );
00776     }
00777 }
00778 
00779 void ChatView::slotRemoteTypingTimeout()
00780 {
00781     // Remove the topmost timer from the list. Why does QPtrDict use void* keys and not typed keys? *sigh*
00782     // FIXME: should remove the right item, not the topmost
00783     if ( !m_remoteTypingMap.isEmpty() )
00784         remoteTyping( m_remoteTypingMap.begin().key(), false );
00785 }
00786 
00787 void ChatView::dragEnterEvent ( QDragEnterEvent * event )
00788 {
00789     if( event->provides( "kopete/x-contact" ) )
00790     {
00791         QStringList lst = QString::fromUtf8(event->encodedData ( "kopete/x-contact" )).split( QChar( 0xE000 ) , QString::SkipEmptyParts );
00792         if(m_manager->mayInvite() && m_manager->protocol()->pluginId() == lst[0] && m_manager->account()->accountId() == lst[1])
00793         {
00794             QString contact=lst[2];
00795 
00796             bool found =false;
00797             foreach(Kopete::Contact * cts, m_manager->members())
00798             {
00799                 if(cts->contactId() == contact)
00800                 {
00801                     found=true;
00802                     break;
00803                 }
00804             }
00805 
00806             if(!found && contact != m_manager->myself()->contactId())
00807                 event->accept();
00808         }
00809     }
00810     else if( event->provides( "kopete/x-metacontact" ) )
00811     {
00812         QString metacontactID=QString::fromUtf8(event->encodedData ( "kopete/x-metacontact" ));
00813         Kopete::MetaContact *parent = Kopete::ContactList::self()->metaContact(metacontactID);
00814         if ( parent && m_manager->mayInvite() )
00815         {
00816             foreach ( Kopete::Contact * candidate, parent->contacts() )
00817             {
00818                 if( candidate && candidate->account() == m_manager->account() && candidate->isOnline())
00819                 {
00820                     if( candidate != m_manager->myself() &&  !m_manager->members().contains( candidate ) )
00821                         event->accept();
00822                 }
00823             }
00824         }
00825     }
00826     // make sure it doesn't come from the current chat view - then it's an emoticon
00827     else if ( event->provides( "text/uri-list" ) && m_manager->members().count() == 1 &&
00828                  ( event->source() != (QWidget*)m_messagePart->view()->viewport() ) )
00829     {
00830         Kopete::ContactPtrList members = m_manager->members();
00831         Kopete::Contact *contact = members.first();
00832         if ( contact && contact->canAcceptFiles() )
00833             event->accept();
00834     }
00835     else
00836         QWidget::dragEnterEvent(event);
00837 }
00838 
00839 void ChatView::dropEvent ( QDropEvent * event )
00840 {
00841     Kopete::ContactPtrList contacts;
00842 
00843     if( event->provides( "kopete/x-contact" ) )
00844     {
00845         QStringList lst = QString::fromUtf8(event->encodedData ( "kopete/x-contact" )).split( QChar( 0xE000 ) , QString::SkipEmptyParts );
00846         if(m_manager->mayInvite() && m_manager->protocol()->pluginId() == lst[0] && m_manager->account()->accountId() == lst[1])
00847         {
00848             QString contact=lst[2];
00849 
00850             bool found =false;
00851             foreach ( Kopete::Contact * candidate, m_manager->members() )
00852             {
00853                 if(candidate->contactId() == contact)
00854                 {
00855                     found=true;
00856                     break;
00857                 }
00858             }
00859             if(!found && contact != m_manager->myself()->contactId())
00860                 m_manager->inviteContact(contact);
00861         }
00862     }
00863     else if( event->provides( "kopete/x-metacontact" ) )
00864     {
00865         QString metacontactID=QString::fromUtf8(event->encodedData ( "kopete/x-metacontact" ));
00866         Kopete::MetaContact *parent = Kopete::ContactList::self()->metaContact(metacontactID);
00867         if ( parent && m_manager->mayInvite() )
00868         {
00869             foreach ( Kopete::Contact * candidate, parent->contacts() )
00870             {
00871                 if( candidate && candidate->account() == m_manager->account() && candidate->isOnline())
00872                 {
00873                     if( candidate != m_manager->myself() &&  !m_manager->members().contains( candidate ) )
00874                         m_manager->inviteContact(candidate->contactId());
00875                 }
00876             }
00877         }
00878     }
00879     else if ( event->provides( "text/uri-list" ) && m_manager->members().count() == 1 )
00880     {
00881         Kopete::ContactPtrList members = m_manager->members();
00882         Kopete::Contact *contact = members.first();
00883 
00884         if ( !contact || !contact->canAcceptFiles() || !Q3UriDrag::canDecode( event ) )
00885         {
00886             event->ignore();
00887             return;
00888         }
00889 
00890         KUrl::List urlList = KUrl::List::fromMimeData( event->mimeData() );
00891 
00892         for ( KUrl::List::Iterator it = urlList.begin(); it != urlList.end(); ++it )
00893         {
00894             if ( (*it).isLocalFile() )
00895             { //send a file
00896                 contact->sendFile( *it );
00897             }
00898             else
00899             { //this is a URL, send the URL in a message
00900                 addText( (*it).url() );
00901             }
00902         }
00903         event->accept();
00904         return;
00905     }
00906     else
00907         QWidget::dropEvent(event);
00908 
00909 }
00910 
00911 void ChatView::registerContextMenuHandler( QObject *target, const char* slot )
00912 {
00913     connect( m_messagePart,
00914         SIGNAL( contextMenuEvent( Kopete::Message &, const QString &, KMenu * ) ),
00915         target,
00916         slot
00917     );
00918 }
00919 
00920 void ChatView::registerTooltipHandler( QObject *target, const char* slot )
00921 {
00922     connect( m_messagePart,
00923         SIGNAL( tooltipEvent( Kopete::Message &, const QString &, QString & ) ),
00924         target,
00925         slot
00926     );
00927 }
00928 
00929 #include "chatview.moc"
00930 
00931 // vim: set noet ts=4 sts=4 sw=4:
00932 

kopete/kopete

Skip menu "kopete/kopete"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdenetwork

Skip menu "kdenetwork"
  • kget
  • kopete
  •   kopete
  •   libkopete
  •       libpapillon
  • krfb
Generated for kdenetwork by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal